OMAPDSS: VENC: fix NULL pointer dereference in DSS2 VENC sysfs debug attr on OMAP4
[zen-stable.git] / drivers / mfd / ab5500-debugfs.c
blob72006940937ae54a1500ac66fd3461d2e6ca9b32
1 /*
2 * Copyright (C) 2011 ST-Ericsson
3 * License terms: GNU General Public License (GPL) version 2
4 * Debugfs support for the AB5500 MFD driver
5 */
7 #include <linux/module.h>
8 #include <linux/debugfs.h>
9 #include <linux/seq_file.h>
10 #include <linux/mfd/abx500.h>
11 #include <linux/mfd/abx500/ab5500.h>
12 #include <linux/uaccess.h>
14 #include "ab5500-core.h"
15 #include "ab5500-debugfs.h"
17 static struct ab5500_i2c_ranges ab5500_reg_ranges[AB5500_NUM_BANKS] = {
18 [AB5500_BANK_LED] = {
19 .bankid = AB5500_BANK_LED,
20 .nranges = 1,
21 .range = (struct ab5500_reg_range[]) {
23 .first = 0x00,
24 .last = 0x0C,
25 .perm = AB5500_PERM_RW,
29 [AB5500_BANK_ADC] = {
30 .bankid = AB5500_BANK_ADC,
31 .nranges = 6,
32 .range = (struct ab5500_reg_range[]) {
34 .first = 0x1F,
35 .last = 0x22,
36 .perm = AB5500_PERM_RO,
39 .first = 0x23,
40 .last = 0x24,
41 .perm = AB5500_PERM_RW,
44 .first = 0x26,
45 .last = 0x2D,
46 .perm = AB5500_PERM_RO,
49 .first = 0x2F,
50 .last = 0x34,
51 .perm = AB5500_PERM_RW,
54 .first = 0x37,
55 .last = 0x57,
56 .perm = AB5500_PERM_RW,
59 .first = 0x58,
60 .last = 0x58,
61 .perm = AB5500_PERM_RO,
65 [AB5500_BANK_RTC] = {
66 .bankid = AB5500_BANK_RTC,
67 .nranges = 2,
68 .range = (struct ab5500_reg_range[]) {
70 .first = 0x00,
71 .last = 0x04,
72 .perm = AB5500_PERM_RW,
75 .first = 0x06,
76 .last = 0x0C,
77 .perm = AB5500_PERM_RW,
81 [AB5500_BANK_STARTUP] = {
82 .bankid = AB5500_BANK_STARTUP,
83 .nranges = 12,
84 .range = (struct ab5500_reg_range[]) {
86 .first = 0x00,
87 .last = 0x01,
88 .perm = AB5500_PERM_RW,
91 .first = 0x1F,
92 .last = 0x1F,
93 .perm = AB5500_PERM_RW,
96 .first = 0x2E,
97 .last = 0x2E,
98 .perm = AB5500_PERM_RO,
101 .first = 0x2F,
102 .last = 0x30,
103 .perm = AB5500_PERM_RW,
106 .first = 0x50,
107 .last = 0x51,
108 .perm = AB5500_PERM_RW,
111 .first = 0x60,
112 .last = 0x61,
113 .perm = AB5500_PERM_RW,
116 .first = 0x66,
117 .last = 0x8A,
118 .perm = AB5500_PERM_RW,
121 .first = 0x8C,
122 .last = 0x96,
123 .perm = AB5500_PERM_RW,
126 .first = 0xAA,
127 .last = 0xB4,
128 .perm = AB5500_PERM_RW,
131 .first = 0xB7,
132 .last = 0xBF,
133 .perm = AB5500_PERM_RW,
136 .first = 0xC1,
137 .last = 0xCA,
138 .perm = AB5500_PERM_RW,
141 .first = 0xD3,
142 .last = 0xE0,
143 .perm = AB5500_PERM_RW,
147 [AB5500_BANK_DBI_ECI] = {
148 .bankid = AB5500_BANK_DBI_ECI,
149 .nranges = 3,
150 .range = (struct ab5500_reg_range[]) {
152 .first = 0x00,
153 .last = 0x07,
154 .perm = AB5500_PERM_RW,
157 .first = 0x10,
158 .last = 0x10,
159 .perm = AB5500_PERM_RW,
162 .first = 0x13,
163 .last = 0x13,
164 .perm = AB5500_PERM_RW,
168 [AB5500_BANK_CHG] = {
169 .bankid = AB5500_BANK_CHG,
170 .nranges = 2,
171 .range = (struct ab5500_reg_range[]) {
173 .first = 0x11,
174 .last = 0x11,
175 .perm = AB5500_PERM_RO,
178 .first = 0x12,
179 .last = 0x1B,
180 .perm = AB5500_PERM_RW,
184 [AB5500_BANK_FG_BATTCOM_ACC] = {
185 .bankid = AB5500_BANK_FG_BATTCOM_ACC,
186 .nranges = 2,
187 .range = (struct ab5500_reg_range[]) {
189 .first = 0x00,
190 .last = 0x0B,
191 .perm = AB5500_PERM_RO,
194 .first = 0x0C,
195 .last = 0x10,
196 .perm = AB5500_PERM_RW,
200 [AB5500_BANK_USB] = {
201 .bankid = AB5500_BANK_USB,
202 .nranges = 12,
203 .range = (struct ab5500_reg_range[]) {
205 .first = 0x01,
206 .last = 0x01,
207 .perm = AB5500_PERM_RW,
210 .first = 0x80,
211 .last = 0x83,
212 .perm = AB5500_PERM_RW,
215 .first = 0x87,
216 .last = 0x8A,
217 .perm = AB5500_PERM_RW,
220 .first = 0x8B,
221 .last = 0x8B,
222 .perm = AB5500_PERM_RO,
225 .first = 0x91,
226 .last = 0x92,
227 .perm = AB5500_PERM_RO,
230 .first = 0x93,
231 .last = 0x93,
232 .perm = AB5500_PERM_RW,
235 .first = 0x94,
236 .last = 0x94,
237 .perm = AB5500_PERM_RO,
240 .first = 0xA8,
241 .last = 0xB0,
242 .perm = AB5500_PERM_RO,
245 .first = 0xB2,
246 .last = 0xB2,
247 .perm = AB5500_PERM_RO,
250 .first = 0xB4,
251 .last = 0xBC,
252 .perm = AB5500_PERM_RO,
255 .first = 0xBF,
256 .last = 0xBF,
257 .perm = AB5500_PERM_RO,
260 .first = 0xC1,
261 .last = 0xC5,
262 .perm = AB5500_PERM_RO,
266 [AB5500_BANK_IT] = {
267 .bankid = AB5500_BANK_IT,
268 .nranges = 4,
269 .range = (struct ab5500_reg_range[]) {
271 .first = 0x00,
272 .last = 0x02,
273 .perm = AB5500_PERM_RO,
276 .first = 0x20,
277 .last = 0x36,
278 .perm = AB5500_PERM_RO,
281 .first = 0x40,
282 .last = 0x56,
283 .perm = AB5500_PERM_RO,
286 .first = 0x60,
287 .last = 0x76,
288 .perm = AB5500_PERM_RO,
292 [AB5500_BANK_VDDDIG_IO_I2C_CLK_TST] = {
293 .bankid = AB5500_BANK_VDDDIG_IO_I2C_CLK_TST,
294 .nranges = 7,
295 .range = (struct ab5500_reg_range[]) {
297 .first = 0x02,
298 .last = 0x02,
299 .perm = AB5500_PERM_RW,
302 .first = 0x12,
303 .last = 0x12,
304 .perm = AB5500_PERM_RW,
307 .first = 0x30,
308 .last = 0x34,
309 .perm = AB5500_PERM_RW,
312 .first = 0x40,
313 .last = 0x44,
314 .perm = AB5500_PERM_RW,
317 .first = 0x50,
318 .last = 0x54,
319 .perm = AB5500_PERM_RW,
322 .first = 0x60,
323 .last = 0x64,
324 .perm = AB5500_PERM_RW,
327 .first = 0x70,
328 .last = 0x74,
329 .perm = AB5500_PERM_RW,
333 [AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP] = {
334 .bankid = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP,
335 .nranges = 13,
336 .range = (struct ab5500_reg_range[]) {
338 .first = 0x01,
339 .last = 0x01,
340 .perm = AB5500_PERM_RW,
343 .first = 0x02,
344 .last = 0x02,
345 .perm = AB5500_PERM_RO,
348 .first = 0x0D,
349 .last = 0x0F,
350 .perm = AB5500_PERM_RW,
353 .first = 0x1C,
354 .last = 0x1C,
355 .perm = AB5500_PERM_RW,
358 .first = 0x1E,
359 .last = 0x1E,
360 .perm = AB5500_PERM_RW,
363 .first = 0x20,
364 .last = 0x21,
365 .perm = AB5500_PERM_RW,
368 .first = 0x25,
369 .last = 0x25,
370 .perm = AB5500_PERM_RW,
373 .first = 0x28,
374 .last = 0x2A,
375 .perm = AB5500_PERM_RW,
378 .first = 0x30,
379 .last = 0x33,
380 .perm = AB5500_PERM_RW,
383 .first = 0x40,
384 .last = 0x43,
385 .perm = AB5500_PERM_RW,
388 .first = 0x50,
389 .last = 0x53,
390 .perm = AB5500_PERM_RW,
393 .first = 0x60,
394 .last = 0x63,
395 .perm = AB5500_PERM_RW,
398 .first = 0x70,
399 .last = 0x73,
400 .perm = AB5500_PERM_RW,
404 [AB5500_BANK_VIBRA] = {
405 .bankid = AB5500_BANK_VIBRA,
406 .nranges = 2,
407 .range = (struct ab5500_reg_range[]) {
409 .first = 0x10,
410 .last = 0x13,
411 .perm = AB5500_PERM_RW,
414 .first = 0xFE,
415 .last = 0xFE,
416 .perm = AB5500_PERM_RW,
420 [AB5500_BANK_AUDIO_HEADSETUSB] = {
421 .bankid = AB5500_BANK_AUDIO_HEADSETUSB,
422 .nranges = 2,
423 .range = (struct ab5500_reg_range[]) {
425 .first = 0x00,
426 .last = 0x48,
427 .perm = AB5500_PERM_RW,
430 .first = 0xEB,
431 .last = 0xFB,
432 .perm = AB5500_PERM_RW,
436 [AB5500_BANK_SIM_USBSIM] = {
437 .bankid = AB5500_BANK_SIM_USBSIM,
438 .nranges = 1,
439 .range = (struct ab5500_reg_range[]) {
441 .first = 0x13,
442 .last = 0x19,
443 .perm = AB5500_PERM_RW,
447 [AB5500_BANK_VDENC] = {
448 .bankid = AB5500_BANK_VDENC,
449 .nranges = 12,
450 .range = (struct ab5500_reg_range[]) {
452 .first = 0x00,
453 .last = 0x08,
454 .perm = AB5500_PERM_RW,
457 .first = 0x09,
458 .last = 0x09,
459 .perm = AB5500_PERM_RO,
462 .first = 0x0A,
463 .last = 0x12,
464 .perm = AB5500_PERM_RW,
467 .first = 0x15,
468 .last = 0x19,
469 .perm = AB5500_PERM_RW,
472 .first = 0x1B,
473 .last = 0x21,
474 .perm = AB5500_PERM_RW,
477 .first = 0x27,
478 .last = 0x2C,
479 .perm = AB5500_PERM_RW,
482 .first = 0x41,
483 .last = 0x41,
484 .perm = AB5500_PERM_RW,
487 .first = 0x45,
488 .last = 0x5B,
489 .perm = AB5500_PERM_RW,
492 .first = 0x5D,
493 .last = 0x5D,
494 .perm = AB5500_PERM_RW,
497 .first = 0x69,
498 .last = 0x69,
499 .perm = AB5500_PERM_RW,
502 .first = 0x6C,
503 .last = 0x6D,
504 .perm = AB5500_PERM_RW,
507 .first = 0x80,
508 .last = 0x81,
509 .perm = AB5500_PERM_RW,
515 static int ab5500_registers_print(struct seq_file *s, void *p)
517 struct ab5500 *ab = s->private;
518 unsigned int i;
519 u8 bank = (u8)ab->debug_bank;
521 seq_printf(s, "ab5500 register values:\n");
522 for (bank = 0; bank < AB5500_NUM_BANKS; bank++) {
523 seq_printf(s, " bank %u, %s (0x%x):\n", bank,
524 bankinfo[bank].name,
525 bankinfo[bank].slave_addr);
526 for (i = 0; i < ab5500_reg_ranges[bank].nranges; i++) {
527 u8 reg;
528 int err;
530 for (reg = ab5500_reg_ranges[bank].range[i].first;
531 reg <= ab5500_reg_ranges[bank].range[i].last;
532 reg++) {
533 u8 value;
535 err = ab5500_get_register_interruptible_raw(ab,
536 bank, reg,
537 &value);
538 if (err < 0) {
539 dev_err(ab->dev, "get_reg failed %d"
540 "bank 0x%x reg 0x%x\n",
541 err, bank, reg);
542 return err;
545 err = seq_printf(s, "[%d/0x%02X]: 0x%02X\n",
546 bank, reg, value);
547 if (err < 0) {
548 dev_err(ab->dev,
549 "seq_printf overflow\n");
551 * Error is not returned here since
552 * the output is wanted in any case
554 return 0;
559 return 0;
562 static int ab5500_registers_open(struct inode *inode, struct file *file)
564 return single_open(file, ab5500_registers_print, inode->i_private);
567 static const struct file_operations ab5500_registers_fops = {
568 .open = ab5500_registers_open,
569 .read = seq_read,
570 .llseek = seq_lseek,
571 .release = single_release,
572 .owner = THIS_MODULE,
575 static int ab5500_bank_print(struct seq_file *s, void *p)
577 struct ab5500 *ab = s->private;
579 seq_printf(s, "%d\n", ab->debug_bank);
580 return 0;
583 static int ab5500_bank_open(struct inode *inode, struct file *file)
585 return single_open(file, ab5500_bank_print, inode->i_private);
588 static ssize_t ab5500_bank_write(struct file *file,
589 const char __user *user_buf,
590 size_t count, loff_t *ppos)
592 struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
593 char buf[32];
594 int buf_size;
595 unsigned long user_bank;
596 int err;
598 /* Get userspace string and assure termination */
599 buf_size = min(count, (sizeof(buf) - 1));
600 if (copy_from_user(buf, user_buf, buf_size))
601 return -EFAULT;
602 buf[buf_size] = 0;
604 err = strict_strtoul(buf, 0, &user_bank);
605 if (err)
606 return -EINVAL;
608 if (user_bank >= AB5500_NUM_BANKS) {
609 dev_err(ab->dev,
610 "debugfs error input > number of banks\n");
611 return -EINVAL;
614 ab->debug_bank = user_bank;
616 return buf_size;
619 static int ab5500_address_print(struct seq_file *s, void *p)
621 struct ab5500 *ab = s->private;
623 seq_printf(s, "0x%02X\n", ab->debug_address);
624 return 0;
627 static int ab5500_address_open(struct inode *inode, struct file *file)
629 return single_open(file, ab5500_address_print, inode->i_private);
632 static ssize_t ab5500_address_write(struct file *file,
633 const char __user *user_buf,
634 size_t count, loff_t *ppos)
636 struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
637 char buf[32];
638 int buf_size;
639 unsigned long user_address;
640 int err;
642 /* Get userspace string and assure termination */
643 buf_size = min(count, (sizeof(buf) - 1));
644 if (copy_from_user(buf, user_buf, buf_size))
645 return -EFAULT;
646 buf[buf_size] = 0;
648 err = strict_strtoul(buf, 0, &user_address);
649 if (err)
650 return -EINVAL;
651 if (user_address > 0xff) {
652 dev_err(ab->dev,
653 "debugfs error input > 0xff\n");
654 return -EINVAL;
656 ab->debug_address = user_address;
657 return buf_size;
660 static int ab5500_val_print(struct seq_file *s, void *p)
662 struct ab5500 *ab = s->private;
663 int err;
664 u8 regvalue;
666 err = ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank,
667 (u8)ab->debug_address, &regvalue);
668 if (err) {
669 dev_err(ab->dev, "get_reg failed %d, bank 0x%x"
670 ", reg 0x%x\n", err, ab->debug_bank,
671 ab->debug_address);
672 return -EINVAL;
674 seq_printf(s, "0x%02X\n", regvalue);
676 return 0;
679 static int ab5500_val_open(struct inode *inode, struct file *file)
681 return single_open(file, ab5500_val_print, inode->i_private);
684 static ssize_t ab5500_val_write(struct file *file,
685 const char __user *user_buf,
686 size_t count, loff_t *ppos)
688 struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
689 char buf[32];
690 int buf_size;
691 unsigned long user_val;
692 int err;
693 u8 regvalue;
695 /* Get userspace string and assure termination */
696 buf_size = min(count, (sizeof(buf)-1));
697 if (copy_from_user(buf, user_buf, buf_size))
698 return -EFAULT;
699 buf[buf_size] = 0;
701 err = strict_strtoul(buf, 0, &user_val);
702 if (err)
703 return -EINVAL;
704 if (user_val > 0xff) {
705 dev_err(ab->dev,
706 "debugfs error input > 0xff\n");
707 return -EINVAL;
709 err = ab5500_mask_and_set_register_interruptible_raw(
710 ab, (u8)ab->debug_bank,
711 (u8)ab->debug_address, 0xFF, (u8)user_val);
712 if (err)
713 return -EINVAL;
715 ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank,
716 (u8)ab->debug_address, &regvalue);
717 if (err)
718 return -EINVAL;
720 return buf_size;
723 static const struct file_operations ab5500_bank_fops = {
724 .open = ab5500_bank_open,
725 .write = ab5500_bank_write,
726 .read = seq_read,
727 .llseek = seq_lseek,
728 .release = single_release,
729 .owner = THIS_MODULE,
732 static const struct file_operations ab5500_address_fops = {
733 .open = ab5500_address_open,
734 .write = ab5500_address_write,
735 .read = seq_read,
736 .llseek = seq_lseek,
737 .release = single_release,
738 .owner = THIS_MODULE,
741 static const struct file_operations ab5500_val_fops = {
742 .open = ab5500_val_open,
743 .write = ab5500_val_write,
744 .read = seq_read,
745 .llseek = seq_lseek,
746 .release = single_release,
747 .owner = THIS_MODULE,
750 static struct dentry *ab5500_dir;
751 static struct dentry *ab5500_reg_file;
752 static struct dentry *ab5500_bank_file;
753 static struct dentry *ab5500_address_file;
754 static struct dentry *ab5500_val_file;
756 void __init ab5500_setup_debugfs(struct ab5500 *ab)
758 ab->debug_bank = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP;
759 ab->debug_address = AB5500_CHIP_ID;
761 ab5500_dir = debugfs_create_dir("ab5500", NULL);
762 if (!ab5500_dir)
763 goto exit_no_debugfs;
765 ab5500_reg_file = debugfs_create_file("all-bank-registers",
766 S_IRUGO, ab5500_dir, ab, &ab5500_registers_fops);
767 if (!ab5500_reg_file)
768 goto exit_destroy_dir;
770 ab5500_bank_file = debugfs_create_file("register-bank",
771 (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_bank_fops);
772 if (!ab5500_bank_file)
773 goto exit_destroy_reg;
775 ab5500_address_file = debugfs_create_file("register-address",
776 (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_address_fops);
777 if (!ab5500_address_file)
778 goto exit_destroy_bank;
780 ab5500_val_file = debugfs_create_file("register-value",
781 (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_val_fops);
782 if (!ab5500_val_file)
783 goto exit_destroy_address;
785 return;
787 exit_destroy_address:
788 debugfs_remove(ab5500_address_file);
789 exit_destroy_bank:
790 debugfs_remove(ab5500_bank_file);
791 exit_destroy_reg:
792 debugfs_remove(ab5500_reg_file);
793 exit_destroy_dir:
794 debugfs_remove(ab5500_dir);
795 exit_no_debugfs:
796 dev_err(ab->dev, "failed to create debugfs entries.\n");
797 return;
800 void __exit ab5500_remove_debugfs(void)
802 debugfs_remove(ab5500_val_file);
803 debugfs_remove(ab5500_address_file);
804 debugfs_remove(ab5500_bank_file);
805 debugfs_remove(ab5500_reg_file);
806 debugfs_remove(ab5500_dir);