| /* | |
| * Copyright (C) 2011 ST-Ericsson | |
| * License terms: GNU General Public License (GPL) version 2 | |
| * Debugfs support for the AB5500 MFD driver | |
| */ | |
| #include <linux/module.h> | |
| #include <linux/debugfs.h> | |
| #include <linux/seq_file.h> | |
| #include <linux/mfd/abx500.h> | |
| #include <linux/mfd/abx500/ab5500.h> | |
| #include <linux/uaccess.h> | |
| #include "ab5500-core.h" | |
| #include "ab5500-debugfs.h" | |
| static struct ab5500_i2c_ranges ab5500_reg_ranges[AB5500_NUM_BANKS] = { | |
| [AB5500_BANK_LED] = { | |
| .bankid = AB5500_BANK_LED, | |
| .nranges = 1, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x00, | |
| .last = 0x0C, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_ADC] = { | |
| .bankid = AB5500_BANK_ADC, | |
| .nranges = 6, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x1F, | |
| .last = 0x22, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0x23, | |
| .last = 0x24, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x26, | |
| .last = 0x2D, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0x2F, | |
| .last = 0x34, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x37, | |
| .last = 0x57, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x58, | |
| .last = 0x58, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_RTC] = { | |
| .bankid = AB5500_BANK_RTC, | |
| .nranges = 2, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x00, | |
| .last = 0x04, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x06, | |
| .last = 0x0C, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_STARTUP] = { | |
| .bankid = AB5500_BANK_STARTUP, | |
| .nranges = 12, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x00, | |
| .last = 0x01, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x1F, | |
| .last = 0x1F, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x2E, | |
| .last = 0x2E, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0x2F, | |
| .last = 0x30, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x50, | |
| .last = 0x51, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x60, | |
| .last = 0x61, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x66, | |
| .last = 0x8A, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x8C, | |
| .last = 0x96, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0xAA, | |
| .last = 0xB4, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0xB7, | |
| .last = 0xBF, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0xC1, | |
| .last = 0xCA, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0xD3, | |
| .last = 0xE0, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_DBI_ECI] = { | |
| .bankid = AB5500_BANK_DBI_ECI, | |
| .nranges = 3, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x00, | |
| .last = 0x07, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x10, | |
| .last = 0x10, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x13, | |
| .last = 0x13, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_CHG] = { | |
| .bankid = AB5500_BANK_CHG, | |
| .nranges = 2, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x11, | |
| .last = 0x11, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0x12, | |
| .last = 0x1B, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_FG_BATTCOM_ACC] = { | |
| .bankid = AB5500_BANK_FG_BATTCOM_ACC, | |
| .nranges = 2, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x00, | |
| .last = 0x0B, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0x0C, | |
| .last = 0x10, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_USB] = { | |
| .bankid = AB5500_BANK_USB, | |
| .nranges = 12, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x01, | |
| .last = 0x01, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x80, | |
| .last = 0x83, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x87, | |
| .last = 0x8A, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x8B, | |
| .last = 0x8B, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0x91, | |
| .last = 0x92, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0x93, | |
| .last = 0x93, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x94, | |
| .last = 0x94, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0xA8, | |
| .last = 0xB0, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0xB2, | |
| .last = 0xB2, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0xB4, | |
| .last = 0xBC, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0xBF, | |
| .last = 0xBF, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0xC1, | |
| .last = 0xC5, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_IT] = { | |
| .bankid = AB5500_BANK_IT, | |
| .nranges = 4, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x00, | |
| .last = 0x02, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0x20, | |
| .last = 0x36, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0x40, | |
| .last = 0x56, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0x60, | |
| .last = 0x76, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_VDDDIG_IO_I2C_CLK_TST] = { | |
| .bankid = AB5500_BANK_VDDDIG_IO_I2C_CLK_TST, | |
| .nranges = 7, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x02, | |
| .last = 0x02, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x12, | |
| .last = 0x12, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x30, | |
| .last = 0x34, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x40, | |
| .last = 0x44, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x50, | |
| .last = 0x54, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x60, | |
| .last = 0x64, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x70, | |
| .last = 0x74, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP] = { | |
| .bankid = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP, | |
| .nranges = 13, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x01, | |
| .last = 0x01, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x02, | |
| .last = 0x02, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0x0D, | |
| .last = 0x0F, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x1C, | |
| .last = 0x1C, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x1E, | |
| .last = 0x1E, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x20, | |
| .last = 0x21, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x25, | |
| .last = 0x25, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x28, | |
| .last = 0x2A, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x30, | |
| .last = 0x33, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x40, | |
| .last = 0x43, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x50, | |
| .last = 0x53, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x60, | |
| .last = 0x63, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x70, | |
| .last = 0x73, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_VIBRA] = { | |
| .bankid = AB5500_BANK_VIBRA, | |
| .nranges = 2, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x10, | |
| .last = 0x13, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0xFE, | |
| .last = 0xFE, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_AUDIO_HEADSETUSB] = { | |
| .bankid = AB5500_BANK_AUDIO_HEADSETUSB, | |
| .nranges = 2, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x00, | |
| .last = 0x48, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0xEB, | |
| .last = 0xFB, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_SIM_USBSIM] = { | |
| .bankid = AB5500_BANK_SIM_USBSIM, | |
| .nranges = 1, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x13, | |
| .last = 0x19, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| }, | |
| }, | |
| [AB5500_BANK_VDENC] = { | |
| .bankid = AB5500_BANK_VDENC, | |
| .nranges = 12, | |
| .range = (struct ab5500_reg_range[]) { | |
| { | |
| .first = 0x00, | |
| .last = 0x08, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x09, | |
| .last = 0x09, | |
| .perm = AB5500_PERM_RO, | |
| }, | |
| { | |
| .first = 0x0A, | |
| .last = 0x12, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x15, | |
| .last = 0x19, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x1B, | |
| .last = 0x21, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x27, | |
| .last = 0x2C, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x41, | |
| .last = 0x41, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x45, | |
| .last = 0x5B, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x5D, | |
| .last = 0x5D, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x69, | |
| .last = 0x69, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x6C, | |
| .last = 0x6D, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| { | |
| .first = 0x80, | |
| .last = 0x81, | |
| .perm = AB5500_PERM_RW, | |
| }, | |
| }, | |
| }, | |
| }; | |
| static int ab5500_registers_print(struct seq_file *s, void *p) | |
| { | |
| struct ab5500 *ab = s->private; | |
| unsigned int i; | |
| u8 bank = (u8)ab->debug_bank; | |
| seq_printf(s, "ab5500 register values:\n"); | |
| for (bank = 0; bank < AB5500_NUM_BANKS; bank++) { | |
| seq_printf(s, " bank %u, %s (0x%x):\n", bank, | |
| bankinfo[bank].name, | |
| bankinfo[bank].slave_addr); | |
| for (i = 0; i < ab5500_reg_ranges[bank].nranges; i++) { | |
| u8 reg; | |
| int err; | |
| for (reg = ab5500_reg_ranges[bank].range[i].first; | |
| reg <= ab5500_reg_ranges[bank].range[i].last; | |
| reg++) { | |
| u8 value; | |
| err = ab5500_get_register_interruptible_raw(ab, | |
| bank, reg, | |
| &value); | |
| if (err < 0) { | |
| dev_err(ab->dev, "get_reg failed %d" | |
| "bank 0x%x reg 0x%x\n", | |
| err, bank, reg); | |
| return err; | |
| } | |
| err = seq_printf(s, "[%d/0x%02X]: 0x%02X\n", | |
| bank, reg, value); | |
| if (err < 0) { | |
| dev_err(ab->dev, | |
| "seq_printf overflow\n"); | |
| /* | |
| * Error is not returned here since | |
| * the output is wanted in any case | |
| */ | |
| return 0; | |
| } | |
| } | |
| } | |
| } | |
| return 0; | |
| } | |
| static int ab5500_registers_open(struct inode *inode, struct file *file) | |
| { | |
| return single_open(file, ab5500_registers_print, inode->i_private); | |
| } | |
| static const struct file_operations ab5500_registers_fops = { | |
| .open = ab5500_registers_open, | |
| .read = seq_read, | |
| .llseek = seq_lseek, | |
| .release = single_release, | |
| .owner = THIS_MODULE, | |
| }; | |
| static int ab5500_bank_print(struct seq_file *s, void *p) | |
| { | |
| struct ab5500 *ab = s->private; | |
| seq_printf(s, "%d\n", ab->debug_bank); | |
| return 0; | |
| } | |
| static int ab5500_bank_open(struct inode *inode, struct file *file) | |
| { | |
| return single_open(file, ab5500_bank_print, inode->i_private); | |
| } | |
| static ssize_t ab5500_bank_write(struct file *file, | |
| const char __user *user_buf, | |
| size_t count, loff_t *ppos) | |
| { | |
| struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private; | |
| char buf[32]; | |
| int buf_size; | |
| unsigned long user_bank; | |
| int err; | |
| /* Get userspace string and assure termination */ | |
| buf_size = min(count, (sizeof(buf) - 1)); | |
| if (copy_from_user(buf, user_buf, buf_size)) | |
| return -EFAULT; | |
| buf[buf_size] = 0; | |
| err = strict_strtoul(buf, 0, &user_bank); | |
| if (err) | |
| return -EINVAL; | |
| if (user_bank >= AB5500_NUM_BANKS) { | |
| dev_err(ab->dev, | |
| "debugfs error input > number of banks\n"); | |
| return -EINVAL; | |
| } | |
| ab->debug_bank = user_bank; | |
| return buf_size; | |
| } | |
| static int ab5500_address_print(struct seq_file *s, void *p) | |
| { | |
| struct ab5500 *ab = s->private; | |
| seq_printf(s, "0x%02X\n", ab->debug_address); | |
| return 0; | |
| } | |
| static int ab5500_address_open(struct inode *inode, struct file *file) | |
| { | |
| return single_open(file, ab5500_address_print, inode->i_private); | |
| } | |
| static ssize_t ab5500_address_write(struct file *file, | |
| const char __user *user_buf, | |
| size_t count, loff_t *ppos) | |
| { | |
| struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private; | |
| char buf[32]; | |
| int buf_size; | |
| unsigned long user_address; | |
| int err; | |
| /* Get userspace string and assure termination */ | |
| buf_size = min(count, (sizeof(buf) - 1)); | |
| if (copy_from_user(buf, user_buf, buf_size)) | |
| return -EFAULT; | |
| buf[buf_size] = 0; | |
| err = strict_strtoul(buf, 0, &user_address); | |
| if (err) | |
| return -EINVAL; | |
| if (user_address > 0xff) { | |
| dev_err(ab->dev, | |
| "debugfs error input > 0xff\n"); | |
| return -EINVAL; | |
| } | |
| ab->debug_address = user_address; | |
| return buf_size; | |
| } | |
| static int ab5500_val_print(struct seq_file *s, void *p) | |
| { | |
| struct ab5500 *ab = s->private; | |
| int err; | |
| u8 regvalue; | |
| err = ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank, | |
| (u8)ab->debug_address, ®value); | |
| if (err) { | |
| dev_err(ab->dev, "get_reg failed %d, bank 0x%x" | |
| ", reg 0x%x\n", err, ab->debug_bank, | |
| ab->debug_address); | |
| return -EINVAL; | |
| } | |
| seq_printf(s, "0x%02X\n", regvalue); | |
| return 0; | |
| } | |
| static int ab5500_val_open(struct inode *inode, struct file *file) | |
| { | |
| return single_open(file, ab5500_val_print, inode->i_private); | |
| } | |
| static ssize_t ab5500_val_write(struct file *file, | |
| const char __user *user_buf, | |
| size_t count, loff_t *ppos) | |
| { | |
| struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private; | |
| char buf[32]; | |
| int buf_size; | |
| unsigned long user_val; | |
| int err; | |
| u8 regvalue; | |
| /* Get userspace string and assure termination */ | |
| buf_size = min(count, (sizeof(buf)-1)); | |
| if (copy_from_user(buf, user_buf, buf_size)) | |
| return -EFAULT; | |
| buf[buf_size] = 0; | |
| err = strict_strtoul(buf, 0, &user_val); | |
| if (err) | |
| return -EINVAL; | |
| if (user_val > 0xff) { | |
| dev_err(ab->dev, | |
| "debugfs error input > 0xff\n"); | |
| return -EINVAL; | |
| } | |
| err = ab5500_mask_and_set_register_interruptible_raw( | |
| ab, (u8)ab->debug_bank, | |
| (u8)ab->debug_address, 0xFF, (u8)user_val); | |
| if (err) | |
| return -EINVAL; | |
| ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank, | |
| (u8)ab->debug_address, ®value); | |
| if (err) | |
| return -EINVAL; | |
| return buf_size; | |
| } | |
| static const struct file_operations ab5500_bank_fops = { | |
| .open = ab5500_bank_open, | |
| .write = ab5500_bank_write, | |
| .read = seq_read, | |
| .llseek = seq_lseek, | |
| .release = single_release, | |
| .owner = THIS_MODULE, | |
| }; | |
| static const struct file_operations ab5500_address_fops = { | |
| .open = ab5500_address_open, | |
| .write = ab5500_address_write, | |
| .read = seq_read, | |
| .llseek = seq_lseek, | |
| .release = single_release, | |
| .owner = THIS_MODULE, | |
| }; | |
| static const struct file_operations ab5500_val_fops = { | |
| .open = ab5500_val_open, | |
| .write = ab5500_val_write, | |
| .read = seq_read, | |
| .llseek = seq_lseek, | |
| .release = single_release, | |
| .owner = THIS_MODULE, | |
| }; | |
| static struct dentry *ab5500_dir; | |
| static struct dentry *ab5500_reg_file; | |
| static struct dentry *ab5500_bank_file; | |
| static struct dentry *ab5500_address_file; | |
| static struct dentry *ab5500_val_file; | |
| void __init ab5500_setup_debugfs(struct ab5500 *ab) | |
| { | |
| ab->debug_bank = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP; | |
| ab->debug_address = AB5500_CHIP_ID; | |
| ab5500_dir = debugfs_create_dir("ab5500", NULL); | |
| if (!ab5500_dir) | |
| goto exit_no_debugfs; | |
| ab5500_reg_file = debugfs_create_file("all-bank-registers", | |
| S_IRUGO, ab5500_dir, ab, &ab5500_registers_fops); | |
| if (!ab5500_reg_file) | |
| goto exit_destroy_dir; | |
| ab5500_bank_file = debugfs_create_file("register-bank", | |
| (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_bank_fops); | |
| if (!ab5500_bank_file) | |
| goto exit_destroy_reg; | |
| ab5500_address_file = debugfs_create_file("register-address", | |
| (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_address_fops); | |
| if (!ab5500_address_file) | |
| goto exit_destroy_bank; | |
| ab5500_val_file = debugfs_create_file("register-value", | |
| (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_val_fops); | |
| if (!ab5500_val_file) | |
| goto exit_destroy_address; | |
| return; | |
| exit_destroy_address: | |
| debugfs_remove(ab5500_address_file); | |
| exit_destroy_bank: | |
| debugfs_remove(ab5500_bank_file); | |
| exit_destroy_reg: | |
| debugfs_remove(ab5500_reg_file); | |
| exit_destroy_dir: | |
| debugfs_remove(ab5500_dir); | |
| exit_no_debugfs: | |
| dev_err(ab->dev, "failed to create debugfs entries.\n"); | |
| return; | |
| } | |
| void __exit ab5500_remove_debugfs(void) | |
| { | |
| debugfs_remove(ab5500_val_file); | |
| debugfs_remove(ab5500_address_file); | |
| debugfs_remove(ab5500_bank_file); | |
| debugfs_remove(ab5500_reg_file); | |
| debugfs_remove(ab5500_dir); | |
| } |