diff options
author | Mattias Wallin <mattias.wallin@stericsson.com> | 2010-09-13 10:05:04 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2010-10-28 18:29:25 -0400 |
commit | 5814fc35e1837e30b82c3d57f41310d4c4c52824 (patch) | |
tree | a1af93694c140cb5bf54aff2a194fc084d12d7fb /drivers/mfd | |
parent | 38b340527aa44bb8d1b88ef1e5a4e26b27695c2b (diff) |
mfd: AB8500 debugfs
This patch adds the possibility to read and write registers
via the debug_fs. It also adds ranges of registers sorted by bank
which makes it possible to read all defined registers in a bank.
Signed-off-by: Mattias Wallin <mattias.wallin@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/Kconfig | 8 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/ab8500-core.c | 5 | ||||
-rw-r--r-- | drivers/mfd/ab8500-debugfs.c | 652 |
4 files changed, 666 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ec0af47a9058..e310cb26f520 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -483,6 +483,14 @@ config AB8500_CORE | |||
483 | read/write functions for the devices to get access to this chip. | 483 | read/write functions for the devices to get access to this chip. |
484 | This chip embeds various other multimedia funtionalities as well. | 484 | This chip embeds various other multimedia funtionalities as well. |
485 | 485 | ||
486 | config AB8500_DEBUG | ||
487 | bool "Enable debug info via debugfs" | ||
488 | depends on AB8500_CORE && DEBUG_FS | ||
489 | default y if DEBUG_FS | ||
490 | help | ||
491 | Select this option if you want debug information using the debug | ||
492 | filesystem, debugfs. | ||
493 | |||
486 | config AB3550_CORE | 494 | config AB3550_CORE |
487 | bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions" | 495 | bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions" |
488 | select MFD_CORE | 496 | select MFD_CORE |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index b1ad74da2351..f771c52c40db 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -69,6 +69,7 @@ obj-$(CONFIG_AB3100_CORE) += ab3100-core.o | |||
69 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o | 69 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o |
70 | obj-$(CONFIG_AB3550_CORE) += ab3550-core.o | 70 | obj-$(CONFIG_AB3550_CORE) += ab3550-core.o |
71 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o | 71 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o |
72 | obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o | ||
72 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o | 73 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o |
73 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o | 74 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o |
74 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o | 75 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o |
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 4132b5395fc4..dbe1c93c1af3 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
@@ -394,6 +394,11 @@ static struct resource ab8500_poweronkey_db_resources[] = { | |||
394 | }; | 394 | }; |
395 | 395 | ||
396 | static struct mfd_cell ab8500_devs[] = { | 396 | static struct mfd_cell ab8500_devs[] = { |
397 | #ifdef CONFIG_DEBUG_FS | ||
398 | { | ||
399 | .name = "ab8500-debug", | ||
400 | }, | ||
401 | #endif | ||
397 | { | 402 | { |
398 | .name = "ab8500-gpadc", | 403 | .name = "ab8500-gpadc", |
399 | .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), | 404 | .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), |
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c new file mode 100644 index 000000000000..8d1e05a39815 --- /dev/null +++ b/drivers/mfd/ab8500-debugfs.c | |||
@@ -0,0 +1,652 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson. | ||
5 | * License Terms: GNU General Public License v2 | ||
6 | */ | ||
7 | |||
8 | #include <linux/seq_file.h> | ||
9 | #include <linux/uaccess.h> | ||
10 | #include <linux/fs.h> | ||
11 | #include <linux/debugfs.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | |||
14 | #include <linux/mfd/abx500.h> | ||
15 | #include <linux/mfd/ab8500.h> | ||
16 | |||
17 | static u32 debug_bank; | ||
18 | static u32 debug_address; | ||
19 | |||
20 | /** | ||
21 | * struct ab8500_reg_range | ||
22 | * @first: the first address of the range | ||
23 | * @last: the last address of the range | ||
24 | * @perm: access permissions for the range | ||
25 | */ | ||
26 | struct ab8500_reg_range { | ||
27 | u8 first; | ||
28 | u8 last; | ||
29 | u8 perm; | ||
30 | }; | ||
31 | |||
32 | /** | ||
33 | * struct ab8500_i2c_ranges | ||
34 | * @num_ranges: the number of ranges in the list | ||
35 | * @bankid: bank identifier | ||
36 | * @range: the list of register ranges | ||
37 | */ | ||
38 | struct ab8500_i2c_ranges { | ||
39 | u8 num_ranges; | ||
40 | u8 bankid; | ||
41 | const struct ab8500_reg_range *range; | ||
42 | }; | ||
43 | |||
44 | #define AB8500_NAME_STRING "ab8500" | ||
45 | #define AB8500_NUM_BANKS 22 | ||
46 | |||
47 | #define AB8500_REV_REG 0x80 | ||
48 | |||
49 | static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = { | ||
50 | [0x0] = { | ||
51 | .num_ranges = 0, | ||
52 | .range = 0, | ||
53 | }, | ||
54 | [AB8500_SYS_CTRL1_BLOCK] = { | ||
55 | .num_ranges = 3, | ||
56 | .range = (struct ab8500_reg_range[]) { | ||
57 | { | ||
58 | .first = 0x00, | ||
59 | .last = 0x02, | ||
60 | }, | ||
61 | { | ||
62 | .first = 0x42, | ||
63 | .last = 0x42, | ||
64 | }, | ||
65 | { | ||
66 | .first = 0x80, | ||
67 | .last = 0x81, | ||
68 | }, | ||
69 | }, | ||
70 | }, | ||
71 | [AB8500_SYS_CTRL2_BLOCK] = { | ||
72 | .num_ranges = 4, | ||
73 | .range = (struct ab8500_reg_range[]) { | ||
74 | { | ||
75 | .first = 0x00, | ||
76 | .last = 0x0D, | ||
77 | }, | ||
78 | { | ||
79 | .first = 0x0F, | ||
80 | .last = 0x17, | ||
81 | }, | ||
82 | { | ||
83 | .first = 0x30, | ||
84 | .last = 0x30, | ||
85 | }, | ||
86 | { | ||
87 | .first = 0x32, | ||
88 | .last = 0x33, | ||
89 | }, | ||
90 | }, | ||
91 | }, | ||
92 | [AB8500_REGU_CTRL1] = { | ||
93 | .num_ranges = 3, | ||
94 | .range = (struct ab8500_reg_range[]) { | ||
95 | { | ||
96 | .first = 0x00, | ||
97 | .last = 0x00, | ||
98 | }, | ||
99 | { | ||
100 | .first = 0x03, | ||
101 | .last = 0x10, | ||
102 | }, | ||
103 | { | ||
104 | .first = 0x80, | ||
105 | .last = 0x84, | ||
106 | }, | ||
107 | }, | ||
108 | }, | ||
109 | [AB8500_REGU_CTRL2] = { | ||
110 | .num_ranges = 5, | ||
111 | .range = (struct ab8500_reg_range[]) { | ||
112 | { | ||
113 | .first = 0x00, | ||
114 | .last = 0x15, | ||
115 | }, | ||
116 | { | ||
117 | .first = 0x17, | ||
118 | .last = 0x19, | ||
119 | }, | ||
120 | { | ||
121 | .first = 0x1B, | ||
122 | .last = 0x1D, | ||
123 | }, | ||
124 | { | ||
125 | .first = 0x1F, | ||
126 | .last = 0x22, | ||
127 | }, | ||
128 | { | ||
129 | .first = 0x40, | ||
130 | .last = 0x44, | ||
131 | }, | ||
132 | /* 0x80-0x8B is SIM registers and should | ||
133 | * not be accessed from here */ | ||
134 | }, | ||
135 | }, | ||
136 | [AB8500_USB] = { | ||
137 | .num_ranges = 2, | ||
138 | .range = (struct ab8500_reg_range[]) { | ||
139 | { | ||
140 | .first = 0x80, | ||
141 | .last = 0x83, | ||
142 | }, | ||
143 | { | ||
144 | .first = 0x87, | ||
145 | .last = 0x8A, | ||
146 | }, | ||
147 | }, | ||
148 | }, | ||
149 | [AB8500_TVOUT] = { | ||
150 | .num_ranges = 9, | ||
151 | .range = (struct ab8500_reg_range[]) { | ||
152 | { | ||
153 | .first = 0x00, | ||
154 | .last = 0x12, | ||
155 | }, | ||
156 | { | ||
157 | .first = 0x15, | ||
158 | .last = 0x17, | ||
159 | }, | ||
160 | { | ||
161 | .first = 0x19, | ||
162 | .last = 0x21, | ||
163 | }, | ||
164 | { | ||
165 | .first = 0x27, | ||
166 | .last = 0x2C, | ||
167 | }, | ||
168 | { | ||
169 | .first = 0x41, | ||
170 | .last = 0x41, | ||
171 | }, | ||
172 | { | ||
173 | .first = 0x45, | ||
174 | .last = 0x5B, | ||
175 | }, | ||
176 | { | ||
177 | .first = 0x5D, | ||
178 | .last = 0x5D, | ||
179 | }, | ||
180 | { | ||
181 | .first = 0x69, | ||
182 | .last = 0x69, | ||
183 | }, | ||
184 | { | ||
185 | .first = 0x80, | ||
186 | .last = 0x81, | ||
187 | }, | ||
188 | }, | ||
189 | }, | ||
190 | [AB8500_DBI] = { | ||
191 | .num_ranges = 0, | ||
192 | .range = 0, | ||
193 | }, | ||
194 | [AB8500_ECI_AV_ACC] = { | ||
195 | .num_ranges = 1, | ||
196 | .range = (struct ab8500_reg_range[]) { | ||
197 | { | ||
198 | .first = 0x80, | ||
199 | .last = 0x82, | ||
200 | }, | ||
201 | }, | ||
202 | }, | ||
203 | [0x9] = { | ||
204 | .num_ranges = 0, | ||
205 | .range = 0, | ||
206 | }, | ||
207 | [AB8500_GPADC] = { | ||
208 | .num_ranges = 1, | ||
209 | .range = (struct ab8500_reg_range[]) { | ||
210 | { | ||
211 | .first = 0x00, | ||
212 | .last = 0x08, | ||
213 | }, | ||
214 | }, | ||
215 | }, | ||
216 | [AB8500_CHARGER] = { | ||
217 | .num_ranges = 8, | ||
218 | .range = (struct ab8500_reg_range[]) { | ||
219 | { | ||
220 | .first = 0x00, | ||
221 | .last = 0x03, | ||
222 | }, | ||
223 | { | ||
224 | .first = 0x05, | ||
225 | .last = 0x05, | ||
226 | }, | ||
227 | { | ||
228 | .first = 0x40, | ||
229 | .last = 0x40, | ||
230 | }, | ||
231 | { | ||
232 | .first = 0x42, | ||
233 | .last = 0x42, | ||
234 | }, | ||
235 | { | ||
236 | .first = 0x44, | ||
237 | .last = 0x44, | ||
238 | }, | ||
239 | { | ||
240 | .first = 0x50, | ||
241 | .last = 0x55, | ||
242 | }, | ||
243 | { | ||
244 | .first = 0x80, | ||
245 | .last = 0x82, | ||
246 | }, | ||
247 | { | ||
248 | .first = 0xC0, | ||
249 | .last = 0xC2, | ||
250 | }, | ||
251 | }, | ||
252 | }, | ||
253 | [AB8500_GAS_GAUGE] = { | ||
254 | .num_ranges = 3, | ||
255 | .range = (struct ab8500_reg_range[]) { | ||
256 | { | ||
257 | .first = 0x00, | ||
258 | .last = 0x00, | ||
259 | }, | ||
260 | { | ||
261 | .first = 0x07, | ||
262 | .last = 0x0A, | ||
263 | }, | ||
264 | { | ||
265 | .first = 0x10, | ||
266 | .last = 0x14, | ||
267 | }, | ||
268 | }, | ||
269 | }, | ||
270 | [AB8500_AUDIO] = { | ||
271 | .num_ranges = 1, | ||
272 | .range = (struct ab8500_reg_range[]) { | ||
273 | { | ||
274 | .first = 0x00, | ||
275 | .last = 0x6F, | ||
276 | }, | ||
277 | }, | ||
278 | }, | ||
279 | [AB8500_INTERRUPT] = { | ||
280 | .num_ranges = 0, | ||
281 | .range = 0, | ||
282 | }, | ||
283 | [AB8500_RTC] = { | ||
284 | .num_ranges = 1, | ||
285 | .range = (struct ab8500_reg_range[]) { | ||
286 | { | ||
287 | .first = 0x00, | ||
288 | .last = 0x0F, | ||
289 | }, | ||
290 | }, | ||
291 | }, | ||
292 | [AB8500_MISC] = { | ||
293 | .num_ranges = 8, | ||
294 | .range = (struct ab8500_reg_range[]) { | ||
295 | { | ||
296 | .first = 0x00, | ||
297 | .last = 0x05, | ||
298 | }, | ||
299 | { | ||
300 | .first = 0x10, | ||
301 | .last = 0x15, | ||
302 | }, | ||
303 | { | ||
304 | .first = 0x20, | ||
305 | .last = 0x25, | ||
306 | }, | ||
307 | { | ||
308 | .first = 0x30, | ||
309 | .last = 0x35, | ||
310 | }, | ||
311 | { | ||
312 | .first = 0x40, | ||
313 | .last = 0x45, | ||
314 | }, | ||
315 | { | ||
316 | .first = 0x50, | ||
317 | .last = 0x50, | ||
318 | }, | ||
319 | { | ||
320 | .first = 0x60, | ||
321 | .last = 0x67, | ||
322 | }, | ||
323 | { | ||
324 | .first = 0x80, | ||
325 | .last = 0x80, | ||
326 | }, | ||
327 | }, | ||
328 | }, | ||
329 | [0x11] = { | ||
330 | .num_ranges = 0, | ||
331 | .range = 0, | ||
332 | }, | ||
333 | [0x12] = { | ||
334 | .num_ranges = 0, | ||
335 | .range = 0, | ||
336 | }, | ||
337 | [0x13] = { | ||
338 | .num_ranges = 0, | ||
339 | .range = 0, | ||
340 | }, | ||
341 | [0x14] = { | ||
342 | .num_ranges = 0, | ||
343 | .range = 0, | ||
344 | }, | ||
345 | [AB8500_OTP_EMUL] = { | ||
346 | .num_ranges = 1, | ||
347 | .range = (struct ab8500_reg_range[]) { | ||
348 | { | ||
349 | .first = 0x01, | ||
350 | .last = 0x0F, | ||
351 | }, | ||
352 | }, | ||
353 | }, | ||
354 | }; | ||
355 | |||
356 | static int ab8500_registers_print(struct seq_file *s, void *p) | ||
357 | { | ||
358 | struct device *dev = s->private; | ||
359 | unsigned int i; | ||
360 | u32 bank = debug_bank; | ||
361 | |||
362 | seq_printf(s, AB8500_NAME_STRING " register values:\n"); | ||
363 | |||
364 | seq_printf(s, " bank %u:\n", bank); | ||
365 | for (i = 0; i < debug_ranges[bank].num_ranges; i++) { | ||
366 | u32 reg; | ||
367 | |||
368 | for (reg = debug_ranges[bank].range[i].first; | ||
369 | reg <= debug_ranges[bank].range[i].last; | ||
370 | reg++) { | ||
371 | u8 value; | ||
372 | int err; | ||
373 | |||
374 | err = abx500_get_register_interruptible(dev, | ||
375 | (u8)bank, (u8)reg, &value); | ||
376 | if (err < 0) { | ||
377 | dev_err(dev, "ab->read fail %d\n", err); | ||
378 | return err; | ||
379 | } | ||
380 | |||
381 | err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank, | ||
382 | reg, value); | ||
383 | if (err < 0) { | ||
384 | dev_err(dev, "seq_printf overflow\n"); | ||
385 | /* Error is not returned here since | ||
386 | * the output is wanted in any case */ | ||
387 | return 0; | ||
388 | } | ||
389 | } | ||
390 | } | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int ab8500_registers_open(struct inode *inode, struct file *file) | ||
395 | { | ||
396 | return single_open(file, ab8500_registers_print, inode->i_private); | ||
397 | } | ||
398 | |||
399 | static const struct file_operations ab8500_registers_fops = { | ||
400 | .open = ab8500_registers_open, | ||
401 | .read = seq_read, | ||
402 | .llseek = seq_lseek, | ||
403 | .release = single_release, | ||
404 | .owner = THIS_MODULE, | ||
405 | }; | ||
406 | |||
407 | static int ab8500_bank_print(struct seq_file *s, void *p) | ||
408 | { | ||
409 | return seq_printf(s, "%d\n", debug_bank); | ||
410 | } | ||
411 | |||
412 | static int ab8500_bank_open(struct inode *inode, struct file *file) | ||
413 | { | ||
414 | return single_open(file, ab8500_bank_print, inode->i_private); | ||
415 | } | ||
416 | |||
417 | static ssize_t ab8500_bank_write(struct file *file, | ||
418 | const char __user *user_buf, | ||
419 | size_t count, loff_t *ppos) | ||
420 | { | ||
421 | struct device *dev = ((struct seq_file *)(file->private_data))->private; | ||
422 | char buf[32]; | ||
423 | int buf_size; | ||
424 | unsigned long user_bank; | ||
425 | int err; | ||
426 | |||
427 | /* Get userspace string and assure termination */ | ||
428 | buf_size = min(count, (sizeof(buf) - 1)); | ||
429 | if (copy_from_user(buf, user_buf, buf_size)) | ||
430 | return -EFAULT; | ||
431 | buf[buf_size] = 0; | ||
432 | |||
433 | err = strict_strtoul(buf, 0, &user_bank); | ||
434 | if (err) | ||
435 | return -EINVAL; | ||
436 | |||
437 | if (user_bank >= AB8500_NUM_BANKS) { | ||
438 | dev_err(dev, "debugfs error input > number of banks\n"); | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | |||
442 | debug_bank = user_bank; | ||
443 | |||
444 | return buf_size; | ||
445 | } | ||
446 | |||
447 | static int ab8500_address_print(struct seq_file *s, void *p) | ||
448 | { | ||
449 | return seq_printf(s, "0x%02X\n", debug_address); | ||
450 | } | ||
451 | |||
452 | static int ab8500_address_open(struct inode *inode, struct file *file) | ||
453 | { | ||
454 | return single_open(file, ab8500_address_print, inode->i_private); | ||
455 | } | ||
456 | |||
457 | static ssize_t ab8500_address_write(struct file *file, | ||
458 | const char __user *user_buf, | ||
459 | size_t count, loff_t *ppos) | ||
460 | { | ||
461 | struct device *dev = ((struct seq_file *)(file->private_data))->private; | ||
462 | char buf[32]; | ||
463 | int buf_size; | ||
464 | unsigned long user_address; | ||
465 | int err; | ||
466 | |||
467 | /* Get userspace string and assure termination */ | ||
468 | buf_size = min(count, (sizeof(buf) - 1)); | ||
469 | if (copy_from_user(buf, user_buf, buf_size)) | ||
470 | return -EFAULT; | ||
471 | buf[buf_size] = 0; | ||
472 | |||
473 | err = strict_strtoul(buf, 0, &user_address); | ||
474 | if (err) | ||
475 | return -EINVAL; | ||
476 | if (user_address > 0xff) { | ||
477 | dev_err(dev, "debugfs error input > 0xff\n"); | ||
478 | return -EINVAL; | ||
479 | } | ||
480 | debug_address = user_address; | ||
481 | return buf_size; | ||
482 | } | ||
483 | |||
484 | static int ab8500_val_print(struct seq_file *s, void *p) | ||
485 | { | ||
486 | struct device *dev = s->private; | ||
487 | int ret; | ||
488 | u8 regvalue; | ||
489 | |||
490 | ret = abx500_get_register_interruptible(dev, | ||
491 | (u8)debug_bank, (u8)debug_address, ®value); | ||
492 | if (ret < 0) { | ||
493 | dev_err(dev, "abx500_get_reg fail %d, %d\n", | ||
494 | ret, __LINE__); | ||
495 | return -EINVAL; | ||
496 | } | ||
497 | seq_printf(s, "0x%02X\n", regvalue); | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int ab8500_val_open(struct inode *inode, struct file *file) | ||
503 | { | ||
504 | return single_open(file, ab8500_val_print, inode->i_private); | ||
505 | } | ||
506 | |||
507 | static ssize_t ab8500_val_write(struct file *file, | ||
508 | const char __user *user_buf, | ||
509 | size_t count, loff_t *ppos) | ||
510 | { | ||
511 | struct device *dev = ((struct seq_file *)(file->private_data))->private; | ||
512 | char buf[32]; | ||
513 | int buf_size; | ||
514 | unsigned long user_val; | ||
515 | int err; | ||
516 | |||
517 | /* Get userspace string and assure termination */ | ||
518 | buf_size = min(count, (sizeof(buf)-1)); | ||
519 | if (copy_from_user(buf, user_buf, buf_size)) | ||
520 | return -EFAULT; | ||
521 | buf[buf_size] = 0; | ||
522 | |||
523 | err = strict_strtoul(buf, 0, &user_val); | ||
524 | if (err) | ||
525 | return -EINVAL; | ||
526 | if (user_val > 0xff) { | ||
527 | dev_err(dev, "debugfs error input > 0xff\n"); | ||
528 | return -EINVAL; | ||
529 | } | ||
530 | err = abx500_set_register_interruptible(dev, | ||
531 | (u8)debug_bank, debug_address, (u8)user_val); | ||
532 | if (err < 0) { | ||
533 | printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__); | ||
534 | return -EINVAL; | ||
535 | } | ||
536 | |||
537 | return buf_size; | ||
538 | } | ||
539 | |||
540 | static const struct file_operations ab8500_bank_fops = { | ||
541 | .open = ab8500_bank_open, | ||
542 | .write = ab8500_bank_write, | ||
543 | .read = seq_read, | ||
544 | .llseek = seq_lseek, | ||
545 | .release = single_release, | ||
546 | .owner = THIS_MODULE, | ||
547 | }; | ||
548 | |||
549 | static const struct file_operations ab8500_address_fops = { | ||
550 | .open = ab8500_address_open, | ||
551 | .write = ab8500_address_write, | ||
552 | .read = seq_read, | ||
553 | .llseek = seq_lseek, | ||
554 | .release = single_release, | ||
555 | .owner = THIS_MODULE, | ||
556 | }; | ||
557 | |||
558 | static const struct file_operations ab8500_val_fops = { | ||
559 | .open = ab8500_val_open, | ||
560 | .write = ab8500_val_write, | ||
561 | .read = seq_read, | ||
562 | .llseek = seq_lseek, | ||
563 | .release = single_release, | ||
564 | .owner = THIS_MODULE, | ||
565 | }; | ||
566 | |||
567 | static struct dentry *ab8500_dir; | ||
568 | static struct dentry *ab8500_reg_file; | ||
569 | static struct dentry *ab8500_bank_file; | ||
570 | static struct dentry *ab8500_address_file; | ||
571 | static struct dentry *ab8500_val_file; | ||
572 | |||
573 | static int __devinit ab8500_debug_probe(struct platform_device *plf) | ||
574 | { | ||
575 | debug_bank = AB8500_MISC; | ||
576 | debug_address = AB8500_REV_REG & 0x00FF; | ||
577 | |||
578 | ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL); | ||
579 | if (!ab8500_dir) | ||
580 | goto exit_no_debugfs; | ||
581 | |||
582 | ab8500_reg_file = debugfs_create_file("all-bank-registers", | ||
583 | S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops); | ||
584 | if (!ab8500_reg_file) | ||
585 | goto exit_destroy_dir; | ||
586 | |||
587 | ab8500_bank_file = debugfs_create_file("register-bank", | ||
588 | (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops); | ||
589 | if (!ab8500_bank_file) | ||
590 | goto exit_destroy_reg; | ||
591 | |||
592 | ab8500_address_file = debugfs_create_file("register-address", | ||
593 | (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, | ||
594 | &ab8500_address_fops); | ||
595 | if (!ab8500_address_file) | ||
596 | goto exit_destroy_bank; | ||
597 | |||
598 | ab8500_val_file = debugfs_create_file("register-value", | ||
599 | (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops); | ||
600 | if (!ab8500_val_file) | ||
601 | goto exit_destroy_address; | ||
602 | |||
603 | return 0; | ||
604 | |||
605 | exit_destroy_address: | ||
606 | debugfs_remove(ab8500_address_file); | ||
607 | exit_destroy_bank: | ||
608 | debugfs_remove(ab8500_bank_file); | ||
609 | exit_destroy_reg: | ||
610 | debugfs_remove(ab8500_reg_file); | ||
611 | exit_destroy_dir: | ||
612 | debugfs_remove(ab8500_dir); | ||
613 | exit_no_debugfs: | ||
614 | dev_err(&plf->dev, "failed to create debugfs entries.\n"); | ||
615 | return -ENOMEM; | ||
616 | } | ||
617 | |||
618 | static int __devexit ab8500_debug_remove(struct platform_device *plf) | ||
619 | { | ||
620 | debugfs_remove(ab8500_val_file); | ||
621 | debugfs_remove(ab8500_address_file); | ||
622 | debugfs_remove(ab8500_bank_file); | ||
623 | debugfs_remove(ab8500_reg_file); | ||
624 | debugfs_remove(ab8500_dir); | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | static struct platform_driver ab8500_debug_driver = { | ||
630 | .driver = { | ||
631 | .name = "ab8500-debug", | ||
632 | .owner = THIS_MODULE, | ||
633 | }, | ||
634 | .probe = ab8500_debug_probe, | ||
635 | .remove = __devexit_p(ab8500_debug_remove) | ||
636 | }; | ||
637 | |||
638 | static int __init ab8500_debug_init(void) | ||
639 | { | ||
640 | return platform_driver_register(&ab8500_debug_driver); | ||
641 | } | ||
642 | |||
643 | static void __exit ab8500_debug_exit(void) | ||
644 | { | ||
645 | platform_driver_unregister(&ab8500_debug_driver); | ||
646 | } | ||
647 | subsys_initcall(ab8500_debug_init); | ||
648 | module_exit(ab8500_debug_exit); | ||
649 | |||
650 | MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com"); | ||
651 | MODULE_DESCRIPTION("AB8500 DEBUG"); | ||
652 | MODULE_LICENSE("GPL v2"); | ||