Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/mfd/ab8500-debugfs.c
15109 views
1
/*
2
* Copyright (C) ST-Ericsson SA 2010
3
*
4
* Author: Mattias Wallin <[email protected]> for ST-Ericsson.
5
* License Terms: GNU General Public License v2
6
*/
7
8
#include <linux/seq_file.h>
9
#include <linux/uaccess.h>
10
#include <linux/fs.h>
11
#include <linux/debugfs.h>
12
#include <linux/platform_device.h>
13
14
#include <linux/mfd/abx500.h>
15
#include <linux/mfd/ab8500.h>
16
17
static u32 debug_bank;
18
static u32 debug_address;
19
20
/**
21
* struct ab8500_reg_range
22
* @first: the first address of the range
23
* @last: the last address of the range
24
* @perm: access permissions for the range
25
*/
26
struct ab8500_reg_range {
27
u8 first;
28
u8 last;
29
u8 perm;
30
};
31
32
/**
33
* struct ab8500_i2c_ranges
34
* @num_ranges: the number of ranges in the list
35
* @bankid: bank identifier
36
* @range: the list of register ranges
37
*/
38
struct ab8500_i2c_ranges {
39
u8 num_ranges;
40
u8 bankid;
41
const struct ab8500_reg_range *range;
42
};
43
44
#define AB8500_NAME_STRING "ab8500"
45
#define AB8500_NUM_BANKS 22
46
47
#define AB8500_REV_REG 0x80
48
49
static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = {
50
[0x0] = {
51
.num_ranges = 0,
52
.range = 0,
53
},
54
[AB8500_SYS_CTRL1_BLOCK] = {
55
.num_ranges = 3,
56
.range = (struct ab8500_reg_range[]) {
57
{
58
.first = 0x00,
59
.last = 0x02,
60
},
61
{
62
.first = 0x42,
63
.last = 0x42,
64
},
65
{
66
.first = 0x80,
67
.last = 0x81,
68
},
69
},
70
},
71
[AB8500_SYS_CTRL2_BLOCK] = {
72
.num_ranges = 4,
73
.range = (struct ab8500_reg_range[]) {
74
{
75
.first = 0x00,
76
.last = 0x0D,
77
},
78
{
79
.first = 0x0F,
80
.last = 0x17,
81
},
82
{
83
.first = 0x30,
84
.last = 0x30,
85
},
86
{
87
.first = 0x32,
88
.last = 0x33,
89
},
90
},
91
},
92
[AB8500_REGU_CTRL1] = {
93
.num_ranges = 3,
94
.range = (struct ab8500_reg_range[]) {
95
{
96
.first = 0x00,
97
.last = 0x00,
98
},
99
{
100
.first = 0x03,
101
.last = 0x10,
102
},
103
{
104
.first = 0x80,
105
.last = 0x84,
106
},
107
},
108
},
109
[AB8500_REGU_CTRL2] = {
110
.num_ranges = 5,
111
.range = (struct ab8500_reg_range[]) {
112
{
113
.first = 0x00,
114
.last = 0x15,
115
},
116
{
117
.first = 0x17,
118
.last = 0x19,
119
},
120
{
121
.first = 0x1B,
122
.last = 0x1D,
123
},
124
{
125
.first = 0x1F,
126
.last = 0x22,
127
},
128
{
129
.first = 0x40,
130
.last = 0x44,
131
},
132
/* 0x80-0x8B is SIM registers and should
133
* not be accessed from here */
134
},
135
},
136
[AB8500_USB] = {
137
.num_ranges = 2,
138
.range = (struct ab8500_reg_range[]) {
139
{
140
.first = 0x80,
141
.last = 0x83,
142
},
143
{
144
.first = 0x87,
145
.last = 0x8A,
146
},
147
},
148
},
149
[AB8500_TVOUT] = {
150
.num_ranges = 9,
151
.range = (struct ab8500_reg_range[]) {
152
{
153
.first = 0x00,
154
.last = 0x12,
155
},
156
{
157
.first = 0x15,
158
.last = 0x17,
159
},
160
{
161
.first = 0x19,
162
.last = 0x21,
163
},
164
{
165
.first = 0x27,
166
.last = 0x2C,
167
},
168
{
169
.first = 0x41,
170
.last = 0x41,
171
},
172
{
173
.first = 0x45,
174
.last = 0x5B,
175
},
176
{
177
.first = 0x5D,
178
.last = 0x5D,
179
},
180
{
181
.first = 0x69,
182
.last = 0x69,
183
},
184
{
185
.first = 0x80,
186
.last = 0x81,
187
},
188
},
189
},
190
[AB8500_DBI] = {
191
.num_ranges = 0,
192
.range = NULL,
193
},
194
[AB8500_ECI_AV_ACC] = {
195
.num_ranges = 1,
196
.range = (struct ab8500_reg_range[]) {
197
{
198
.first = 0x80,
199
.last = 0x82,
200
},
201
},
202
},
203
[0x9] = {
204
.num_ranges = 0,
205
.range = NULL,
206
},
207
[AB8500_GPADC] = {
208
.num_ranges = 1,
209
.range = (struct ab8500_reg_range[]) {
210
{
211
.first = 0x00,
212
.last = 0x08,
213
},
214
},
215
},
216
[AB8500_CHARGER] = {
217
.num_ranges = 8,
218
.range = (struct ab8500_reg_range[]) {
219
{
220
.first = 0x00,
221
.last = 0x03,
222
},
223
{
224
.first = 0x05,
225
.last = 0x05,
226
},
227
{
228
.first = 0x40,
229
.last = 0x40,
230
},
231
{
232
.first = 0x42,
233
.last = 0x42,
234
},
235
{
236
.first = 0x44,
237
.last = 0x44,
238
},
239
{
240
.first = 0x50,
241
.last = 0x55,
242
},
243
{
244
.first = 0x80,
245
.last = 0x82,
246
},
247
{
248
.first = 0xC0,
249
.last = 0xC2,
250
},
251
},
252
},
253
[AB8500_GAS_GAUGE] = {
254
.num_ranges = 3,
255
.range = (struct ab8500_reg_range[]) {
256
{
257
.first = 0x00,
258
.last = 0x00,
259
},
260
{
261
.first = 0x07,
262
.last = 0x0A,
263
},
264
{
265
.first = 0x10,
266
.last = 0x14,
267
},
268
},
269
},
270
[AB8500_AUDIO] = {
271
.num_ranges = 1,
272
.range = (struct ab8500_reg_range[]) {
273
{
274
.first = 0x00,
275
.last = 0x6F,
276
},
277
},
278
},
279
[AB8500_INTERRUPT] = {
280
.num_ranges = 0,
281
.range = NULL,
282
},
283
[AB8500_RTC] = {
284
.num_ranges = 1,
285
.range = (struct ab8500_reg_range[]) {
286
{
287
.first = 0x00,
288
.last = 0x0F,
289
},
290
},
291
},
292
[AB8500_MISC] = {
293
.num_ranges = 8,
294
.range = (struct ab8500_reg_range[]) {
295
{
296
.first = 0x00,
297
.last = 0x05,
298
},
299
{
300
.first = 0x10,
301
.last = 0x15,
302
},
303
{
304
.first = 0x20,
305
.last = 0x25,
306
},
307
{
308
.first = 0x30,
309
.last = 0x35,
310
},
311
{
312
.first = 0x40,
313
.last = 0x45,
314
},
315
{
316
.first = 0x50,
317
.last = 0x50,
318
},
319
{
320
.first = 0x60,
321
.last = 0x67,
322
},
323
{
324
.first = 0x80,
325
.last = 0x80,
326
},
327
},
328
},
329
[0x11] = {
330
.num_ranges = 0,
331
.range = NULL,
332
},
333
[0x12] = {
334
.num_ranges = 0,
335
.range = NULL,
336
},
337
[0x13] = {
338
.num_ranges = 0,
339
.range = NULL,
340
},
341
[0x14] = {
342
.num_ranges = 0,
343
.range = NULL,
344
},
345
[AB8500_OTP_EMUL] = {
346
.num_ranges = 1,
347
.range = (struct ab8500_reg_range[]) {
348
{
349
.first = 0x01,
350
.last = 0x0F,
351
},
352
},
353
},
354
};
355
356
static int ab8500_registers_print(struct seq_file *s, void *p)
357
{
358
struct device *dev = s->private;
359
unsigned int i;
360
u32 bank = debug_bank;
361
362
seq_printf(s, AB8500_NAME_STRING " register values:\n");
363
364
seq_printf(s, " bank %u:\n", bank);
365
for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
366
u32 reg;
367
368
for (reg = debug_ranges[bank].range[i].first;
369
reg <= debug_ranges[bank].range[i].last;
370
reg++) {
371
u8 value;
372
int err;
373
374
err = abx500_get_register_interruptible(dev,
375
(u8)bank, (u8)reg, &value);
376
if (err < 0) {
377
dev_err(dev, "ab->read fail %d\n", err);
378
return err;
379
}
380
381
err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank,
382
reg, value);
383
if (err < 0) {
384
dev_err(dev, "seq_printf overflow\n");
385
/* Error is not returned here since
386
* the output is wanted in any case */
387
return 0;
388
}
389
}
390
}
391
return 0;
392
}
393
394
static int ab8500_registers_open(struct inode *inode, struct file *file)
395
{
396
return single_open(file, ab8500_registers_print, inode->i_private);
397
}
398
399
static const struct file_operations ab8500_registers_fops = {
400
.open = ab8500_registers_open,
401
.read = seq_read,
402
.llseek = seq_lseek,
403
.release = single_release,
404
.owner = THIS_MODULE,
405
};
406
407
static int ab8500_bank_print(struct seq_file *s, void *p)
408
{
409
return seq_printf(s, "%d\n", debug_bank);
410
}
411
412
static int ab8500_bank_open(struct inode *inode, struct file *file)
413
{
414
return single_open(file, ab8500_bank_print, inode->i_private);
415
}
416
417
static ssize_t ab8500_bank_write(struct file *file,
418
const char __user *user_buf,
419
size_t count, loff_t *ppos)
420
{
421
struct device *dev = ((struct seq_file *)(file->private_data))->private;
422
char buf[32];
423
int buf_size;
424
unsigned long user_bank;
425
int err;
426
427
/* Get userspace string and assure termination */
428
buf_size = min(count, (sizeof(buf) - 1));
429
if (copy_from_user(buf, user_buf, buf_size))
430
return -EFAULT;
431
buf[buf_size] = 0;
432
433
err = strict_strtoul(buf, 0, &user_bank);
434
if (err)
435
return -EINVAL;
436
437
if (user_bank >= AB8500_NUM_BANKS) {
438
dev_err(dev, "debugfs error input > number of banks\n");
439
return -EINVAL;
440
}
441
442
debug_bank = user_bank;
443
444
return buf_size;
445
}
446
447
static int ab8500_address_print(struct seq_file *s, void *p)
448
{
449
return seq_printf(s, "0x%02X\n", debug_address);
450
}
451
452
static int ab8500_address_open(struct inode *inode, struct file *file)
453
{
454
return single_open(file, ab8500_address_print, inode->i_private);
455
}
456
457
static ssize_t ab8500_address_write(struct file *file,
458
const char __user *user_buf,
459
size_t count, loff_t *ppos)
460
{
461
struct device *dev = ((struct seq_file *)(file->private_data))->private;
462
char buf[32];
463
int buf_size;
464
unsigned long user_address;
465
int err;
466
467
/* Get userspace string and assure termination */
468
buf_size = min(count, (sizeof(buf) - 1));
469
if (copy_from_user(buf, user_buf, buf_size))
470
return -EFAULT;
471
buf[buf_size] = 0;
472
473
err = strict_strtoul(buf, 0, &user_address);
474
if (err)
475
return -EINVAL;
476
if (user_address > 0xff) {
477
dev_err(dev, "debugfs error input > 0xff\n");
478
return -EINVAL;
479
}
480
debug_address = user_address;
481
return buf_size;
482
}
483
484
static int ab8500_val_print(struct seq_file *s, void *p)
485
{
486
struct device *dev = s->private;
487
int ret;
488
u8 regvalue;
489
490
ret = abx500_get_register_interruptible(dev,
491
(u8)debug_bank, (u8)debug_address, &regvalue);
492
if (ret < 0) {
493
dev_err(dev, "abx500_get_reg fail %d, %d\n",
494
ret, __LINE__);
495
return -EINVAL;
496
}
497
seq_printf(s, "0x%02X\n", regvalue);
498
499
return 0;
500
}
501
502
static int ab8500_val_open(struct inode *inode, struct file *file)
503
{
504
return single_open(file, ab8500_val_print, inode->i_private);
505
}
506
507
static ssize_t ab8500_val_write(struct file *file,
508
const char __user *user_buf,
509
size_t count, loff_t *ppos)
510
{
511
struct device *dev = ((struct seq_file *)(file->private_data))->private;
512
char buf[32];
513
int buf_size;
514
unsigned long user_val;
515
int err;
516
517
/* Get userspace string and assure termination */
518
buf_size = min(count, (sizeof(buf)-1));
519
if (copy_from_user(buf, user_buf, buf_size))
520
return -EFAULT;
521
buf[buf_size] = 0;
522
523
err = strict_strtoul(buf, 0, &user_val);
524
if (err)
525
return -EINVAL;
526
if (user_val > 0xff) {
527
dev_err(dev, "debugfs error input > 0xff\n");
528
return -EINVAL;
529
}
530
err = abx500_set_register_interruptible(dev,
531
(u8)debug_bank, debug_address, (u8)user_val);
532
if (err < 0) {
533
printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__);
534
return -EINVAL;
535
}
536
537
return buf_size;
538
}
539
540
static const struct file_operations ab8500_bank_fops = {
541
.open = ab8500_bank_open,
542
.write = ab8500_bank_write,
543
.read = seq_read,
544
.llseek = seq_lseek,
545
.release = single_release,
546
.owner = THIS_MODULE,
547
};
548
549
static const struct file_operations ab8500_address_fops = {
550
.open = ab8500_address_open,
551
.write = ab8500_address_write,
552
.read = seq_read,
553
.llseek = seq_lseek,
554
.release = single_release,
555
.owner = THIS_MODULE,
556
};
557
558
static const struct file_operations ab8500_val_fops = {
559
.open = ab8500_val_open,
560
.write = ab8500_val_write,
561
.read = seq_read,
562
.llseek = seq_lseek,
563
.release = single_release,
564
.owner = THIS_MODULE,
565
};
566
567
static struct dentry *ab8500_dir;
568
static struct dentry *ab8500_reg_file;
569
static struct dentry *ab8500_bank_file;
570
static struct dentry *ab8500_address_file;
571
static struct dentry *ab8500_val_file;
572
573
static int __devinit ab8500_debug_probe(struct platform_device *plf)
574
{
575
debug_bank = AB8500_MISC;
576
debug_address = AB8500_REV_REG & 0x00FF;
577
578
ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
579
if (!ab8500_dir)
580
goto exit_no_debugfs;
581
582
ab8500_reg_file = debugfs_create_file("all-bank-registers",
583
S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
584
if (!ab8500_reg_file)
585
goto exit_destroy_dir;
586
587
ab8500_bank_file = debugfs_create_file("register-bank",
588
(S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_bank_fops);
589
if (!ab8500_bank_file)
590
goto exit_destroy_reg;
591
592
ab8500_address_file = debugfs_create_file("register-address",
593
(S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev,
594
&ab8500_address_fops);
595
if (!ab8500_address_file)
596
goto exit_destroy_bank;
597
598
ab8500_val_file = debugfs_create_file("register-value",
599
(S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_val_fops);
600
if (!ab8500_val_file)
601
goto exit_destroy_address;
602
603
return 0;
604
605
exit_destroy_address:
606
debugfs_remove(ab8500_address_file);
607
exit_destroy_bank:
608
debugfs_remove(ab8500_bank_file);
609
exit_destroy_reg:
610
debugfs_remove(ab8500_reg_file);
611
exit_destroy_dir:
612
debugfs_remove(ab8500_dir);
613
exit_no_debugfs:
614
dev_err(&plf->dev, "failed to create debugfs entries.\n");
615
return -ENOMEM;
616
}
617
618
static int __devexit ab8500_debug_remove(struct platform_device *plf)
619
{
620
debugfs_remove(ab8500_val_file);
621
debugfs_remove(ab8500_address_file);
622
debugfs_remove(ab8500_bank_file);
623
debugfs_remove(ab8500_reg_file);
624
debugfs_remove(ab8500_dir);
625
626
return 0;
627
}
628
629
static struct platform_driver ab8500_debug_driver = {
630
.driver = {
631
.name = "ab8500-debug",
632
.owner = THIS_MODULE,
633
},
634
.probe = ab8500_debug_probe,
635
.remove = __devexit_p(ab8500_debug_remove)
636
};
637
638
static int __init ab8500_debug_init(void)
639
{
640
return platform_driver_register(&ab8500_debug_driver);
641
}
642
643
static void __exit ab8500_debug_exit(void)
644
{
645
platform_driver_unregister(&ab8500_debug_driver);
646
}
647
subsys_initcall(ab8500_debug_init);
648
module_exit(ab8500_debug_exit);
649
650
MODULE_AUTHOR("Mattias WALLIN <[email protected]");
651
MODULE_DESCRIPTION("AB8500 DEBUG");
652
MODULE_LICENSE("GPL v2");
653
654