blob: 226d751d7e5104c31f16d7eab807f074f9c1d2a6 [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
Mattias Wallin5814fc32010-09-13 16:05:04 +0200498static int ab8500_registers_print(struct seq_file *s, void *p)
499{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100500 struct device *dev = s->private;
501 unsigned int i;
502 u32 bank = debug_bank;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200503
Mattias Wallind7b9f322010-11-26 13:06:39 +0100504 seq_printf(s, AB8500_NAME_STRING " register values:\n");
Mattias Wallin5814fc32010-09-13 16:05:04 +0200505
Mattias Wallind7b9f322010-11-26 13:06:39 +0100506 seq_printf(s, " bank %u:\n", bank);
507 for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
508 u32 reg;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200509
Mattias Wallind7b9f322010-11-26 13:06:39 +0100510 for (reg = debug_ranges[bank].range[i].first;
511 reg <= debug_ranges[bank].range[i].last;
512 reg++) {
513 u8 value;
514 int err;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200515
Mattias Wallind7b9f322010-11-26 13:06:39 +0100516 err = abx500_get_register_interruptible(dev,
517 (u8)bank, (u8)reg, &value);
518 if (err < 0) {
519 dev_err(dev, "ab->read fail %d\n", err);
520 return err;
521 }
Mattias Wallin5814fc32010-09-13 16:05:04 +0200522
Mattias Wallind7b9f322010-11-26 13:06:39 +0100523 err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank,
524 reg, value);
525 if (err < 0) {
526 dev_err(dev, "seq_printf overflow\n");
527 /* Error is not returned here since
528 * the output is wanted in any case */
529 return 0;
530 }
531 }
532 }
533 return 0;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200534}
535
536static int ab8500_registers_open(struct inode *inode, struct file *file)
537{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100538 return single_open(file, ab8500_registers_print, inode->i_private);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200539}
540
541static const struct file_operations ab8500_registers_fops = {
Mattias Wallind7b9f322010-11-26 13:06:39 +0100542 .open = ab8500_registers_open,
543 .read = seq_read,
544 .llseek = seq_lseek,
545 .release = single_release,
546 .owner = THIS_MODULE,
Mattias Wallin5814fc32010-09-13 16:05:04 +0200547};
548
549static int ab8500_bank_print(struct seq_file *s, void *p)
550{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100551 return seq_printf(s, "%d\n", debug_bank);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200552}
553
554static int ab8500_bank_open(struct inode *inode, struct file *file)
555{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100556 return single_open(file, ab8500_bank_print, inode->i_private);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200557}
558
559static ssize_t ab8500_bank_write(struct file *file,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100560 const char __user *user_buf,
561 size_t count, loff_t *ppos)
Mattias Wallin5814fc32010-09-13 16:05:04 +0200562{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100563 struct device *dev = ((struct seq_file *)(file->private_data))->private;
Mattias Wallind7b9f322010-11-26 13:06:39 +0100564 unsigned long user_bank;
565 int err;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200566
Mattias Wallind7b9f322010-11-26 13:06:39 +0100567 /* Get userspace string and assure termination */
Peter Huewe8504d632011-06-06 22:43:32 +0200568 err = kstrtoul_from_user(user_buf, count, 0, &user_bank);
Mattias Wallind7b9f322010-11-26 13:06:39 +0100569 if (err)
Peter Huewe8504d632011-06-06 22:43:32 +0200570 return err;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200571
Mattias Wallind7b9f322010-11-26 13:06:39 +0100572 if (user_bank >= AB8500_NUM_BANKS) {
573 dev_err(dev, "debugfs error input > number of banks\n");
574 return -EINVAL;
575 }
Mattias Wallin5814fc32010-09-13 16:05:04 +0200576
Mattias Wallind7b9f322010-11-26 13:06:39 +0100577 debug_bank = user_bank;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200578
Peter Huewe8504d632011-06-06 22:43:32 +0200579 return count;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200580}
581
582static int ab8500_address_print(struct seq_file *s, void *p)
583{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100584 return seq_printf(s, "0x%02X\n", debug_address);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200585}
586
587static int ab8500_address_open(struct inode *inode, struct file *file)
588{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100589 return single_open(file, ab8500_address_print, inode->i_private);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200590}
591
592static ssize_t ab8500_address_write(struct file *file,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100593 const char __user *user_buf,
594 size_t count, loff_t *ppos)
Mattias Wallin5814fc32010-09-13 16:05:04 +0200595{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100596 struct device *dev = ((struct seq_file *)(file->private_data))->private;
Mattias Wallind7b9f322010-11-26 13:06:39 +0100597 unsigned long user_address;
598 int err;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200599
Mattias Wallind7b9f322010-11-26 13:06:39 +0100600 /* Get userspace string and assure termination */
Peter Huewe8504d632011-06-06 22:43:32 +0200601 err = kstrtoul_from_user(user_buf, count, 0, &user_address);
Mattias Wallind7b9f322010-11-26 13:06:39 +0100602 if (err)
Peter Huewe8504d632011-06-06 22:43:32 +0200603 return err;
604
Mattias Wallind7b9f322010-11-26 13:06:39 +0100605 if (user_address > 0xff) {
606 dev_err(dev, "debugfs error input > 0xff\n");
607 return -EINVAL;
608 }
609 debug_address = user_address;
Peter Huewe8504d632011-06-06 22:43:32 +0200610 return count;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200611}
612
613static int ab8500_val_print(struct seq_file *s, void *p)
614{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100615 struct device *dev = s->private;
616 int ret;
617 u8 regvalue;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200618
Mattias Wallind7b9f322010-11-26 13:06:39 +0100619 ret = abx500_get_register_interruptible(dev,
620 (u8)debug_bank, (u8)debug_address, &regvalue);
621 if (ret < 0) {
622 dev_err(dev, "abx500_get_reg fail %d, %d\n",
623 ret, __LINE__);
624 return -EINVAL;
625 }
626 seq_printf(s, "0x%02X\n", regvalue);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200627
Mattias Wallind7b9f322010-11-26 13:06:39 +0100628 return 0;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200629}
630
631static int ab8500_val_open(struct inode *inode, struct file *file)
632{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100633 return single_open(file, ab8500_val_print, inode->i_private);
Mattias Wallin5814fc32010-09-13 16:05:04 +0200634}
635
636static ssize_t ab8500_val_write(struct file *file,
Mattias Wallind7b9f322010-11-26 13:06:39 +0100637 const char __user *user_buf,
638 size_t count, loff_t *ppos)
Mattias Wallin5814fc32010-09-13 16:05:04 +0200639{
Mattias Wallind7b9f322010-11-26 13:06:39 +0100640 struct device *dev = ((struct seq_file *)(file->private_data))->private;
Mattias Wallind7b9f322010-11-26 13:06:39 +0100641 unsigned long user_val;
642 int err;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200643
Mattias Wallind7b9f322010-11-26 13:06:39 +0100644 /* Get userspace string and assure termination */
Peter Huewe8504d632011-06-06 22:43:32 +0200645 err = kstrtoul_from_user(user_buf, count, 0, &user_val);
Mattias Wallind7b9f322010-11-26 13:06:39 +0100646 if (err)
Peter Huewe8504d632011-06-06 22:43:32 +0200647 return err;
648
Mattias Wallind7b9f322010-11-26 13:06:39 +0100649 if (user_val > 0xff) {
650 dev_err(dev, "debugfs error input > 0xff\n");
651 return -EINVAL;
652 }
653 err = abx500_set_register_interruptible(dev,
654 (u8)debug_bank, debug_address, (u8)user_val);
655 if (err < 0) {
656 printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__);
657 return -EINVAL;
658 }
Mattias Wallin5814fc32010-09-13 16:05:04 +0200659
Peter Huewe8504d632011-06-06 22:43:32 +0200660 return count;
Mattias Wallin5814fc32010-09-13 16:05:04 +0200661}
662
carriere etienne0fbce762011-04-08 16:26:36 +0200663/*
664 * - HWREG DB8500 formated routines
665 */
666static int ab8500_hwreg_print(struct seq_file *s, void *d)
667{
668 struct device *dev = s->private;
669 int ret;
670 u8 regvalue;
671
672 ret = abx500_get_register_interruptible(dev,
673 (u8)hwreg_cfg.bank, (u8)hwreg_cfg.addr, &regvalue);
674 if (ret < 0) {
675 dev_err(dev, "abx500_get_reg fail %d, %d\n",
676 ret, __LINE__);
677 return -EINVAL;
678 }
679
680 if (hwreg_cfg.shift >= 0)
681 regvalue >>= hwreg_cfg.shift;
682 else
683 regvalue <<= -hwreg_cfg.shift;
684 regvalue &= hwreg_cfg.mask;
685
686 if (REG_FMT_DEC(&hwreg_cfg))
687 seq_printf(s, "%d\n", regvalue);
688 else
689 seq_printf(s, "0x%02X\n", regvalue);
690 return 0;
691}
692
693static int ab8500_hwreg_open(struct inode *inode, struct file *file)
694{
695 return single_open(file, ab8500_hwreg_print, inode->i_private);
696}
697
John Beckett1478a312011-05-31 13:54:27 +0100698static int ab8500_gpadc_bat_ctrl_print(struct seq_file *s, void *p)
699{
700 int bat_ctrl_raw;
701 int bat_ctrl_convert;
702 struct ab8500_gpadc *gpadc;
703
704 gpadc = ab8500_gpadc_get();
705 bat_ctrl_raw = ab8500_gpadc_read_raw(gpadc, BAT_CTRL);
706 bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc,
707 BAT_CTRL, bat_ctrl_raw);
708
709 return seq_printf(s, "%d,0x%X\n",
710 bat_ctrl_convert, bat_ctrl_raw);
711}
712
713static int ab8500_gpadc_bat_ctrl_open(struct inode *inode, struct file *file)
714{
715 return single_open(file, ab8500_gpadc_bat_ctrl_print, inode->i_private);
716}
717
718static const struct file_operations ab8500_gpadc_bat_ctrl_fops = {
719 .open = ab8500_gpadc_bat_ctrl_open,
720 .read = seq_read,
721 .llseek = seq_lseek,
722 .release = single_release,
723 .owner = THIS_MODULE,
724};
725
726static int ab8500_gpadc_btemp_ball_print(struct seq_file *s, void *p)
727{
728 int btemp_ball_raw;
729 int btemp_ball_convert;
730 struct ab8500_gpadc *gpadc;
731
732 gpadc = ab8500_gpadc_get();
733 btemp_ball_raw = ab8500_gpadc_read_raw(gpadc, BTEMP_BALL);
734 btemp_ball_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL,
735 btemp_ball_raw);
736
737 return seq_printf(s,
738 "%d,0x%X\n", btemp_ball_convert, btemp_ball_raw);
739}
740
741static int ab8500_gpadc_btemp_ball_open(struct inode *inode,
742 struct file *file)
743{
744 return single_open(file, ab8500_gpadc_btemp_ball_print, inode->i_private);
745}
746
747static const struct file_operations ab8500_gpadc_btemp_ball_fops = {
748 .open = ab8500_gpadc_btemp_ball_open,
749 .read = seq_read,
750 .llseek = seq_lseek,
751 .release = single_release,
752 .owner = THIS_MODULE,
753};
754
755static int ab8500_gpadc_main_charger_v_print(struct seq_file *s, void *p)
756{
757 int main_charger_v_raw;
758 int main_charger_v_convert;
759 struct ab8500_gpadc *gpadc;
760
761 gpadc = ab8500_gpadc_get();
762 main_charger_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_V);
763 main_charger_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
764 MAIN_CHARGER_V, main_charger_v_raw);
765
766 return seq_printf(s, "%d,0x%X\n",
767 main_charger_v_convert, main_charger_v_raw);
768}
769
770static int ab8500_gpadc_main_charger_v_open(struct inode *inode,
771 struct file *file)
772{
773 return single_open(file, ab8500_gpadc_main_charger_v_print,
774 inode->i_private);
775}
776
777static const struct file_operations ab8500_gpadc_main_charger_v_fops = {
778 .open = ab8500_gpadc_main_charger_v_open,
779 .read = seq_read,
780 .llseek = seq_lseek,
781 .release = single_release,
782 .owner = THIS_MODULE,
783};
784
785static int ab8500_gpadc_acc_detect1_print(struct seq_file *s, void *p)
786{
787 int acc_detect1_raw;
788 int acc_detect1_convert;
789 struct ab8500_gpadc *gpadc;
790
791 gpadc = ab8500_gpadc_get();
792 acc_detect1_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT1);
793 acc_detect1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ACC_DETECT1,
794 acc_detect1_raw);
795
796 return seq_printf(s, "%d,0x%X\n",
797 acc_detect1_convert, acc_detect1_raw);
798}
799
800static int ab8500_gpadc_acc_detect1_open(struct inode *inode,
801 struct file *file)
802{
803 return single_open(file, ab8500_gpadc_acc_detect1_print,
804 inode->i_private);
805}
806
807static const struct file_operations ab8500_gpadc_acc_detect1_fops = {
808 .open = ab8500_gpadc_acc_detect1_open,
809 .read = seq_read,
810 .llseek = seq_lseek,
811 .release = single_release,
812 .owner = THIS_MODULE,
813};
814
815static int ab8500_gpadc_acc_detect2_print(struct seq_file *s, void *p)
816{
817 int acc_detect2_raw;
818 int acc_detect2_convert;
819 struct ab8500_gpadc *gpadc;
820
821 gpadc = ab8500_gpadc_get();
822 acc_detect2_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT2);
823 acc_detect2_convert = ab8500_gpadc_ad_to_voltage(gpadc,
824 ACC_DETECT2, acc_detect2_raw);
825
826 return seq_printf(s, "%d,0x%X\n",
827 acc_detect2_convert, acc_detect2_raw);
828}
829
830static int ab8500_gpadc_acc_detect2_open(struct inode *inode,
831 struct file *file)
832{
833 return single_open(file, ab8500_gpadc_acc_detect2_print,
834 inode->i_private);
835}
836
837static const struct file_operations ab8500_gpadc_acc_detect2_fops = {
838 .open = ab8500_gpadc_acc_detect2_open,
839 .read = seq_read,
840 .llseek = seq_lseek,
841 .release = single_release,
842 .owner = THIS_MODULE,
843};
844
845static int ab8500_gpadc_aux1_print(struct seq_file *s, void *p)
846{
847 int aux1_raw;
848 int aux1_convert;
849 struct ab8500_gpadc *gpadc;
850
851 gpadc = ab8500_gpadc_get();
852 aux1_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX1);
853 aux1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX1,
854 aux1_raw);
855
856 return seq_printf(s, "%d,0x%X\n",
857 aux1_convert, aux1_raw);
858}
859
860static int ab8500_gpadc_aux1_open(struct inode *inode, struct file *file)
861{
862 return single_open(file, ab8500_gpadc_aux1_print, inode->i_private);
863}
864
865static const struct file_operations ab8500_gpadc_aux1_fops = {
866 .open = ab8500_gpadc_aux1_open,
867 .read = seq_read,
868 .llseek = seq_lseek,
869 .release = single_release,
870 .owner = THIS_MODULE,
871};
872
873static int ab8500_gpadc_aux2_print(struct seq_file *s, void *p)
874{
875 int aux2_raw;
876 int aux2_convert;
877 struct ab8500_gpadc *gpadc;
878
879 gpadc = ab8500_gpadc_get();
880 aux2_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX2);
881 aux2_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX2,
882 aux2_raw);
883
884 return seq_printf(s, "%d,0x%X\n",
885 aux2_convert, aux2_raw);
886}
887
888static int ab8500_gpadc_aux2_open(struct inode *inode, struct file *file)
889{
890 return single_open(file, ab8500_gpadc_aux2_print, inode->i_private);
891}
892
893static const struct file_operations ab8500_gpadc_aux2_fops = {
894 .open = ab8500_gpadc_aux2_open,
895 .read = seq_read,
896 .llseek = seq_lseek,
897 .release = single_release,
898 .owner = THIS_MODULE,
899};
900
901static int ab8500_gpadc_main_bat_v_print(struct seq_file *s, void *p)
902{
903 int main_bat_v_raw;
904 int main_bat_v_convert;
905 struct ab8500_gpadc *gpadc;
906
907 gpadc = ab8500_gpadc_get();
908 main_bat_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_BAT_V);
909 main_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V,
910 main_bat_v_raw);
911
912 return seq_printf(s, "%d,0x%X\n",
913 main_bat_v_convert, main_bat_v_raw);
914}
915
916static int ab8500_gpadc_main_bat_v_open(struct inode *inode,
917 struct file *file)
918{
919 return single_open(file, ab8500_gpadc_main_bat_v_print, inode->i_private);
920}
921
922static const struct file_operations ab8500_gpadc_main_bat_v_fops = {
923 .open = ab8500_gpadc_main_bat_v_open,
924 .read = seq_read,
925 .llseek = seq_lseek,
926 .release = single_release,
927 .owner = THIS_MODULE,
928};
929
930static int ab8500_gpadc_vbus_v_print(struct seq_file *s, void *p)
931{
932 int vbus_v_raw;
933 int vbus_v_convert;
934 struct ab8500_gpadc *gpadc;
935
936 gpadc = ab8500_gpadc_get();
937 vbus_v_raw = ab8500_gpadc_read_raw(gpadc, VBUS_V);
938 vbus_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, VBUS_V,
939 vbus_v_raw);
940
941 return seq_printf(s, "%d,0x%X\n",
942 vbus_v_convert, vbus_v_raw);
943}
944
945static int ab8500_gpadc_vbus_v_open(struct inode *inode, struct file *file)
946{
947 return single_open(file, ab8500_gpadc_vbus_v_print, inode->i_private);
948}
949
950static const struct file_operations ab8500_gpadc_vbus_v_fops = {
951 .open = ab8500_gpadc_vbus_v_open,
952 .read = seq_read,
953 .llseek = seq_lseek,
954 .release = single_release,
955 .owner = THIS_MODULE,
956};
957
958static int ab8500_gpadc_main_charger_c_print(struct seq_file *s, void *p)
959{
960 int main_charger_c_raw;
961 int main_charger_c_convert;
962 struct ab8500_gpadc *gpadc;
963
964 gpadc = ab8500_gpadc_get();
965 main_charger_c_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_C);
966 main_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
967 MAIN_CHARGER_C, main_charger_c_raw);
968
969 return seq_printf(s, "%d,0x%X\n",
970 main_charger_c_convert, main_charger_c_raw);
971}
972
973static int ab8500_gpadc_main_charger_c_open(struct inode *inode,
974 struct file *file)
975{
976 return single_open(file, ab8500_gpadc_main_charger_c_print,
977 inode->i_private);
978}
979
980static const struct file_operations ab8500_gpadc_main_charger_c_fops = {
981 .open = ab8500_gpadc_main_charger_c_open,
982 .read = seq_read,
983 .llseek = seq_lseek,
984 .release = single_release,
985 .owner = THIS_MODULE,
986};
987
988static int ab8500_gpadc_usb_charger_c_print(struct seq_file *s, void *p)
989{
990 int usb_charger_c_raw;
991 int usb_charger_c_convert;
992 struct ab8500_gpadc *gpadc;
993
994 gpadc = ab8500_gpadc_get();
995 usb_charger_c_raw = ab8500_gpadc_read_raw(gpadc, USB_CHARGER_C);
996 usb_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
997 USB_CHARGER_C, usb_charger_c_raw);
998
999 return seq_printf(s, "%d,0x%X\n",
1000 usb_charger_c_convert, usb_charger_c_raw);
1001}
1002
1003static int ab8500_gpadc_usb_charger_c_open(struct inode *inode,
1004 struct file *file)
1005{
1006 return single_open(file, ab8500_gpadc_usb_charger_c_print,
1007 inode->i_private);
1008}
1009
1010static const struct file_operations ab8500_gpadc_usb_charger_c_fops = {
1011 .open = ab8500_gpadc_usb_charger_c_open,
1012 .read = seq_read,
1013 .llseek = seq_lseek,
1014 .release = single_release,
1015 .owner = THIS_MODULE,
1016};
1017
1018static int ab8500_gpadc_bk_bat_v_print(struct seq_file *s, void *p)
1019{
1020 int bk_bat_v_raw;
1021 int bk_bat_v_convert;
1022 struct ab8500_gpadc *gpadc;
1023
1024 gpadc = ab8500_gpadc_get();
1025 bk_bat_v_raw = ab8500_gpadc_read_raw(gpadc, BK_BAT_V);
1026 bk_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
1027 BK_BAT_V, bk_bat_v_raw);
1028
1029 return seq_printf(s, "%d,0x%X\n",
1030 bk_bat_v_convert, bk_bat_v_raw);
1031}
1032
1033static int ab8500_gpadc_bk_bat_v_open(struct inode *inode, struct file *file)
1034{
1035 return single_open(file, ab8500_gpadc_bk_bat_v_print, inode->i_private);
1036}
1037
1038static const struct file_operations ab8500_gpadc_bk_bat_v_fops = {
1039 .open = ab8500_gpadc_bk_bat_v_open,
1040 .read = seq_read,
1041 .llseek = seq_lseek,
1042 .release = single_release,
1043 .owner = THIS_MODULE,
1044};
1045
1046static int ab8500_gpadc_die_temp_print(struct seq_file *s, void *p)
1047{
1048 int die_temp_raw;
1049 int die_temp_convert;
1050 struct ab8500_gpadc *gpadc;
1051
1052 gpadc = ab8500_gpadc_get();
1053 die_temp_raw = ab8500_gpadc_read_raw(gpadc, DIE_TEMP);
1054 die_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, DIE_TEMP,
1055 die_temp_raw);
1056
1057 return seq_printf(s, "%d,0x%X\n",
1058 die_temp_convert, die_temp_raw);
1059}
1060
1061static int ab8500_gpadc_die_temp_open(struct inode *inode, struct file *file)
1062{
1063 return single_open(file, ab8500_gpadc_die_temp_print, inode->i_private);
1064}
1065
1066static const struct file_operations ab8500_gpadc_die_temp_fops = {
1067 .open = ab8500_gpadc_die_temp_open,
1068 .read = seq_read,
1069 .llseek = seq_lseek,
1070 .release = single_release,
1071 .owner = THIS_MODULE,
1072};
1073
carriere etienne0fbce762011-04-08 16:26:36 +02001074/*
1075 * return length of an ASCII numerical value, 0 is string is not a
1076 * numerical value.
1077 * string shall start at value 1st char.
1078 * string can be tailed with \0 or space or newline chars only.
1079 * value can be decimal or hexadecimal (prefixed 0x or 0X).
1080 */
1081static int strval_len(char *b)
1082{
1083 char *s = b;
1084 if ((*s == '0') && ((*(s+1) == 'x') || (*(s+1) == 'X'))) {
1085 s += 2;
1086 for (; *s && (*s != ' ') && (*s != '\n'); s++) {
1087 if (!isxdigit(*s))
1088 return 0;
1089 }
1090 } else {
1091 if (*s == '-')
1092 s++;
1093 for (; *s && (*s != ' ') && (*s != '\n'); s++) {
1094 if (!isdigit(*s))
1095 return 0;
1096 }
1097 }
1098 return (int) (s-b);
1099}
1100
1101/*
1102 * parse hwreg input data.
1103 * update global hwreg_cfg only if input data syntax is ok.
1104 */
1105static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg,
1106 struct device *dev)
1107{
1108 uint write, val = 0;
1109 u8 regvalue;
1110 int ret;
1111 struct hwreg_cfg loc = {
1112 .bank = 0, /* default: invalid phys addr */
1113 .addr = 0, /* default: invalid phys addr */
1114 .fmt = 0, /* default: 32bit access, hex output */
1115 .mask = 0xFFFFFFFF, /* default: no mask */
1116 .shift = 0, /* default: no bit shift */
1117 };
1118
1119 /* read or write ? */
1120 if (!strncmp(b, "read ", 5)) {
1121 write = 0;
1122 b += 5;
1123 } else if (!strncmp(b, "write ", 6)) {
1124 write = 1;
1125 b += 6;
1126 } else
1127 return -EINVAL;
1128
1129 /* OPTIONS -l|-w|-b -s -m -o */
1130 while ((*b == ' ') || (*b == '-')) {
1131 if (*(b-1) != ' ') {
1132 b++;
1133 continue;
1134 }
1135 if ((!strncmp(b, "-d ", 3)) ||
1136 (!strncmp(b, "-dec ", 5))) {
1137 b += (*(b+2) == ' ') ? 3 : 5;
1138 loc.fmt |= (1<<0);
1139 } else if ((!strncmp(b, "-h ", 3)) ||
1140 (!strncmp(b, "-hex ", 5))) {
1141 b += (*(b+2) == ' ') ? 3 : 5;
1142 loc.fmt &= ~(1<<0);
1143 } else if ((!strncmp(b, "-m ", 3)) ||
1144 (!strncmp(b, "-mask ", 6))) {
1145 b += (*(b+2) == ' ') ? 3 : 6;
1146 if (strval_len(b) == 0)
1147 return -EINVAL;
1148 loc.mask = simple_strtoul(b, &b, 0);
1149 } else if ((!strncmp(b, "-s ", 3)) ||
1150 (!strncmp(b, "-shift ", 7))) {
1151 b += (*(b+2) == ' ') ? 3 : 7;
1152 if (strval_len(b) == 0)
1153 return -EINVAL;
1154 loc.shift = simple_strtol(b, &b, 0);
1155 } else {
1156 return -EINVAL;
1157 }
1158 }
1159 /* get arg BANK and ADDRESS */
1160 if (strval_len(b) == 0)
1161 return -EINVAL;
1162 loc.bank = simple_strtoul(b, &b, 0);
1163 while (*b == ' ')
1164 b++;
1165 if (strval_len(b) == 0)
1166 return -EINVAL;
1167 loc.addr = simple_strtoul(b, &b, 0);
1168
1169 if (write) {
1170 while (*b == ' ')
1171 b++;
1172 if (strval_len(b) == 0)
1173 return -EINVAL;
1174 val = simple_strtoul(b, &b, 0);
1175 }
1176
1177 /* args are ok, update target cfg (mainly for read) */
1178 *cfg = loc;
1179
1180#ifdef ABB_HWREG_DEBUG
1181 pr_warn("HWREG request: %s, %s, addr=0x%08X, mask=0x%X, shift=%d"
1182 "value=0x%X\n", (write) ? "write" : "read",
1183 REG_FMT_DEC(cfg) ? "decimal" : "hexa",
1184 cfg->addr, cfg->mask, cfg->shift, val);
1185#endif
1186
1187 if (!write)
1188 return 0;
1189
1190 ret = abx500_get_register_interruptible(dev,
1191 (u8)cfg->bank, (u8)cfg->addr, &regvalue);
1192 if (ret < 0) {
1193 dev_err(dev, "abx500_get_reg fail %d, %d\n",
1194 ret, __LINE__);
1195 return -EINVAL;
1196 }
1197
1198 if (cfg->shift >= 0) {
1199 regvalue &= ~(cfg->mask << (cfg->shift));
1200 val = (val & cfg->mask) << (cfg->shift);
1201 } else {
1202 regvalue &= ~(cfg->mask >> (-cfg->shift));
1203 val = (val & cfg->mask) >> (-cfg->shift);
1204 }
1205 val = val | regvalue;
1206
1207 ret = abx500_set_register_interruptible(dev,
1208 (u8)cfg->bank, (u8)cfg->addr, (u8)val);
1209 if (ret < 0) {
1210 pr_err("abx500_set_reg failed %d, %d", ret, __LINE__);
1211 return -EINVAL;
1212 }
1213
1214 return 0;
1215}
1216
1217static ssize_t ab8500_hwreg_write(struct file *file,
1218 const char __user *user_buf, size_t count, loff_t *ppos)
1219{
1220 struct device *dev = ((struct seq_file *)(file->private_data))->private;
1221 char buf[128];
1222 int buf_size, ret;
1223
1224 /* Get userspace string and assure termination */
1225 buf_size = min(count, (sizeof(buf)-1));
1226 if (copy_from_user(buf, user_buf, buf_size))
1227 return -EFAULT;
1228 buf[buf_size] = 0;
1229
1230 /* get args and process */
1231 ret = hwreg_common_write(buf, &hwreg_cfg, dev);
1232 return (ret) ? ret : buf_size;
1233}
1234
1235/*
1236 * - irq subscribe/unsubscribe stuff
1237 */
Lee Jones4b8ac082013-01-14 16:10:36 +00001238static int ab8500_subscribe_unsubscribe_print(struct seq_file *s, void *p)
1239{
1240 seq_printf(s, "%d\n", irq_first);
1241
1242 return 0;
1243}
1244
1245static int ab8500_subscribe_unsubscribe_open(struct inode *inode,
1246 struct file *file)
1247{
1248 return single_open(file, ab8500_subscribe_unsubscribe_print,
1249 inode->i_private);
1250}
1251
1252/*
Mattias Wallin0b337e72010-11-19 17:55:11 +01001253 * Userspace should use poll() on this file. When an event occur
Lee Jones4b8ac082013-01-14 16:10:36 +00001254 * the blocking poll will be released.
1255 */
1256static ssize_t show_irq(struct device *dev,
1257 struct device_attribute *attr, char *buf)
1258{
Mattias Wallin0b337e72010-11-19 17:55:11 +01001259 unsigned long name;
1260 unsigned int irq_index;
1261 int err;
Lee Jones4b8ac082013-01-14 16:10:36 +00001262
Mattias Wallin0b337e72010-11-19 17:55:11 +01001263 err = strict_strtoul(attr->attr.name, 0, &name);
1264 if (err)
1265 return err;
1266
1267 irq_index = name - irq_first;
1268 if (irq_index >= AB8500_NR_IRQS)
1269 return -EINVAL;
1270 else
1271 return sprintf(buf, "%u\n", irq_count[irq_index]);
1272}
Lee Jones4b8ac082013-01-14 16:10:36 +00001273
1274static ssize_t ab8500_subscribe_write(struct file *file,
1275 const char __user *user_buf,
1276 size_t count, loff_t *ppos)
1277{
1278 struct device *dev = ((struct seq_file *)(file->private_data))->private;
1279 char buf[32];
1280 int buf_size;
1281 unsigned long user_val;
1282 int err;
Mattias Wallin0b337e72010-11-19 17:55:11 +01001283 unsigned int irq_index;
Lee Jones4b8ac082013-01-14 16:10:36 +00001284
1285 /* Get userspace string and assure termination */
1286 buf_size = min(count, (sizeof(buf)-1));
1287 if (copy_from_user(buf, user_buf, buf_size))
1288 return -EFAULT;
1289 buf[buf_size] = 0;
1290
1291 err = strict_strtoul(buf, 0, &user_val);
1292 if (err)
1293 return -EINVAL;
1294 if (user_val < irq_first) {
1295 dev_err(dev, "debugfs error input < %d\n", irq_first);
1296 return -EINVAL;
1297 }
1298 if (user_val > irq_last) {
1299 dev_err(dev, "debugfs error input > %d\n", irq_last);
1300 return -EINVAL;
1301 }
1302
Mattias Wallin0b337e72010-11-19 17:55:11 +01001303 irq_index = user_val - irq_first;
1304 if (irq_index >= AB8500_NR_IRQS)
1305 return -EINVAL;
1306
Lee Jones4b8ac082013-01-14 16:10:36 +00001307 /*
Mattias Wallin0b337e72010-11-19 17:55:11 +01001308 * This will create a sysfs file named <irq-nr> which userspace can
Lee Jones4b8ac082013-01-14 16:10:36 +00001309 * use to select or poll and get the AB8500 events
1310 */
Mattias Wallin0b337e72010-11-19 17:55:11 +01001311 dev_attr[irq_index] = kmalloc(sizeof(struct device_attribute),
1312 GFP_KERNEL);
1313 event_name[irq_index] = kmalloc(buf_size, GFP_KERNEL);
1314 sprintf(event_name[irq_index], "%lu", user_val);
1315 dev_attr[irq_index]->show = show_irq;
1316 dev_attr[irq_index]->store = NULL;
1317 dev_attr[irq_index]->attr.name = event_name[irq_index];
1318 dev_attr[irq_index]->attr.mode = S_IRUGO;
1319 err = sysfs_create_file(&dev->kobj, &dev_attr[irq_index]->attr);
Lee Jones4b8ac082013-01-14 16:10:36 +00001320 if (err < 0) {
1321 printk(KERN_ERR "sysfs_create_file failed %d\n", err);
1322 return err;
1323 }
1324
1325 err = request_threaded_irq(user_val, NULL, ab8500_debug_handler,
1326 IRQF_SHARED | IRQF_NO_SUSPEND,
1327 "ab8500-debug", &dev->kobj);
1328 if (err < 0) {
1329 printk(KERN_ERR "request_threaded_irq failed %d, %lu\n",
1330 err, user_val);
Mattias Wallin0b337e72010-11-19 17:55:11 +01001331 sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr);
Lee Jones4b8ac082013-01-14 16:10:36 +00001332 return err;
1333 }
1334
1335 return buf_size;
1336}
1337
1338static ssize_t ab8500_unsubscribe_write(struct file *file,
1339 const char __user *user_buf,
1340 size_t count, loff_t *ppos)
1341{
1342 struct device *dev = ((struct seq_file *)(file->private_data))->private;
1343 char buf[32];
1344 int buf_size;
1345 unsigned long user_val;
1346 int err;
Mattias Wallin0b337e72010-11-19 17:55:11 +01001347 unsigned int irq_index;
Lee Jones4b8ac082013-01-14 16:10:36 +00001348
1349 /* Get userspace string and assure termination */
1350 buf_size = min(count, (sizeof(buf)-1));
1351 if (copy_from_user(buf, user_buf, buf_size))
1352 return -EFAULT;
1353 buf[buf_size] = 0;
1354
1355 err = strict_strtoul(buf, 0, &user_val);
1356 if (err)
1357 return -EINVAL;
1358 if (user_val < irq_first) {
1359 dev_err(dev, "debugfs error input < %d\n", irq_first);
1360 return -EINVAL;
1361 }
1362 if (user_val > irq_last) {
1363 dev_err(dev, "debugfs error input > %d\n", irq_last);
1364 return -EINVAL;
1365 }
1366
Mattias Wallin0b337e72010-11-19 17:55:11 +01001367 irq_index = user_val - irq_first;
1368 if (irq_index >= AB8500_NR_IRQS)
1369 return -EINVAL;
Lee Jones4b8ac082013-01-14 16:10:36 +00001370
Mattias Wallin0b337e72010-11-19 17:55:11 +01001371 /* Set irq count to 0 when unsubscribe */
1372 irq_count[irq_index] = 0;
1373
1374 if (dev_attr[irq_index])
1375 sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr);
1376
1377
1378 free_irq(user_val, &dev->kobj);
1379 kfree(event_name[irq_index]);
1380 kfree(dev_attr[irq_index]);
Lee Jones4b8ac082013-01-14 16:10:36 +00001381
1382 return buf_size;
1383}
1384
carriere etienne0fbce762011-04-08 16:26:36 +02001385/*
1386 * - several deubgfs nodes fops
1387 */
1388
Mattias Wallin5814fc32010-09-13 16:05:04 +02001389static const struct file_operations ab8500_bank_fops = {
Mattias Wallind7b9f322010-11-26 13:06:39 +01001390 .open = ab8500_bank_open,
1391 .write = ab8500_bank_write,
1392 .read = seq_read,
1393 .llseek = seq_lseek,
1394 .release = single_release,
1395 .owner = THIS_MODULE,
Mattias Wallin5814fc32010-09-13 16:05:04 +02001396};
1397
1398static const struct file_operations ab8500_address_fops = {
Mattias Wallind7b9f322010-11-26 13:06:39 +01001399 .open = ab8500_address_open,
1400 .write = ab8500_address_write,
1401 .read = seq_read,
1402 .llseek = seq_lseek,
1403 .release = single_release,
1404 .owner = THIS_MODULE,
Mattias Wallin5814fc32010-09-13 16:05:04 +02001405};
1406
1407static const struct file_operations ab8500_val_fops = {
Mattias Wallind7b9f322010-11-26 13:06:39 +01001408 .open = ab8500_val_open,
1409 .write = ab8500_val_write,
1410 .read = seq_read,
1411 .llseek = seq_lseek,
1412 .release = single_release,
1413 .owner = THIS_MODULE,
Mattias Wallin5814fc32010-09-13 16:05:04 +02001414};
1415
Lee Jones4b8ac082013-01-14 16:10:36 +00001416static const struct file_operations ab8500_subscribe_fops = {
1417 .open = ab8500_subscribe_unsubscribe_open,
1418 .write = ab8500_subscribe_write,
1419 .read = seq_read,
1420 .llseek = seq_lseek,
1421 .release = single_release,
1422 .owner = THIS_MODULE,
1423};
1424
1425static const struct file_operations ab8500_unsubscribe_fops = {
1426 .open = ab8500_subscribe_unsubscribe_open,
1427 .write = ab8500_unsubscribe_write,
1428 .read = seq_read,
1429 .llseek = seq_lseek,
1430 .release = single_release,
1431 .owner = THIS_MODULE,
1432};
1433
carriere etienne0fbce762011-04-08 16:26:36 +02001434static const struct file_operations ab8500_hwreg_fops = {
1435 .open = ab8500_hwreg_open,
1436 .write = ab8500_hwreg_write,
1437 .read = seq_read,
1438 .llseek = seq_lseek,
1439 .release = single_release,
1440 .owner = THIS_MODULE,
1441};
1442
Mattias Wallin5814fc32010-09-13 16:05:04 +02001443static struct dentry *ab8500_dir;
John Beckett1478a312011-05-31 13:54:27 +01001444static struct dentry *ab8500_gpadc_dir;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001445
Bill Pembertonf791be42012-11-19 13:23:04 -05001446static int ab8500_debug_probe(struct platform_device *plf)
Mattias Wallin5814fc32010-09-13 16:05:04 +02001447{
carriere etienne0fbce762011-04-08 16:26:36 +02001448 struct dentry *file;
Mattias Wallind7b9f322010-11-26 13:06:39 +01001449 debug_bank = AB8500_MISC;
1450 debug_address = AB8500_REV_REG & 0x00FF;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001451
Lee Jones4b8ac082013-01-14 16:10:36 +00001452 irq_first = platform_get_irq_byname(plf, "IRQ_FIRST");
1453 if (irq_first < 0) {
1454 dev_err(&plf->dev, "First irq not found, err %d\n",
John Beckett1478a312011-05-31 13:54:27 +01001455 irq_first);
Lee Jones4b8ac082013-01-14 16:10:36 +00001456 return irq_first;
1457 }
1458
1459 irq_last = platform_get_irq_byname(plf, "IRQ_LAST");
1460 if (irq_last < 0) {
1461 dev_err(&plf->dev, "Last irq not found, err %d\n",
John Beckett1478a312011-05-31 13:54:27 +01001462 irq_last);
Lee Jones4b8ac082013-01-14 16:10:36 +00001463 return irq_last;
1464 }
1465
Mattias Wallind7b9f322010-11-26 13:06:39 +01001466 ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
1467 if (!ab8500_dir)
carriere etienne0fbce762011-04-08 16:26:36 +02001468 goto err;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001469
John Beckett1478a312011-05-31 13:54:27 +01001470 ab8500_gpadc_dir = debugfs_create_dir(AB8500_ADC_NAME_STRING,
1471 ab8500_dir);
1472 if (!ab8500_gpadc_dir)
1473 goto err;
1474
1475 file = debugfs_create_file("all-bank-registers", S_IRUGO,
1476 ab8500_dir, &plf->dev, &ab8500_registers_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001477 if (!file)
1478 goto err;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001479
John Beckett1478a312011-05-31 13:54:27 +01001480 file = debugfs_create_file("register-bank", (S_IRUGO | S_IWUSR),
1481 ab8500_dir, &plf->dev, &ab8500_bank_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001482 if (!file)
1483 goto err;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001484
John Beckett1478a312011-05-31 13:54:27 +01001485 file = debugfs_create_file("register-address", (S_IRUGO | S_IWUSR),
1486 ab8500_dir, &plf->dev, &ab8500_address_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001487 if (!file)
1488 goto err;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001489
John Beckett1478a312011-05-31 13:54:27 +01001490 file = debugfs_create_file("register-value", (S_IRUGO | S_IWUSR),
1491 ab8500_dir, &plf->dev, &ab8500_val_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001492 if (!file)
1493 goto err;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001494
John Beckett1478a312011-05-31 13:54:27 +01001495 file = debugfs_create_file("irq-subscribe", (S_IRUGO | S_IWUSR),
1496 ab8500_dir, &plf->dev, &ab8500_subscribe_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001497 if (!file)
1498 goto err;
Lee Jones4b8ac082013-01-14 16:10:36 +00001499
John Beckett1478a312011-05-31 13:54:27 +01001500 file = debugfs_create_file("irq-unsubscribe", (S_IRUGO | S_IWUSR),
1501 ab8500_dir, &plf->dev, &ab8500_unsubscribe_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001502 if (!file)
1503 goto err;
1504
John Beckett1478a312011-05-31 13:54:27 +01001505 file = debugfs_create_file("hwreg", (S_IRUGO | S_IWUSR),
1506 ab8500_dir, &plf->dev, &ab8500_hwreg_fops);
1507 if (!file)
1508 goto err;
1509
1510 file = debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR),
1511 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bat_ctrl_fops);
1512 if (!file)
1513 goto err;
1514
1515 file = debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR),
1516 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_btemp_ball_fops);
1517 if (!file)
1518 goto err;
1519
1520 file = debugfs_create_file("main_charger_v", (S_IRUGO | S_IWUSR),
1521 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_v_fops);
1522 if (!file)
1523 goto err;
1524
1525 file = debugfs_create_file("acc_detect1", (S_IRUGO | S_IWUSR),
1526 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect1_fops);
1527 if (!file)
1528 goto err;
1529
1530 file = debugfs_create_file("acc_detect2", (S_IRUGO | S_IWUSR),
1531 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect2_fops);
1532 if (!file)
1533 goto err;
1534
1535 file = debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR),
1536 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux1_fops);
1537 if (!file)
1538 goto err;
1539
1540 file = debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR),
1541 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux2_fops);
1542 if (!file)
1543 goto err;
1544
1545 file = debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR),
1546 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_bat_v_fops);
1547 if (!file)
1548 goto err;
1549
1550 file = debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR),
1551 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_vbus_v_fops);
1552 if (!file)
1553 goto err;
1554
1555 file = debugfs_create_file("main_charger_c", (S_IRUGO | S_IWUSR),
1556 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_c_fops);
1557 if (!file)
1558 goto err;
1559
1560 file = debugfs_create_file("usb_charger_c", (S_IRUGO | S_IWUSR),
1561 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_usb_charger_c_fops);
1562 if (!file)
1563 goto err;
1564
1565 file = debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR),
1566 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bk_bat_v_fops);
1567 if (!file)
1568 goto err;
1569
1570 file = debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR),
1571 ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_die_temp_fops);
carriere etienne0fbce762011-04-08 16:26:36 +02001572 if (!file)
1573 goto err;
Lee Jones4b8ac082013-01-14 16:10:36 +00001574
Mattias Wallind7b9f322010-11-26 13:06:39 +01001575 return 0;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001576
carriere etienne0fbce762011-04-08 16:26:36 +02001577err:
1578 if (ab8500_dir)
1579 debugfs_remove_recursive(ab8500_dir);
Mattias Wallind7b9f322010-11-26 13:06:39 +01001580 dev_err(&plf->dev, "failed to create debugfs entries.\n");
1581 return -ENOMEM;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001582}
1583
Bill Pemberton4740f732012-11-19 13:26:01 -05001584static int ab8500_debug_remove(struct platform_device *plf)
Mattias Wallin5814fc32010-09-13 16:05:04 +02001585{
carriere etienne0fbce762011-04-08 16:26:36 +02001586 debugfs_remove_recursive(ab8500_dir);
Mattias Wallind7b9f322010-11-26 13:06:39 +01001587 return 0;
Mattias Wallin5814fc32010-09-13 16:05:04 +02001588}
1589
1590static struct platform_driver ab8500_debug_driver = {
Mattias Wallind7b9f322010-11-26 13:06:39 +01001591 .driver = {
1592 .name = "ab8500-debug",
1593 .owner = THIS_MODULE,
1594 },
1595 .probe = ab8500_debug_probe,
Bill Pemberton84449212012-11-19 13:20:24 -05001596 .remove = ab8500_debug_remove
Mattias Wallin5814fc32010-09-13 16:05:04 +02001597};
1598
1599static int __init ab8500_debug_init(void)
1600{
Mattias Wallind7b9f322010-11-26 13:06:39 +01001601 return platform_driver_register(&ab8500_debug_driver);
Mattias Wallin5814fc32010-09-13 16:05:04 +02001602}
1603
1604static void __exit ab8500_debug_exit(void)
1605{
Mattias Wallind7b9f322010-11-26 13:06:39 +01001606 platform_driver_unregister(&ab8500_debug_driver);
Mattias Wallin5814fc32010-09-13 16:05:04 +02001607}
1608subsys_initcall(ab8500_debug_init);
1609module_exit(ab8500_debug_exit);
1610
1611MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com");
1612MODULE_DESCRIPTION("AB8500 DEBUG");
1613MODULE_LICENSE("GPL v2");