blob: 6be1fe6b5f9ac70c8ef31df1a3d546a3dc695707 [file] [log] [blame]
Linus Walleij94be70d2011-09-22 08:22:33 +02001/*
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/debugfs.h>
8#include <linux/seq_file.h>
9#include <linux/mfd/ab5500/ab5500.h>
10#include <linux/mfd/abx500.h>
11#include <linux/uaccess.h>
12
13#include "ab5500-core.h"
14#include "ab5500-debugfs.h"
15
16static struct ab5500_i2c_ranges ab5500_reg_ranges[AB5500_NUM_BANKS] = {
17 [AB5500_BANK_LED] = {
18 .bankid = AB5500_BANK_LED,
19 .nranges = 1,
20 .range = (struct ab5500_reg_range[]) {
21 {
22 .first = 0x00,
23 .last = 0x0C,
24 .perm = AB5500_PERM_RW,
25 },
26 },
27 },
28 [AB5500_BANK_ADC] = {
29 .bankid = AB5500_BANK_ADC,
30 .nranges = 6,
31 .range = (struct ab5500_reg_range[]) {
32 {
33 .first = 0x1F,
34 .last = 0x22,
35 .perm = AB5500_PERM_RO,
36 },
37 {
38 .first = 0x23,
39 .last = 0x24,
40 .perm = AB5500_PERM_RW,
41 },
42 {
43 .first = 0x26,
44 .last = 0x2D,
45 .perm = AB5500_PERM_RO,
46 },
47 {
48 .first = 0x2F,
49 .last = 0x34,
50 .perm = AB5500_PERM_RW,
51 },
52 {
53 .first = 0x37,
54 .last = 0x57,
55 .perm = AB5500_PERM_RW,
56 },
57 {
58 .first = 0x58,
59 .last = 0x58,
60 .perm = AB5500_PERM_RO,
61 },
62 },
63 },
64 [AB5500_BANK_RTC] = {
65 .bankid = AB5500_BANK_RTC,
66 .nranges = 2,
67 .range = (struct ab5500_reg_range[]) {
68 {
69 .first = 0x00,
70 .last = 0x04,
71 .perm = AB5500_PERM_RW,
72 },
73 {
74 .first = 0x06,
75 .last = 0x0C,
76 .perm = AB5500_PERM_RW,
77 },
78 },
79 },
80 [AB5500_BANK_STARTUP] = {
81 .bankid = AB5500_BANK_STARTUP,
82 .nranges = 12,
83 .range = (struct ab5500_reg_range[]) {
84 {
85 .first = 0x00,
86 .last = 0x01,
87 .perm = AB5500_PERM_RW,
88 },
89 {
90 .first = 0x1F,
91 .last = 0x1F,
92 .perm = AB5500_PERM_RW,
93 },
94 {
95 .first = 0x2E,
96 .last = 0x2E,
97 .perm = AB5500_PERM_RO,
98 },
99 {
100 .first = 0x2F,
101 .last = 0x30,
102 .perm = AB5500_PERM_RW,
103 },
104 {
105 .first = 0x50,
106 .last = 0x51,
107 .perm = AB5500_PERM_RW,
108 },
109 {
110 .first = 0x60,
111 .last = 0x61,
112 .perm = AB5500_PERM_RW,
113 },
114 {
115 .first = 0x66,
116 .last = 0x8A,
117 .perm = AB5500_PERM_RW,
118 },
119 {
120 .first = 0x8C,
121 .last = 0x96,
122 .perm = AB5500_PERM_RW,
123 },
124 {
125 .first = 0xAA,
126 .last = 0xB4,
127 .perm = AB5500_PERM_RW,
128 },
129 {
130 .first = 0xB7,
131 .last = 0xBF,
132 .perm = AB5500_PERM_RW,
133 },
134 {
135 .first = 0xC1,
136 .last = 0xCA,
137 .perm = AB5500_PERM_RW,
138 },
139 {
140 .first = 0xD3,
141 .last = 0xE0,
142 .perm = AB5500_PERM_RW,
143 },
144 },
145 },
146 [AB5500_BANK_DBI_ECI] = {
147 .bankid = AB5500_BANK_DBI_ECI,
148 .nranges = 3,
149 .range = (struct ab5500_reg_range[]) {
150 {
151 .first = 0x00,
152 .last = 0x07,
153 .perm = AB5500_PERM_RW,
154 },
155 {
156 .first = 0x10,
157 .last = 0x10,
158 .perm = AB5500_PERM_RW,
159 },
160 {
161 .first = 0x13,
162 .last = 0x13,
163 .perm = AB5500_PERM_RW,
164 },
165 },
166 },
167 [AB5500_BANK_CHG] = {
168 .bankid = AB5500_BANK_CHG,
169 .nranges = 2,
170 .range = (struct ab5500_reg_range[]) {
171 {
172 .first = 0x11,
173 .last = 0x11,
174 .perm = AB5500_PERM_RO,
175 },
176 {
177 .first = 0x12,
178 .last = 0x1B,
179 .perm = AB5500_PERM_RW,
180 },
181 },
182 },
183 [AB5500_BANK_FG_BATTCOM_ACC] = {
184 .bankid = AB5500_BANK_FG_BATTCOM_ACC,
185 .nranges = 2,
186 .range = (struct ab5500_reg_range[]) {
187 {
188 .first = 0x00,
189 .last = 0x0B,
190 .perm = AB5500_PERM_RO,
191 },
192 {
193 .first = 0x0C,
194 .last = 0x10,
195 .perm = AB5500_PERM_RW,
196 },
197 },
198 },
199 [AB5500_BANK_USB] = {
200 .bankid = AB5500_BANK_USB,
201 .nranges = 12,
202 .range = (struct ab5500_reg_range[]) {
203 {
204 .first = 0x01,
205 .last = 0x01,
206 .perm = AB5500_PERM_RW,
207 },
208 {
209 .first = 0x80,
210 .last = 0x83,
211 .perm = AB5500_PERM_RW,
212 },
213 {
214 .first = 0x87,
215 .last = 0x8A,
216 .perm = AB5500_PERM_RW,
217 },
218 {
219 .first = 0x8B,
220 .last = 0x8B,
221 .perm = AB5500_PERM_RO,
222 },
223 {
224 .first = 0x91,
225 .last = 0x92,
226 .perm = AB5500_PERM_RO,
227 },
228 {
229 .first = 0x93,
230 .last = 0x93,
231 .perm = AB5500_PERM_RW,
232 },
233 {
234 .first = 0x94,
235 .last = 0x94,
236 .perm = AB5500_PERM_RO,
237 },
238 {
239 .first = 0xA8,
240 .last = 0xB0,
241 .perm = AB5500_PERM_RO,
242 },
243 {
244 .first = 0xB2,
245 .last = 0xB2,
246 .perm = AB5500_PERM_RO,
247 },
248 {
249 .first = 0xB4,
250 .last = 0xBC,
251 .perm = AB5500_PERM_RO,
252 },
253 {
254 .first = 0xBF,
255 .last = 0xBF,
256 .perm = AB5500_PERM_RO,
257 },
258 {
259 .first = 0xC1,
260 .last = 0xC5,
261 .perm = AB5500_PERM_RO,
262 },
263 },
264 },
265 [AB5500_BANK_IT] = {
266 .bankid = AB5500_BANK_IT,
267 .nranges = 4,
268 .range = (struct ab5500_reg_range[]) {
269 {
270 .first = 0x00,
271 .last = 0x02,
272 .perm = AB5500_PERM_RO,
273 },
274 {
275 .first = 0x20,
276 .last = 0x36,
277 .perm = AB5500_PERM_RO,
278 },
279 {
280 .first = 0x40,
281 .last = 0x56,
282 .perm = AB5500_PERM_RO,
283 },
284 {
285 .first = 0x60,
286 .last = 0x76,
287 .perm = AB5500_PERM_RO,
288 },
289 },
290 },
291 [AB5500_BANK_VDDDIG_IO_I2C_CLK_TST] = {
292 .bankid = AB5500_BANK_VDDDIG_IO_I2C_CLK_TST,
293 .nranges = 7,
294 .range = (struct ab5500_reg_range[]) {
295 {
296 .first = 0x02,
297 .last = 0x02,
298 .perm = AB5500_PERM_RW,
299 },
300 {
301 .first = 0x12,
302 .last = 0x12,
303 .perm = AB5500_PERM_RW,
304 },
305 {
306 .first = 0x30,
307 .last = 0x34,
308 .perm = AB5500_PERM_RW,
309 },
310 {
311 .first = 0x40,
312 .last = 0x44,
313 .perm = AB5500_PERM_RW,
314 },
315 {
316 .first = 0x50,
317 .last = 0x54,
318 .perm = AB5500_PERM_RW,
319 },
320 {
321 .first = 0x60,
322 .last = 0x64,
323 .perm = AB5500_PERM_RW,
324 },
325 {
326 .first = 0x70,
327 .last = 0x74,
328 .perm = AB5500_PERM_RW,
329 },
330 },
331 },
332 [AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP] = {
333 .bankid = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP,
334 .nranges = 13,
335 .range = (struct ab5500_reg_range[]) {
336 {
337 .first = 0x01,
338 .last = 0x01,
339 .perm = AB5500_PERM_RW,
340 },
341 {
342 .first = 0x02,
343 .last = 0x02,
344 .perm = AB5500_PERM_RO,
345 },
346 {
347 .first = 0x0D,
348 .last = 0x0F,
349 .perm = AB5500_PERM_RW,
350 },
351 {
352 .first = 0x1C,
353 .last = 0x1C,
354 .perm = AB5500_PERM_RW,
355 },
356 {
357 .first = 0x1E,
358 .last = 0x1E,
359 .perm = AB5500_PERM_RW,
360 },
361 {
362 .first = 0x20,
363 .last = 0x21,
364 .perm = AB5500_PERM_RW,
365 },
366 {
367 .first = 0x25,
368 .last = 0x25,
369 .perm = AB5500_PERM_RW,
370 },
371 {
372 .first = 0x28,
373 .last = 0x2A,
374 .perm = AB5500_PERM_RW,
375 },
376 {
377 .first = 0x30,
378 .last = 0x33,
379 .perm = AB5500_PERM_RW,
380 },
381 {
382 .first = 0x40,
383 .last = 0x43,
384 .perm = AB5500_PERM_RW,
385 },
386 {
387 .first = 0x50,
388 .last = 0x53,
389 .perm = AB5500_PERM_RW,
390 },
391 {
392 .first = 0x60,
393 .last = 0x63,
394 .perm = AB5500_PERM_RW,
395 },
396 {
397 .first = 0x70,
398 .last = 0x73,
399 .perm = AB5500_PERM_RW,
400 },
401 },
402 },
403 [AB5500_BANK_VIBRA] = {
404 .bankid = AB5500_BANK_VIBRA,
405 .nranges = 2,
406 .range = (struct ab5500_reg_range[]) {
407 {
408 .first = 0x10,
409 .last = 0x13,
410 .perm = AB5500_PERM_RW,
411 },
412 {
413 .first = 0xFE,
414 .last = 0xFE,
415 .perm = AB5500_PERM_RW,
416 },
417 },
418 },
419 [AB5500_BANK_AUDIO_HEADSETUSB] = {
420 .bankid = AB5500_BANK_AUDIO_HEADSETUSB,
421 .nranges = 2,
422 .range = (struct ab5500_reg_range[]) {
423 {
424 .first = 0x00,
425 .last = 0x48,
426 .perm = AB5500_PERM_RW,
427 },
428 {
429 .first = 0xEB,
430 .last = 0xFB,
431 .perm = AB5500_PERM_RW,
432 },
433 },
434 },
435 [AB5500_BANK_SIM_USBSIM] = {
436 .bankid = AB5500_BANK_SIM_USBSIM,
437 .nranges = 1,
438 .range = (struct ab5500_reg_range[]) {
439 {
440 .first = 0x13,
441 .last = 0x19,
442 .perm = AB5500_PERM_RW,
443 },
444 },
445 },
446 [AB5500_BANK_VDENC] = {
447 .bankid = AB5500_BANK_VDENC,
448 .nranges = 12,
449 .range = (struct ab5500_reg_range[]) {
450 {
451 .first = 0x00,
452 .last = 0x08,
453 .perm = AB5500_PERM_RW,
454 },
455 {
456 .first = 0x09,
457 .last = 0x09,
458 .perm = AB5500_PERM_RO,
459 },
460 {
461 .first = 0x0A,
462 .last = 0x12,
463 .perm = AB5500_PERM_RW,
464 },
465 {
466 .first = 0x15,
467 .last = 0x19,
468 .perm = AB5500_PERM_RW,
469 },
470 {
471 .first = 0x1B,
472 .last = 0x21,
473 .perm = AB5500_PERM_RW,
474 },
475 {
476 .first = 0x27,
477 .last = 0x2C,
478 .perm = AB5500_PERM_RW,
479 },
480 {
481 .first = 0x41,
482 .last = 0x41,
483 .perm = AB5500_PERM_RW,
484 },
485 {
486 .first = 0x45,
487 .last = 0x5B,
488 .perm = AB5500_PERM_RW,
489 },
490 {
491 .first = 0x5D,
492 .last = 0x5D,
493 .perm = AB5500_PERM_RW,
494 },
495 {
496 .first = 0x69,
497 .last = 0x69,
498 .perm = AB5500_PERM_RW,
499 },
500 {
501 .first = 0x6C,
502 .last = 0x6D,
503 .perm = AB5500_PERM_RW,
504 },
505 {
506 .first = 0x80,
507 .last = 0x81,
508 .perm = AB5500_PERM_RW,
509 },
510 },
511 },
512};
513
514static int ab5500_registers_print(struct seq_file *s, void *p)
515{
516 struct ab5500 *ab = s->private;
517 unsigned int i;
518 u8 bank = (u8)ab->debug_bank;
519
520 seq_printf(s, "ab5500 register values:\n");
521 for (bank = 0; bank < AB5500_NUM_BANKS; bank++) {
522 seq_printf(s, " bank %u, %s (0x%x):\n", bank,
523 bankinfo[bank].name,
524 bankinfo[bank].slave_addr);
525 for (i = 0; i < ab5500_reg_ranges[bank].nranges; i++) {
526 u8 reg;
527 int err;
528
529 for (reg = ab5500_reg_ranges[bank].range[i].first;
530 reg <= ab5500_reg_ranges[bank].range[i].last;
531 reg++) {
532 u8 value;
533
534 err = ab5500_get_register_interruptible_raw(ab,
535 bank, reg,
536 &value);
537 if (err < 0) {
538 dev_err(ab->dev, "get_reg failed %d"
539 "bank 0x%x reg 0x%x\n",
540 err, bank, reg);
541 return err;
542 }
543
544 err = seq_printf(s, "[%d/0x%02X]: 0x%02X\n",
545 bank, reg, value);
546 if (err < 0) {
547 dev_err(ab->dev,
548 "seq_printf overflow\n");
549 /*
550 * Error is not returned here since
551 * the output is wanted in any case
552 */
553 return 0;
554 }
555 }
556 }
557 }
558 return 0;
559}
560
561static int ab5500_registers_open(struct inode *inode, struct file *file)
562{
563 return single_open(file, ab5500_registers_print, inode->i_private);
564}
565
566static const struct file_operations ab5500_registers_fops = {
567 .open = ab5500_registers_open,
568 .read = seq_read,
569 .llseek = seq_lseek,
570 .release = single_release,
571 .owner = THIS_MODULE,
572};
573
574static int ab5500_bank_print(struct seq_file *s, void *p)
575{
576 struct ab5500 *ab = s->private;
577
578 seq_printf(s, "%d\n", ab->debug_bank);
579 return 0;
580}
581
582static int ab5500_bank_open(struct inode *inode, struct file *file)
583{
584 return single_open(file, ab5500_bank_print, inode->i_private);
585}
586
587static ssize_t ab5500_bank_write(struct file *file,
588 const char __user *user_buf,
589 size_t count, loff_t *ppos)
590{
591 struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
592 char buf[32];
593 int buf_size;
594 unsigned long user_bank;
595 int err;
596
597 /* Get userspace string and assure termination */
598 buf_size = min(count, (sizeof(buf) - 1));
599 if (copy_from_user(buf, user_buf, buf_size))
600 return -EFAULT;
601 buf[buf_size] = 0;
602
603 err = strict_strtoul(buf, 0, &user_bank);
604 if (err)
605 return -EINVAL;
606
607 if (user_bank >= AB5500_NUM_BANKS) {
608 dev_err(ab->dev,
609 "debugfs error input > number of banks\n");
610 return -EINVAL;
611 }
612
613 ab->debug_bank = user_bank;
614
615 return buf_size;
616}
617
618static int ab5500_address_print(struct seq_file *s, void *p)
619{
620 struct ab5500 *ab = s->private;
621
622 seq_printf(s, "0x%02X\n", ab->debug_address);
623 return 0;
624}
625
626static int ab5500_address_open(struct inode *inode, struct file *file)
627{
628 return single_open(file, ab5500_address_print, inode->i_private);
629}
630
631static ssize_t ab5500_address_write(struct file *file,
632 const char __user *user_buf,
633 size_t count, loff_t *ppos)
634{
635 struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
636 char buf[32];
637 int buf_size;
638 unsigned long user_address;
639 int err;
640
641 /* Get userspace string and assure termination */
642 buf_size = min(count, (sizeof(buf) - 1));
643 if (copy_from_user(buf, user_buf, buf_size))
644 return -EFAULT;
645 buf[buf_size] = 0;
646
647 err = strict_strtoul(buf, 0, &user_address);
648 if (err)
649 return -EINVAL;
650 if (user_address > 0xff) {
651 dev_err(ab->dev,
652 "debugfs error input > 0xff\n");
653 return -EINVAL;
654 }
655 ab->debug_address = user_address;
656 return buf_size;
657}
658
659static int ab5500_val_print(struct seq_file *s, void *p)
660{
661 struct ab5500 *ab = s->private;
662 int err;
663 u8 regvalue;
664
665 err = ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank,
666 (u8)ab->debug_address, &regvalue);
667 if (err) {
668 dev_err(ab->dev, "get_reg failed %d, bank 0x%x"
669 ", reg 0x%x\n", err, ab->debug_bank,
670 ab->debug_address);
671 return -EINVAL;
672 }
673 seq_printf(s, "0x%02X\n", regvalue);
674
675 return 0;
676}
677
678static int ab5500_val_open(struct inode *inode, struct file *file)
679{
680 return single_open(file, ab5500_val_print, inode->i_private);
681}
682
683static ssize_t ab5500_val_write(struct file *file,
684 const char __user *user_buf,
685 size_t count, loff_t *ppos)
686{
687 struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
688 char buf[32];
689 int buf_size;
690 unsigned long user_val;
691 int err;
692 u8 regvalue;
693
694 /* Get userspace string and assure termination */
695 buf_size = min(count, (sizeof(buf)-1));
696 if (copy_from_user(buf, user_buf, buf_size))
697 return -EFAULT;
698 buf[buf_size] = 0;
699
700 err = strict_strtoul(buf, 0, &user_val);
701 if (err)
702 return -EINVAL;
703 if (user_val > 0xff) {
704 dev_err(ab->dev,
705 "debugfs error input > 0xff\n");
706 return -EINVAL;
707 }
708 err = ab5500_mask_and_set_register_interruptible_raw(
709 ab, (u8)ab->debug_bank,
710 (u8)ab->debug_address, 0xFF, (u8)user_val);
711 if (err)
712 return -EINVAL;
713
714 ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank,
715 (u8)ab->debug_address, &regvalue);
716 if (err)
717 return -EINVAL;
718
719 return buf_size;
720}
721
722static const struct file_operations ab5500_bank_fops = {
723 .open = ab5500_bank_open,
724 .write = ab5500_bank_write,
725 .read = seq_read,
726 .llseek = seq_lseek,
727 .release = single_release,
728 .owner = THIS_MODULE,
729};
730
731static const struct file_operations ab5500_address_fops = {
732 .open = ab5500_address_open,
733 .write = ab5500_address_write,
734 .read = seq_read,
735 .llseek = seq_lseek,
736 .release = single_release,
737 .owner = THIS_MODULE,
738};
739
740static const struct file_operations ab5500_val_fops = {
741 .open = ab5500_val_open,
742 .write = ab5500_val_write,
743 .read = seq_read,
744 .llseek = seq_lseek,
745 .release = single_release,
746 .owner = THIS_MODULE,
747};
748
749static struct dentry *ab5500_dir;
750static struct dentry *ab5500_reg_file;
751static struct dentry *ab5500_bank_file;
752static struct dentry *ab5500_address_file;
753static struct dentry *ab5500_val_file;
754
755void __init ab5500_setup_debugfs(struct ab5500 *ab)
756{
757 ab->debug_bank = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP;
758 ab->debug_address = AB5500_CHIP_ID;
759
760 ab5500_dir = debugfs_create_dir("ab5500", NULL);
761 if (!ab5500_dir)
762 goto exit_no_debugfs;
763
764 ab5500_reg_file = debugfs_create_file("all-bank-registers",
765 S_IRUGO, ab5500_dir, ab, &ab5500_registers_fops);
766 if (!ab5500_reg_file)
767 goto exit_destroy_dir;
768
769 ab5500_bank_file = debugfs_create_file("register-bank",
770 (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_bank_fops);
771 if (!ab5500_bank_file)
772 goto exit_destroy_reg;
773
774 ab5500_address_file = debugfs_create_file("register-address",
775 (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_address_fops);
776 if (!ab5500_address_file)
777 goto exit_destroy_bank;
778
779 ab5500_val_file = debugfs_create_file("register-value",
780 (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_val_fops);
781 if (!ab5500_val_file)
782 goto exit_destroy_address;
783
784 return;
785
786exit_destroy_address:
787 debugfs_remove(ab5500_address_file);
788exit_destroy_bank:
789 debugfs_remove(ab5500_bank_file);
790exit_destroy_reg:
791 debugfs_remove(ab5500_reg_file);
792exit_destroy_dir:
793 debugfs_remove(ab5500_dir);
794exit_no_debugfs:
795 dev_err(ab->dev, "failed to create debugfs entries.\n");
796 return;
797}
798
799void __exit ab5500_remove_debugfs(void)
800{
801 debugfs_remove(ab5500_val_file);
802 debugfs_remove(ab5500_address_file);
803 debugfs_remove(ab5500_bank_file);
804 debugfs_remove(ab5500_reg_file);
805 debugfs_remove(ab5500_dir);
806}