blob: 17d7aaad3a8d88d483eadc914eb7a974b405a6c5 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*
2 * Debugfs inteface for Marvell 88PM80X
3 *
4 * Copyright (C) 2014 Marvell International Ltd.
5 * Jett Zhou <jtzhou@marvell.com>
6 * Yi Zhang <yizhang@marvell.com>
7 * Shay Pathov <shayp@marvell.com>
8 *
9 * This file is subject to the terms and conditions of the GNU General
10 * Public License. See the file "COPYING" in the main directory of this
11 * archive for more details.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/mfd/88pm80x.h>
23#include <linux/slab.h>
24#include <linux/uaccess.h>
25
26#define PM80X_BASE_REG_NUM 0xf0
27#define PM80X_POWER_REG_NUM 0x9b
28#define PM80X_GPADC_REG_NUM 0xb6
29
30static int reg_pm800 = 0xffff;
31static int pg_index;
32
33static ssize_t pm800_regdump_read(struct file *file, char __user *userbuf,
34 size_t count, loff_t *ppos)
35{
36 struct pm80x_chip *chip = file->private_data;
37 unsigned int i, reg_val = 0, len = 0;
38 char *buf;
39 ssize_t ret;
40 /* all the registers dumped need almost two pages space to store */
41 buf = kzalloc(PAGE_SIZE * 2, GFP_KERNEL);
42 if (!buf) {
43 pr_err("Cannot allocate buffer!\n");
44 return -ENOMEM;
45 }
46
47 if (reg_pm800 == 0xffff) {
48
49 /* base page */
50 len += sprintf(buf + len, "pm800: base page:\n");
51
52 for (i = 0; i < PM80X_BASE_REG_NUM; i++) {
53 regmap_read(chip->regmap, i, &reg_val);
54 len += sprintf(buf + len, "[0x%02x]=0x%02x\n", i, reg_val);
55 }
56
57 /* power page */
58 len += sprintf(buf + len, "pm800: power page:\n");
59
60 for (i = 0; i < PM80X_POWER_REG_NUM; i++) {
61 regmap_read(chip->subchip->regmap_power, i, &reg_val);
62 len += sprintf(buf + len, "[0x%02x]=0x%02x\n", i, reg_val);
63 }
64
65 if (CHIP_PM803 == chip->type)
66 goto out;
67
68 /* gpadc page */
69 len += sprintf(buf + len, "pm800: gpadc page:\n");
70
71 for (i = 0; i < PM80X_GPADC_REG_NUM; i++) {
72 regmap_read(chip->subchip->regmap_gpadc, i, &reg_val);
73 len += sprintf(buf + len, "[0x%02x]=0x%02x\n", i, reg_val);
74
75 }
76 } else {
77 switch (pg_index) {
78 case 0:
79 regmap_read(chip->regmap, reg_pm800, &reg_val);
80 break;
81 case 1:
82 regmap_read(chip->subchip->regmap_power, reg_pm800,
83 &reg_val);
84 break;
85 case 2:
86 if (CHIP_PM803 == chip->type)
87 goto out;
88 regmap_read(chip->subchip->regmap_gpadc, reg_pm800,
89 &reg_val);
90 break;
91 case 7:
92 regmap_read(chip->subchip->regmap_test, reg_pm800,
93 &reg_val);
94 break;
95 default:
96 pr_err("pg_index error!\n");
97 kfree(buf);
98 return 0;
99 }
100
101 len += sprintf(buf, "reg_pm800=0x%x, pg_index=0x%x, val=0x%x\n",
102 reg_pm800, pg_index, reg_val);
103 }
104
105out:
106 ret = simple_read_from_buffer(userbuf, count, ppos, buf, len);
107 kfree(buf);
108 return ret;
109}
110
111static ssize_t pm800_regdump_write(struct file *file,
112 const char __user *buff,
113 size_t len, loff_t *ppos)
114{
115 u8 reg_val;
116 struct pm80x_chip *chip = file->private_data;
117
118 char messages[20], index[20];
119 memset(messages, '\0', 20);
120 memset(index, '\0', 20);
121
122 if (copy_from_user(messages, buff, len))
123 return -EFAULT;
124
125 if ('-' == messages[0]) {
126 if ((strlen(messages) != 10) &&
127 (strlen(messages) != 9)) {
128 pr_err("Right format: -0x[page_addr] 0x[reg_addr]\n");
129 return len;
130 }
131 /* set the register index */
132 memcpy(index, messages + 1, 3);
133
134 if (kstrtoint(index, 16, &pg_index) < 0)
135 return -EINVAL;
136
137 pr_info("pg_index = 0x%x\n", pg_index);
138
139 memcpy(index, messages + 5, 4);
140 if (kstrtoint(index, 16, &reg_pm800) < 0)
141 return -EINVAL;
142 pr_info("reg_pm800 = 0x%x\n", reg_pm800);
143 } else if ('+' == messages[0]) {
144 /* enable to get all the reg value */
145 reg_pm800 = 0xffff;
146 pr_info("read all reg enabled!\n");
147 } else {
148 if ((reg_pm800 == 0xffff) ||
149 ('0' != messages[0])) {
150 pr_err("Right format: -0x[page_addr] 0x[reg_addr]\n");
151 return len;
152 }
153 /* set the register value */
154 if (kstrtou8(messages, 16, &reg_val) < 0)
155 return -EINVAL;
156
157 switch (pg_index) {
158 case 0:
159 regmap_write(chip->regmap, reg_pm800, reg_val & 0xff);
160 break;
161 case 1:
162 regmap_write(chip->subchip->regmap_power,
163 reg_pm800, reg_val & 0xff);
164 break;
165 case 2:
166 if (CHIP_PM803 == chip->type)
167 break;
168
169 regmap_write(chip->subchip->regmap_gpadc,
170 reg_pm800, reg_val & 0xff);
171 break;
172 case 7:
173 regmap_write(chip->subchip->regmap_test,
174 reg_pm800, reg_val & 0xff);
175 break;
176 default:
177 pr_err("pg_index error!\n");
178 break;
179
180 }
181 }
182
183 return len;
184}
185
186static const struct file_operations pm800_regdump_ops = {
187 .owner = THIS_MODULE,
188 .open = simple_open,
189 .read = pm800_regdump_read,
190 .write = pm800_regdump_write,
191};
192
193static ssize_t pm800_powerup_log_read(struct file *file, char __user *user_buf,
194 size_t count, loff_t *ppos)
195{
196 struct pm80x_chip *chip = file->private_data;
197 unsigned int i, size;
198 int len = 0;
199 char buf[100];
200 char *powerup_name[] = {
201 "ONKEY_WAKEUP",
202 "CHG_WAKEUP",
203 "EXTON_WAKEUP",
204 "RSVD",
205 "RTC_ALARM_WAKEUP",
206 "FAULT_WAKEUP",
207 "BAT_WAKEUP"
208 };
209
210 size = sizeof(powerup_name) / sizeof(char *);
211 for (i = 0; i < size; i++) {
212 if ((1 << i) & chip->powerup)
213 len += sprintf(&buf[len], "0x%x (%s)\n", chip->powerup, powerup_name[i]);
214 }
215
216 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
217}
218
219static const struct file_operations pm800_powerup_log_ops = {
220 .owner = THIS_MODULE,
221 .open = simple_open,
222 .read = pm800_powerup_log_read,
223 .write = NULL,
224};
225
226
227static ssize_t pm800_powerdown_log_read(struct file *file,
228 char __user *user_buf,
229 size_t count, loff_t *ppos)
230{
231 struct pm80x_chip *chip = file->private_data;
232 unsigned int i, size;
233 int len = 0;
234 char buf[100];
235 char *powerdown1_name[] = {
236 "OVER_TEMP",
237 "UV_VSYS1",
238 "SW_PDOWN",
239 "FL_ALARM",
240 "WD",
241 "LONG_ONKEY",
242 "OV_VSYS",
243 "RTC_RESET"
244 };
245 char *powerdown2_name[] = {
246 "HYB_DONE",
247 "UV_VSYS2",
248 "HW_RESET",
249 "PGOOD_PDOWN",
250 "LONKEY_RTC"
251 };
252
253 len += sprintf(&buf[len], "0x%x,0x%x ",
254 chip->powerdown1, chip->powerdown2);
255 if (!chip->powerdown1 && !chip->powerdown2) {
256 len += sprintf(&buf[len], "(NO_PMIC_RESET)\n");
257 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
258 }
259
260 len += sprintf(&buf[len], "(");
261 size = sizeof(powerdown1_name) / sizeof(char *);
262 for (i = 0; i < size; i++) {
263 if ((1 << i) & chip->powerdown1)
264 len += sprintf(&buf[len], "%s ", powerdown1_name[i]);
265 }
266
267 size = sizeof(powerdown2_name) / sizeof(char *);
268 for (i = 0; i < size; i++) {
269 if ((1 << i) & chip->powerdown2)
270 len += sprintf(&buf[len], "%s ", powerdown2_name[i]);
271 }
272
273 len--;
274 len += sprintf(&buf[len], ")\n");
275
276 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
277}
278
279static const struct file_operations pm800_powerdown_log_ops = {
280 .owner = THIS_MODULE,
281 .open = simple_open,
282 .read = pm800_powerdown_log_read,
283 .write = NULL,
284};
285
286static ssize_t pm800_debug_read(struct file *file, char __user *userbuf,
287 size_t count, loff_t *ppos)
288{
289#if defined CONFIG_REGULATOR_88PM800
290 struct pm80x_chip *chip = file->private_data;
291 int len;
292 ssize_t ret = -EINVAL;
293 char *buf;
294
295 if (!chip) {
296 pr_err("Cannot find chip!\n");
297 return -EINVAL;
298 }
299
300 buf = kzalloc(7000, GFP_KERNEL);
301 if (!buf) {
302 pr_err("Cannot allocate buffer!\n");
303 return -ENOMEM;
304 }
305
306 ret = pm800_display_regulator(chip, buf);
307 if (ret < 0) {
308 pr_err("Error in printing the buck & ldo list!\n");
309 goto out_print;
310 }
311
312 len = ret;
313
314 ret = pm800_display_gpadc(chip, buf + len);
315 if (ret < 0) {
316 pr_err("Error in printing the GPADC values!\n");
317 goto out_print;
318 }
319
320 len += ret;
321
322 ret = simple_read_from_buffer(userbuf, count, ppos, buf, len);
323out_print:
324 kfree(buf);
325 return ret;
326#else
327 return 0;
328#endif
329}
330
331static const struct file_operations pm800_debug_ops = {
332 .owner = THIS_MODULE,
333 .open = simple_open,
334 .read = pm800_debug_read,
335 .write = NULL,
336};
337
338static int pm80x_debug_probe(struct platform_device *pdev)
339{
340 struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
341 struct dentry *pm800_regdump_reg;
342 struct dentry *pm800_powerup_log;
343 struct dentry *pm800_powerdown_log;
344
345 pm800_regdump_reg = debugfs_create_file("pm800_reg", S_IRUGO | S_IFREG,
346 NULL, (void *)chip, &pm800_regdump_ops);
347
348 if (pm800_regdump_reg == NULL) {
349 dev_err(&pdev->dev, "create pm800 debugfs error!\n");
350 return -ENOENT;
351 } else if (pm800_regdump_reg == ERR_PTR(-ENODEV)) {
352 dev_err(&pdev->dev, "pm800_regdump_reg error!\n");
353 return -ENOENT;
354 }
355
356 pm800_powerup_log =
357 debugfs_create_file("pm800_powerup_log", S_IRUGO | S_IFREG,
358 NULL, (void *)chip, &pm800_powerup_log_ops);
359
360 if (pm800_powerup_log == NULL) {
361 dev_err(&pdev->dev, "create pm800_powerup_log debugfs error!\n");
362 return -ENOENT;
363 } else if (pm800_powerup_log == ERR_PTR(-ENODEV)) {
364 dev_err(&pdev->dev, "CONFIG_DEBUG_FS is not enabled!\n");
365 return -ENOENT;
366 }
367
368 pm800_powerdown_log =
369 debugfs_create_file("pm800_powerdown_log", S_IRUGO | S_IFREG,
370 NULL, (void *)chip, &pm800_powerdown_log_ops);
371
372 if (pm800_powerdown_log == NULL) {
373 dev_err(&pdev->dev, "create pm800_powerdown_log debugfs error!\n");
374 return -ENOENT;
375 } else if (pm800_powerdown_log == ERR_PTR(-ENODEV)) {
376 dev_err(&pdev->dev, "CONFIG_DEBUG_FS is not enabled!\n");
377 return -ENOENT;
378 }
379
380 chip->debugfs = debugfs_create_file("pm800_debug", S_IRUGO | S_IFREG,
381 NULL, (void *)chip, &pm800_debug_ops);
382
383 if (chip->debugfs == NULL) {
384 dev_err(&pdev->dev, "create pm800_debug debugfs error!\n");
385 return -ENOENT;
386 } else if (chip->debugfs == ERR_PTR(-ENODEV)) {
387 dev_err(&pdev->dev, "CONFIG_DEBUG_FS is not enabled!\n");
388 return -ENOENT;
389 }
390
391 return 0;
392}
393
394static int pm80x_debug_remove(struct platform_device *pdev)
395{
396 struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
397
398 debugfs_remove_recursive(chip->debugfs);
399 return 0;
400}
401
402static struct platform_driver pm80x_debug_driver = {
403 .probe = pm80x_debug_probe,
404 .remove = pm80x_debug_remove,
405 .driver = {
406 .owner = THIS_MODULE,
407 .name = "88pm80x-debug",
408 },
409};
410
411module_platform_driver(pm80x_debug_driver);
412
413MODULE_LICENSE("GPL");
414MODULE_DESCRIPTION("88pm80x debug Driver");
415MODULE_AUTHOR("Yi Zhang<yizhang@marvell.com>");