]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - arch/sh/kernel/cpu/hwblk.c
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[mirror_ubuntu-bionic-kernel.git] / arch / sh / kernel / cpu / hwblk.c
CommitLineData
79714acb
MD
1#include <linux/clk.h>
2#include <linux/compiler.h>
79714acb
MD
3#include <linux/io.h>
4#include <linux/spinlock.h>
5#include <asm/suspend.h>
6#include <asm/hwblk.h>
7#include <asm/clock.h>
8
9static DEFINE_SPINLOCK(hwblk_lock);
10
0f8ee187
MD
11static void hwblk_area_mod_cnt(struct hwblk_info *info,
12 int area, int counter, int value, int goal)
79714acb
MD
13{
14 struct hwblk_area *hap = info->areas + area;
15
0f8ee187
MD
16 hap->cnt[counter] += value;
17
18 if (hap->cnt[counter] != goal)
19 return;
20
21 if (hap->flags & HWBLK_AREA_FLAG_PARENT)
22 hwblk_area_mod_cnt(info, hap->parent, counter, value, goal);
79714acb
MD
23}
24
0f8ee187
MD
25
26static int __hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
27 int counter, int value, int goal)
79714acb 28{
0f8ee187
MD
29 struct hwblk *hp = info->hwblks + hwblk;
30
31 hp->cnt[counter] += value;
32 if (hp->cnt[counter] == goal)
33 hwblk_area_mod_cnt(info, hp->area, counter, value, goal);
79714acb 34
0f8ee187 35 return hp->cnt[counter];
79714acb
MD
36}
37
0f8ee187
MD
38static void hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
39 int counter, int value, int goal)
40{
41 unsigned long flags;
42
43 spin_lock_irqsave(&hwblk_lock, flags);
44 __hwblk_mod_cnt(info, hwblk, counter, value, goal);
45 spin_unlock_irqrestore(&hwblk_lock, flags);
46}
47
48void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int counter)
49{
50 hwblk_mod_cnt(info, hwblk, counter, 1, 1);
51}
52
53void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter)
54{
55 hwblk_mod_cnt(info, hwblk, counter, -1, 0);
56}
57
58void hwblk_enable(struct hwblk_info *info, int hwblk)
79714acb
MD
59{
60 struct hwblk *hp = info->hwblks + hwblk;
61 unsigned long tmp;
62 unsigned long flags;
0f8ee187 63 int ret;
79714acb
MD
64
65 spin_lock_irqsave(&hwblk_lock, flags);
66
0f8ee187
MD
67 ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, 1, 1);
68 if (ret == 1) {
79714acb
MD
69 tmp = __raw_readl(hp->mstp);
70 tmp &= ~(1 << hp->bit);
71 __raw_writel(tmp, hp->mstp);
72 }
73
74 spin_unlock_irqrestore(&hwblk_lock, flags);
75}
76
0f8ee187 77void hwblk_disable(struct hwblk_info *info, int hwblk)
79714acb
MD
78{
79 struct hwblk *hp = info->hwblks + hwblk;
80 unsigned long tmp;
81 unsigned long flags;
0f8ee187 82 int ret;
79714acb
MD
83
84 spin_lock_irqsave(&hwblk_lock, flags);
85
0f8ee187
MD
86 ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, -1, 0);
87 if (ret == 0) {
79714acb
MD
88 tmp = __raw_readl(hp->mstp);
89 tmp |= 1 << hp->bit;
90 __raw_writel(tmp, hp->mstp);
91 }
79714acb
MD
92
93 spin_unlock_irqrestore(&hwblk_lock, flags);
94}
95
0f8ee187 96struct hwblk_info *hwblk_info;
79714acb
MD
97
98int __init hwblk_register(struct hwblk_info *info)
99{
100 hwblk_info = info;
101 return 0;
102}
103
104int __init __weak arch_hwblk_init(void)
105{
106 return 0;
107}
108
109int __weak arch_hwblk_sleep_mode(void)
110{
111 return SUSP_SH_SLEEP;
112}
113
114int __init hwblk_init(void)
115{
116 return arch_hwblk_init();
117}
118
119/* allow clocks to enable and disable hardware blocks */
120static int sh_hwblk_clk_enable(struct clk *clk)
121{
122 if (!hwblk_info)
123 return -ENOENT;
124
125 hwblk_enable(hwblk_info, clk->arch_flags);
126 return 0;
127}
128
129static void sh_hwblk_clk_disable(struct clk *clk)
130{
131 if (hwblk_info)
132 hwblk_disable(hwblk_info, clk->arch_flags);
133}
134
135static struct clk_ops sh_hwblk_clk_ops = {
136 .enable = sh_hwblk_clk_enable,
137 .disable = sh_hwblk_clk_disable,
138 .recalc = followparent_recalc,
139};
140
141int __init sh_hwblk_clk_register(struct clk *clks, int nr)
142{
143 struct clk *clkp;
144 int ret = 0;
145 int k;
146
147 for (k = 0; !ret && (k < nr); k++) {
148 clkp = clks + k;
149 clkp->ops = &sh_hwblk_clk_ops;
150 ret |= clk_register(clkp);
151 }
152
153 return ret;
154}