/* Copyright (c) 2012-2013 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only 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. * */ #define pr_fmt(fmt) "%s: " fmt, __func__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Register definitions */ #define CHG_CURRENT_REG 0x00 /* Non-Volatile + mirror */ #define CHG_OTHER_CURRENT_REG 0x01 /* Non-Volatile + mirror */ #define VAR_FUNC_REG 0x02 /* Non-Volatile + mirror */ #define FLOAT_VOLTAGE_REG 0x03 /* Non-Volatile + mirror */ #define CHG_CTRL_REG 0x04 /* Non-Volatile + mirror */ #define STAT_TIMER_REG 0x05 /* Non-Volatile + mirror */ #define PIN_ENABLE_CTRL_REG 0x06 /* Non-Volatile + mirror */ #define THERM_CTRL_A_REG 0x07 /* Non-Volatile + mirror */ #define SYSOK_USB3_SELECT_REG 0x08 /* Non-Volatile + mirror */ #define CTRL_FUNCTIONS_REG 0x09 /* Non-Volatile + mirror */ #define OTG_TLIM_THERM_CNTRL_REG 0x0A /* Non-Volatile + mirror */ #define TEMP_MONITOR_REG 0x0B /* Non-Volatile + mirror */ #define FAULT_IRQ_REG 0x0C /* Non-Volatile */ #define IRQ_ENABLE_REG 0x0D /* Non-Volatile */ #define SYSOK_REG 0x0E /* Non-Volatile + mirror */ #define AUTO_INPUT_VOLT_DETECT_REG 0x10 /* Non-Volatile Read-Only */ #define STATUS_IRQ_REG 0x11 /* Non-Volatile Read-Only */ #define I2C_SLAVE_ADDR_REG 0x12 /* Non-Volatile Read-Only */ #define CMD_A_REG 0x30 /* Volatile Read-Write */ #define CMD_B_REG 0x31 /* Volatile Read-Write */ #define CMD_C_REG 0x33 /* Volatile Read-Write */ #define HW_VERSION_REG 0x34 /* Volatile Read-Only */ #define IRQ_STATUS_A_REG 0x35 /* Volatile Read-Only */ #define IRQ_STATUS_B_REG 0x36 /* Volatile Read-Only */ #define IRQ_STATUS_C_REG 0x37 /* Volatile Read-Only */ #define IRQ_STATUS_D_REG 0x38 /* Volatile Read-Only */ #define IRQ_STATUS_E_REG 0x39 /* Volatile Read-Only */ #define IRQ_STATUS_F_REG 0x3A /* Volatile Read-Only */ #define STATUS_A_REG 0x3B /* Volatile Read-Only */ #define STATUS_B_REG 0x3D /* Volatile Read-Only */ /* Note: STATUS_C_REG was removed from SMB349 to SMB350 */ #define STATUS_D_REG 0x3E /* Volatile Read-Only */ #define STATUS_E_REG 0x3F /* Volatile Read-Only */ #define IRQ_STATUS_NUM (IRQ_STATUS_F_REG - IRQ_STATUS_A_REG + 1) /* Status bits and masks */ #define SMB350_MASK(BITS, POS) ((u8)(((1 << BITS) - 1) << POS)) #define FAST_CHG_CURRENT_MASK SMB350_MASK(4, 4) #define SMB350_FAST_CHG_MIN_MA 1000 #define SMB350_FAST_CHG_STEP_MA 200 #define SMB350_FAST_CHG_MAX_MA 3600 #define TERM_CURRENT_MASK SMB350_MASK(3, 2) #define SMB350_TERM_CUR_MIN_MA 200 #define SMB350_TERM_CUR_STEP_MA 100 #define SMB350_TERM_CUR_MAX_MA 700 #define CMD_A_VOLATILE_WR_PERM BIT(7) #define CHG_CTRL_CURR_TERM_END_CHG BIT(6) enum smb350_chg_status { SMB_CHG_STATUS_NONE = 0, SMB_CHG_STATUS_PRE_CHARGE = 1, SMB_CHG_STATUS_FAST_CHARGE = 2, SMB_CHG_STATUS_TAPER_CHARGE = 3, }; static const char * const smb350_chg_status[] = { "none", "pre-charge", "fast-charge", "taper-charge" }; struct smb350_device { /* setup */ int chg_current_ma; int term_current_ma; int chg_en_n_gpio; int chg_susp_n_gpio; int stat_gpio; int irq; /* internal */ enum smb350_chg_status chg_status; struct i2c_client *client; struct delayed_work irq_work; struct dentry *dent; struct wake_lock chg_wake_lock; struct power_supply dc_psy; }; static struct smb350_device *smb350_dev; struct debug_reg { char *name; u8 reg; }; #define SMB350_DEBUG_REG(x) {#x, x##_REG} static struct debug_reg smb350_debug_regs[] = { SMB350_DEBUG_REG(CHG_CURRENT), SMB350_DEBUG_REG(CHG_OTHER_CURRENT), SMB350_DEBUG_REG(VAR_FUNC), SMB350_DEBUG_REG(FLOAT_VOLTAGE), SMB350_DEBUG_REG(CHG_CTRL), SMB350_DEBUG_REG(STAT_TIMER), SMB350_DEBUG_REG(PIN_ENABLE_CTRL), SMB350_DEBUG_REG(THERM_CTRL_A), SMB350_DEBUG_REG(SYSOK_USB3_SELECT), SMB350_DEBUG_REG(CTRL_FUNCTIONS), SMB350_DEBUG_REG(OTG_TLIM_THERM_CNTRL), SMB350_DEBUG_REG(TEMP_MONITOR), SMB350_DEBUG_REG(FAULT_IRQ), SMB350_DEBUG_REG(IRQ_ENABLE), SMB350_DEBUG_REG(SYSOK), SMB350_DEBUG_REG(AUTO_INPUT_VOLT_DETECT), SMB350_DEBUG_REG(STATUS_IRQ), SMB350_DEBUG_REG(I2C_SLAVE_ADDR), SMB350_DEBUG_REG(CMD_A), SMB350_DEBUG_REG(CMD_B), SMB350_DEBUG_REG(CMD_C), SMB350_DEBUG_REG(HW_VERSION), SMB350_DEBUG_REG(IRQ_STATUS_A), SMB350_DEBUG_REG(IRQ_STATUS_B), SMB350_DEBUG_REG(IRQ_STATUS_C), SMB350_DEBUG_REG(IRQ_STATUS_D), SMB350_DEBUG_REG(IRQ_STATUS_E), SMB350_DEBUG_REG(IRQ_STATUS_F), SMB350_DEBUG_REG(STATUS_A), SMB350_DEBUG_REG(STATUS_B), SMB350_DEBUG_REG(STATUS_D), SMB350_DEBUG_REG(STATUS_E), }; /* * Read 8-bit register value. return negative value on error. */ static int smb350_read_reg(struct i2c_client *client, u8 reg) { int val; val = i2c_smbus_read_byte_data(client, reg); if (val < 0) pr_err("i2c read fail. reg=0x%x.ret=%d.\n", reg, val); else pr_debug("reg=0x%02X.val=0x%02X.\n", reg , val); return val; } /* * Write 8-bit register value. return negative value on error. */ static int smb350_write_reg(struct i2c_client *client, u8 reg, u8 val) { int ret; ret = i2c_smbus_write_byte_data(client, reg, val); if (ret < 0) pr_err("i2c read fail. reg=0x%x.val=0x%x.ret=%d.\n", reg, val, ret); else pr_debug("reg=0x%02X.val=0x%02X.\n", reg , val); return ret; } static int smb350_masked_write(struct i2c_client *client, int reg, u8 mask, u8 val) { int ret; int temp; int shift = find_first_bit((unsigned long *) &mask, 8); temp = smb350_read_reg(client, reg); if (temp < 0) return temp; temp &= ~mask; temp |= (val << shift) & mask; ret = smb350_write_reg(client, reg, temp); return ret; } static bool smb350_is_dc_present(struct i2c_client *client) { u16 irq_status_f = smb350_read_reg(client, IRQ_STATUS_F_REG); bool power_ok = irq_status_f & 0x01; /* Power-ok , IRQ_STATUS_F_REG bit#0 */ if (power_ok) pr_debug("DC is present.\n"); else pr_debug("DC is missing.\n"); return power_ok; } static bool smb350_is_charger_present(struct i2c_client *client) { int val; /* Normally the device is non-removable and embedded on the board. * Verify that charger is present by getting I2C response. */ val = smb350_read_reg(client, STATUS_B_REG); if (val < 0) return false; return true; } static int smb350_get_prop_charge_type(struct smb350_device *dev) { int status_b; enum smb350_chg_status status; int chg_type = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; bool chg_enabled; bool charger_err; struct i2c_client *client = dev->client; status_b = smb350_read_reg(client, STATUS_B_REG); if (status_b < 0) { pr_err("failed to read STATUS_B_REG.\n"); return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; } chg_enabled = (bool) (status_b & 0x01); charger_err = (bool) (status_b & (1<<6)); if (!chg_enabled) { pr_warn("Charging not enabled.\n"); /* release the wake-lock when DC power removed */ if (wake_lock_active(&dev->chg_wake_lock)) wake_unlock(&dev->chg_wake_lock); return POWER_SUPPLY_CHARGE_TYPE_NONE; } if (charger_err) { pr_warn("Charger error detected.\n"); return POWER_SUPPLY_CHARGE_TYPE_NONE; } status = (status_b >> 1) & 0x3; if (status == SMB_CHG_STATUS_NONE) chg_type = POWER_SUPPLY_CHARGE_TYPE_NONE; else if (status == SMB_CHG_STATUS_FAST_CHARGE) /* constant current */ chg_type = POWER_SUPPLY_CHARGE_TYPE_FAST; else if (status == SMB_CHG_STATUS_TAPER_CHARGE) /* constant voltage */ chg_type = POWER_SUPPLY_CHARGE_TYPE_FAST; else if (status == SMB_CHG_STATUS_PRE_CHARGE) chg_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; pr_debug("smb-chg-status=%d=%s.\n", status, smb350_chg_status[status]); if (dev->chg_status != status) { /* Status changed */ if (status == SMB_CHG_STATUS_NONE) { pr_debug("Charging stopped.\n"); wake_unlock(&dev->chg_wake_lock); } else { pr_debug("Charging started.\n"); wake_lock(&dev->chg_wake_lock); } } dev->chg_status = status; return chg_type; } static void smb350_enable_charging(struct smb350_device *dev, bool enable) { int val = !enable; /* active low */ pr_debug("enable=%d.\n", enable); gpio_set_value_cansleep(dev->chg_en_n_gpio, val); } /* When the status bit of a certain condition is read, * the corresponding IRQ signal is cleared. */ static int smb350_clear_irq(struct i2c_client *client) { int ret; ret = smb350_read_reg(client, IRQ_STATUS_A_REG); if (ret < 0) return ret; ret = smb350_read_reg(client, IRQ_STATUS_B_REG); if (ret < 0) return ret; ret = smb350_read_reg(client, IRQ_STATUS_C_REG); if (ret < 0) return ret; ret = smb350_read_reg(client, IRQ_STATUS_D_REG); if (ret < 0) return ret; ret = smb350_read_reg(client, IRQ_STATUS_E_REG); if (ret < 0) return ret; ret = smb350_read_reg(client, IRQ_STATUS_F_REG); if (ret < 0) return ret; return 0; } /* * Do the IRQ work from a thread context rather than interrupt context. * Read status registers to clear interrupt source. * Notify the power-supply driver about change detected. * Relevant events for start/stop charging: * 1. DC insert/remove * 2. End-Of-Charging * 3. Battery insert/remove * 4. Temperture too hot/cold * 5. Charging timeout expired. */ static void smb350_irq_worker(struct work_struct *work) { int ret = 0; struct smb350_device *dev = container_of(work, struct smb350_device, irq_work.work); ret = smb350_clear_irq(dev->client); if (ret == 0) { /* Cleared ok */ /* Notify Battery-psy about status changed */ pr_debug("Notify power_supply_changed.\n"); power_supply_changed(&dev->dc_psy); } } /* * The STAT pin is low when charging and high when not charging. * When the smb350 start/stop charging the STAT pin triggers an interrupt. * Interrupt is triggered on both rising or falling edge. */ static irqreturn_t smb350_irq(int irq, void *dev_id) { struct smb350_device *dev = dev_id; pr_debug("\n"); /* I2C transfers API should not run in interrupt context */ schedule_delayed_work(&dev->irq_work, msecs_to_jiffies(100)); return IRQ_HANDLED; } static enum power_supply_property pm_power_props[] = { /* real time */ POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_CHARGE_TYPE, /* fixed */ POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_CURRENT_MAX, }; static char *pm_power_supplied_to[] = { "battery", }; static int smb350_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { int ret = 0; struct smb350_device *dev = container_of(psy, struct smb350_device, dc_psy); struct i2c_client *client = dev->client; switch (psp) { case POWER_SUPPLY_PROP_PRESENT: val->intval = smb350_is_charger_present(client); break; case POWER_SUPPLY_PROP_ONLINE: val->intval = smb350_is_dc_present(client); break; case POWER_SUPPLY_PROP_CHARGE_TYPE: val->intval = smb350_get_prop_charge_type(dev); break; case POWER_SUPPLY_PROP_MODEL_NAME: val->strval = SMB350_NAME; break; case POWER_SUPPLY_PROP_MANUFACTURER: val->strval = "Summit Microelectronics"; break; case POWER_SUPPLY_PROP_CURRENT_MAX: val->intval = dev->chg_current_ma; break; default: pr_err("Invalid prop = %d.\n", psp); ret = -EINVAL; break; } return ret; } static int smb350_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val) { int ret = 0; struct smb350_device *dev = container_of(psy, struct smb350_device, dc_psy); switch (psp) { /* * Allow a smart battery to Start/Stop charging. * i.e. when End-Of-Charging detected. * The SMB350 can be configured to terminate charging * when charge-current reaching Termination-Current. */ case POWER_SUPPLY_PROP_ONLINE: smb350_enable_charging(dev, val->intval); break; default: pr_err("Invalid prop = %d.\n", psp); ret = -EINVAL; } return ret; } static int smb350_set_chg_current(struct i2c_client *client, int current_ma) { int ret; u8 temp; if ((current_ma < SMB350_FAST_CHG_MIN_MA) || (current_ma > SMB350_FAST_CHG_MAX_MA)) { pr_err("invalid current %d mA.\n", current_ma); return -EINVAL; } temp = (current_ma - SMB350_FAST_CHG_MIN_MA) / SMB350_FAST_CHG_STEP_MA; pr_debug("fast-chg-current=%d mA setting %02x\n", current_ma, temp); ret = smb350_masked_write(client, CHG_CURRENT_REG, FAST_CHG_CURRENT_MASK, temp); return ret; } static int smb350_set_term_current(struct i2c_client *client, int current_ma) { int ret; u8 temp; if ((current_ma < SMB350_TERM_CUR_MIN_MA) || (current_ma > SMB350_TERM_CUR_MAX_MA)) { pr_err("invalid current %d mA to set\n", current_ma); return -EINVAL; } temp = (current_ma - SMB350_TERM_CUR_MIN_MA) / SMB350_TERM_CUR_STEP_MA; pr_debug("term-current=%d mA setting %02x\n", current_ma, temp); ret = smb350_masked_write(client, CHG_OTHER_CURRENT_REG, TERM_CURRENT_MASK, temp); return ret; } static int smb350_set_reg(void *data, u64 val) { u32 addr = (u32) data; int ret; struct i2c_client *client = smb350_dev->client; ret = smb350_write_reg(client, addr, (u8) val); return ret; } static int smb350_get_reg(void *data, u64 *val) { u32 addr = (u32) data; int ret; struct i2c_client *client = smb350_dev->client; ret = smb350_read_reg(client, addr); if (ret < 0) return ret; *val = ret; return 0; } DEFINE_SIMPLE_ATTRIBUTE(reg_fops, smb350_get_reg, smb350_set_reg, "0x%02llx\n"); static int smb350_create_debugfs_entries(struct smb350_device *dev) { int i; dev->dent = debugfs_create_dir(SMB350_NAME, NULL); if (IS_ERR(dev->dent)) { pr_err("smb350 driver couldn't create debugfs dir\n"); return -EFAULT; } for (i = 0 ; i < ARRAY_SIZE(smb350_debug_regs) ; i++) { char *name = smb350_debug_regs[i].name; u32 reg = smb350_debug_regs[i].reg; struct dentry *file; file = debugfs_create_file(name, 0644, dev->dent, (void *) reg, ®_fops); if (IS_ERR(file)) { pr_err("debugfs_create_file %s failed.\n", name); return -EFAULT; } } return 0; } static int smb350_set_volatile_params(struct smb350_device *dev) { int ret; struct i2c_client *client = dev->client; pr_debug("\n"); ret = smb350_write_reg(client, CMD_A_REG, CMD_A_VOLATILE_WR_PERM); if (ret) { pr_err("Failed to set VOLATILE_WR_PERM ret=%d\n", ret); return ret; } /* Disable SMB350 pulse-IRQ mechanism, * we use interrupts based on charging-status-transition */ /* Enable STATUS output (regardless of IRQ-pulses) */ smb350_masked_write(client, CMD_A_REG, BIT(0), 0); /* Disable LED blinking - avoid periodic irq */ smb350_masked_write(client, PIN_ENABLE_CTRL_REG, BIT(7), 0); /* Disable Failure SMB-IRQ */ ret = smb350_write_reg(client, FAULT_IRQ_REG, 0x00); if (ret) { pr_err("Failed to set FAULT_IRQ_REG ret=%d\n", ret); return ret; } /* Disable Event IRQ */ ret = smb350_write_reg(client, IRQ_ENABLE_REG, 0x00); if (ret) { pr_err("Failed to set IRQ_ENABLE_REG ret=%d\n", ret); return ret; } /* Enable charging/not-charging status output via STAT pin */ smb350_masked_write(client, STAT_TIMER_REG, BIT(5), 0); /* Disable Automatic Recharge */ smb350_masked_write(client, CHG_CTRL_REG, BIT(7), 1); /* Set fast-charge current */ ret = smb350_set_chg_current(client, dev->chg_current_ma); if (ret) { pr_err("Failed to set FAST_CHG_CURRENT ret=%d\n", ret); return ret; } if (dev->term_current_ma > 0) { /* Enable Current Termination */ smb350_masked_write(client, CHG_CTRL_REG, BIT(6), 0); /* Set Termination current */ smb350_set_term_current(client, dev->term_current_ma); } else { /* Disable Current Termination */ smb350_masked_write(client, CHG_CTRL_REG, BIT(6), 1); } return 0; } static int __devinit smb350_register_psy(struct smb350_device *dev) { int ret; dev->dc_psy.name = "dc"; dev->dc_psy.type = POWER_SUPPLY_TYPE_MAINS; dev->dc_psy.supplied_to = pm_power_supplied_to; dev->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to); dev->dc_psy.properties = pm_power_props; dev->dc_psy.num_properties = ARRAY_SIZE(pm_power_props); dev->dc_psy.get_property = smb350_get_property; dev->dc_psy.set_property = smb350_set_property; ret = power_supply_register(&dev->client->dev, &dev->dc_psy); if (ret) { pr_err("failed to register power_supply. ret=%d.\n", ret); return ret; } return 0; } static int __devinit smb350_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = 0; const struct smb350_platform_data *pdata; struct device_node *dev_node = client->dev.of_node; struct smb350_device *dev; u8 version; /* STAT pin change on start/stop charging */ u32 irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { pr_err("i2c func fail.\n"); return -EIO; } dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { pr_err("alloc fail.\n"); return -ENOMEM; } smb350_dev = dev; dev->client = client; if (dev_node) { dev->chg_en_n_gpio = of_get_named_gpio(dev_node, "summit,chg-en-n-gpio", 0); pr_debug("chg_en_n_gpio = %d.\n", dev->chg_en_n_gpio); dev->chg_susp_n_gpio = of_get_named_gpio(dev_node, "summit,chg-susp-n-gpio", 0); pr_debug("chg_susp_n_gpio = %d.\n", dev->chg_susp_n_gpio); dev->stat_gpio = of_get_named_gpio(dev_node, "summit,stat-gpio", 0); pr_debug("stat_gpio = %d.\n", dev->stat_gpio); ret = of_property_read_u32(dev_node, "summit,chg-current-ma", &(dev->chg_current_ma)); pr_debug("chg_current_ma = %d.\n", dev->chg_current_ma); if (ret) { pr_err("Unable to read chg_current.\n"); return ret; } ret = of_property_read_u32(dev_node, "summit,term-current-ma", &(dev->term_current_ma)); pr_debug("term_current_ma = %d.\n", dev->term_current_ma); if (ret) { pr_err("Unable to read term_current_ma.\n"); return ret; } } else { pdata = client->dev.platform_data; if (pdata == NULL) { pr_err("no platform data.\n"); return -EINVAL; } dev->chg_en_n_gpio = pdata->chg_en_n_gpio; dev->chg_susp_n_gpio = pdata->chg_susp_n_gpio; dev->stat_gpio = pdata->stat_gpio; dev->chg_current_ma = pdata->chg_current_ma; dev->term_current_ma = pdata->term_current_ma; } ret = gpio_request(dev->stat_gpio, "smb350_stat"); if (ret) { pr_err("gpio_request failed for %d ret=%d\n", dev->stat_gpio, ret); goto err_stat_gpio; } dev->irq = gpio_to_irq(dev->stat_gpio); pr_debug("irq#=%d.\n", dev->irq); ret = gpio_request(dev->chg_susp_n_gpio, "smb350_suspend"); if (ret) { pr_err("gpio_request failed for %d ret=%d\n", dev->chg_susp_n_gpio, ret); goto err_susp_gpio; } ret = gpio_request(dev->chg_en_n_gpio, "smb350_charger_enable"); if (ret) { pr_err("gpio_request failed for %d ret=%d\n", dev->chg_en_n_gpio, ret); goto err_en_gpio; } i2c_set_clientdata(client, dev); /* Disable battery charging by default on power up. * Battery charging is enabled by BMS or Battery-Gauge * by using the set_property callback. */ smb350_enable_charging(dev, false); msleep(100); gpio_set_value_cansleep(dev->chg_susp_n_gpio, 1); /* Normal */ msleep(100); /* Allow the device to exist shutdown */ /* I2C transaction allowed only after device exit suspend */ ret = smb350_read_reg(client, I2C_SLAVE_ADDR_REG); if ((ret>>1) != client->addr) { pr_err("No device.\n"); ret = -ENODEV; goto err_no_dev; } version = smb350_read_reg(client, HW_VERSION_REG); version &= 0x0F; /* bits 0..3 */ ret = smb350_set_volatile_params(dev); if (ret) goto err_set_params; ret = smb350_register_psy(dev); if (ret) goto err_set_params; ret = smb350_create_debugfs_entries(dev); if (ret) goto err_debugfs; INIT_DELAYED_WORK(&dev->irq_work, smb350_irq_worker); wake_lock_init(&dev->chg_wake_lock, WAKE_LOCK_SUSPEND, SMB350_NAME); ret = request_irq(dev->irq, smb350_irq, irq_flags, "smb350_irq", dev); if (ret) { pr_err("request_irq %d failed.ret=%d\n", dev->irq, ret); goto err_irq; } pr_info("HW Version = 0x%X.\n", version); return 0; err_irq: err_debugfs: if (dev->dent) debugfs_remove_recursive(dev->dent); err_no_dev: err_set_params: gpio_free(dev->chg_en_n_gpio); err_en_gpio: gpio_free(dev->chg_susp_n_gpio); err_susp_gpio: gpio_free(dev->stat_gpio); err_stat_gpio: kfree(smb350_dev); smb350_dev = NULL; pr_info("FAIL.\n"); return ret; } static int __devexit smb350_remove(struct i2c_client *client) { struct smb350_device *dev = i2c_get_clientdata(client); power_supply_unregister(&dev->dc_psy); gpio_free(dev->chg_en_n_gpio); gpio_free(dev->chg_susp_n_gpio); if (dev->stat_gpio) gpio_free(dev->stat_gpio); if (dev->irq) free_irq(dev->irq, dev); if (dev->dent) debugfs_remove_recursive(dev->dent); kfree(smb350_dev); smb350_dev = NULL; return 0; } static const struct i2c_device_id smb350_id[] = { {SMB350_NAME, 0}, {}, }; MODULE_DEVICE_TABLE(i2c, smb350_id); static const struct of_device_id smb350_match[] = { { .compatible = "summit,smb350-charger", }, { }, }; static struct i2c_driver smb350_driver = { .driver = { .name = SMB350_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(smb350_match), }, .probe = smb350_probe, .remove = __devexit_p(smb350_remove), .id_table = smb350_id, }; static int __init smb350_init(void) { return i2c_add_driver(&smb350_driver); } module_init(smb350_init); static void __exit smb350_exit(void) { return i2c_del_driver(&smb350_driver); } module_exit(smb350_exit); MODULE_DESCRIPTION("Driver for SMB350 charger chip"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("i2c:" SMB350_NAME);