| /* |
| * Copyright (C) 2013 Motorola Mobility LLC |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| * 02111-1307, USA |
| */ |
| |
| #include <linux/debugfs.h> |
| #include <linux/device.h> |
| #include <linux/errno.h> |
| #include <linux/fs.h> |
| #include <linux/gpio.h> |
| #include <linux/kernel.h> |
| #include <linux/slab.h> |
| #include <linux/stat.h> |
| #include <linux/mfd/tps65912.h> |
| |
| |
| struct tps65912_debugfs_reg_descr { |
| char *name; /* Debugfs file name */ |
| u8 reg; /* Register address */ |
| }; |
| |
| /* Registers exposed in debugfs */ |
| static const struct tps65912_debugfs_reg_descr debugfs_regs[] = { |
| { "DCDC1_CTRL", 0x00 }, |
| { "DCDC2_CTRL", 0x01 }, |
| { "DCDC3_CTRL", 0x02 }, |
| { "DCDC4_CTRL", 0x03 }, |
| { "DCDC1_OP", 0x04 }, |
| { "DCDC1_AVS", 0x05 }, |
| { "DCDC1_LIMIT", 0x06 }, |
| { "DCDC2_OP", 0x07 }, |
| { "DCDC2_AVS", 0x08 }, |
| { "DCDC2_LIMIT", 0x09 }, |
| { "DCDC3_OP", 0x0A }, |
| { "DCDC3_AVS", 0x0B }, |
| { "DCDC3_LIMIT", 0x0C }, |
| { "DCDC4_OP", 0x0D }, |
| { "DCDC4_AVS", 0x0E }, |
| { "DCDC4_LIMIT", 0x0F }, |
| { "LDO1_OP", 0x10 }, |
| { "LDO1_AVS", 0x11 }, |
| { "LDO1_LIMIT", 0x12 }, |
| { "LDO2_OP", 0x13 }, |
| { "LDO2_AVS", 0x14 }, |
| { "LDO2_LIMIT", 0x15 }, |
| { "LDO3_OP", 0x16 }, |
| { "LDO3_AVS", 0x17 }, |
| { "LDO3_LIMIT", 0x18 }, |
| { "LDO4_OP", 0x19 }, |
| { "LDO4_AVS", 0x1A }, |
| { "LDO4_LIMIT", 0x1B }, |
| { "LDO5", 0x1C }, |
| { "LDO6", 0x1D }, |
| { "LDO7", 0x1E }, |
| { "LDO8", 0x1F }, |
| { "LDO9", 0x20 }, |
| { "LDO10", 0x21 }, |
| { "THRM", 0x22 }, |
| { "CLK32OUT", 0x23 }, |
| { "DEVCTRL", 0x24 }, |
| { "DEVCTRL2", 0x25 }, |
| { "I2C_SPI_CFG", 0x26 }, |
| { "KEEP_ON", 0x27 }, |
| { "KEEP_ON2", 0x28 }, |
| { "SET_OFF1", 0x29 }, |
| { "SET_OFF2", 0x2A }, |
| { "DEF_VOLT", 0x2B }, |
| { "DEF_VOLT_MAPPING", 0x2C }, |
| { "DISCHARGE", 0x2D }, |
| { "DISCHARGE2", 0x2E }, |
| { "EN1_SET1", 0x2F }, |
| { "EN1_SET2", 0x30 }, |
| { "EN2_SET1", 0x31 }, |
| { "EN2_SET2", 0x32 }, |
| { "EN3_SET1", 0x33 }, |
| { "EN3_SET2", 0x34 }, |
| { "EN4_SET1", 0x35 }, |
| { "EN4_SET2", 0x36 }, |
| { "PGOOD", 0x37 }, |
| { "PGOOD2", 0x38 }, |
| { "INT_STS", 0x39 }, |
| { "INT_MSK", 0x3A }, |
| { "INT_STS2", 0x3B }, |
| { "INT_MSK2", 0x3C }, |
| { "INT_STS3", 0x3D }, |
| { "INT_MSK3", 0x3E }, |
| { "INT_STS4", 0x3F }, |
| { "INT_MSK4", 0x40 }, |
| { "GPIO1", 0x41 }, |
| { "GPIO2", 0x42 }, |
| { "GPIO3", 0x43 }, |
| { "GPIO4", 0x44 }, |
| { "GPIO5", 0x45 }, |
| { "VMON", 0x46 }, |
| { "LEDA_CTRL1", 0x47 }, |
| { "LEDA_CTRL2", 0x48 }, |
| { "LEDA_CTRL3", 0x49 }, |
| { "LEDA_CTRL4", 0x4A }, |
| { "LEDA_CTRL5", 0x4B }, |
| { "LEDA_CTRL6", 0x4C }, |
| { "LEDA_CTRL7", 0x4D }, |
| { "LEDA_CTRL8", 0x4E }, |
| { "LEDB_CTRL1", 0x4F }, |
| { "LEDB_CTRL2", 0x50 }, |
| { "LEDB_CTRL3", 0x51 }, |
| { "LEDB_CTRL4", 0x52 }, |
| { "LEDB_CTRL5", 0x53 }, |
| { "LEDB_CTRL6", 0x54 }, |
| { "LEDB_CTRL7", 0x55 }, |
| { "LEDB_CTRL8", 0x56 }, |
| { "LEDC_CTRL1", 0x57 }, |
| { "LEDC_CTRL2", 0x58 }, |
| { "LEDC_CTRL3", 0x59 }, |
| { "LEDC_CTRL4", 0x5A }, |
| { "LEDC_CTRL5", 0x5B }, |
| { "LEDC_CTRL6", 0x5C }, |
| { "LEDC_CTRL7", 0x5D }, |
| { "LEDC_CTRL8", 0x5E }, |
| { "LED_RAMP_UP_TIME", 0x5F }, |
| { "LED_RAMP_DOWN_TIME", 0x60 }, |
| { "LED_SEQ_EN", 0x61 }, |
| { "LOADSWITCH", 0x62 }, |
| { "SPARE", 0x63 }, |
| { "VERNUM", 0x64 }, |
| }; |
| |
| struct tps65912_debugfs_reg_data { |
| struct tps65912 *tps65912; /* Device */ |
| u8 reg; /* Register address */ |
| }; |
| |
| struct tps65912_debugfs_data { |
| struct dentry *root; /* Debugfs directory of the device */ |
| struct tps65912_debugfs_reg_data reg_data[ARRAY_SIZE(debugfs_regs)]; |
| }; |
| |
| static int reg_read(void *data, u64 *val) |
| { |
| struct tps65912_debugfs_reg_data *reg_data; |
| |
| reg_data = (struct tps65912_debugfs_reg_data *) data; |
| *val = tps65912_reg_read(reg_data->tps65912, reg_data->reg); |
| return 0; |
| } |
| |
| static int reg_write(void *data, u64 val) |
| { |
| struct tps65912_debugfs_reg_data *reg_data; |
| |
| reg_data = (struct tps65912_debugfs_reg_data *) data; |
| return tps65912_reg_write(reg_data->tps65912, reg_data->reg, val); |
| } |
| |
| DEFINE_SIMPLE_ATTRIBUTE(reg_fops, reg_read, reg_write, "0x%02llx\n"); |
| |
| void tps65912_dump_registers(struct tps65912 *tps65912) |
| { |
| int i, reg_data; |
| for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) { |
| reg_data = tps65912_reg_read(tps65912, debugfs_regs[i].reg); |
| pr_info("dump register %s addr %02x with value %02x\n", |
| debugfs_regs[i].name, debugfs_regs[i].reg, reg_data); |
| } |
| } |
| |
| int tps65912_debugfs_create(struct tps65912 *tps65912) |
| { |
| int i; |
| struct tps65912_debugfs_data *debugfs_data; |
| |
| debugfs_data = kzalloc(sizeof(struct tps65912_debugfs_data), |
| GFP_KERNEL); |
| if (!debugfs_data) |
| goto err_data; |
| |
| debugfs_data->root = debugfs_create_dir(dev_name(tps65912->dev), NULL); |
| if (!debugfs_data->root) |
| goto err_root; |
| |
| for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) { |
| debugfs_data->reg_data[i].tps65912 = tps65912; |
| debugfs_data->reg_data[i].reg = debugfs_regs[i].reg; |
| if (!debugfs_create_file(debugfs_regs[i].name, |
| S_IRUGO | S_IWUSR, debugfs_data->root, |
| debugfs_data->reg_data + i, ®_fops)) |
| goto err_file; |
| } |
| |
| tps65912->debugfs_data = debugfs_data; |
| return 0; |
| |
| err_file: |
| debugfs_remove_recursive(debugfs_data->root); |
| err_root: |
| kfree(debugfs_data); |
| err_data: |
| tps65912->debugfs_data = NULL; |
| return -ENOMEM; |
| } |
| |
| void tps65912_debugfs_remove(struct tps65912 *tps65912) |
| { |
| struct tps65912_debugfs_data *debugfs_data; |
| |
| debugfs_data = (struct tps65912_debugfs_data *) tps65912->debugfs_data; |
| if (debugfs_data) { |
| debugfs_remove_recursive(debugfs_data->root); |
| kfree(debugfs_data); |
| } |
| } |