blob: cd3cee814fb763bba3cf161e9181cf2597aaa5fc [file] [log] [blame]
Mattias Wallin5814fc32010-09-13 16:05:04 +02001/*
2 * Copyright (C) ST-Ericsson SA 2010
3 *
4 * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson.
5 * License Terms: GNU General Public License v2
6 */
carriere etienne0fbce762011-04-08 16:26:36 +02007/*
8 * AB8500 register access
9 * ======================
10 *
11 * read:
12 * # echo BANK > <debugfs>/ab8500/register-bank
13 * # echo ADDR > <debugfs>/ab8500/register-address
14 * # cat <debugfs>/ab8500/register-value
15 *
16 * write:
17 * # echo BANK > <debugfs>/ab8500/register-bank
18 * # echo ADDR > <debugfs>/ab8500/register-address
19 * # echo VALUE > <debugfs>/ab8500/register-value
20 *
21 * read all registers from a bank:
22 * # echo BANK > <debugfs>/ab8500/register-bank
23 * # cat <debugfs>/ab8500/all-bank-register
24 *
25 * BANK target AB8500 register bank
26 * ADDR target AB8500 register address
27 * VALUE decimal or 0x-prefixed hexadecimal
28 *
29 *
30 * User Space notification on AB8500 IRQ
31 * =====================================
32 *
33 * Allows user space entity to be notified when target AB8500 IRQ occurs.
34 * When subscribed, a sysfs entry is created in ab8500.i2c platform device.
35 * One can pool this file to get target IRQ occurence information.
36 *
37 * subscribe to an AB8500 IRQ:
38 * # echo IRQ > <debugfs>/ab8500/irq-subscribe
39 *
40 * unsubscribe from an AB8500 IRQ:
41 * # echo IRQ > <debugfs>/ab8500/irq-unsubscribe
42 *
43 *
44 * AB8500 register formated read/write access
45 * ==========================================
46 *
47 * Read: read data, data>>SHIFT, data&=MASK, output data
48 * [0xABCDEF98] shift=12 mask=0xFFF => 0x00000CDE
49 * Write: read data, data &= ~(MASK<<SHIFT), data |= (VALUE<<SHIFT), write data
50 * [0xABCDEF98] shift=12 mask=0xFFF value=0x123 => [0xAB123F98]
51 *
52 * Usage:
53 * # echo "CMD [OPTIONS] BANK ADRESS [VALUE]" > $debugfs/ab8500/hwreg
54 *
55 * CMD read read access
56 * write write access
57 *
58 * BANK target reg bank
59 * ADDRESS target reg address
60 * VALUE (write) value to be updated
61 *
62 * OPTIONS
63 * -d|-dec (read) output in decimal
64 * -h|-hexa (read) output in 0x-hexa (default)
65 * -l|-w|-b 32bit (default), 16bit or 8bit reg access
66 * -m|-mask MASK 0x-hexa mask (default 0xFFFFFFFF)
67 * -s|-shift SHIFT bit shift value (read:left, write:right)
68 * -o|-offset OFFSET address offset to add to ADDRESS value
69 *
70 * Warning: bit shift operation is applied to bit-mask.
71 * Warning: bit shift direction depends on read or right command.
72 */
Mattias Wallin5814fc32010-09-13 16:05:04 +020073
74#include <linux/seq_file.h>
75#include <linux/uaccess.h>
76#include <linux/fs.h>
Paul Gortmaker4e36dd32011-07-03 15:13:27 -040077#include <linux/module.h>
Mattias Wallin5814fc32010-09-13 16:05:04 +020078#include <linux/debugfs.h>
79#include <linux/platform_device.h>
Lee Jones4b8ac082013-01-14 16:10:36 +000080#include <linux/interrupt.h>
81#include <linux/kobject.h>
82#include <linux/slab.h>
Mattias Wallin5814fc32010-09-13 16:05:04 +020083
84#include <linux/mfd/abx500.h>
John Beckett1478a312011-05-31 13:54:27 +010085#include <linux/mfd/abx500/ab8500-gpadc.h>
Mattias Wallin5814fc32010-09-13 16:05:04 +020086
carriere etienne0fbce762011-04-08 16:26:36 +020087#ifdef CONFIG_DEBUG_FS
88#include <linux/string.h>
89#include <linux/ctype.h>
90#endif
91
Mattias Wallin5814fc32010-09-13 16:05:04 +020092static u32 debug_bank;
93static u32 debug_address;
94
Lee Jones4b8ac082013-01-14 16:10:36 +000095static int irq_first;
96static int irq_last;
Mattias Wallin0b337e72010-11-19 17:55:11 +010097static u32 irq_count[AB8500_NR_IRQS];
98
99static struct device_attribute *dev_attr[AB8500_NR_IRQS];
100static char *event_name[AB8500_NR_IRQS];
Lee Jones4b8ac082013-01-14 16:10:36 +0000101
Mattias Wallin5814fc32010-09-13 16:05:04 +0200102/**
103 * struct ab8500_reg_range
104 * @first: the first address of the range
105 * @last: the last address of the range
106 * @perm: access permissions for the range
107 */
108struct ab8500_reg_range {
Mattias Wallind7b9f322010-11-26 13:06:39 +0100109 u8 first;
110 u8 last;
111 u8 perm;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200112};
113
114/**
Lee Jones822672a2012-06-20 13:56:38 +0100115 * struct ab8500_prcmu_ranges
Mattias Wallin5814fc32010-09-13 16:05:04 +0200116 * @num_ranges: the number of ranges in the list
117 * @bankid: bank identifier
118 * @range: the list of register ranges
119 */
Lee Jones822672a2012-06-20 13:56:38 +0100120struct ab8500_prcmu_ranges {
Mattias Wallind7b9f322010-11-26 13:06:39 +0100121 u8 num_ranges;
122 u8 bankid;
123 const struct ab8500_reg_range *range;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200124};
125
carriere etienne0fbce762011-04-08 16:26:36 +0200126/* hwreg- "mask" and "shift" entries ressources */
127struct hwreg_cfg {
128 u32 bank; /* target bank */
129 u32 addr; /* target address */
130 uint fmt; /* format */
131 uint mask; /* read/write mask, applied before any bit shift */
132 int shift; /* bit shift (read:right shift, write:left shift */
133};
134/* fmt bit #0: 0=hexa, 1=dec */
135#define REG_FMT_DEC(c) ((c)->fmt & 0x1)
136#define REG_FMT_HEX(c) (!REG_FMT_DEC(c))
137
138static struct hwreg_cfg hwreg_cfg = {
139 .addr = 0, /* default: invalid phys addr */
140 .fmt = 0, /* default: 32bit access, hex output */
141 .mask = 0xFFFFFFFF, /* default: no mask */
142 .shift = 0, /* default: no bit shift */
143};
144
Mattias Wallin5814fc32010-09-13 16:05:04 +0200145#define AB8500_NAME_STRING "ab8500"
John Beckett1478a312011-05-31 13:54:27 +0100146#define AB8500_ADC_NAME_STRING "gpadc"
Philippe Langlais40c064e2011-10-17 09:48:55 +0200147#define AB8500_NUM_BANKS 24
Mattias Wallin5814fc32010-09-13 16:05:04 +0200148
149#define AB8500_REV_REG 0x80
150
Lee Jones822672a2012-06-20 13:56:38 +0100151static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
Mattias Wallind7b9f322010-11-26 13:06:39 +0100152 [0x0] = {
153 .num_ranges = 0,
Lee Jonesfad55a82013-01-14 17:17:34 +0000154 .range = NULL,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100155 },
156 [AB8500_SYS_CTRL1_BLOCK] = {
157 .num_ranges = 3,
158 .range = (struct ab8500_reg_range[]) {
159 {
160 .first = 0x00,
161 .last = 0x02,
162 },
163 {
164 .first = 0x42,
165 .last = 0x42,
166 },
167 {
168 .first = 0x80,
169 .last = 0x81,
170 },
171 },
172 },
173 [AB8500_SYS_CTRL2_BLOCK] = {
174 .num_ranges = 4,
175 .range = (struct ab8500_reg_range[]) {
176 {
177 .first = 0x00,
178 .last = 0x0D,
179 },
180 {
181 .first = 0x0F,
182 .last = 0x17,
183 },
184 {
185 .first = 0x30,
186 .last = 0x30,
187 },
188 {
189 .first = 0x32,
190 .last = 0x33,
191 },
192 },
193 },
194 [AB8500_REGU_CTRL1] = {
195 .num_ranges = 3,
196 .range = (struct ab8500_reg_range[]) {
197 {
198 .first = 0x00,
199 .last = 0x00,
200 },
201 {
202 .first = 0x03,
203 .last = 0x10,
204 },
205 {
206 .first = 0x80,
207 .last = 0x84,
208 },
209 },
210 },
211 [AB8500_REGU_CTRL2] = {
212 .num_ranges = 5,
213 .range = (struct ab8500_reg_range[]) {
214 {
215 .first = 0x00,
216 .last = 0x15,
217 },
218 {
219 .first = 0x17,
220 .last = 0x19,
221 },
222 {
223 .first = 0x1B,
224 .last = 0x1D,
225 },
226 {
227 .first = 0x1F,
228 .last = 0x22,
229 },
230 {
231 .first = 0x40,
232 .last = 0x44,
233 },
234 /* 0x80-0x8B is SIM registers and should
235 * not be accessed from here */
236 },
237 },
238 [AB8500_USB] = {
239 .num_ranges = 2,
240 .range = (struct ab8500_reg_range[]) {
241 {
242 .first = 0x80,
243 .last = 0x83,
244 },
245 {
246 .first = 0x87,
247 .last = 0x8A,
248 },
249 },
250 },
251 [AB8500_TVOUT] = {
252 .num_ranges = 9,
253 .range = (struct ab8500_reg_range[]) {
254 {
255 .first = 0x00,
256 .last = 0x12,
257 },
258 {
259 .first = 0x15,
260 .last = 0x17,
261 },
262 {
263 .first = 0x19,
264 .last = 0x21,
265 },
266 {
267 .first = 0x27,
268 .last = 0x2C,
269 },
270 {
271 .first = 0x41,
272 .last = 0x41,
273 },
274 {
275 .first = 0x45,
276 .last = 0x5B,
277 },
278 {
279 .first = 0x5D,
280 .last = 0x5D,
281 },
282 {
283 .first = 0x69,
284 .last = 0x69,
285 },
286 {
287 .first = 0x80,
288 .last = 0x81,
289 },
290 },
291 },
292 [AB8500_DBI] = {
293 .num_ranges = 0,
Mark Brown87fff232010-12-13 14:06:47 +0000294 .range = NULL,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100295 },
296 [AB8500_ECI_AV_ACC] = {
297 .num_ranges = 1,
298 .range = (struct ab8500_reg_range[]) {
299 {
300 .first = 0x80,
301 .last = 0x82,
302 },
303 },
304 },
305 [0x9] = {
306 .num_ranges = 0,
Mark Brown87fff232010-12-13 14:06:47 +0000307 .range = NULL,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100308 },
309 [AB8500_GPADC] = {
310 .num_ranges = 1,
311 .range = (struct ab8500_reg_range[]) {
312 {
313 .first = 0x00,
314 .last = 0x08,
315 },
316 },
317 },
318 [AB8500_CHARGER] = {
Philippe Langlais40c064e2011-10-17 09:48:55 +0200319 .num_ranges = 9,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100320 .range = (struct ab8500_reg_range[]) {
321 {
322 .first = 0x00,
323 .last = 0x03,
324 },
325 {
326 .first = 0x05,
327 .last = 0x05,
328 },
329 {
330 .first = 0x40,
331 .last = 0x40,
332 },
333 {
334 .first = 0x42,
335 .last = 0x42,
336 },
337 {
338 .first = 0x44,
339 .last = 0x44,
340 },
341 {
342 .first = 0x50,
343 .last = 0x55,
344 },
345 {
346 .first = 0x80,
347 .last = 0x82,
348 },
349 {
350 .first = 0xC0,
351 .last = 0xC2,
352 },
Philippe Langlais40c064e2011-10-17 09:48:55 +0200353 {
354 .first = 0xf5,
355 .last = 0xf6,
356 },
Mattias Wallind7b9f322010-11-26 13:06:39 +0100357 },
358 },
359 [AB8500_GAS_GAUGE] = {
360 .num_ranges = 3,
361 .range = (struct ab8500_reg_range[]) {
362 {
363 .first = 0x00,
364 .last = 0x00,
365 },
366 {
367 .first = 0x07,
368 .last = 0x0A,
369 },
370 {
371 .first = 0x10,
372 .last = 0x14,
373 },
374 },
375 },
Philippe Langlais40c064e2011-10-17 09:48:55 +0200376 [AB8500_DEVELOPMENT] = {
377 .num_ranges = 1,
378 .range = (struct ab8500_reg_range[]) {
379 {
380 .first = 0x00,
381 .last = 0x00,
382 },
383 },
384 },
385 [AB8500_DEBUG] = {
386 .num_ranges = 1,
387 .range = (struct ab8500_reg_range[]) {
388 {
389 .first = 0x05,
390 .last = 0x07,
391 },
392 },
393 },
Mattias Wallind7b9f322010-11-26 13:06:39 +0100394 [AB8500_AUDIO] = {
395 .num_ranges = 1,
396 .range = (struct ab8500_reg_range[]) {
397 {
398 .first = 0x00,
399 .last = 0x6F,
400 },
401 },
402 },
403 [AB8500_INTERRUPT] = {
404 .num_ranges = 0,
Mark Brown87fff232010-12-13 14:06:47 +0000405 .range = NULL,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100406 },
407 [AB8500_RTC] = {
408 .num_ranges = 1,
409 .range = (struct ab8500_reg_range[]) {
410 {
411 .first = 0x00,
412 .last = 0x0F,
413 },
414 },
415 },
416 [AB8500_MISC] = {
417 .num_ranges = 8,
418 .range = (struct ab8500_reg_range[]) {
419 {
420 .first = 0x00,
421 .last = 0x05,
422 },
423 {
424 .first = 0x10,
425 .last = 0x15,
426 },
427 {
428 .first = 0x20,
429 .last = 0x25,
430 },
431 {
432 .first = 0x30,
433 .last = 0x35,
434 },
435 {
436 .first = 0x40,
437 .last = 0x45,
438 },
439 {
440 .first = 0x50,
441 .last = 0x50,
442 },
443 {
444 .first = 0x60,
445 .last = 0x67,
446 },
447 {
448 .first = 0x80,
449 .last = 0x80,
450 },
451 },
452 },
453 [0x11] = {
454 .num_ranges = 0,
Mark Brown87fff232010-12-13 14:06:47 +0000455 .range = NULL,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100456 },
457 [0x12] = {
458 .num_ranges = 0,
Mark Brown87fff232010-12-13 14:06:47 +0000459 .range = NULL,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100460 },
461 [0x13] = {
462 .num_ranges = 0,
Mark Brown87fff232010-12-13 14:06:47 +0000463 .range = NULL,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100464 },
465 [0x14] = {
466 .num_ranges = 0,
Mark Brown87fff232010-12-13 14:06:47 +0000467 .range = NULL,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100468 },
469 [AB8500_OTP_EMUL] = {
470 .num_ranges = 1,
471 .range = (struct ab8500_reg_range[]) {
472 {
473 .first = 0x01,
474 .last = 0x0F,
475 },
476 },
477 },
Mattias Wallin5814fc32010-09-13 16:05:04 +0200478};
479
Lee Jones4b8ac082013-01-14 16:10:36 +0000480static irqreturn_t ab8500_debug_handler(int irq, void *data)
481{
482 char buf[16];
483 struct kobject *kobj = (struct kobject *)data;
Mattias Wallin0b337e72010-11-19 17:55:11 +0100484 unsigned int irq_abb = irq - irq_first;
Lee Jones4b8ac082013-01-14 16:10:36 +0000485
Mattias Wallin0b337e72010-11-19 17:55:11 +0100486 if (irq_abb < AB8500_NR_IRQS)
487 irq_count[irq_abb]++;
Lee Jones4b8ac082013-01-14 16:10:36 +0000488 /*
489 * This makes it possible to use poll for events (POLLPRI | POLLERR)
Mattias Wallin0b337e72010-11-19 17:55:11 +0100490 * from userspace on sysfs file named <irq-nr>
Lee Jones4b8ac082013-01-14 16:10:36 +0000491 */
Mattias Wallin0b337e72010-11-19 17:55:11 +0100492 sprintf(buf, "%d", irq);
Lee Jones4b8ac082013-01-14 16:10:36 +0000493 sysfs_notify(kobj, NULL, buf);
494
495 return IRQ_HANDLED;
496}
497
Mian Yousaf Kaukab42002c62012-01-26 15:39:20 +0100498/* Prints to seq_file or log_buf */
499static int ab8500_registers_print(struct device *dev, u32 bank,
500 struct seq_file *s)
Mattias Wallin5814fc32010-09-13 16:05:04 +0200501{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100502 unsigned int i;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200503
Mattias Wallind7b9f322010-11-26 13:06:39 +0100504 for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
505 u32 reg;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200506
Mattias Wallind7b9f322010-11-26 13:06:39 +0100507 for (reg = debug_ranges[bank].range[i].first;
508 reg <= debug_ranges[bank].range[i].last;
509 reg++) {
510 u8 value;
511 int err;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200512
Mattias Wallind7b9f322010-11-26 13:06:39 +0100513 err = abx500_get_register_interruptible(dev,
514 (u8)bank, (u8)reg, &value);
515 if (err < 0) {
516 dev_err(dev, "ab->read fail %d\n", err);
517 return err;
518 }
Mattias Wallin5814fc32010-09-13 16:05:04 +0200519
Mian Yousaf Kaukab42002c62012-01-26 15:39:20 +0100520 if (s) {
521 err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n",
522 bank, reg, value);
523 if (err < 0) {
524 dev_err(dev,
525 "seq_printf overflow bank=%d reg=%d\n",
526 bank, reg);
527 /* Error is not returned here since
528 * the output is wanted in any case */
529 return 0;
530 }
531 } else {
532 printk(KERN_INFO" [%u/0x%02X]: 0x%02X\n", bank,
533 reg, value);
Mattias Wallind7b9f322010-11-26 13:06:39 +0100534 }
535 }
536 }
537 return 0;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200538}
539
Mian Yousaf Kaukab42002c62012-01-26 15:39:20 +0100540static int ab8500_print_bank_registers(struct seq_file *s, void *p)
541{
542 struct device *dev = s->private;
543 u32 bank = debug_bank;
544
545 seq_printf(s, AB8500_NAME_STRING " register values:\n");
546
547 seq_printf(s, " bank %u:\n", bank);
548
549 ab8500_registers_print(dev, bank, s);
550 return 0;
551}
552
Mattias Wallin5814fc32010-09-13 16:05:04 +0200553static int ab8500_registers_open(struct inode *inode, struct file *file)
554{
Mian Yousaf Kaukab42002c62012-01-26 15:39:20 +0100555 return single_open(file, ab8500_print_bank_registers, inode->i_private);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200556}
557
558static const struct file_operations ab8500_registers_fops = {
Mattias Wallind7b9f322010-11-26 13:06:39 +0100559 .open = ab8500_registers_open,
560 .read = seq_read,
561 .llseek = seq_lseek,
562 .release = single_release,
563 .owner = THIS_MODULE,
Mattias Wallin5814fc32010-09-13 16:05:04 +0200564};
565
Mian Yousaf Kaukab42002c62012-01-26 15:39:20 +0100566static int ab8500_print_all_banks(struct seq_file *s, void *p)
567{
568 struct device *dev = s->private;
569 unsigned int i;
570 int err;
571
572 seq_printf(s, AB8500_NAME_STRING " register values:\n");
573
574 for (i = 1; i < AB8500_NUM_BANKS; i++) {
575 err = seq_printf(s, " bank %u:\n", i);
576 if (err < 0)
577 dev_err(dev, "seq_printf overflow, bank=%d\n", i);
578
579 ab8500_registers_print(dev, i, s);
580 }
581 return 0;
582}
583
584static int ab8500_all_banks_open(struct inode *inode, struct file *file)
585{
586 struct seq_file *s;
587 int err;
588
589 err = single_open(file, ab8500_print_all_banks, inode->i_private);
590 if (!err) {
591 /* Default buf size in seq_read is not enough */
592 s = (struct seq_file *)file->private_data;
593 s->size = (PAGE_SIZE * 2);
594 s->buf = kmalloc(s->size, GFP_KERNEL);
595 if (!s->buf) {
596 single_release(inode, file);
597 err = -ENOMEM;
598 }
599 }
600 return err;
601}
602
603static const struct file_operations ab8500_all_banks_fops = {
604 .open = ab8500_all_banks_open,
605 .read = seq_read,
606 .llseek = seq_lseek,
607 .release = single_release,
608 .owner = THIS_MODULE,
609};
610
Mattias Wallin5814fc32010-09-13 16:05:04 +0200611static int ab8500_bank_print(struct seq_file *s, void *p)
612{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100613 return seq_printf(s, "%d\n", debug_bank);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200614}
615
616static int ab8500_bank_open(struct inode *inode, struct file *file)
617{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100618 return single_open(file, ab8500_bank_print, inode->i_private);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200619}
620
621static ssize_t ab8500_bank_write(struct file *file,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100622 const char __user *user_buf,
623 size_t count, loff_t *ppos)
Mattias Wallin5814fc32010-09-13 16:05:04 +0200624{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100625 struct device *dev = ((struct seq_file *)(file->private_data))->private;
Mattias Wallind7b9f322010-11-26 13:06:39 +0100626 unsigned long user_bank;
627 int err;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200628
Mattias Wallind7b9f322010-11-26 13:06:39 +0100629 /* Get userspace string and assure termination */
Peter Huewe8504d632011-06-06 22:43:32 +0200630 err = kstrtoul_from_user(user_buf, count, 0, &user_bank);
Mattias Wallind7b9f322010-11-26 13:06:39 +0100631 if (err)
Peter Huewe8504d632011-06-06 22:43:32 +0200632 return err;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200633
Mattias Wallind7b9f322010-11-26 13:06:39 +0100634 if (user_bank >= AB8500_NUM_BANKS) {
635 dev_err(dev, "debugfs error input > number of banks\n");
636 return -EINVAL;
637 }
Mattias Wallin5814fc32010-09-13 16:05:04 +0200638
Mattias Wallind7b9f322010-11-26 13:06:39 +0100639 debug_bank = user_bank;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200640
Peter Huewe8504d632011-06-06 22:43:32 +0200641 return count;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200642}
643
644static int ab8500_address_print(struct seq_file *s, void *p)
645{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100646 return seq_printf(s, "0x%02X\n", debug_address);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200647}
648
649static int ab8500_address_open(struct inode *inode, struct file *file)
650{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100651 return single_open(file, ab8500_address_print, inode->i_private);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200652}
653
654static ssize_t ab8500_address_write(struct file *file,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100655 const char __user *user_buf,
656 size_t count, loff_t *ppos)
Mattias Wallin5814fc32010-09-13 16:05:04 +0200657{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100658 struct device *dev = ((struct seq_file *)(file->private_data))->private;
Mattias Wallind7b9f322010-11-26 13:06:39 +0100659 unsigned long user_address;
660 int err;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200661
Mattias Wallind7b9f322010-11-26 13:06:39 +0100662 /* Get userspace string and assure termination */
Peter Huewe8504d632011-06-06 22:43:32 +0200663 err = kstrtoul_from_user(user_buf, count, 0, &user_address);
Mattias Wallind7b9f322010-11-26 13:06:39 +0100664 if (err)
Peter Huewe8504d632011-06-06 22:43:32 +0200665 return err;
666
Mattias Wallind7b9f322010-11-26 13:06:39 +0100667 if (user_address > 0xff) {
668 dev_err(dev, "debugfs error input > 0xff\n");
669 return -EINVAL;
670 }
671 debug_address = user_address;
Peter Huewe8504d632011-06-06 22:43:32 +0200672 return count;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200673}
674
675static int ab8500_val_print(struct seq_file *s, void *p)
676{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100677 struct device *dev = s->private;
678 int ret;
679 u8 regvalue;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200680
Mattias Wallind7b9f322010-11-26 13:06:39 +0100681 ret = abx500_get_register_interruptible(dev,
682 (u8)debug_bank, (u8)debug_address, &regvalue);
683 if (ret < 0) {
684 dev_err(dev, "abx500_get_reg fail %d, %d\n",
685 ret, __LINE__);
686 return -EINVAL;
687 }
688 seq_printf(s, "0x%02X\n", regvalue);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200689
Mattias Wallind7b9f322010-11-26 13:06:39 +0100690 return 0;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200691}
692
693static int ab8500_val_open(struct inode *inode, struct file *file)
694{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100695 return single_open(file, ab8500_val_print, inode->i_private);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200696}
697
698static ssize_t ab8500_val_write(struct file *file,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100699 const char __user *user_buf,
700 size_t count, loff_t *ppos)
Mattias Wallin5814fc32010-09-13 16:05:04 +0200701{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100702 struct device *dev = ((struct seq_file *)(file->private_data))->private;
Mattias Wallind7b9f322010-11-26 13:06:39 +0100703 unsigned long user_val;
704 int err;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200705
Mattias Wallind7b9f322010-11-26 13:06:39 +0100706 /* Get userspace string and assure termination */
Peter Huewe8504d632011-06-06 22:43:32 +0200707 err = kstrtoul_from_user(user_buf, count, 0, &user_val);
Mattias Wallind7b9f322010-11-26 13:06:39 +0100708 if (err)
Peter Huewe8504d632011-06-06 22:43:32 +0200709 return err;
710
Mattias Wallind7b9f322010-11-26 13:06:39 +0100711 if (user_val > 0xff) {
712 dev_err(dev, "debugfs error input > 0xff\n");
713 return -EINVAL;
714 }
715 err = abx500_set_register_interruptible(dev,
716 (u8)debug_bank, debug_address, (u8)user_val);
717 if (err < 0) {
718 printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__);
719 return -EINVAL;
720 }
Mattias Wallin5814fc32010-09-13 16:05:04 +0200721
Peter Huewe8504d632011-06-06 22:43:32 +0200722 return count;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200723}
724
carriere etienne0fbce762011-04-08 16:26:36 +0200725/*
726 * - HWREG DB8500 formated routines
727 */
728static int ab8500_hwreg_print(struct seq_file *s, void *d)
729{
730 struct device *dev = s->private;
731 int ret;
732 u8 regvalue;
733
734 ret = abx500_get_register_interruptible(dev,
735 (u8)hwreg_cfg.bank, (u8)hwreg_cfg.addr, &regvalue);
736 if (ret < 0) {
737 dev_err(dev, "abx500_get_reg fail %d, %d\n",
738 ret, __LINE__);
739 return -EINVAL;
740 }
741
742 if (hwreg_cfg.shift >= 0)
743 regvalue >>= hwreg_cfg.shift;
744 else
745 regvalue <<= -hwreg_cfg.shift;
746 regvalue &= hwreg_cfg.mask;
747
748 if (REG_FMT_DEC(&hwreg_cfg))
749 seq_printf(s, "%d\n", regvalue);
750 else
751 seq_printf(s, "0x%02X\n", regvalue);
752 return 0;
753}
754
755static int ab8500_hwreg_open(struct inode *inode, struct file *file)
756{
757 return single_open(file, ab8500_hwreg_print, inode->i_private);
758}
759
John Beckett1478a312011-05-31 13:54:27 +0100760static int ab8500_gpadc_bat_ctrl_print(struct seq_file *s, void *p)
761{
762 int bat_ctrl_raw;
763 int bat_ctrl_convert;
764 struct ab8500_gpadc *gpadc;
765
766 gpadc = ab8500_gpadc_get();
767 bat_ctrl_raw = ab8500_gpadc_read_raw(gpadc, BAT_CTRL);
768 bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc,
769 BAT_CTRL, bat_ctrl_raw);
770
771 return seq_printf(s, "%d,0x%X\n",
772 bat_ctrl_convert, bat_ctrl_raw);
773}
774
775static int ab8500_gpadc_bat_ctrl_open(struct inode *inode, struct file *file)
776{
777 return single_open(file, ab8500_gpadc_bat_ctrl_print, inode->i_private);
778}
779
780static const struct file_operations ab8500_gpadc_bat_ctrl_fops = {
781 .open = ab8500_gpadc_bat_ctrl_open,
782 .read = seq_read,
783 .llseek = seq_lseek,
784 .release = single_release,
785 .owner = THIS_MODULE,
786};
787
788static int ab8500_gpadc_btemp_ball_print(struct seq_file *s, void *p)
789{
790 int btemp_ball_raw;
791 int btemp_ball_convert;
792 struct ab8500_gpadc *gpadc;
793
794 gpadc = ab8500_gpadc_get();
795 btemp_ball_raw = ab8500_gpadc_read_raw(gpadc, BTEMP_BALL);
796 btemp_ball_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL,
797 btemp_ball_raw);
798
799 return seq_printf(s,
800 "%d,0x%X\n", btemp_ball_convert, btemp_ball_raw);
801}
802
803static int ab8500_gpadc_btemp_ball_open(struct inode *inode,
804 struct file *file)
805{
806 return single_open(file, ab8500_gpadc_btemp_ball_print, inode->i_private);
807}
808
809static const struct file_operations ab8500_gpadc_btemp_ball_fops = {
810 .open = ab8500_gpadc_btemp_ball_open,
811 .read = seq_read,
812 .llseek = seq_lseek,
813 .release = single_release,
814 .owner = THIS_MODULE,
815};
816
817static int ab8500_gpadc_main_charger_v_print(struct seq_file *s, void *p)
818{
819 int main_charger_v_raw;
820 int main_charger_v_convert;
821 struct ab8500_gpadc *gpadc;
822
823 gpadc = ab8500_gpadc_get();
824 main_charger_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_V);
825 main_charger_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
826 MAIN_CHARGER_V, main_charger_v_raw);
827
828 return seq_printf(s, "%d,0x%X\n",
829 main_charger_v_convert, main_charger_v_raw);
830}
831
832static int ab8500_gpadc_main_charger_v_open(struct inode *inode,
833 struct file *file)
834{
835 return single_open(file, ab8500_gpadc_main_charger_v_print,
836 inode->i_private);
837}
838
839static const struct file_operations ab8500_gpadc_main_charger_v_fops = {
840 .open = ab8500_gpadc_main_charger_v_open,
841 .read = seq_read,
842 .llseek = seq_lseek,
843 .release = single_release,
844 .owner = THIS_MODULE,
845};
846
847static int ab8500_gpadc_acc_detect1_print(struct seq_file *s, void *p)
848{
849 int acc_detect1_raw;
850 int acc_detect1_convert;
851 struct ab8500_gpadc *gpadc;
852
853 gpadc = ab8500_gpadc_get();
854 acc_detect1_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT1);
855 acc_detect1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ACC_DETECT1,
856 acc_detect1_raw);
857
858 return seq_printf(s, "%d,0x%X\n",
859 acc_detect1_convert, acc_detect1_raw);
860}
861
862static int ab8500_gpadc_acc_detect1_open(struct inode *inode,
863 struct file *file)
864{
865 return single_open(file, ab8500_gpadc_acc_detect1_print,
866 inode->i_private);
867}
868
869static const struct file_operations ab8500_gpadc_acc_detect1_fops = {
870 .open = ab8500_gpadc_acc_detect1_open,
871 .read = seq_read,
872 .llseek = seq_lseek,
873 .release = single_release,
874 .owner = THIS_MODULE,
875};
876
877static int ab8500_gpadc_acc_detect2_print(struct seq_file *s, void *p)
878{
879 int acc_detect2_raw;
880 int acc_detect2_convert;
881 struct ab8500_gpadc *gpadc;
882
883 gpadc = ab8500_gpadc_get();
884 acc_detect2_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT2);
885 acc_detect2_convert = ab8500_gpadc_ad_to_voltage(gpadc,
886 ACC_DETECT2, acc_detect2_raw);
887
888 return seq_printf(s, "%d,0x%X\n",
889 acc_detect2_convert, acc_detect2_raw);
890}
891
892static int ab8500_gpadc_acc_detect2_open(struct inode *inode,
893 struct file *file)
894{
895 return single_open(file, ab8500_gpadc_acc_detect2_print,
896 inode->i_private);
897}
898
899static const struct file_operations ab8500_gpadc_acc_detect2_fops = {
900 .open = ab8500_gpadc_acc_detect2_open,
901 .read = seq_read,
902 .llseek = seq_lseek,
903 .release = single_release,
904 .owner = THIS_MODULE,
905};
906
907static int ab8500_gpadc_aux1_print(struct seq_file *s, void *p)
908{
909 int aux1_raw;
910 int aux1_convert;
911 struct ab8500_gpadc *gpadc;
912
913 gpadc = ab8500_gpadc_get();
914 aux1_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX1);
915 aux1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX1,
916 aux1_raw);
917
918 return seq_printf(s, "%d,0x%X\n",
919 aux1_convert, aux1_raw);
920}
921
922static int ab8500_gpadc_aux1_open(struct inode *inode, struct file *file)
923{
924 return single_open(file, ab8500_gpadc_aux1_print, inode->i_private);
925}
926
927static const struct file_operations ab8500_gpadc_aux1_fops = {
928 .open = ab8500_gpadc_aux1_open,
929 .read = seq_read,
930 .llseek = seq_lseek,
931 .release = single_release,
932 .owner = THIS_MODULE,
933};
934
935static int ab8500_gpadc_aux2_print(struct seq_file *s, void *p)
936{
937 int aux2_raw;
938 int aux2_convert;
939 struct ab8500_gpadc *gpadc;
940
941 gpadc = ab8500_gpadc_get();
942 aux2_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX2);
943 aux2_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX2,
944 aux2_raw);
945
946 return seq_printf(s, "%d,0x%X\n",
947 aux2_convert, aux2_raw);
948}
949
950static int ab8500_gpadc_aux2_open(struct inode *inode, struct file *file)
951{
952 return single_open(file, ab8500_gpadc_aux2_print, inode->i_private);
953}
954
955static const struct file_operations ab8500_gpadc_aux2_fops = {
956 .open = ab8500_gpadc_aux2_open,
957 .read = seq_read,
958 .llseek = seq_lseek,
959 .release = single_release,
960 .owner = THIS_MODULE,
961};
962
963static int ab8500_gpadc_main_bat_v_print(struct seq_file *s, void *p)
964{
965 int main_bat_v_raw;
966 int main_bat_v_convert;
967 struct ab8500_gpadc *gpadc;
968
969 gpadc = ab8500_gpadc_get();
970 main_bat_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_BAT_V);
971 main_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V,
972 main_bat_v_raw);
973
974 return seq_printf(s, "%d,0x%X\n",
975 main_bat_v_convert, main_bat_v_raw);
976}
977
978static int ab8500_gpadc_main_bat_v_open(struct inode *inode,
979 struct file *file)
980{
981 return single_open(file, ab8500_gpadc_main_bat_v_print, inode->i_private);
982}
983
984static const struct file_operations ab8500_gpadc_main_bat_v_fops = {
985 .open = ab8500_gpadc_main_bat_v_open,
986 .read = seq_read,
987 .llseek = seq_lseek,
988 .release = single_release,
989 .owner = THIS_MODULE,
990};
991
992static int ab8500_gpadc_vbus_v_print(struct seq_file *s, void *p)
993{
994 int vbus_v_raw;
995 int vbus_v_convert;
996 struct ab8500_gpadc *gpadc;
997
998 gpadc = ab8500_gpadc_get();
999 vbus_v_raw = ab8500_gpadc_read_raw(gpadc, VBUS_V);
1000 vbus_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, VBUS_V,
1001 vbus_v_raw);
1002
1003 return seq_printf(s, "%d,0x%X\n",
1004 vbus_v_convert, vbus_v_raw);
1005}
1006
1007static int ab8500_gpadc_vbus_v_open(struct inode *inode, struct file *file)
1008{
1009 return single_open(file, ab8500_gpadc_vbus_v_print, inode->i_private);
1010}
1011
1012static const struct file_operations ab8500_gpadc_vbus_v_fops = {
1013 .open = ab8500_gpadc_vbus_v_open,
1014 .read = seq_read,
1015 .llseek = seq_lseek,
1016 .release = single_release,
1017 .owner = THIS_MODULE,
1018};
1019
1020static int ab8500_gpadc_main_charger_c_print(struct seq_file *s, void *p)
1021{
1022 int main_charger_c_raw;
1023 int main_charger_c_convert;
1024 struct ab8500_gpadc *gpadc;
1025
1026 gpadc = ab8500_gpadc_get();
1027 main_charger_c_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_C);
1028 main_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
1029 MAIN_CHARGER_C, main_charger_c_raw);
1030
1031 return seq_printf(s, "%d,0x%X\n",
1032 main_charger_c_convert, main_charger_c_raw);
1033}
1034
1035static int ab8500_gpadc_main_charger_c_open(struct inode *inode,
1036 struct file *file)
1037{
1038 return single_open(file, ab8500_gpadc_main_charger_c_print,
1039 inode->i_private);
1040}
1041
1042static const struct file_operations ab8500_gpadc_main_charger_c_fops = {
1043 .open = ab8500_gpadc_main_charger_c_open,
1044 .read = seq_read,
1045 .llseek = seq_lseek,
1046 .release = single_release,
1047 .owner = THIS_MODULE,
1048};
1049
1050static int ab8500_gpadc_usb_charger_c_print(struct seq_file *s, void *p)
1051{
1052 int usb_charger_c_raw;
1053 int usb_charger_c_convert;
1054 struct ab8500_gpadc *gpadc;
1055
1056 gpadc = ab8500_gpadc_get();
1057 usb_charger_c_raw = ab8500_gpadc_read_raw(gpadc, USB_CHARGER_C);
1058 usb_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
1059 USB_CHARGER_C, usb_charger_c_raw);
1060
1061 return seq_printf(s, "%d,0x%X\n",
1062 usb_charger_c_convert, usb_charger_c_raw);
1063}
1064
1065static int ab8500_gpadc_usb_charger_c_open(struct inode *inode,
1066 struct file *file)
1067{
1068 return single_open(file, ab8500_gpadc_usb_charger_c_print,
1069 inode->i_private);
1070}
1071
1072static const struct file_operations ab8500_gpadc_usb_charger_c_fops = {
1073 .open = ab8500_gpadc_usb_charger_c_open,
1074 .read = seq_read,
1075 .llseek = seq_lseek,
1076 .release = single_release,
1077 .owner = THIS_MODULE,
1078};
1079
1080static int ab8500_gpadc_bk_bat_v_print(struct seq_file *s, void *p)
1081{
1082 int bk_bat_v_raw;
1083 int bk_bat_v_convert;
1084 struct ab8500_gpadc *gpadc;
1085
1086 gpadc = ab8500_gpadc_get();
1087 bk_bat_v_raw = ab8500_gpadc_read_raw(gpadc, BK_BAT_V);
1088 bk_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
1089 BK_BAT_V, bk_bat_v_raw);
1090
1091 return seq_printf(s, "%d,0x%X\n",
1092 bk_bat_v_convert, bk_bat_v_raw);
1093}
1094
1095static int ab8500_gpadc_bk_bat_v_open(struct inode *inode, struct file *file)
1096{
1097 return single_open(file, ab8500_gpadc_bk_bat_v_print, inode->i_private);
1098}
1099
1100static const struct file_operations ab8500_gpadc_bk_bat_v_fops = {
1101 .open = ab8500_gpadc_bk_bat_v_open,
1102 .read = seq_read,
1103 .llseek = seq_lseek,
1104 .release = single_release,
1105 .owner = THIS_MODULE,
1106};
1107
1108static int ab8500_gpadc_die_temp_print(struct seq_file *s, void *p)
1109{
1110 int die_temp_raw;
1111 int die_temp_convert;
1112 struct ab8500_gpadc *gpadc;
1113
1114 gpadc = ab8500_gpadc_get();
1115 die_temp_raw = ab8500_gpadc_read_raw(gpadc, DIE_TEMP);
1116 die_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, DIE_TEMP,
1117 die_temp_raw);
1118
1119 return seq_printf(s, "%d,0x%X\n",
1120 die_temp_convert, die_temp_raw);
1121}
1122
1123static int ab8500_gpadc_die_temp_open(struct inode *inode, struct file *file)
1124{
1125 return single_open(file, ab8500_gpadc_die_temp_print, inode->i_private);
1126}
1127
1128static const struct file_operations ab8500_gpadc_die_temp_fops = {
1129 .open = ab8500_gpadc_die_temp_open,
1130 .read = seq_read,
1131 .llseek = seq_lseek,
1132 .release = single_release,
1133 .owner = THIS_MODULE,
1134};
1135
carriere etienne0fbce762011-04-08 16:26:36 +02001136/*
1137 * return length of an ASCII numerical value, 0 is string is not a
1138 * numerical value.
1139 * string shall start at value 1st char.
1140 * string can be tailed with \0 or space or newline chars only.
1141 * value can be decimal or hexadecimal (prefixed 0x or 0X).
1142 */
1143static int strval_len(char *b)
1144{
1145 char *s = b;
1146 if ((*s == '0') && ((*(s+1) == 'x') || (*(s+1) == 'X'))) {
1147 s += 2;
1148 for (; *s && (*s != ' ') && (*s != '\n'); s++) {
1149 if (!isxdigit(*s))
1150 return 0;
1151 }
1152 } else {
1153 if (*s == '-')
1154 s++;
1155 for (; *s && (*s != ' ') && (*s != '\n'); s++) {
1156 if (!isdigit(*s))
1157 return 0;
1158 }
1159 }
1160 return (int) (s-b);
1161}
1162
1163/*
1164 * parse hwreg input data.
1165 * update global hwreg_cfg only if input data syntax is ok.
1166 */
1167static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg,
1168 struct device *dev)
1169{
1170 uint write, val = 0;
1171 u8 regvalue;
1172 int ret;
1173 struct hwreg_cfg loc = {
1174 .bank = 0, /* default: invalid phys addr */
1175 .addr = 0, /* default: invalid phys addr */
1176 .fmt = 0, /* default: 32bit access, hex output */
1177 .mask = 0xFFFFFFFF, /* default: no mask */
1178 .shift = 0, /* default: no bit shift */
1179 };
1180
1181 /* read or write ? */
1182 if (!strncmp(b, "read ", 5)) {
1183 write = 0;
1184 b += 5;
1185 } else if (!strncmp(b, "write ", 6)) {
1186 write = 1;
1187 b += 6;
1188 } else
1189 return -EINVAL;
1190
1191 /* OPTIONS -l|-w|-b -s -m -o */
1192 while ((*b == ' ') || (*b == '-')) {
1193 if (*(b-1) != ' ') {
1194 b++;
1195 continue;
1196 }
1197 if ((!strncmp(b, "-d ", 3)) ||
1198 (!strncmp(b, "-dec ", 5))) {
1199 b += (*(b+2) == ' ') ? 3 : 5;
1200 loc.fmt |= (1<<0);
1201 } else if ((!strncmp(b, "-h ", 3)) ||
1202 (!strncmp(b, "-hex ", 5))) {
1203 b += (*(b+2) == ' ') ? 3 : 5;
1204 loc.fmt &= ~(1<<0);
1205 } else if ((!strncmp(b, "-m ", 3)) ||
1206 (!strncmp(b, "-mask ", 6))) {
1207 b += (*(b+2) == ' ') ? 3 : 6;
1208 if (strval_len(b) == 0)
1209 return -EINVAL;
1210 loc.mask = simple_strtoul(b, &b, 0);
1211 } else if ((!strncmp(b, "-s ", 3)) ||
1212 (!strncmp(b, "-shift ", 7))) {
1213 b += (*(b+2) == ' ') ? 3 : 7;
1214 if (strval_len(b) == 0)
1215 return -EINVAL;
1216 loc.shift = simple_strtol(b, &b, 0);
1217 } else {
1218 return -EINVAL;
1219 }
1220 }
1221 /* get arg BANK and ADDRESS */
1222 if (strval_len(b) == 0)
1223 return -EINVAL;
1224 loc.bank = simple_strtoul(b, &b, 0);
1225 while (*b == ' ')
1226 b++;
1227 if (strval_len(b) == 0)
1228 return -EINVAL;
1229 loc.addr = simple_strtoul(b, &b, 0);
1230
1231 if (write) {
1232 while (*b == ' ')
1233 b++;
1234 if (strval_len(b) == 0)
1235 return -EINVAL;
1236 val = simple_strtoul(b, &b, 0);
1237 }
1238
1239 /* args are ok, update target cfg (mainly for read) */
1240 *cfg = loc;
1241
1242#ifdef ABB_HWREG_DEBUG
1243 pr_warn("HWREG request: %s, %s, addr=0x%08X, mask=0x%X, shift=%d"
1244 "value=0x%X\n", (write) ? "write" : "read",
1245 REG_FMT_DEC(cfg) ? "decimal" : "hexa",
1246 cfg->addr, cfg->mask, cfg->shift, val);
1247#endif
1248
1249 if (!write)
1250 return 0;
1251
1252 ret = abx500_get_register_interruptible(dev,
1253 (u8)cfg->bank, (u8)cfg->addr, &regvalue);
1254 if (ret < 0) {
1255 dev_err(dev, "abx500_get_reg fail %d, %d\n",
1256 ret, __LINE__);
1257 return -EINVAL;
1258 }
1259
1260 if (cfg->shift >= 0) {
1261 regvalue &= ~(cfg->mask << (cfg->shift));
1262 val = (val & cfg->mask) << (cfg->shift);
1263 } else {
1264 regvalue &= ~(cfg->mask >> (-cfg->shift));
1265 val = (val & cfg->mask) >> (-cfg->shift);
1266 }
1267 val = val | regvalue;
1268
1269 ret = abx500_set_register_interruptible(dev,
1270 (u8)cfg->bank, (u8)cfg->addr, (u8)val);
1271 if (ret < 0) {
1272 pr_err("abx500_set_reg failed %d, %d", ret, __LINE__);
1273 return -EINVAL;
1274 }
1275
1276 return 0;
1277}
1278
1279static ssize_t ab8500_hwreg_write(struct file *file,
1280 const char __user *user_buf, size_t count, loff_t *ppos)
1281{
1282 struct device *dev = ((struct seq_file *)(file->private_data))->private;
1283 char buf[128];
1284 int buf_size, ret;
1285
1286 /* Get userspace string and assure termination */
1287 buf_size = min(count, (sizeof(buf)-1));
1288 if (copy_from_user(buf, user_buf, buf_size))
1289 return -EFAULT;
1290 buf[buf_size] = 0;
1291
1292 /* get args and process */
1293 ret = hwreg_common_write(buf, &hwreg_cfg, dev);
1294 return (ret) ? ret : buf_size;
1295}
1296
1297/*
1298 * - irq subscribe/unsubscribe stuff
1299 */
Lee Jones4b8ac082013-01-14 16:10:36 +00001300static int ab8500_subscribe_unsubscribe_print(struct seq_file *s, void *p)
1301{
1302 seq_printf(s, "%d\n", irq_first);
1303
1304 return 0;
1305}
1306
1307static int ab8500_subscribe_unsubscribe_open(struct inode *inode,
1308 struct file *file)
1309{
1310 return single_open(file, ab8500_subscribe_unsubscribe_print,
1311 inode->i_private);
1312}
1313
1314/*
Mattias Wallin0b337e72010-11-19 17:55:11 +01001315 * Userspace should use poll() on this file. When an event occur
Lee Jones4b8ac082013-01-14 16:10:36 +00001316 * the blocking poll will be released.
1317 */
1318static ssize_t show_irq(struct device *dev,
1319 struct device_attribute *attr, char *buf)
1320{
Mattias Wallin0b337e72010-11-19 17:55:11 +01001321 unsigned long name;
1322 unsigned int irq_index;
1323 int err;
Lee Jones4b8ac082013-01-14 16:10:36 +00001324
Mattias Wallin0b337e72010-11-19 17:55:11 +01001325 err = strict_strtoul(attr->attr.name, 0, &name);
1326 if (err)
1327 return err;
1328
1329 irq_index = name - irq_first;
1330 if (irq_index >= AB8500_NR_IRQS)
1331 return -EINVAL;
1332 else
1333 return sprintf(buf, "%u\n", irq_count[irq_index]);
1334}
Lee Jones4b8ac082013-01-14 16:10:36 +00001335
1336static ssize_t ab8500_subscribe_write(struct file *file,
1337 const char __user *user_buf,
1338 size_t count, loff_t *ppos)
1339{
1340 struct device *dev = ((struct seq_file *)(file->private_data))->private;
1341 char buf[32];
1342 int buf_size;
1343 unsigned long user_val;
1344 int err;
Mattias Wallin0b337e72010-11-19 17:55:11 +01001345 unsigned int irq_index;
Lee Jones4b8ac082013-01-14 16:10:36 +00001346
1347 /* Get userspace string and assure termination */
1348 buf_size = min(count, (sizeof(buf)-1));
1349 if (copy_from_user(buf, user_buf, buf_size))
1350 return -EFAULT;
1351 buf[buf_size] = 0;
1352
1353 err = strict_strtoul(buf, 0, &user_val);
1354 if (err)
1355 return -EINVAL;
1356 if (user_val < irq_first) {
1357 dev_err(dev, "debugfs error input < %d\n", irq_first);
1358 return -EINVAL;
1359 }
1360 if (user_val > irq_last) {
1361 dev_err(dev, "debugfs error input > %d\n", irq_last);
1362 return -EINVAL;
1363 }
1364
Mattias Wallin0b337e72010-11-19 17:55:11 +01001365 irq_index = user_val - irq_first;
1366 if (irq_index >= AB8500_NR_IRQS)
1367 return -EINVAL;
1368
Lee Jones4b8ac082013-01-14 16:10:36 +00001369 /*
Mattias Wallin0b337e72010-11-19 17:55:11 +01001370 * This will create a sysfs file named <irq-nr> which userspace can
Lee Jones4b8ac082013-01-14 16:10:36 +00001371 * use to select or poll and get the AB8500 events
1372 */
Mattias Wallin0b337e72010-11-19 17:55:11 +01001373 dev_attr[irq_index] = kmalloc(sizeof(struct device_attribute),
1374 GFP_KERNEL);
1375 event_name[irq_index] = kmalloc(buf_size, GFP_KERNEL);
1376 sprintf(event_name[irq_index], "%lu", user_val);
1377 dev_attr[irq_index]->show = show_irq;
1378 dev_attr[irq_index]->store = NULL;
1379 dev_attr[irq_index]->attr.name = event_name[irq_index];
1380 dev_attr[irq_index]->attr.mode = S_IRUGO;
1381 err = sysfs_create_file(&dev->kobj, &dev_attr[irq_index]->attr);
Lee Jones4b8ac082013-01-14 16:10:36 +00001382 if (err < 0) {
1383 printk(KERN_ERR "sysfs_create_file failed %d\n", err);
1384 return err;
1385 }
1386
1387 err = request_threaded_irq(user_val, NULL, ab8500_debug_handler,
1388 IRQF_SHARED | IRQF_NO_SUSPEND,
1389 "ab8500-debug", &dev->kobj);
1390 if (err < 0) {
1391 printk(KERN_ERR "request_threaded_irq failed %d, %lu\n",
1392 err, user_val);
Mattias Wallin0b337e72010-11-19 17:55:11 +01001393 sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr);
Lee Jones4b8ac082013-01-14 16:10:36 +00001394 return err;
1395 }
1396
1397 return buf_size;
1398}
1399
1400static ssize_t ab8500_unsubscribe_write(struct file *file,
1401 const char __user *user_buf,
1402 size_t count, loff_t *ppos)
1403{
1404 struct device *dev = ((struct seq_file *)(file->private_data))->private;
1405 char buf[32];
1406 int buf_size;
1407 unsigned long user_val;
1408 int err;
Mattias Wallin0b337e72010-11-19 17:55:11 +01001409 unsigned int irq_index;
Lee Jones4b8ac082013-01-14 16:10:36 +00001410
1411 /* Get userspace string and assure termination */
1412 buf_size = min(count, (sizeof(buf)-1));
1413 if (copy_from_user(buf, user_buf, buf_size))
1414 return -EFAULT;
1415 buf[buf_size] = 0;
1416
1417 err = strict_strtoul(buf, 0, &user_val);
1418 if (err)
1419 return -EINVAL;
1420 if (user_val < irq_first) {
1421 dev_err(dev, "debugfs error input < %d\n", irq_first);
1422 return -EINVAL;
1423 }
1424 if (user_val > irq_last) {
1425 dev_err(dev, "debugfs error input > %d\n", irq_last);
1426 return -EINVAL;
1427 }
1428
Mattias Wallin0b337e72010-11-19 17:55:11 +01001429 irq_index = user_val - irq_first;
1430 if (irq_index >= AB8500_NR_IRQS)
1431 return -EINVAL;
Lee Jones4b8ac082013-01-14 16:10:36 +00001432
Mattias Wallin0b337e72010-11-19 17:55:11 +01001433 /* Set irq count to 0 when unsubscribe */
1434 irq_count[irq_index] = 0;
1435
1436 if (dev_attr[irq_index])
1437 sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr);
1438
1439
1440 free_irq(user_val, &dev->kobj);
1441 kfree(event_name[irq_index]);
1442 kfree(dev_attr[irq_index]);
Lee Jones4b8ac082013-01-14 16:10:36 +00001443
1444 return buf_size;
1445}
1446
carriere etienne0fbce762011-04-08 16:26:36 +02001447/*
1448 * - several deubgfs nodes fops
1449 */
1450
Mattias Wallin5814fc32010-09-13 16:05:04 +02001451static const struct file_operations ab8500_bank_fops = {
Mattias Wallind7b9f322010-11-26 13:06:39 +01001452 .open = ab8500_bank_open,
1453 .write = ab8500_bank_write,
1454 .read = seq_read,
1455 .llseek = seq_lseek,
1456 .release = single_release,
1457 .owner = THIS_MODULE,
Mattias Wallin5814fc32010-09-13 16:05:04 +02001458};
1459
1460static const struct file_operations ab8500_address_fops = {
Mattias Wallind7b9f322010-11-26 13:06:39 +01001461 .open = ab8500_address_open,
1462 .write = ab8500_address_write,
1463 .read = seq_read,
1464 .llseek = seq_lseek,
1465 .release = single_release,
1466 .owner = THIS_MODULE,
Mattias Wallin5814fc32010-09-13 16:05:04 +02001467};
1468
1469static const struct file_operations ab8500_val_fops = {
Mattias Wallind7b9f322010-11-26 13:06:39 +01001470 .open = ab8500_val_open,
1471 .write = ab8500_val_write,
1472 .read = seq_read,
1473 .llseek = seq_lseek,
1474 .release = single_release,
1475 .owner = THIS_MODULE,
Mattias Wallin5814fc32010-09-13 16:05:04 +02001476};
1477
Lee Jones4b8ac082013-01-14 16:10:36 +00001478static const struct file_operations ab8500_subscribe_fops = {
1479 .open = ab8500_subscribe_unsubscribe_open,
1480 .write = ab8500_subscribe_write,
1481 .read = seq_read,
1482 .llseek = seq_lseek,
1483 .release = single_release,
1484 .owner = THIS_MODULE,
1485};
1486
1487static const struct file_operations ab8500_unsubscribe_fops = {
1488 .open = ab8500_subscribe_unsubscribe_open,
1489 .write = ab8500_unsubscribe_write,
1490 .read = seq_read,
1491 .llseek = seq_lseek,
1492 .release = single_release,
1493 .owner = THIS_MODULE,
1494};
1495
carriere etienne0fbce762011-04-08 16:26:36 +02001496static const struct file_operations ab8500_hwreg_fops = {
1497 .open = ab8500_hwreg_open,
1498 .write = ab8500_hwreg_write,
1499 .read = seq_read,
1500 .llseek = seq_lseek,
1501 .release = single_release,
1502 .owner = THIS_MODULE,
1503};
1504
Mattias Wallin5814fc32010-09-13 16:05:04 +02001505static struct dentry *ab8500_dir;
John Beckett1478a312011-05-31 13:54:27 +01001506static struct dentry *ab8500_gpadc_dir;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001507
Bill Pembertonf791be42012-11-19 13:23:04 -05001508static int ab8500_debug_probe(struct platform_device *plf)
Mattias Wallin5814fc32010-09-13 16:05:04 +02001509{
carriere etienne0fbce762011-04-08 16:26:36 +02001510 struct dentry *file;
Mattias Wallind7b9f322010-11-26 13:06:39 +01001511 debug_bank = AB8500_MISC;
1512 debug_address = AB8500_REV_REG & 0x00FF;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001513
Lee Jones4b8ac082013-01-14 16:10:36 +00001514 irq_first = platform_get_irq_byname(plf, "IRQ_FIRST");
1515 if (irq_first < 0) {
1516 dev_err(&plf->dev, "First irq not found, err %d\n",
John Beckett1478a312011-05-31 13:54:27 +01001517 irq_first);
Lee Jones4b8ac082013-01-14 16:10:36 +00001518 return irq_first;
1519 }
1520
1521 irq_last = platform_get_irq_byname(plf, "IRQ_LAST");
1522 if (irq_last < 0) {
1523 dev_err(&plf->dev, "Last irq not found, err %d\n",
John Beckett1478a312011-05-31 13:54:27 +01001524 irq_last);
Lee Jones4b8ac082013-01-14 16:10:36 +00001525 return irq_last;
1526 }
1527
Mattias Wallind7b9f322010-11-26 13:06:39 +01001528 ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
1529 if (!ab8500_dir)
carriere etienne0fbce762011-04-08 16:26:36 +02001530 goto err;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001531
John Beckett1478a312011-05-31 13:54:27 +01001532 ab8500_gpadc_dir = debugfs_create_dir(AB8500_ADC_NAME_STRING,
1533 ab8500_dir);
1534 if (!ab8500_gpadc_dir)
1535 goto err;
1536
1537 file = debugfs_create_file("all-bank-registers", S_IRUGO,
1538 ab8500_dir, &plf->dev, &ab8500_registers_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001539 if (!file)
1540 goto err;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001541
Mian Yousaf Kaukab42002c62012-01-26 15:39:20 +01001542 file = debugfs_create_file("all-banks", S_IRUGO,
1543 ab8500_dir, &plf->dev, &ab8500_all_banks_fops);
1544 if (!file)
1545 goto err;
1546
John Beckett1478a312011-05-31 13:54:27 +01001547 file = debugfs_create_file("register-bank", (S_IRUGO | S_IWUSR),
1548 ab8500_dir, &plf->dev, &ab8500_bank_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001549 if (!file)
1550 goto err;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001551
John Beckett1478a312011-05-31 13:54:27 +01001552 file = debugfs_create_file("register-address", (S_IRUGO | S_IWUSR),
1553 ab8500_dir, &plf->dev, &ab8500_address_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001554 if (!file)
1555 goto err;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001556
John Beckett1478a312011-05-31 13:54:27 +01001557 file = debugfs_create_file("register-value", (S_IRUGO | S_IWUSR),
1558 ab8500_dir, &plf->dev, &ab8500_val_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001559 if (!file)
1560 goto err;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001561
John Beckett1478a312011-05-31 13:54:27 +01001562 file = debugfs_create_file("irq-subscribe", (S_IRUGO | S_IWUSR),
1563 ab8500_dir, &plf->dev, &ab8500_subscribe_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001564 if (!file)
1565 goto err;
Lee Jones4b8ac082013-01-14 16:10:36 +00001566
John Beckett1478a312011-05-31 13:54:27 +01001567 file = debugfs_create_file("irq-unsubscribe", (S_IRUGO | S_IWUSR),
1568 ab8500_dir, &plf->dev, &ab8500_unsubscribe_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001569 if (!file)
1570 goto err;
1571
John Beckett1478a312011-05-31 13:54:27 +01001572 file = debugfs_create_file("hwreg", (S_IRUGO | S_IWUSR),
1573 ab8500_dir, &plf->dev, &ab8500_hwreg_fops);
1574 if (!file)
1575 goto err;
1576
1577 file = debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR),
1578 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bat_ctrl_fops);
1579 if (!file)
1580 goto err;
1581
1582 file = debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR),
1583 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_btemp_ball_fops);
1584 if (!file)
1585 goto err;
1586
1587 file = debugfs_create_file("main_charger_v", (S_IRUGO | S_IWUSR),
1588 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_v_fops);
1589 if (!file)
1590 goto err;
1591
1592 file = debugfs_create_file("acc_detect1", (S_IRUGO | S_IWUSR),
1593 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect1_fops);
1594 if (!file)
1595 goto err;
1596
1597 file = debugfs_create_file("acc_detect2", (S_IRUGO | S_IWUSR),
1598 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect2_fops);
1599 if (!file)
1600 goto err;
1601
1602 file = debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR),
1603 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux1_fops);
1604 if (!file)
1605 goto err;
1606
1607 file = debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR),
1608 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux2_fops);
1609 if (!file)
1610 goto err;
1611
1612 file = debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR),
1613 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_bat_v_fops);
1614 if (!file)
1615 goto err;
1616
1617 file = debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR),
1618 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_vbus_v_fops);
1619 if (!file)
1620 goto err;
1621
1622 file = debugfs_create_file("main_charger_c", (S_IRUGO | S_IWUSR),
1623 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_c_fops);
1624 if (!file)
1625 goto err;
1626
1627 file = debugfs_create_file("usb_charger_c", (S_IRUGO | S_IWUSR),
1628 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_usb_charger_c_fops);
1629 if (!file)
1630 goto err;
1631
1632 file = debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR),
1633 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bk_bat_v_fops);
1634 if (!file)
1635 goto err;
1636
1637 file = debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR),
1638 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_die_temp_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001639 if (!file)
1640 goto err;
Lee Jones4b8ac082013-01-14 16:10:36 +00001641
Mattias Wallind7b9f322010-11-26 13:06:39 +01001642 return 0;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001643
carriere etienne0fbce762011-04-08 16:26:36 +02001644err:
1645 if (ab8500_dir)
1646 debugfs_remove_recursive(ab8500_dir);
Mattias Wallind7b9f322010-11-26 13:06:39 +01001647 dev_err(&plf->dev, "failed to create debugfs entries.\n");
1648 return -ENOMEM;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001649}
1650
Bill Pemberton4740f732012-11-19 13:26:01 -05001651static int ab8500_debug_remove(struct platform_device *plf)
Mattias Wallin5814fc32010-09-13 16:05:04 +02001652{
carriere etienne0fbce762011-04-08 16:26:36 +02001653 debugfs_remove_recursive(ab8500_dir);
Mattias Wallind7b9f322010-11-26 13:06:39 +01001654 return 0;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001655}
1656
1657static struct platform_driver ab8500_debug_driver = {
Mattias Wallind7b9f322010-11-26 13:06:39 +01001658 .driver = {
1659 .name = "ab8500-debug",
1660 .owner = THIS_MODULE,
1661 },
1662 .probe = ab8500_debug_probe,
Bill Pemberton84449212012-11-19 13:20:24 -05001663 .remove = ab8500_debug_remove
Mattias Wallin5814fc32010-09-13 16:05:04 +02001664};
1665
1666static int __init ab8500_debug_init(void)
1667{
Mattias Wallind7b9f322010-11-26 13:06:39 +01001668 return platform_driver_register(&ab8500_debug_driver);
Mattias Wallin5814fc32010-09-13 16:05:04 +02001669}
1670
1671static void __exit ab8500_debug_exit(void)
1672{
Mattias Wallind7b9f322010-11-26 13:06:39 +01001673 platform_driver_unregister(&ab8500_debug_driver);
Mattias Wallin5814fc32010-09-13 16:05:04 +02001674}
1675subsys_initcall(ab8500_debug_init);
1676module_exit(ab8500_debug_exit);
1677
1678MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com");
1679MODULE_DESCRIPTION("AB8500 DEBUG");
1680MODULE_LICENSE("GPL v2");