sh: Add support for multiple hwblk counters
authorMagnus Damm <damm@igel.co.jp>
Fri, 17 Jul 2009 14:24:55 +0000 (14:24 +0000)
committerPaul Mundt <lethal@linux-sh.org>
Sun, 19 Jul 2009 19:23:39 +0000 (04:23 +0900)
Extend the SuperH hwblk code to support more than one counter.
Contains ground work for the future Runtime PM implementation.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/include/asm/hwblk.h
arch/sh/kernel/cpu/hwblk.c
arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c

index 51a46f4966393afc643a4a6dc17e39c9d238dd3b..c01d72cb6757ec68374086b9ebafc41eee6bfafb 100644 (file)
@@ -4,6 +4,9 @@
 #include <asm/clock.h>
 #include <asm/io.h>
 
+#define HWBLK_CNT_USAGE 0
+#define HWBLK_CNT_NR 1
+
 #define HWBLK_AREA_FLAG_PARENT (1 << 0) /* valid parent */
 
 #define HWBLK_AREA(_flags, _parent)            \
@@ -13,7 +16,7 @@
 }
 
 struct hwblk_area {
-       unsigned long cnt;
+       int cnt[HWBLK_CNT_NR];
        unsigned char parent;
        unsigned char flags;
 };
@@ -29,7 +32,7 @@ struct hwblk {
        void __iomem *mstp;
        unsigned char bit;
        unsigned char area;
-       unsigned long cnt;
+       int cnt[HWBLK_CNT_NR];
 };
 
 struct hwblk_info {
@@ -46,6 +49,12 @@ int arch_hwblk_sleep_mode(void);
 int hwblk_register(struct hwblk_info *info);
 int hwblk_init(void);
 
+void hwblk_enable(struct hwblk_info *info, int hwblk);
+void hwblk_disable(struct hwblk_info *info, int hwblk);
+
+void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int cnt);
+void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int cnt);
+
 /* allow clocks to enable and disable hardware blocks */
 #define SH_HWBLK_CLK(_name, _id, _parent, _hwblk, _flags)      \
 {                                                      \
index 7c3a73deff247398c74e8fafaf1b27f82a7b0ca2..c0ad7d46e7848687b5103ad826bb1a92b1a284de 100644 (file)
@@ -9,38 +9,64 @@
 
 static DEFINE_SPINLOCK(hwblk_lock);
 
-static void hwblk_area_inc(struct hwblk_info *info, int area)
+static void hwblk_area_mod_cnt(struct hwblk_info *info,
+                              int area, int counter, int value, int goal)
 {
        struct hwblk_area *hap = info->areas + area;
 
-       hap->cnt++;
-       if (hap->cnt == 1)
-               if (hap->flags & HWBLK_AREA_FLAG_PARENT)
-                       hwblk_area_inc(info, hap->parent);
+       hap->cnt[counter] += value;
+
+       if (hap->cnt[counter] != goal)
+               return;
+
+       if (hap->flags & HWBLK_AREA_FLAG_PARENT)
+               hwblk_area_mod_cnt(info, hap->parent, counter, value, goal);
 }
 
-static void hwblk_area_dec(struct hwblk_info *info, int area)
+
+static int __hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
+                         int counter, int value, int goal)
 {
-       struct hwblk_area *hap = info->areas + area;
+       struct hwblk *hp = info->hwblks + hwblk;
+
+       hp->cnt[counter] += value;
+       if (hp->cnt[counter] == goal)
+               hwblk_area_mod_cnt(info, hp->area, counter, value, goal);
 
-       if (hap->cnt == 1)
-               if (hap->flags & HWBLK_AREA_FLAG_PARENT)
-                       hwblk_area_dec(info, hap->parent);
-       hap->cnt--;
+       return hp->cnt[counter];
 }
 
-static void hwblk_enable(struct hwblk_info *info, int hwblk)
+static void hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
+                         int counter, int value, int goal)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hwblk_lock, flags);
+       __hwblk_mod_cnt(info, hwblk, counter, value, goal);
+       spin_unlock_irqrestore(&hwblk_lock, flags);
+}
+
+void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int counter)
+{
+       hwblk_mod_cnt(info, hwblk, counter, 1, 1);
+}
+
+void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter)
+{
+       hwblk_mod_cnt(info, hwblk, counter, -1, 0);
+}
+
+void hwblk_enable(struct hwblk_info *info, int hwblk)
 {
        struct hwblk *hp = info->hwblks + hwblk;
        unsigned long tmp;
        unsigned long flags;
+       int ret;
 
        spin_lock_irqsave(&hwblk_lock, flags);
 
-       hp->cnt++;
-       if (hp->cnt == 1) {
-               hwblk_area_inc(info, hp->area);
-
+       ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, 1, 1);
+       if (ret == 1) {
                tmp = __raw_readl(hp->mstp);
                tmp &= ~(1 << hp->bit);
                __raw_writel(tmp, hp->mstp);
@@ -49,27 +75,26 @@ static void hwblk_enable(struct hwblk_info *info, int hwblk)
        spin_unlock_irqrestore(&hwblk_lock, flags);
 }
 
-static void hwblk_disable(struct hwblk_info *info, int hwblk)
+void hwblk_disable(struct hwblk_info *info, int hwblk)
 {
        struct hwblk *hp = info->hwblks + hwblk;
        unsigned long tmp;
        unsigned long flags;
+       int ret;
 
        spin_lock_irqsave(&hwblk_lock, flags);
 
-       if (hp->cnt == 1) {
-               hwblk_area_dec(info, hp->area);
-
+       ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, -1, 0);
+       if (ret == 0) {
                tmp = __raw_readl(hp->mstp);
                tmp |= 1 << hp->bit;
                __raw_writel(tmp, hp->mstp);
        }
-       hp->cnt--;
 
        spin_unlock_irqrestore(&hwblk_lock, flags);
 }
 
-static struct hwblk_info *hwblk_info;
+struct hwblk_info *hwblk_info;
 
 int __init hwblk_register(struct hwblk_info *info)
 {
index 00a1c02d82b1f2be53850afc864e4f0eb7fc77b1..a288b5d9234190fa234a79d6e783ebaca2076564 100644 (file)
@@ -91,10 +91,10 @@ static struct hwblk_info sh7722_hwblk_info = {
 
 int arch_hwblk_sleep_mode(void)
 {
-       if (!sh7722_hwblk_area[CORE_AREA].cnt)
+       if (!sh7722_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE])
                return SUSP_SH_STANDBY | SUSP_SH_SF;
 
-       if (!sh7722_hwblk_area[CORE_AREA_BM].cnt)
+       if (!sh7722_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE])
                return SUSP_SH_SLEEP | SUSP_SH_SF;
 
        return SUSP_SH_SLEEP;