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
17static 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
515static 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
562static int ab5500_registers_open(struct inode *inode, struct file *file)
563{
564	return single_open(file, ab5500_registers_print, inode->i_private);
565}
566
567static 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
575static 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
583static int ab5500_bank_open(struct inode *inode, struct file *file)
584{
585	return single_open(file, ab5500_bank_print, inode->i_private);
586}
587
588static 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
619static 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
627static int ab5500_address_open(struct inode *inode, struct file *file)
628{
629	return single_open(file, ab5500_address_print, inode->i_private);
630}
631
632static 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
660static 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, &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;
673	}
674	seq_printf(s, "0x%02X\n", regvalue);
675
676	return 0;
677}
678
679static int ab5500_val_open(struct inode *inode, struct file *file)
680{
681	return single_open(file, ab5500_val_print, inode->i_private);
682}
683
684static 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, &regvalue);
717	if (err)
718		return -EINVAL;
719
720	return buf_size;
721}
722
723static 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
732static 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
741static 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
750static struct dentry *ab5500_dir;
751static struct dentry *ab5500_reg_file;
752static struct dentry *ab5500_bank_file;
753static struct dentry *ab5500_address_file;
754static struct dentry *ab5500_val_file;
755
756void __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
787exit_destroy_address:
788	debugfs_remove(ab5500_address_file);
789exit_destroy_bank:
790	debugfs_remove(ab5500_bank_file);
791exit_destroy_reg:
792	debugfs_remove(ab5500_reg_file);
793exit_destroy_dir:
794	debugfs_remove(ab5500_dir);
795exit_no_debugfs:
796	dev_err(ab->dev, "failed to create debugfs entries.\n");
797	return;
798}
799
800void __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