Root/
1 | /* |
2 | * Copyright (C) ST-Ericsson SA 2010 |
3 | * |
4 | * License Terms: GNU General Public License v2 |
5 | * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson |
6 | * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson |
7 | * |
8 | * UX500 common part of Power domain regulators |
9 | */ |
10 | |
11 | #include <linux/kernel.h> |
12 | #include <linux/err.h> |
13 | #include <linux/regulator/driver.h> |
14 | #include <linux/debugfs.h> |
15 | #include <linux/seq_file.h> |
16 | #include <linux/slab.h> |
17 | #include <linux/module.h> |
18 | |
19 | #include "dbx500-prcmu.h" |
20 | |
21 | /* |
22 | * power state reference count |
23 | */ |
24 | static int power_state_active_cnt; /* will initialize to zero */ |
25 | static DEFINE_SPINLOCK(power_state_active_lock); |
26 | |
27 | int power_state_active_get(void) |
28 | { |
29 | unsigned long flags; |
30 | int cnt; |
31 | |
32 | spin_lock_irqsave(&power_state_active_lock, flags); |
33 | cnt = power_state_active_cnt; |
34 | spin_unlock_irqrestore(&power_state_active_lock, flags); |
35 | |
36 | return cnt; |
37 | } |
38 | |
39 | void power_state_active_enable(void) |
40 | { |
41 | unsigned long flags; |
42 | |
43 | spin_lock_irqsave(&power_state_active_lock, flags); |
44 | power_state_active_cnt++; |
45 | spin_unlock_irqrestore(&power_state_active_lock, flags); |
46 | } |
47 | |
48 | int power_state_active_disable(void) |
49 | { |
50 | int ret = 0; |
51 | unsigned long flags; |
52 | |
53 | spin_lock_irqsave(&power_state_active_lock, flags); |
54 | if (power_state_active_cnt <= 0) { |
55 | pr_err("power state: unbalanced enable/disable calls\n"); |
56 | ret = -EINVAL; |
57 | goto out; |
58 | } |
59 | |
60 | power_state_active_cnt--; |
61 | out: |
62 | spin_unlock_irqrestore(&power_state_active_lock, flags); |
63 | return ret; |
64 | } |
65 | |
66 | #ifdef CONFIG_REGULATOR_DEBUG |
67 | |
68 | static struct ux500_regulator_debug { |
69 | struct dentry *dir; |
70 | struct dentry *status_file; |
71 | struct dentry *power_state_cnt_file; |
72 | struct dbx500_regulator_info *regulator_array; |
73 | int num_regulators; |
74 | u8 *state_before_suspend; |
75 | u8 *state_after_suspend; |
76 | } rdebug; |
77 | |
78 | void ux500_regulator_suspend_debug(void) |
79 | { |
80 | int i; |
81 | for (i = 0; i < rdebug.num_regulators; i++) |
82 | rdebug.state_before_suspend[i] = |
83 | rdebug.regulator_array[i].is_enabled; |
84 | } |
85 | |
86 | void ux500_regulator_resume_debug(void) |
87 | { |
88 | int i; |
89 | for (i = 0; i < rdebug.num_regulators; i++) |
90 | rdebug.state_after_suspend[i] = |
91 | rdebug.regulator_array[i].is_enabled; |
92 | } |
93 | |
94 | static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p) |
95 | { |
96 | struct device *dev = s->private; |
97 | int err; |
98 | |
99 | /* print power state count */ |
100 | err = seq_printf(s, "ux500-regulator power state count: %i\n", |
101 | power_state_active_get()); |
102 | if (err < 0) |
103 | dev_err(dev, "seq_printf overflow\n"); |
104 | |
105 | return 0; |
106 | } |
107 | |
108 | static int ux500_regulator_power_state_cnt_open(struct inode *inode, |
109 | struct file *file) |
110 | { |
111 | return single_open(file, ux500_regulator_power_state_cnt_print, |
112 | inode->i_private); |
113 | } |
114 | |
115 | static const struct file_operations ux500_regulator_power_state_cnt_fops = { |
116 | .open = ux500_regulator_power_state_cnt_open, |
117 | .read = seq_read, |
118 | .llseek = seq_lseek, |
119 | .release = single_release, |
120 | .owner = THIS_MODULE, |
121 | }; |
122 | |
123 | static int ux500_regulator_status_print(struct seq_file *s, void *p) |
124 | { |
125 | struct device *dev = s->private; |
126 | int err; |
127 | int i; |
128 | |
129 | /* print dump header */ |
130 | err = seq_printf(s, "ux500-regulator status:\n"); |
131 | if (err < 0) |
132 | dev_err(dev, "seq_printf overflow\n"); |
133 | |
134 | err = seq_printf(s, "%31s : %8s : %8s\n", "current", |
135 | "before", "after"); |
136 | if (err < 0) |
137 | dev_err(dev, "seq_printf overflow\n"); |
138 | |
139 | for (i = 0; i < rdebug.num_regulators; i++) { |
140 | struct dbx500_regulator_info *info; |
141 | /* Access per-regulator data */ |
142 | info = &rdebug.regulator_array[i]; |
143 | |
144 | /* print status */ |
145 | err = seq_printf(s, "%20s : %8s : %8s : %8s\n", info->desc.name, |
146 | info->is_enabled ? "enabled" : "disabled", |
147 | rdebug.state_before_suspend[i] ? "enabled" : "disabled", |
148 | rdebug.state_after_suspend[i] ? "enabled" : "disabled"); |
149 | if (err < 0) |
150 | dev_err(dev, "seq_printf overflow\n"); |
151 | } |
152 | |
153 | return 0; |
154 | } |
155 | |
156 | static int ux500_regulator_status_open(struct inode *inode, struct file *file) |
157 | { |
158 | return single_open(file, ux500_regulator_status_print, |
159 | inode->i_private); |
160 | } |
161 | |
162 | static const struct file_operations ux500_regulator_status_fops = { |
163 | .open = ux500_regulator_status_open, |
164 | .read = seq_read, |
165 | .llseek = seq_lseek, |
166 | .release = single_release, |
167 | .owner = THIS_MODULE, |
168 | }; |
169 | |
170 | int __attribute__((weak)) dbx500_regulator_testcase( |
171 | struct dbx500_regulator_info *regulator_info, |
172 | int num_regulators) |
173 | { |
174 | return 0; |
175 | } |
176 | |
177 | int |
178 | ux500_regulator_debug_init(struct platform_device *pdev, |
179 | struct dbx500_regulator_info *regulator_info, |
180 | int num_regulators) |
181 | { |
182 | /* create directory */ |
183 | rdebug.dir = debugfs_create_dir("ux500-regulator", NULL); |
184 | if (!rdebug.dir) |
185 | goto exit_no_debugfs; |
186 | |
187 | /* create "status" file */ |
188 | rdebug.status_file = debugfs_create_file("status", |
189 | S_IRUGO, rdebug.dir, &pdev->dev, |
190 | &ux500_regulator_status_fops); |
191 | if (!rdebug.status_file) |
192 | goto exit_destroy_dir; |
193 | |
194 | /* create "power-state-count" file */ |
195 | rdebug.power_state_cnt_file = debugfs_create_file("power-state-count", |
196 | S_IRUGO, rdebug.dir, &pdev->dev, |
197 | &ux500_regulator_power_state_cnt_fops); |
198 | if (!rdebug.power_state_cnt_file) |
199 | goto exit_destroy_status; |
200 | |
201 | rdebug.regulator_array = regulator_info; |
202 | rdebug.num_regulators = num_regulators; |
203 | |
204 | rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL); |
205 | if (!rdebug.state_before_suspend) { |
206 | dev_err(&pdev->dev, |
207 | "could not allocate memory for saving state\n"); |
208 | goto exit_destroy_power_state; |
209 | } |
210 | |
211 | rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL); |
212 | if (!rdebug.state_after_suspend) { |
213 | dev_err(&pdev->dev, |
214 | "could not allocate memory for saving state\n"); |
215 | goto exit_free; |
216 | } |
217 | |
218 | dbx500_regulator_testcase(regulator_info, num_regulators); |
219 | return 0; |
220 | |
221 | exit_free: |
222 | kfree(rdebug.state_before_suspend); |
223 | exit_destroy_power_state: |
224 | debugfs_remove(rdebug.power_state_cnt_file); |
225 | exit_destroy_status: |
226 | debugfs_remove(rdebug.status_file); |
227 | exit_destroy_dir: |
228 | debugfs_remove(rdebug.dir); |
229 | exit_no_debugfs: |
230 | dev_err(&pdev->dev, "failed to create debugfs entries.\n"); |
231 | return -ENOMEM; |
232 | } |
233 | |
234 | int ux500_regulator_debug_exit(void) |
235 | { |
236 | debugfs_remove_recursive(rdebug.dir); |
237 | kfree(rdebug.state_after_suspend); |
238 | kfree(rdebug.state_before_suspend); |
239 | |
240 | return 0; |
241 | } |
242 | #endif |
243 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9