1/* 2 * Copyright (C) 2011 ST-Ericsson 3 * License terms: GNU General Public License (GPL) version 2 4 * Debugfs support for the AB5500 MFD driver 5 */ 6 7#include <linux/module.h> 8#include <linux/debugfs.h> 9#include <linux/seq_file.h> 10#include <linux/mfd/abx500.h> 11#include <linux/mfd/abx500/ab5500.h> 12#include <linux/uaccess.h> 13 14#include "ab5500-core.h" 15#include "ab5500-debugfs.h" 16 17static struct ab5500_i2c_ranges ab5500_reg_ranges[AB5500_NUM_BANKS] = { 18 [AB5500_BANK_LED] = { 19 .bankid = AB5500_BANK_LED, 20 .nranges = 1, 21 .range = (struct ab5500_reg_range[]) { 22 { 23 .first = 0x00, 24 .last = 0x0C, 25 .perm = AB5500_PERM_RW, 26 }, 27 }, 28 }, 29 [AB5500_BANK_ADC] = { 30 .bankid = AB5500_BANK_ADC, 31 .nranges = 6, 32 .range = (struct ab5500_reg_range[]) { 33 { 34 .first = 0x1F, 35 .last = 0x22, 36 .perm = AB5500_PERM_RO, 37 }, 38 { 39 .first = 0x23, 40 .last = 0x24, 41 .perm = AB5500_PERM_RW, 42 }, 43 { 44 .first = 0x26, 45 .last = 0x2D, 46 .perm = AB5500_PERM_RO, 47 }, 48 { 49 .first = 0x2F, 50 .last = 0x34, 51 .perm = AB5500_PERM_RW, 52 }, 53 { 54 .first = 0x37, 55 .last = 0x57, 56 .perm = AB5500_PERM_RW, 57 }, 58 { 59 .first = 0x58, 60 .last = 0x58, 61 .perm = AB5500_PERM_RO, 62 }, 63 }, 64 }, 65 [AB5500_BANK_RTC] = { 66 .bankid = AB5500_BANK_RTC, 67 .nranges = 2, 68 .range = (struct ab5500_reg_range[]) { 69 { 70 .first = 0x00, 71 .last = 0x04, 72 .perm = AB5500_PERM_RW, 73 }, 74 { 75 .first = 0x06, 76 .last = 0x0C, 77 .perm = AB5500_PERM_RW, 78 }, 79 }, 80 }, 81 [AB5500_BANK_STARTUP] = { 82 .bankid = AB5500_BANK_STARTUP, 83 .nranges = 12, 84 .range = (struct ab5500_reg_range[]) { 85 { 86 .first = 0x00, 87 .last = 0x01, 88 .perm = AB5500_PERM_RW, 89 }, 90 { 91 .first = 0x1F, 92 .last = 0x1F, 93 .perm = AB5500_PERM_RW, 94 }, 95 { 96 .first = 0x2E, 97 .last = 0x2E, 98 .perm = AB5500_PERM_RO, 99 }, 100 { 101 .first = 0x2F, 102 .last = 0x30, 103 .perm = AB5500_PERM_RW, 104 }, 105 { 106 .first = 0x50, 107 .last = 0x51, 108 .perm = AB5500_PERM_RW, 109 }, 110 { 111 .first = 0x60, 112 .last = 0x61, 113 .perm = AB5500_PERM_RW, 114 }, 115 { 116 .first = 0x66, 117 .last = 0x8A, 118 .perm = AB5500_PERM_RW, 119 }, 120 { 121 .first = 0x8C, 122 .last = 0x96, 123 .perm = AB5500_PERM_RW, 124 }, 125 { 126 .first = 0xAA, 127 .last = 0xB4, 128 .perm = AB5500_PERM_RW, 129 }, 130 { 131 .first = 0xB7, 132 .last = 0xBF, 133 .perm = AB5500_PERM_RW, 134 }, 135 { 136 .first = 0xC1, 137 .last = 0xCA, 138 .perm = AB5500_PERM_RW, 139 }, 140 { 141 .first = 0xD3, 142 .last = 0xE0, 143 .perm = AB5500_PERM_RW, 144 }, 145 }, 146 }, 147 [AB5500_BANK_DBI_ECI] = { 148 .bankid = AB5500_BANK_DBI_ECI, 149 .nranges = 3, 150 .range = (struct ab5500_reg_range[]) { 151 { 152 .first = 0x00, 153 .last = 0x07, 154 .perm = AB5500_PERM_RW, 155 }, 156 { 157 .first = 0x10, 158 .last = 0x10, 159 .perm = AB5500_PERM_RW, 160 }, 161 { 162 .first = 0x13, 163 .last = 0x13, 164 .perm = AB5500_PERM_RW, 165 }, 166 }, 167 }, 168 [AB5500_BANK_CHG] = { 169 .bankid = AB5500_BANK_CHG, 170 .nranges = 2, 171 .range = (struct ab5500_reg_range[]) { 172 { 173 .first = 0x11, 174 .last = 0x11, 175 .perm = AB5500_PERM_RO, 176 }, 177 { 178 .first = 0x12, 179 .last = 0x1B, 180 .perm = AB5500_PERM_RW, 181 }, 182 }, 183 }, 184 [AB5500_BANK_FG_BATTCOM_ACC] = { 185 .bankid = AB5500_BANK_FG_BATTCOM_ACC, 186 .nranges = 2, 187 .range = (struct ab5500_reg_range[]) { 188 { 189 .first = 0x00, 190 .last = 0x0B, 191 .perm = AB5500_PERM_RO, 192 }, 193 { 194 .first = 0x0C, 195 .last = 0x10, 196 .perm = AB5500_PERM_RW, 197 }, 198 }, 199 }, 200 [AB5500_BANK_USB] = { 201 .bankid = AB5500_BANK_USB, 202 .nranges = 12, 203 .range = (struct ab5500_reg_range[]) { 204 { 205 .first = 0x01, 206 .last = 0x01, 207 .perm = AB5500_PERM_RW, 208 }, 209 { 210 .first = 0x80, 211 .last = 0x83, 212 .perm = AB5500_PERM_RW, 213 }, 214 { 215 .first = 0x87, 216 .last = 0x8A, 217 .perm = AB5500_PERM_RW, 218 }, 219 { 220 .first = 0x8B, 221 .last = 0x8B, 222 .perm = AB5500_PERM_RO, 223 }, 224 { 225 .first = 0x91, 226 .last = 0x92, 227 .perm = AB5500_PERM_RO, 228 }, 229 { 230 .first = 0x93, 231 .last = 0x93, 232 .perm = AB5500_PERM_RW, 233 }, 234 { 235 .first = 0x94, 236 .last = 0x94, 237 .perm = AB5500_PERM_RO, 238 }, 239 { 240 .first = 0xA8, 241 .last = 0xB0, 242 .perm = AB5500_PERM_RO, 243 }, 244 { 245 .first = 0xB2, 246 .last = 0xB2, 247 .perm = AB5500_PERM_RO, 248 }, 249 { 250 .first = 0xB4, 251 .last = 0xBC, 252 .perm = AB5500_PERM_RO, 253 }, 254 { 255 .first = 0xBF, 256 .last = 0xBF, 257 .perm = AB5500_PERM_RO, 258 }, 259 { 260 .first = 0xC1, 261 .last = 0xC5, 262 .perm = AB5500_PERM_RO, 263 }, 264 }, 265 }, 266 [AB5500_BANK_IT] = { 267 .bankid = AB5500_BANK_IT, 268 .nranges = 4, 269 .range = (struct ab5500_reg_range[]) { 270 { 271 .first = 0x00, 272 .last = 0x02, 273 .perm = AB5500_PERM_RO, 274 }, 275 { 276 .first = 0x20, 277 .last = 0x36, 278 .perm = AB5500_PERM_RO, 279 }, 280 { 281 .first = 0x40, 282 .last = 0x56, 283 .perm = AB5500_PERM_RO, 284 }, 285 { 286 .first = 0x60, 287 .last = 0x76, 288 .perm = AB5500_PERM_RO, 289 }, 290 }, 291 }, 292 [AB5500_BANK_VDDDIG_IO_I2C_CLK_TST] = { 293 .bankid = AB5500_BANK_VDDDIG_IO_I2C_CLK_TST, 294 .nranges = 7, 295 .range = (struct ab5500_reg_range[]) { 296 { 297 .first = 0x02, 298 .last = 0x02, 299 .perm = AB5500_PERM_RW, 300 }, 301 { 302 .first = 0x12, 303 .last = 0x12, 304 .perm = AB5500_PERM_RW, 305 }, 306 { 307 .first = 0x30, 308 .last = 0x34, 309 .perm = AB5500_PERM_RW, 310 }, 311 { 312 .first = 0x40, 313 .last = 0x44, 314 .perm = AB5500_PERM_RW, 315 }, 316 { 317 .first = 0x50, 318 .last = 0x54, 319 .perm = AB5500_PERM_RW, 320 }, 321 { 322 .first = 0x60, 323 .last = 0x64, 324 .perm = AB5500_PERM_RW, 325 }, 326 { 327 .first = 0x70, 328 .last = 0x74, 329 .perm = AB5500_PERM_RW, 330 }, 331 }, 332 }, 333 [AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP] = { 334 .bankid = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP, 335 .nranges = 13, 336 .range = (struct ab5500_reg_range[]) { 337 { 338 .first = 0x01, 339 .last = 0x01, 340 .perm = AB5500_PERM_RW, 341 }, 342 { 343 .first = 0x02, 344 .last = 0x02, 345 .perm = AB5500_PERM_RO, 346 }, 347 { 348 .first = 0x0D, 349 .last = 0x0F, 350 .perm = AB5500_PERM_RW, 351 }, 352 { 353 .first = 0x1C, 354 .last = 0x1C, 355 .perm = AB5500_PERM_RW, 356 }, 357 { 358 .first = 0x1E, 359 .last = 0x1E, 360 .perm = AB5500_PERM_RW, 361 }, 362 { 363 .first = 0x20, 364 .last = 0x21, 365 .perm = AB5500_PERM_RW, 366 }, 367 { 368 .first = 0x25, 369 .last = 0x25, 370 .perm = AB5500_PERM_RW, 371 }, 372 { 373 .first = 0x28, 374 .last = 0x2A, 375 .perm = AB5500_PERM_RW, 376 }, 377 { 378 .first = 0x30, 379 .last = 0x33, 380 .perm = AB5500_PERM_RW, 381 }, 382 { 383 .first = 0x40, 384 .last = 0x43, 385 .perm = AB5500_PERM_RW, 386 }, 387 { 388 .first = 0x50, 389 .last = 0x53, 390 .perm = AB5500_PERM_RW, 391 }, 392 { 393 .first = 0x60, 394 .last = 0x63, 395 .perm = AB5500_PERM_RW, 396 }, 397 { 398 .first = 0x70, 399 .last = 0x73, 400 .perm = AB5500_PERM_RW, 401 }, 402 }, 403 }, 404 [AB5500_BANK_VIBRA] = { 405 .bankid = AB5500_BANK_VIBRA, 406 .nranges = 2, 407 .range = (struct ab5500_reg_range[]) { 408 { 409 .first = 0x10, 410 .last = 0x13, 411 .perm = AB5500_PERM_RW, 412 }, 413 { 414 .first = 0xFE, 415 .last = 0xFE, 416 .perm = AB5500_PERM_RW, 417 }, 418 }, 419 }, 420 [AB5500_BANK_AUDIO_HEADSETUSB] = { 421 .bankid = AB5500_BANK_AUDIO_HEADSETUSB, 422 .nranges = 2, 423 .range = (struct ab5500_reg_range[]) { 424 { 425 .first = 0x00, 426 .last = 0x48, 427 .perm = AB5500_PERM_RW, 428 }, 429 { 430 .first = 0xEB, 431 .last = 0xFB, 432 .perm = AB5500_PERM_RW, 433 }, 434 }, 435 }, 436 [AB5500_BANK_SIM_USBSIM] = { 437 .bankid = AB5500_BANK_SIM_USBSIM, 438 .nranges = 1, 439 .range = (struct ab5500_reg_range[]) { 440 { 441 .first = 0x13, 442 .last = 0x19, 443 .perm = AB5500_PERM_RW, 444 }, 445 }, 446 }, 447 [AB5500_BANK_VDENC] = { 448 .bankid = AB5500_BANK_VDENC, 449 .nranges = 12, 450 .range = (struct ab5500_reg_range[]) { 451 { 452 .first = 0x00, 453 .last = 0x08, 454 .perm = AB5500_PERM_RW, 455 }, 456 { 457 .first = 0x09, 458 .last = 0x09, 459 .perm = AB5500_PERM_RO, 460 }, 461 { 462 .first = 0x0A, 463 .last = 0x12, 464 .perm = AB5500_PERM_RW, 465 }, 466 { 467 .first = 0x15, 468 .last = 0x19, 469 .perm = AB5500_PERM_RW, 470 }, 471 { 472 .first = 0x1B, 473 .last = 0x21, 474 .perm = AB5500_PERM_RW, 475 }, 476 { 477 .first = 0x27, 478 .last = 0x2C, 479 .perm = AB5500_PERM_RW, 480 }, 481 { 482 .first = 0x41, 483 .last = 0x41, 484 .perm = AB5500_PERM_RW, 485 }, 486 { 487 .first = 0x45, 488 .last = 0x5B, 489 .perm = AB5500_PERM_RW, 490 }, 491 { 492 .first = 0x5D, 493 .last = 0x5D, 494 .perm = AB5500_PERM_RW, 495 }, 496 { 497 .first = 0x69, 498 .last = 0x69, 499 .perm = AB5500_PERM_RW, 500 }, 501 { 502 .first = 0x6C, 503 .last = 0x6D, 504 .perm = AB5500_PERM_RW, 505 }, 506 { 507 .first = 0x80, 508 .last = 0x81, 509 .perm = AB5500_PERM_RW, 510 }, 511 }, 512 }, 513}; 514 515static int ab5500_registers_print(struct seq_file *s, void *p) 516{ 517 struct ab5500 *ab = s->private; 518 unsigned int i; 519 u8 bank = (u8)ab->debug_bank; 520 521 seq_printf(s, "ab5500 register values:\n"); 522 for (bank = 0; bank < AB5500_NUM_BANKS; bank++) { 523 seq_printf(s, " bank %u, %s (0x%x):\n", bank, 524 bankinfo[bank].name, 525 bankinfo[bank].slave_addr); 526 for (i = 0; i < ab5500_reg_ranges[bank].nranges; i++) { 527 u8 reg; 528 int err; 529 530 for (reg = ab5500_reg_ranges[bank].range[i].first; 531 reg <= ab5500_reg_ranges[bank].range[i].last; 532 reg++) { 533 u8 value; 534 535 err = ab5500_get_register_interruptible_raw(ab, 536 bank, reg, 537 &value); 538 if (err < 0) { 539 dev_err(ab->dev, "get_reg failed %d" 540 "bank 0x%x reg 0x%x\n", 541 err, bank, reg); 542 return err; 543 } 544 545 err = seq_printf(s, "[%d/0x%02X]: 0x%02X\n", 546 bank, reg, value); 547 if (err < 0) { 548 dev_err(ab->dev, 549 "seq_printf overflow\n"); 550 /* 551 * Error is not returned here since 552 * the output is wanted in any case 553 */ 554 return 0; 555 } 556 } 557 } 558 } 559 return 0; 560} 561 562static int ab5500_registers_open(struct inode *inode, struct file *file) 563{ 564 return single_open(file, ab5500_registers_print, inode->i_private); 565} 566 567static const struct file_operations ab5500_registers_fops = { 568 .open = ab5500_registers_open, 569 .read = seq_read, 570 .llseek = seq_lseek, 571 .release = single_release, 572 .owner = THIS_MODULE, 573}; 574 575static int ab5500_bank_print(struct seq_file *s, void *p) 576{ 577 struct ab5500 *ab = s->private; 578 579 seq_printf(s, "%d\n", ab->debug_bank); 580 return 0; 581} 582 583static int ab5500_bank_open(struct inode *inode, struct file *file) 584{ 585 return single_open(file, ab5500_bank_print, inode->i_private); 586} 587 588static ssize_t ab5500_bank_write(struct file *file, 589 const char __user *user_buf, 590 size_t count, loff_t *ppos) 591{ 592 struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private; 593 char buf[32]; 594 int buf_size; 595 unsigned long user_bank; 596 int err; 597 598 /* Get userspace string and assure termination */ 599 buf_size = min(count, (sizeof(buf) - 1)); 600 if (copy_from_user(buf, user_buf, buf_size)) 601 return -EFAULT; 602 buf[buf_size] = 0; 603 604 err = strict_strtoul(buf, 0, &user_bank); 605 if (err) 606 return -EINVAL; 607 608 if (user_bank >= AB5500_NUM_BANKS) { 609 dev_err(ab->dev, 610 "debugfs error input > number of banks\n"); 611 return -EINVAL; 612 } 613 614 ab->debug_bank = user_bank; 615 616 return buf_size; 617} 618 619static int ab5500_address_print(struct seq_file *s, void *p) 620{ 621 struct ab5500 *ab = s->private; 622 623 seq_printf(s, "0x%02X\n", ab->debug_address); 624 return 0; 625} 626 627static int ab5500_address_open(struct inode *inode, struct file *file) 628{ 629 return single_open(file, ab5500_address_print, inode->i_private); 630} 631 632static ssize_t ab5500_address_write(struct file *file, 633 const char __user *user_buf, 634 size_t count, loff_t *ppos) 635{ 636 struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private; 637 char buf[32]; 638 int buf_size; 639 unsigned long user_address; 640 int err; 641 642 /* Get userspace string and assure termination */ 643 buf_size = min(count, (sizeof(buf) - 1)); 644 if (copy_from_user(buf, user_buf, buf_size)) 645 return -EFAULT; 646 buf[buf_size] = 0; 647 648 err = strict_strtoul(buf, 0, &user_address); 649 if (err) 650 return -EINVAL; 651 if (user_address > 0xff) { 652 dev_err(ab->dev, 653 "debugfs error input > 0xff\n"); 654 return -EINVAL; 655 } 656 ab->debug_address = user_address; 657 return buf_size; 658} 659 660static int ab5500_val_print(struct seq_file *s, void *p) 661{ 662 struct ab5500 *ab = s->private; 663 int err; 664 u8 regvalue; 665 666 err = ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank, 667 (u8)ab->debug_address, ®value); 668 if (err) { 669 dev_err(ab->dev, "get_reg failed %d, bank 0x%x" 670 ", reg 0x%x\n", err, ab->debug_bank, 671 ab->debug_address); 672 return -EINVAL; 673 } 674 seq_printf(s, "0x%02X\n", regvalue); 675 676 return 0; 677} 678 679static int ab5500_val_open(struct inode *inode, struct file *file) 680{ 681 return single_open(file, ab5500_val_print, inode->i_private); 682} 683 684static ssize_t ab5500_val_write(struct file *file, 685 const char __user *user_buf, 686 size_t count, loff_t *ppos) 687{ 688 struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private; 689 char buf[32]; 690 int buf_size; 691 unsigned long user_val; 692 int err; 693 u8 regvalue; 694 695 /* Get userspace string and assure termination */ 696 buf_size = min(count, (sizeof(buf)-1)); 697 if (copy_from_user(buf, user_buf, buf_size)) 698 return -EFAULT; 699 buf[buf_size] = 0; 700 701 err = strict_strtoul(buf, 0, &user_val); 702 if (err) 703 return -EINVAL; 704 if (user_val > 0xff) { 705 dev_err(ab->dev, 706 "debugfs error input > 0xff\n"); 707 return -EINVAL; 708 } 709 err = ab5500_mask_and_set_register_interruptible_raw( 710 ab, (u8)ab->debug_bank, 711 (u8)ab->debug_address, 0xFF, (u8)user_val); 712 if (err) 713 return -EINVAL; 714 715 ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank, 716 (u8)ab->debug_address, ®value); 717 if (err) 718 return -EINVAL; 719 720 return buf_size; 721} 722 723static const struct file_operations ab5500_bank_fops = { 724 .open = ab5500_bank_open, 725 .write = ab5500_bank_write, 726 .read = seq_read, 727 .llseek = seq_lseek, 728 .release = single_release, 729 .owner = THIS_MODULE, 730}; 731 732static const struct file_operations ab5500_address_fops = { 733 .open = ab5500_address_open, 734 .write = ab5500_address_write, 735 .read = seq_read, 736 .llseek = seq_lseek, 737 .release = single_release, 738 .owner = THIS_MODULE, 739}; 740 741static const struct file_operations ab5500_val_fops = { 742 .open = ab5500_val_open, 743 .write = ab5500_val_write, 744 .read = seq_read, 745 .llseek = seq_lseek, 746 .release = single_release, 747 .owner = THIS_MODULE, 748}; 749 750static struct dentry *ab5500_dir; 751static struct dentry *ab5500_reg_file; 752static struct dentry *ab5500_bank_file; 753static struct dentry *ab5500_address_file; 754static struct dentry *ab5500_val_file; 755 756void __init ab5500_setup_debugfs(struct ab5500 *ab) 757{ 758 ab->debug_bank = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP; 759 ab->debug_address = AB5500_CHIP_ID; 760 761 ab5500_dir = debugfs_create_dir("ab5500", NULL); 762 if (!ab5500_dir) 763 goto exit_no_debugfs; 764 765 ab5500_reg_file = debugfs_create_file("all-bank-registers", 766 S_IRUGO, ab5500_dir, ab, &ab5500_registers_fops); 767 if (!ab5500_reg_file) 768 goto exit_destroy_dir; 769 770 ab5500_bank_file = debugfs_create_file("register-bank", 771 (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_bank_fops); 772 if (!ab5500_bank_file) 773 goto exit_destroy_reg; 774 775 ab5500_address_file = debugfs_create_file("register-address", 776 (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_address_fops); 777 if (!ab5500_address_file) 778 goto exit_destroy_bank; 779 780 ab5500_val_file = debugfs_create_file("register-value", 781 (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_val_fops); 782 if (!ab5500_val_file) 783 goto exit_destroy_address; 784 785 return; 786 787exit_destroy_address: 788 debugfs_remove(ab5500_address_file); 789exit_destroy_bank: 790 debugfs_remove(ab5500_bank_file); 791exit_destroy_reg: 792 debugfs_remove(ab5500_reg_file); 793exit_destroy_dir: 794 debugfs_remove(ab5500_dir); 795exit_no_debugfs: 796 dev_err(ab->dev, "failed to create debugfs entries.\n"); 797 return; 798} 799 800void __exit ab5500_remove_debugfs(void) 801{ 802 debugfs_remove(ab5500_val_file); 803 debugfs_remove(ab5500_address_file); 804 debugfs_remove(ab5500_bank_file); 805 debugfs_remove(ab5500_reg_file); 806 debugfs_remove(ab5500_dir); 807} 808