2 #include <linux/compiler.h>
3 #include <linux/slab.h>
5 #include <linux/spinlock.h>
6 #include <asm/suspend.h>
10 static DEFINE_SPINLOCK(hwblk_lock);
12 static void hwblk_area_mod_cnt(struct hwblk_info *info,
13 int area, int counter, int value, int goal)
15 struct hwblk_area *hap = info->areas + area;
17 hap->cnt[counter] += value;
19 if (hap->cnt[counter] != goal)
22 if (hap->flags & HWBLK_AREA_FLAG_PARENT)
23 hwblk_area_mod_cnt(info, hap->parent, counter, value, goal);
27 static int __hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
28 int counter, int value, int goal)
30 struct hwblk *hp = info->hwblks + hwblk;
32 hp->cnt[counter] += value;
33 if (hp->cnt[counter] == goal)
34 hwblk_area_mod_cnt(info, hp->area, counter, value, goal);
36 return hp->cnt[counter];
39 static void hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
40 int counter, int value, int goal)
44 spin_lock_irqsave(&hwblk_lock, flags);
45 __hwblk_mod_cnt(info, hwblk, counter, value, goal);
46 spin_unlock_irqrestore(&hwblk_lock, flags);
49 void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int counter)
51 hwblk_mod_cnt(info, hwblk, counter, 1, 1);
54 void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter)
56 hwblk_mod_cnt(info, hwblk, counter, -1, 0);
59 void hwblk_enable(struct hwblk_info *info, int hwblk)
61 struct hwblk *hp = info->hwblks + hwblk;
66 spin_lock_irqsave(&hwblk_lock, flags);
68 ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, 1, 1);
70 tmp = __raw_readl(hp->mstp);
71 tmp &= ~(1 << hp->bit);
72 __raw_writel(tmp, hp->mstp);
75 spin_unlock_irqrestore(&hwblk_lock, flags);
78 void hwblk_disable(struct hwblk_info *info, int hwblk)
80 struct hwblk *hp = info->hwblks + hwblk;
85 spin_lock_irqsave(&hwblk_lock, flags);
87 ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, -1, 0);
89 tmp = __raw_readl(hp->mstp);
91 __raw_writel(tmp, hp->mstp);
94 spin_unlock_irqrestore(&hwblk_lock, flags);
97 struct hwblk_info *hwblk_info;
99 int __init hwblk_register(struct hwblk_info *info)
105 int __init __weak arch_hwblk_init(void)
110 int __weak arch_hwblk_sleep_mode(void)
112 return SUSP_SH_SLEEP;
115 int __init hwblk_init(void)
117 return arch_hwblk_init();
120 /* allow clocks to enable and disable hardware blocks */
121 static int sh_hwblk_clk_enable(struct clk *clk)
126 hwblk_enable(hwblk_info, clk->arch_flags);
130 static void sh_hwblk_clk_disable(struct clk *clk)
133 hwblk_disable(hwblk_info, clk->arch_flags);
136 static struct clk_ops sh_hwblk_clk_ops = {
137 .enable = sh_hwblk_clk_enable,
138 .disable = sh_hwblk_clk_disable,
139 .recalc = followparent_recalc,
142 int __init sh_hwblk_clk_register(struct clk *clks, int nr)
148 for (k = 0; !ret && (k < nr); k++) {
150 clkp->ops = &sh_hwblk_clk_ops;
151 ret |= clk_register(clkp);