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
);