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