2 #include <linux/compiler.h>
4 #include <linux/spinlock.h>
5 #include <asm/suspend.h>
9 static DEFINE_SPINLOCK(hwblk_lock
);
11 static void hwblk_area_mod_cnt(struct hwblk_info
*info
,
12 int area
, int counter
, int value
, int goal
)
14 struct hwblk_area
*hap
= info
->areas
+ area
;
16 hap
->cnt
[counter
] += value
;
18 if (hap
->cnt
[counter
] != goal
)
21 if (hap
->flags
& HWBLK_AREA_FLAG_PARENT
)
22 hwblk_area_mod_cnt(info
, hap
->parent
, counter
, value
, goal
);
26 static int __hwblk_mod_cnt(struct hwblk_info
*info
, int hwblk
,
27 int counter
, int value
, int goal
)
29 struct hwblk
*hp
= info
->hwblks
+ hwblk
;
31 hp
->cnt
[counter
] += value
;
32 if (hp
->cnt
[counter
] == goal
)
33 hwblk_area_mod_cnt(info
, hp
->area
, counter
, value
, goal
);
35 return hp
->cnt
[counter
];
38 static void hwblk_mod_cnt(struct hwblk_info
*info
, int hwblk
,
39 int counter
, int value
, int goal
)
43 spin_lock_irqsave(&hwblk_lock
, flags
);
44 __hwblk_mod_cnt(info
, hwblk
, counter
, value
, goal
);
45 spin_unlock_irqrestore(&hwblk_lock
, flags
);
48 void hwblk_cnt_inc(struct hwblk_info
*info
, int hwblk
, int counter
)
50 hwblk_mod_cnt(info
, hwblk
, counter
, 1, 1);
53 void hwblk_cnt_dec(struct hwblk_info
*info
, int hwblk
, int counter
)
55 hwblk_mod_cnt(info
, hwblk
, counter
, -1, 0);
58 void hwblk_enable(struct hwblk_info
*info
, int hwblk
)
60 struct hwblk
*hp
= info
->hwblks
+ hwblk
;
65 spin_lock_irqsave(&hwblk_lock
, flags
);
67 ret
= __hwblk_mod_cnt(info
, hwblk
, HWBLK_CNT_USAGE
, 1, 1);
69 tmp
= __raw_readl(hp
->mstp
);
70 tmp
&= ~(1 << hp
->bit
);
71 __raw_writel(tmp
, hp
->mstp
);
74 spin_unlock_irqrestore(&hwblk_lock
, flags
);
77 void hwblk_disable(struct hwblk_info
*info
, int hwblk
)
79 struct hwblk
*hp
= info
->hwblks
+ hwblk
;
84 spin_lock_irqsave(&hwblk_lock
, flags
);
86 ret
= __hwblk_mod_cnt(info
, hwblk
, HWBLK_CNT_USAGE
, -1, 0);
88 tmp
= __raw_readl(hp
->mstp
);
90 __raw_writel(tmp
, hp
->mstp
);
93 spin_unlock_irqrestore(&hwblk_lock
, flags
);
96 struct hwblk_info
*hwblk_info
;
98 int __init
hwblk_register(struct hwblk_info
*info
)
104 int __init __weak
arch_hwblk_init(void)
109 int __weak
arch_hwblk_sleep_mode(void)
111 return SUSP_SH_SLEEP
;
114 int __init
hwblk_init(void)
116 return arch_hwblk_init();
119 /* allow clocks to enable and disable hardware blocks */
120 static int sh_hwblk_clk_enable(struct clk
*clk
)
125 hwblk_enable(hwblk_info
, clk
->arch_flags
);
129 static void sh_hwblk_clk_disable(struct clk
*clk
)
132 hwblk_disable(hwblk_info
, clk
->arch_flags
);
135 static struct clk_ops sh_hwblk_clk_ops
= {
136 .enable
= sh_hwblk_clk_enable
,
137 .disable
= sh_hwblk_clk_disable
,
138 .recalc
= followparent_recalc
,
141 int __init
sh_hwblk_clk_register(struct clk
*clks
, int nr
)
147 for (k
= 0; !ret
&& (k
< nr
); k
++) {
150 /* skip over clocks using hwblk 0 (HWBLK_UNKNOWN) */
151 if (!clkp
->arch_flags
)
154 clkp
->ops
= &sh_hwblk_clk_ops
;
155 ret
|= clk_register(clkp
);