aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorMattias Wallin <mattias.wallin@stericsson.com>2010-09-13 10:05:04 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2010-10-28 18:29:25 -0400
commit5814fc35e1837e30b82c3d57f41310d4c4c52824 (patch)
treea1af93694c140cb5bf54aff2a194fc084d12d7fb /drivers/mfd
parent38b340527aa44bb8d1b88ef1e5a4e26b27695c2b (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/Kconfig8
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/ab8500-core.c5
-rw-r--r--drivers/mfd/ab8500-debugfs.c652
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
486config 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
486config AB3550_CORE 494config 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
69obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o 69obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
70obj-$(CONFIG_AB3550_CORE) += ab3550-core.o 70obj-$(CONFIG_AB3550_CORE) += ab3550-core.o
71obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o 71obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o
72obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
72obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o 73obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
73obj-$(CONFIG_PMIC_ADP5520) += adp5520.o 74obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
74obj-$(CONFIG_LPC_SCH) += lpc_sch.o 75obj-$(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
396static struct mfd_cell ab8500_devs[] = { 396static 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
17static u32 debug_bank;
18static 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 */
26struct 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 */
38struct 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
49static 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
356static 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
394static int ab8500_registers_open(struct inode *inode, struct file *file)
395{
396 return single_open(file, ab8500_registers_print, inode->i_private);
397}
398
399static 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
407static int ab8500_bank_print(struct seq_file *s, void *p)
408{
409 return seq_printf(s, "%d\n", debug_bank);
410}
411
412static int ab8500_bank_open(struct inode *inode, struct file *file)
413{
414 return single_open(file, ab8500_bank_print, inode->i_private);
415}
416
417static 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
447static int ab8500_address_print(struct seq_file *s, void *p)
448{
449 return seq_printf(s, "0x%02X\n", debug_address);
450}
451
452static int ab8500_address_open(struct inode *inode, struct file *file)
453{
454 return single_open(file, ab8500_address_print, inode->i_private);
455}
456
457static 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
484static 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, &regvalue);
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
502static int ab8500_val_open(struct inode *inode, struct file *file)
503{
504 return single_open(file, ab8500_val_print, inode->i_private);
505}
506
507static 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
540static 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
549static 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
558static 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
567static struct dentry *ab8500_dir;
568static struct dentry *ab8500_reg_file;
569static struct dentry *ab8500_bank_file;
570static struct dentry *ab8500_address_file;
571static struct dentry *ab8500_val_file;
572
573static 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
605exit_destroy_address:
606 debugfs_remove(ab8500_address_file);
607exit_destroy_bank:
608 debugfs_remove(ab8500_bank_file);
609exit_destroy_reg:
610 debugfs_remove(ab8500_reg_file);
611exit_destroy_dir:
612 debugfs_remove(ab8500_dir);
613exit_no_debugfs:
614 dev_err(&plf->dev, "failed to create debugfs entries.\n");
615 return -ENOMEM;
616}
617
618static 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
629static 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
638static int __init ab8500_debug_init(void)
639{
640 return platform_driver_register(&ab8500_debug_driver);
641}
642
643static void __exit ab8500_debug_exit(void)
644{
645 platform_driver_unregister(&ab8500_debug_driver);
646}
647subsys_initcall(ab8500_debug_init);
648module_exit(ab8500_debug_exit);
649
650MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com");
651MODULE_DESCRIPTION("AB8500 DEBUG");
652MODULE_LICENSE("GPL v2");