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 */
6
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>
13
14 #include "ab5500-core.h"
15 #include "ab5500-debugfs.h"
16
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[]) {
22 {
23 .first = 0x00,
24 .last = 0x0C,
25 .perm = AB5500_PERM_RW,
26 },
27 },
28 },
29 [AB5500_BANK_ADC] = {
30 .bankid = AB5500_BANK_ADC,
31 .nranges = 6,
32 .range = (struct ab5500_reg_range[]) {
33 {
34 .first = 0x1F,
35 .last = 0x22,
36 .perm = AB5500_PERM_RO,
37 },
38 {
39 .first = 0x23,
40 .last = 0x24,
41 .perm = AB5500_PERM_RW,
42 },
43 {
44 .first = 0x26,
45 .last = 0x2D,
46 .perm = AB5500_PERM_RO,
47 },
48 {
49 .first = 0x2F,
50 .last = 0x34,
51 .perm = AB5500_PERM_RW,
52 },
53 {
54 .first = 0x37,
55 .last = 0x57,
56 .perm = AB5500_PERM_RW,
57 },
58 {
59 .first = 0x58,
60 .last = 0x58,
61 .perm = AB5500_PERM_RO,
62 },
63 },
64 },
65 [AB5500_BANK_RTC] = {
66 .bankid = AB5500_BANK_RTC,
67 .nranges = 2,
68 .range = (struct ab5500_reg_range[]) {
69 {
70 .first = 0x00,
71 .last = 0x04,
72 .perm = AB5500_PERM_RW,
73 },
74 {
75 .first = 0x06,
76 .last = 0x0C,
77 .perm = AB5500_PERM_RW,
78 },
79 },
80 },
81 [AB5500_BANK_STARTUP] = {
82 .bankid = AB5500_BANK_STARTUP,
83 .nranges = 12,
84 .range = (struct ab5500_reg_range[]) {
85 {
86 .first = 0x00,
87 .last = 0x01,
88 .perm = AB5500_PERM_RW,
89 },
90 {
91 .first = 0x1F,
92 .last = 0x1F,
93 .perm = AB5500_PERM_RW,
94 },
95 {
96 .first = 0x2E,
97 .last = 0x2E,
98 .perm = AB5500_PERM_RO,
99 },
100 {
101 .first = 0x2F,
102 .last = 0x30,
103 .perm = AB5500_PERM_RW,
104 },
105 {
106 .first = 0x50,
107 .last = 0x51,
108 .perm = AB5500_PERM_RW,
109 },
110 {
111 .first = 0x60,
112 .last = 0x61,
113 .perm = AB5500_PERM_RW,
114 },
115 {
116 .first = 0x66,
117 .last = 0x8A,
118 .perm = AB5500_PERM_RW,
119 },
120 {
121 .first = 0x8C,
122 .last = 0x96,
123 .perm = AB5500_PERM_RW,
124 },
125 {
126 .first = 0xAA,
127 .last = 0xB4,
128 .perm = AB5500_PERM_RW,
129 },
130 {
131 .first = 0xB7,
132 .last = 0xBF,
133 .perm = AB5500_PERM_RW,
134 },
135 {
136 .first = 0xC1,
137 .last = 0xCA,
138 .perm = AB5500_PERM_RW,
139 },
140 {
141 .first = 0xD3,
142 .last = 0xE0,
143 .perm = AB5500_PERM_RW,
144 },
145 },
146 },
147 [AB5500_BANK_DBI_ECI] = {
148 .bankid = AB5500_BANK_DBI_ECI,
149 .nranges = 3,
150 .range = (struct ab5500_reg_range[]) {
151 {
152 .first = 0x00,
153 .last = 0x07,
154 .perm = AB5500_PERM_RW,
155 },
156 {
157 .first = 0x10,
158 .last = 0x10,
159 .perm = AB5500_PERM_RW,
160 },
161 {
162 .first = 0x13,
163 .last = 0x13,
164 .perm = AB5500_PERM_RW,
165 },
166 },
167 },
168 [AB5500_BANK_CHG] = {
169 .bankid = AB5500_BANK_CHG,
170 .nranges = 2,
171 .range = (struct ab5500_reg_range[]) {
172 {
173 .first = 0x11,
174 .last = 0x11,
175 .perm = AB5500_PERM_RO,
176 },
177 {
178 .first = 0x12,
179 .last = 0x1B,
180 .perm = AB5500_PERM_RW,
181 },
182 },
183 },
184 [AB5500_BANK_FG_BATTCOM_ACC] = {
185 .bankid = AB5500_BANK_FG_BATTCOM_ACC,
186 .nranges = 2,
187 .range = (struct ab5500_reg_range[]) {
188 {
189 .first = 0x00,
190 .last = 0x0B,
191 .perm = AB5500_PERM_RO,
192 },
193 {
194 .first = 0x0C,
195 .last = 0x10,
196 .perm = AB5500_PERM_RW,
197 },
198 },
199 },
200 [AB5500_BANK_USB] = {
201 .bankid = AB5500_BANK_USB,
202 .nranges = 12,
203 .range = (struct ab5500_reg_range[]) {
204 {
205 .first = 0x01,
206 .last = 0x01,
207 .perm = AB5500_PERM_RW,
208 },
209 {
210 .first = 0x80,
211 .last = 0x83,
212 .perm = AB5500_PERM_RW,
213 },
214 {
215 .first = 0x87,
216 .last = 0x8A,
217 .perm = AB5500_PERM_RW,
218 },
219 {
220 .first = 0x8B,
221 .last = 0x8B,
222 .perm = AB5500_PERM_RO,
223 },
224 {
225 .first = 0x91,
226 .last = 0x92,
227 .perm = AB5500_PERM_RO,
228 },
229 {
230 .first = 0x93,
231 .last = 0x93,
232 .perm = AB5500_PERM_RW,
233 },
234 {
235 .first = 0x94,
236 .last = 0x94,
237 .perm = AB5500_PERM_RO,
238 },
239 {
240 .first = 0xA8,
241 .last = 0xB0,
242 .perm = AB5500_PERM_RO,
243 },
244 {
245 .first = 0xB2,
246 .last = 0xB2,
247 .perm = AB5500_PERM_RO,
248 },
249 {
250 .first = 0xB4,
251 .last = 0xBC,
252 .perm = AB5500_PERM_RO,
253 },
254 {
255 .first = 0xBF,
256 .last = 0xBF,
257 .perm = AB5500_PERM_RO,
258 },
259 {
260 .first = 0xC1,
261 .last = 0xC5,
262 .perm = AB5500_PERM_RO,
263 },
264 },
265 },
266 [AB5500_BANK_IT] = {
267 .bankid = AB5500_BANK_IT,
268 .nranges = 4,
269 .range = (struct ab5500_reg_range[]) {
270 {
271 .first = 0x00,
272 .last = 0x02,
273 .perm = AB5500_PERM_RO,
274 },
275 {
276 .first = 0x20,
277 .last = 0x36,
278 .perm = AB5500_PERM_RO,
279 },
280 {
281 .first = 0x40,
282 .last = 0x56,
283 .perm = AB5500_PERM_RO,
284 },
285 {
286 .first = 0x60,
287 .last = 0x76,
288 .perm = AB5500_PERM_RO,
289 },
290 },
291 },
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[]) {
296 {
297 .first = 0x02,
298 .last = 0x02,
299 .perm = AB5500_PERM_RW,
300 },
301 {
302 .first = 0x12,
303 .last = 0x12,
304 .perm = AB5500_PERM_RW,
305 },
306 {
307 .first = 0x30,
308 .last = 0x34,
309 .perm = AB5500_PERM_RW,
310 },
311 {
312 .first = 0x40,
313 .last = 0x44,
314 .perm = AB5500_PERM_RW,
315 },
316 {
317 .first = 0x50,
318 .last = 0x54,
319 .perm = AB5500_PERM_RW,
320 },
321 {
322 .first = 0x60,
323 .last = 0x64,
324 .perm = AB5500_PERM_RW,
325 },
326 {
327 .first = 0x70,
328 .last = 0x74,
329 .perm = AB5500_PERM_RW,
330 },
331 },
332 },
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[]) {
337 {
338 .first = 0x01,
339 .last = 0x01,
340 .perm = AB5500_PERM_RW,
341 },
342 {
343 .first = 0x02,
344 .last = 0x02,
345 .perm = AB5500_PERM_RO,
346 },
347 {
348 .first = 0x0D,
349 .last = 0x0F,
350 .perm = AB5500_PERM_RW,
351 },
352 {
353 .first = 0x1C,
354 .last = 0x1C,
355 .perm = AB5500_PERM_RW,
356 },
357 {
358 .first = 0x1E,
359 .last = 0x1E,
360 .perm = AB5500_PERM_RW,
361 },
362 {
363 .first = 0x20,
364 .last = 0x21,
365 .perm = AB5500_PERM_RW,
366 },
367 {
368 .first = 0x25,
369 .last = 0x25,
370 .perm = AB5500_PERM_RW,
371 },
372 {
373 .first = 0x28,
374 .last = 0x2A,
375 .perm = AB5500_PERM_RW,
376 },
377 {
378 .first = 0x30,
379 .last = 0x33,
380 .perm = AB5500_PERM_RW,
381 },
382 {
383 .first = 0x40,
384 .last = 0x43,
385 .perm = AB5500_PERM_RW,
386 },
387 {
388 .first = 0x50,
389 .last = 0x53,
390 .perm = AB5500_PERM_RW,
391 },
392 {
393 .first = 0x60,
394 .last = 0x63,
395 .perm = AB5500_PERM_RW,
396 },
397 {
398 .first = 0x70,
399 .last = 0x73,
400 .perm = AB5500_PERM_RW,
401 },
402 },
403 },
404 [AB5500_BANK_VIBRA] = {
405 .bankid = AB5500_BANK_VIBRA,
406 .nranges = 2,
407 .range = (struct ab5500_reg_range[]) {
408 {
409 .first = 0x10,
410 .last = 0x13,
411 .perm = AB5500_PERM_RW,
412 },
413 {
414 .first = 0xFE,
415 .last = 0xFE,
416 .perm = AB5500_PERM_RW,
417 },
418 },
419 },
420 [AB5500_BANK_AUDIO_HEADSETUSB] = {
421 .bankid = AB5500_BANK_AUDIO_HEADSETUSB,
422 .nranges = 2,
423 .range = (struct ab5500_reg_range[]) {
424 {
425 .first = 0x00,
426 .last = 0x48,
427 .perm = AB5500_PERM_RW,
428 },
429 {
430 .first = 0xEB,
431 .last = 0xFB,
432 .perm = AB5500_PERM_RW,
433 },
434 },
435 },
436 [AB5500_BANK_SIM_USBSIM] = {
437 .bankid = AB5500_BANK_SIM_USBSIM,
438 .nranges = 1,
439 .range = (struct ab5500_reg_range[]) {
440 {
441 .first = 0x13,
442 .last = 0x19,
443 .perm = AB5500_PERM_RW,
444 },
445 },
446 },
447 [AB5500_BANK_VDENC] = {
448 .bankid = AB5500_BANK_VDENC,
449 .nranges = 12,
450 .range = (struct ab5500_reg_range[]) {
451 {
452 .first = 0x00,
453 .last = 0x08,
454 .perm = AB5500_PERM_RW,
455 },
456 {
457 .first = 0x09,
458 .last = 0x09,
459 .perm = AB5500_PERM_RO,
460 },
461 {
462 .first = 0x0A,
463 .last = 0x12,
464 .perm = AB5500_PERM_RW,
465 },
466 {
467 .first = 0x15,
468 .last = 0x19,
469 .perm = AB5500_PERM_RW,
470 },
471 {
472 .first = 0x1B,
473 .last = 0x21,
474 .perm = AB5500_PERM_RW,
475 },
476 {
477 .first = 0x27,
478 .last = 0x2C,
479 .perm = AB5500_PERM_RW,
480 },
481 {
482 .first = 0x41,
483 .last = 0x41,
484 .perm = AB5500_PERM_RW,
485 },
486 {
487 .first = 0x45,
488 .last = 0x5B,
489 .perm = AB5500_PERM_RW,
490 },
491 {
492 .first = 0x5D,
493 .last = 0x5D,
494 .perm = AB5500_PERM_RW,
495 },
496 {
497 .first = 0x69,
498 .last = 0x69,
499 .perm = AB5500_PERM_RW,
500 },
501 {
502 .first = 0x6C,
503 .last = 0x6D,
504 .perm = AB5500_PERM_RW,
505 },
506 {
507 .first = 0x80,
508 .last = 0x81,
509 .perm = AB5500_PERM_RW,
510 },
511 },
512 },
513 };
514
ab5500_registers_print(struct seq_file * s,void * p)515 static int ab5500_registers_print(struct seq_file *s, void *p)
516 {
517 struct ab5500 *ab = s->private;
518 unsigned int i;
519 u8 bank = (u8)ab->debug_bank;
520
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;
529
530 for (reg = ab5500_reg_ranges[bank].range[i].first;
531 reg <= ab5500_reg_ranges[bank].range[i].last;
532 reg++) {
533 u8 value;
534
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;
543 }
544
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");
550 /*
551 * Error is not returned here since
552 * the output is wanted in any case
553 */
554 return 0;
555 }
556 }
557 }
558 }
559 return 0;
560 }
561
ab5500_registers_open(struct inode * inode,struct file * file)562 static int ab5500_registers_open(struct inode *inode, struct file *file)
563 {
564 return single_open(file, ab5500_registers_print, inode->i_private);
565 }
566
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,
573 };
574
ab5500_bank_print(struct seq_file * s,void * p)575 static int ab5500_bank_print(struct seq_file *s, void *p)
576 {
577 struct ab5500 *ab = s->private;
578
579 seq_printf(s, "%d\n", ab->debug_bank);
580 return 0;
581 }
582
ab5500_bank_open(struct inode * inode,struct file * file)583 static int ab5500_bank_open(struct inode *inode, struct file *file)
584 {
585 return single_open(file, ab5500_bank_print, inode->i_private);
586 }
587
ab5500_bank_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)588 static ssize_t ab5500_bank_write(struct file *file,
589 const char __user *user_buf,
590 size_t count, loff_t *ppos)
591 {
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;
597
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;
603
604 err = strict_strtoul(buf, 0, &user_bank);
605 if (err)
606 return -EINVAL;
607
608 if (user_bank >= AB5500_NUM_BANKS) {
609 dev_err(ab->dev,
610 "debugfs error input > number of banks\n");
611 return -EINVAL;
612 }
613
614 ab->debug_bank = user_bank;
615
616 return buf_size;
617 }
618
ab5500_address_print(struct seq_file * s,void * p)619 static int ab5500_address_print(struct seq_file *s, void *p)
620 {
621 struct ab5500 *ab = s->private;
622
623 seq_printf(s, "0x%02X\n", ab->debug_address);
624 return 0;
625 }
626
ab5500_address_open(struct inode * inode,struct file * file)627 static int ab5500_address_open(struct inode *inode, struct file *file)
628 {
629 return single_open(file, ab5500_address_print, inode->i_private);
630 }
631
ab5500_address_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)632 static ssize_t ab5500_address_write(struct file *file,
633 const char __user *user_buf,
634 size_t count, loff_t *ppos)
635 {
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;
641
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;
647
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;
655 }
656 ab->debug_address = user_address;
657 return buf_size;
658 }
659
ab5500_val_print(struct seq_file * s,void * p)660 static int ab5500_val_print(struct seq_file *s, void *p)
661 {
662 struct ab5500 *ab = s->private;
663 int err;
664 u8 regvalue;
665
666 err = ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank,
667 (u8)ab->debug_address, ®value);
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;
673 }
674 seq_printf(s, "0x%02X\n", regvalue);
675
676 return 0;
677 }
678
ab5500_val_open(struct inode * inode,struct file * file)679 static int ab5500_val_open(struct inode *inode, struct file *file)
680 {
681 return single_open(file, ab5500_val_print, inode->i_private);
682 }
683
ab5500_val_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)684 static ssize_t ab5500_val_write(struct file *file,
685 const char __user *user_buf,
686 size_t count, loff_t *ppos)
687 {
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;
694
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;
700
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;
708 }
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;
714
715 ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank,
716 (u8)ab->debug_address, ®value);
717 if (err)
718 return -EINVAL;
719
720 return buf_size;
721 }
722
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,
730 };
731
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,
739 };
740
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,
748 };
749
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;
755
ab5500_setup_debugfs(struct ab5500 * ab)756 void __init ab5500_setup_debugfs(struct ab5500 *ab)
757 {
758 ab->debug_bank = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP;
759 ab->debug_address = AB5500_CHIP_ID;
760
761 ab5500_dir = debugfs_create_dir("ab5500", NULL);
762 if (!ab5500_dir)
763 goto exit_no_debugfs;
764
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;
769
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;
774
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;
779
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;
784
785 return;
786
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;
798 }
799
ab5500_remove_debugfs(void)800 void __exit ab5500_remove_debugfs(void)
801 {
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);
807 }
808