b50c70990d5345294ce75397940e57844d9aaa8c
[firefly-linux-kernel-4.4.55.git] / drivers / mfd / rt5025-debug.c
1 /*
2  *  drivers/mfd/rt5025-debug.c
3  *  Driver foo Richtek RT5025 PMIC Debug
4  *
5  *  Copyright (C) 2013 Richtek Electronics
6  *  cy_huang <cy_huang@richtek.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/err.h>
16 #include <linux/i2c.h>
17 #include <linux/platform_device.h>
18 #include <linux/slab.h>
19
20 #include <linux/uaccess.h>
21 #include <linux/debugfs.h>
22 #include <linux/string.h>
23
24 #include <linux/mfd/rt5025.h>
25
26 struct rt5025_debug_info {
27         struct i2c_client *i2c;
28 };
29
30 static struct i2c_client *client;
31 static struct dentry *debugfs_rt_dent;
32 static struct dentry *debugfs_peek;
33 static struct dentry *debugfs_poke;
34 static struct dentry *debugfs_regs;
35
36 static unsigned char read_data[10];
37
38 static int reg_debug_open(struct inode *inode, struct file *file)
39 {
40         file->private_data = inode->i_private;
41         return 0;
42 }
43
44 static int get_parameters(char *buf, long int *param1, int num_of_par)
45 {
46         char *token;
47         int base, cnt;
48
49         token = strsep(&buf, " ");
50
51         for (cnt = 0; cnt < num_of_par; cnt++) {
52                 if (token != NULL) {
53                         if ((token[1] == 'x') || (token[1] == 'X'))
54                                 base = 16;
55                         else
56                                 base = 10;
57
58                         if (strict_strtoul(token, base, &param1[cnt]) != 0)
59                                 return -EINVAL;
60
61                         token = strsep(&buf, " ");
62                         }
63                 else
64                         return -EINVAL;
65         }
66         return 0;
67 }
68
69 #define LOG_FORMAT "0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n"
70
71 static ssize_t reg_debug_read(struct file *filp, char __user *ubuf,
72                                 size_t count, loff_t *ppos)
73 {
74         char *access_str = filp->private_data;
75         char lbuf[150];
76         if (!strcmp(access_str, "regs"))
77         {
78                 RTINFO("read regs file\n");
79                 /* read regs */
80                 snprintf(lbuf, sizeof(lbuf), LOG_FORMAT LOG_FORMAT, read_data[0], \
81                 read_data[1], read_data[2], read_data[3], read_data[4], read_data[5], \
82                 read_data[6], read_data[7], read_data[8], read_data[9]);
83         }
84         else
85                 snprintf(lbuf, sizeof(lbuf), "0x%02x\n", read_data[0]);
86         return simple_read_from_buffer(ubuf, count, ppos, lbuf, strlen(lbuf));
87 }
88
89 static ssize_t reg_debug_write(struct file *filp,
90         const char __user *ubuf, size_t cnt, loff_t *ppos)
91 {
92         char *access_str = filp->private_data;
93         char lbuf[32];
94         int rc;
95         long int param[5];
96
97         if (cnt > sizeof(lbuf) - 1)
98                 return -EINVAL;
99
100         rc = copy_from_user(lbuf, ubuf, cnt);
101         if (rc)
102                 return -EFAULT;
103
104         lbuf[cnt] = '\0';
105
106         if (!strcmp(access_str, "poke")) {
107                 /* write */
108                 rc = get_parameters(lbuf, param, 2);
109                 if ((param[0] <= 0xFF) && (param[1] <= 0xFF) && (rc == 0))
110                 {
111                         rt5025_reg_write(client, param[0], (unsigned char)param[1]);
112                 }
113                 else
114                         rc = -EINVAL;
115         } else if (!strcmp(access_str, "peek")) {
116                 /* read */
117                 rc = get_parameters(lbuf, param, 1);
118                 if ((param[0] <= 0xFF) && (rc == 0))
119                 {
120                         read_data[0] = rt5025_reg_read(client, param[0]);
121                 }
122                 else
123                         rc = -EINVAL;
124         } else if (!strcmp(access_str, "regs")) {
125                 /* read */
126                 rc = get_parameters(lbuf, param, 1);
127                 if ((param[0] <= 0xFF) && (rc == 0))
128                 {
129                         rt5025_reg_block_read(client, param[0], 10, read_data);
130                         RTINFO("regs 0 = 0x%02x\n", read_data[0]);
131                         RTINFO("regs 1 = 0x%02x\n", read_data[1]);
132                         RTINFO("regs 2 = 0x%02x\n", read_data[2]);
133                         RTINFO("regs 3 = 0x%02x\n", read_data[3]);
134                         RTINFO("regs 4 = 0x%02x\n", read_data[4]);
135                         RTINFO("regs 5 = 0x%02x\n", read_data[5]);
136                         RTINFO("regs 6 = 0x%02x\n", read_data[6]);
137                         RTINFO("regs 7 = 0x%02x\n", read_data[7]);
138                         RTINFO("regs 8 = 0x%02x\n", read_data[8]);
139                         RTINFO("regs 9 = 0x%02x\n", read_data[9]);
140                 }
141                 else
142                         rc = -EINVAL;
143         }
144
145         if (rc == 0)
146                 rc = cnt;
147
148         return rc;
149 }
150
151 static const struct file_operations reg_debug_ops = {
152         .open = reg_debug_open,
153         .write = reg_debug_write,
154         .read = reg_debug_read
155 };
156
157 static int __devinit rt5025_debug_probe(struct platform_device *pdev)
158 {
159         struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent);
160         struct rt5025_debug_info *di;
161
162         di = kzalloc(sizeof(*di), GFP_KERNEL);
163         if (!di)
164                 return -ENOMEM;
165
166         di->i2c = chip->i2c;
167
168         RTINFO("add debugfs for core RT5025");
169         client = chip->i2c;
170         debugfs_rt_dent = debugfs_create_dir("rt5025_dbg", 0);
171         if (!IS_ERR(debugfs_rt_dent)) {
172                 debugfs_peek = debugfs_create_file("peek",
173                 S_IFREG | S_IRUGO, debugfs_rt_dent,
174                 (void *) "peek", &reg_debug_ops);
175
176                 debugfs_poke = debugfs_create_file("poke",
177                 S_IFREG | S_IRUGO, debugfs_rt_dent,
178                 (void *) "poke", &reg_debug_ops);
179
180                 debugfs_regs = debugfs_create_file("regs",
181                 S_IFREG | S_IRUGO, debugfs_rt_dent,
182                 (void *) "regs", &reg_debug_ops);
183         }
184
185         platform_set_drvdata(pdev, di);
186
187         return 0;
188 }
189
190 static int __devexit rt5025_debug_remove(struct platform_device *pdev)
191 {
192         struct rt5025_debug_info *di = platform_get_drvdata(pdev);
193
194         if (!IS_ERR(debugfs_rt_dent))
195                 debugfs_remove_recursive(debugfs_rt_dent);
196
197         kfree(di);
198         return 0;
199 }
200
201 static struct platform_driver rt5025_debug_driver = 
202 {
203         .driver = {
204                 .name = RT5025_DEVICE_NAME "-debug",
205                 .owner = THIS_MODULE,
206         },
207         .probe = rt5025_debug_probe,
208         .remove = __devexit_p(rt5025_debug_remove),
209 };
210
211 static int __init rt5025_debug_init(void)
212 {
213         return platform_driver_register(&rt5025_debug_driver);
214 }
215 module_init(rt5025_debug_init);
216
217 static void __exit rt5025_debug_exit(void)
218 {
219         platform_driver_unregister(&rt5025_debug_driver);
220 }
221 module_exit(rt5025_debug_exit);
222
223 MODULE_LICENSE("GPL v2");
224 MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
225 MODULE_DESCRIPTION("Debug driver for RT5025");
226 MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-debug");