/* * max77665-charger.c - Battery charger driver * * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. * Syed Rafiuddin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* fast charge current in mA */ static const uint32_t chg_cc[] = { 0, 33, 66, 99, 133, 166, 199, 233, 266, 299, 333, 366, 399, 432, 466, 499, 532, 566, 599, 632, 666, 699, 732, 765, 799, 832, 865, 899, 932, 965, 999, 1032, 1065, 1098, 1132, 1165, 1198, 1232, 1265, 1298, 1332, 1365, 1398, 1421, 1465, 1498, 1531, 1565, 1598, 1631, 1665, 1698, 1731, 1764, 1798, 1831, 1864, 1898, 1931, 1964, 1998, 2031, 2064, 2097 }; /* primary charge termination voltage in mV */ static const uint32_t chg_cv_prm[] = { 3650, 3675, 3700, 3725, 3750, 3775, 3800, 3825, 3850, 3875, 3900, 3925, 3950, 3975, 4000, 4025, 4050, 4075, 4100, 4125, 4150, 4175, 4200, 4225, 4250, 4275, 4300, 4325, 4340, 4350, 4375, 4400 }; static int max77665_bat_to_sys_oc_thres[] = { 0, 3000, 3250, 3500, 3750, 4000, 4250, 4500 }; struct max77665_regulator_info { struct regulator_dev *rdev; struct regulator_desc reg_desc; struct regulator_init_data reg_init_data; }; struct max77665_charger { enum max77665_mode mode; struct device *dev; int irq; struct max77665_charger_plat_data *plat_data; struct mutex current_limit_mutex; int max_current_mA; struct alarm wdt_alarm; struct delayed_work wdt_ack_work; struct delayed_work set_max_current_work; struct wake_lock wdt_wake_lock; unsigned int oc_count; struct max77665_regulator_info reg_info; }; static int max77665_write_reg(struct max77665_charger *charger, uint8_t reg, int value) { int ret = 0; struct device *dev = charger->dev; if ((value < 0) || (value > 0xFF)) return -EINVAL; ret = max77665_write(dev->parent, MAX77665_I2C_SLAVE_PMIC, reg, value); if (ret < 0) dev_err(dev, "Failed to write to reg 0x%x\n", reg); return ret; } static int max77665_read_reg(struct max77665_charger *charger, uint8_t reg, uint32_t *value) { int ret = 0; uint8_t read = 0; struct device *dev = charger->dev; ret = max77665_read(dev->parent, MAX77665_I2C_SLAVE_PMIC, reg, &read); if (0 > ret) dev_err(dev, "Failed to read register 0x%x\n", reg); else *value = read; return ret; } static int max77665_update_reg(struct max77665_charger *charger, uint8_t reg, int value) { int ret = 0; int read_val; ret = max77665_read_reg(charger, reg, &read_val); if (ret) return ret; ret = max77665_write_reg(charger, reg, read_val | value); return ret; } /* Convert current to register value using lookup table */ static int convert_to_reg(struct device *dev, char *tbl_name, const unsigned int *tbl, size_t size, unsigned int val) { size_t i; if ((val < tbl[0]) || (val > tbl[size - 1])) { dev_err(dev, "%d is not in %s table\n", val, tbl_name); return -EINVAL; } for (i = 0; i < size - 1; i++) if ((tbl[i] <= val) && (val < tbl[i + 1])) break; return i; } #define CONVERT_TO_REG(table, val) \ convert_to_reg(charger->dev, #table, table, ARRAY_SIZE(table), val) int max77665_set_max_input_current(struct max77665_charger *charger, int mA) { int ret; ret = max77665_write_reg(charger, MAX77665_CHG_CNFG_09, mA / CURRENT_STEP_mA); if (ret < 0) dev_err(charger->dev, "failed to set %dmA charging\n", mA); return 0; } int max77665_get_max_input_current(struct max77665_charger *charger, int *mA) { int ret; uint32_t val; ret = max77665_read_reg(charger, MAX77665_CHG_CNFG_09, &val); if (0 > ret) dev_err(charger->dev, "failed to get charging current\n"); val &= 0x7F; *mA = max_t(int, MIN_CURRENT_LIMIT_mA, val * CURRENT_STEP_mA); return ret; } static int max77665_enable_write(struct max77665_charger *charger, bool access) { int ret = 0; if (access) /* enable write acces to registers */ ret = max77665_write_reg(charger, MAX77665_CHG_CNFG_06, 0x0c); else /* Disable write acces to registers */ ret = max77665_write_reg(charger, MAX77665_CHG_CNFG_06, 0x00); if (ret < 0) dev_err(charger->dev, "failed to %s write acess\n", access ? "eanble" : "disable"); return ret; } static bool max77665_check_charging_ok(struct max77665_charger *charger) { uint32_t chgin_dtls; uint32_t byp_dtls; int ret; /* check charging input is OK */ ret = max77665_read_reg(charger, MAX77665_CHG_DTLS_00, &chgin_dtls); if ((ret < 0) || (CHGIN_DTLS_MASK(chgin_dtls) != CHGIN_DTLS_VALID)) return false; /* check voltage regulation loop */ ret = max77665_read_reg(charger, MAX77665_CHG_DTLS_02, &byp_dtls); if ((ret < 0) || (BYP_DTLS_MASK(byp_dtls) != BYP_DTLS_VALID)) return false; return true; } static int max77665_set_ideal_input_current(struct max77665_charger *charger) { int ret; int min; int max; int mid; min = 100; max = charger->max_current_mA; /* binary search the ideal input charger current limit */ do { mid = (min + max) / 2; ret = max77665_set_max_input_current(charger, mid); if (ret < 0) return ret; /* let new charging current settle for 50mS */ msleep(50); if (max77665_check_charging_ok(charger)) min = mid; else max = mid; } while (CURRENT_STEP_mA <= (max - min)); charger->max_current_mA = mid; dev_info(charger->dev, "max current after calibration is %dmA\n", mid); return 0; } static void max77665_set_ideal_input_current_work(struct work_struct *w) { struct max77665_charger *charger = container_of(to_delayed_work(w), struct max77665_charger, set_max_current_work); int irq_mask; int safeout_ctrl; mutex_lock(&charger->current_limit_mutex); if (!max77665_check_charging_ok(charger)) { /* * during the max current searching, we need mask charger * input current related IRQs */ max77665_read_reg(charger, MAX77665_CHG_INT_MASK, &irq_mask); max77665_write_reg(charger, MAX77665_CHG_INT_MASK, irq_mask | BYP_BIT | CHGIN_BIT); /* * also we turn off the SAFEOUT1/2 output, so we don't need * generate extra IRQ for the OTG input. */ max77665_read_reg(charger, MAX77665_SAFEOUTCTRL, &safeout_ctrl); max77665_write_reg(charger, MAX77665_SAFEOUTCTRL, safeout_ctrl & ~(ENSAFEOUT1 | ENSAFEOUT2)); max77665_set_ideal_input_current(charger); /* restore IRQs and safeout */ max77665_write_reg(charger, MAX77665_SAFEOUTCTRL, safeout_ctrl); max77665_write_reg(charger, MAX77665_CHG_INT_MASK, irq_mask); } mutex_unlock(&charger->current_limit_mutex); } static void max77665_display_charger_status(struct max77665_charger *charger, uint32_t status) { int i; uint32_t val; bool ok; int bits[] = { BYP_BIT, DETBAT_BIT, BAT_BIT, CHG_BIT, CHGIN_BIT }; char *info[] = { "bypass", "main battery presence", "battery", "charger", "charging input" }; ok = true; for (i = 0; i < ARRAY_SIZE(bits); i++) { if (0 == (status & bits[i])) { ok = false; dev_dbg(charger->dev, "%s is not OK\n", info[i]); } } if (ok == false) { max77665_read_reg(charger, MAX77665_CHG_DTLS_00, &val); dev_dbg(charger->dev, "chg_details_00 is %x\n", val); max77665_read_reg(charger, MAX77665_CHG_DTLS_01, &val); dev_dbg(charger->dev, "chg_details_01 is %x\n", val); max77665_read_reg(charger, MAX77665_CHG_DTLS_02, &val); dev_dbg(charger->dev, "chg_details_02 is %x\n", val); } } static int max77665_handle_charger_status(struct max77665_charger *charger, uint32_t status) { uint32_t val; max77665_display_charger_status(charger, status); /* * if it is charging input or charing error after charging * started, we will find the ideal charging current again */ if (!(status & CHG_BIT) || !(status & CHGIN_BIT)) schedule_delayed_work(&charger->set_max_current_work, msecs_to_jiffies(100)); if (!(status & BAT_BIT)) { max77665_read_reg(charger, MAX77665_CHG_DTLS_01, &val); if (BAT_DTLS_MASK(val) == BAT_DTLS_OVERCURRENT) charger->oc_count++; } return 0; } static int max77665_set_input_charging_current(struct max77665_charger *charger, int max_current_mA) { int ret; ret = max77665_enable_write(charger, true); if (ret < 0) { dev_err(charger->dev, "eanbling write failed: %d\n", ret); return ret; } ret = max77665_set_max_input_current(charger, max_current_mA); dev_info(charger->dev, "max input current %sset to %dmA\n", (ret == 0) ? "" : "failed ", max_current_mA); return max77665_enable_write(charger, false); } static int max77665_set_charger_mode(struct max77665_charger *charger, enum max77665_mode mode) { int ret; int flags; charger->mode = mode; ret = max77665_enable_write(charger, true); if (ret < 0) return ret; if (mode == OFF) flags = CHARGER_OFF_OTG_OFF_BUCK_ON_BOOST_OFF; if (mode == CHARGER) /* enable charging and charging watchdog */ flags = CHARGER_ON_OTG_OFF_BUCK_ON_BOOST_OFF | WDTEN; else if (mode == OTG) flags = CHARGER_OFF_OTG_ON_BUCK_OFF_BOOST_ON; ret = max77665_write_reg(charger, MAX77665_CHG_CNFG_00, flags); if (ret < 0) goto error; /* * Under regulation loop voltage, the VBUS should be higher then the * Charging Port Undershoot Voltage(4.2v) according the USB charging * spec 1.2 */ max77665_read_reg(charger, MAX77665_CHG_CNFG_12, &flags); flags |= VCHGIN_REGULATION_4V3; ret = max77665_write_reg(charger, MAX77665_CHG_CNFG_12, flags); if (ret < 0) goto error; /* * Set to max current in theory. If the the charger has less current * capability, we will calibrated the current inside the charging error * IRQs handler. */ ret = max77665_set_max_input_current(charger, charger->max_current_mA); dev_info(charger->dev, "max input current %sset to %dmA\n", (ret == 0) ? "" : "failed ", charger->max_current_mA); error: return max77665_enable_write(charger, false); } static int max77665_charger_init(struct max77665_charger *charger) { int ret = 0; int val; ret = max77665_enable_write(charger, true); if (ret < 0) goto error; val = FAST_CHARGE_DURATION_4HR | CHARGER_RESTART_THRESHOLD_150mV | LOW_BATTERY_PREQ_ENABLE; ret = max77665_update_reg(charger, MAX77665_CHG_CNFG_01, val); if (ret < 0) { dev_err(charger->dev, "Failed in writing register 0x%x\n", MAX77665_CHG_CNFG_01); goto error; } if (charger->plat_data->fast_chg_cc) { val = CONVERT_TO_REG(chg_cc, charger->plat_data->fast_chg_cc); ret = max77665_update_reg(charger, MAX77665_CHG_CNFG_02, val); if (ret < 0) { dev_err(charger->dev, "Failed writing register 0x%x\n", MAX77665_CHG_CNFG_02); goto error; } } if (charger->plat_data->term_volt) { val = CONVERT_TO_REG(chg_cv_prm, charger->plat_data->term_volt); ret = max77665_update_reg(charger, MAX77665_CHG_CNFG_04, val); if (ret < 0) { dev_err(charger->dev, "Failed writing to reg:0x%x\n", MAX77665_CHG_CNFG_04); goto error; } } error: ret = max77665_enable_write(charger, false); return ret; } static void max77665_charger_disable_wdt(struct max77665_charger *charger) { cancel_delayed_work_sync(&charger->wdt_ack_work); alarm_cancel(&charger->wdt_alarm); } static int max77665_charging_disable(struct max77665_charger *charger) { int ret; dev_info(charger->dev, "Disabling charging\n"); ret = max77665_set_charger_mode(charger, OFF); if (ret < 0) dev_err(charger->dev, "failed to disable charging"); max77665_charger_disable_wdt(charger); if (charger->plat_data->update_status) charger->plat_data->update_status(0); return ret; } static int max77665_charging_enable(struct max77665_charger *charger) { int ret; dev_info(charger->dev, "Enabling charging\n"); ret = max77665_set_charger_mode(charger, CHARGER); if (ret < 0) { dev_err(charger->dev, "failed to set device to charger mode\n"); return ret; } /* set the charging watchdog timer */ alarm_start(&charger->wdt_alarm, ktime_add(ktime_get_boottime(), ktime_set(MAX77665_WATCHDOG_TIMER_PERIOD_S / 2, 0))); if (charger->plat_data->update_status) { int ilim; ret = max77665_get_max_input_current(charger, &ilim); if (ret < 0) { dev_info(charger->dev, "Not able to get max current\n"); return ret; } charger->plat_data->update_status(ilim); } return ret; } static int max77665_set_charging_current(struct regulator_dev *rdev, int min_uA, int max_uA) { struct max77665_charger *charger = rdev_get_drvdata(rdev); uint32_t val; int ret; dev_info(charger->dev, "Requested max current: %duA\n", max_uA); mutex_lock(&charger->current_limit_mutex); charger->max_current_mA = max_uA/1000; /* * For high current charging, max77665 might cut off the VBUS_SAFE_OUT * to AP if input voltage is below VCHIN_UVLO (in voltage regulation * mode). If that happens, the charging might is still on when AP * send cable unplugged event. We need check this conditon by reading * the CHG_DTLS_01 register. */ ret = max77665_read_reg(charger, MAX77665_CHG_DTLS_01, &val); if (ret < 0) { dev_err(charger->dev, "CHG_DTLS_01 read failed: %d\n", ret); goto scrub; } if (charging_is_on(val)) { dev_dbg(charger->dev, "%s() charging current %u is_on: %s\n", __func__, max_uA, charging_is_on(val) ? "on" : "off"); ret = max77665_set_input_charging_current(charger, charger->max_current_mA); if (ret < 0) dev_err(charger->dev, "Setting input charging current failed: %d\n", ret); goto scrub; } if (charger->plat_data->update_status) charger->plat_data->update_status(0); if (charger->max_current_mA) ret = max77665_charging_enable(charger); else ret = max77665_charging_disable(charger); scrub: mutex_unlock(&charger->current_limit_mutex); return ret; } static int max77665_get_charging_current(struct regulator_dev *rdev) { struct max77665_charger *charger = rdev_get_drvdata(rdev); return charger->max_current_mA * 1000; } static struct regulator_ops max77665_charge_regulator_ops = { .set_current_limit = max77665_set_charging_current, .get_current_limit = max77665_get_charging_current, }; static int max77665_charger_regulator_init( struct max77665_charger *charger, struct max77665_charger_plat_data *pdata) { struct max77665_regulator_info *reg = &charger->reg_info; /* set up the current reg for charging */ reg->reg_desc.name = "vbus_reg"; reg->reg_desc.ops = &max77665_charge_regulator_ops; reg->reg_desc.type = REGULATOR_CURRENT; reg->reg_desc.owner = THIS_MODULE; reg->reg_init_data.supply_regulator = NULL; reg->reg_init_data.num_consumer_supplies = pdata->num_consumer_supplies; reg->reg_init_data.consumer_supplies = pdata->consumer_supplies; reg->reg_init_data.regulator_init = NULL; reg->reg_init_data.driver_data = reg; reg->reg_init_data.constraints.name = "vbus_reg"; reg->reg_init_data.constraints.min_uA = 0; reg->reg_init_data.constraints.max_uA = pdata->curr_lim * 1000; reg->reg_init_data.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY; reg->reg_init_data.constraints.valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_CURRENT; reg->rdev = regulator_register(®->reg_desc, charger->dev, ®->reg_init_data, charger, NULL); if (IS_ERR(reg->rdev)) { dev_err(charger->dev, "failed to register %s regulator\n", reg->reg_desc.name); return PTR_ERR(reg->rdev); } return 0; } static void max77665_charger_wdt_ack_work_handler(struct work_struct *w) { struct max77665_charger *charger = container_of(to_delayed_work(w), struct max77665_charger, wdt_ack_work); if (0 > max77665_update_reg(charger, MAX77665_CHG_CNFG_06, WDTCLR)) dev_err(charger->dev, "fail to ack charging WDT\n"); alarm_start(&charger->wdt_alarm, ktime_add(ktime_get_boottime(), ktime_set(30, 0))); wake_unlock(&charger->wdt_wake_lock); } static enum alarmtimer_restart max77665_charger_wdt_timer(struct alarm *alarm, ktime_t now) { struct max77665_charger *charger = container_of(alarm, struct max77665_charger, wdt_alarm); wake_lock(&charger->wdt_wake_lock); schedule_delayed_work(&charger->wdt_ack_work, 0); return ALARMTIMER_NORESTART; } static int max77665_update_charger_status(struct max77665_charger *charger) { int ret; uint32_t read_val; mutex_lock(&charger->current_limit_mutex); ret = max77665_read_reg(charger, MAX77665_CHG_INT, &read_val); if (ret < 0) goto error; dev_dbg(charger->dev, "CHG_INT = 0x%02x\n", read_val); ret = max77665_read_reg(charger, MAX77665_CHG_INT_OK, &read_val); if (ret < 0) goto error; if (charger->plat_data->is_battery_present) max77665_handle_charger_status(charger, read_val); error: mutex_unlock(&charger->current_limit_mutex); return ret; } static irqreturn_t max77665_charger_irq_handler(int irq, void *data) { struct max77665_charger *charger = data; max77665_update_charger_status(charger); return IRQ_HANDLED; } static ssize_t max77665_set_bat_oc_threshold(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct max77665_charger *charger = dev_get_drvdata(dev); int i; int ret; int val = 0; int n = ARRAY_SIZE(max77665_bat_to_sys_oc_thres); char *p = (char *)buf; int oc_curr = memparse(p, &p); for (i = 0; i < n; ++i) { if (oc_curr <= max77665_bat_to_sys_oc_thres[i]) break; } val = (i < n) ? i : n - 1; ret = max77665_update_bits(charger->dev->parent, MAX77665_I2C_SLAVE_PMIC, MAX77665_CHG_CNFG_12, BAT_TO_SYS_OVERCURRENT_MASK, val); if (ret < 0) { dev_err(charger->dev, "CHG_CNFG_12 update failed: %d\n", ret); return ret; } return count; } static ssize_t max77665_show_bat_oc_threshold(struct device *dev, struct device_attribute *attr, char *buf) { struct max77665_charger *charger = dev_get_drvdata(dev); uint8_t val = 0; int ret; ret = max77665_read(charger->dev->parent, MAX77665_I2C_SLAVE_PMIC, MAX77665_CHG_CNFG_12, &val); if (ret < 0) { dev_err(charger->dev, "CHG_CNFG_12 read failed: %d\n", ret); return ret; } val &= BAT_TO_SYS_OVERCURRENT_MASK; return sprintf(buf, "%d\n", max77665_bat_to_sys_oc_thres[val]); } static DEVICE_ATTR(oc_threshold, 0644, max77665_show_bat_oc_threshold, max77665_set_bat_oc_threshold); static ssize_t max77665_set_battery_oc_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct max77665_charger *charger = dev_get_drvdata(dev); int ret; bool enabled; unsigned int val; if ((*buf == 'E') || (*buf == 'e')) { enabled = true; } else if ((*buf == 'D') || (*buf == 'd')) { enabled = false; } else { dev_err(charger->dev, "Illegal option\n"); return -EINVAL; } val = (enabled) ? 0x0 : 0x8; ret = max77665_update_bits(charger->dev->parent, MAX77665_I2C_SLAVE_PMIC, MAX77665_CHG_INT_MASK, 0x08, val); if (ret < 0) { dev_err(charger->dev, "CHG_INT_MASK update failed: %d\n", ret); return ret; } return count; } static ssize_t max77665_show_battery_oc_state(struct device *dev, struct device_attribute *attr, char *buf) { struct max77665_charger *charger = dev_get_drvdata(dev); uint8_t val = 0; int ret; ret = max77665_read(charger->dev->parent, MAX77665_I2C_SLAVE_PMIC, MAX77665_CHG_INT_MASK, &val); if (ret < 0) { dev_err(charger->dev, "CHG_INT_MASK read failed: %d\n", ret); return ret; } if (val & 0x8) return sprintf(buf, "disabled\n"); else return sprintf(buf, "enabled\n"); } static DEVICE_ATTR(oc_state, 0644, max77665_show_battery_oc_state, max77665_set_battery_oc_state); static ssize_t max77665_show_battery_oc_count(struct device *dev, struct device_attribute *attr, char *buf) { struct max77665_charger *charger = dev_get_drvdata(dev); return sprintf(buf, "%u\n", charger->oc_count); } static DEVICE_ATTR(oc_count, 0444, max77665_show_battery_oc_count, NULL); static ssize_t max77665_show_battery_charging_state(struct device *dev, struct device_attribute *attr, char *buf) { struct max77665_charger *charger = dev_get_drvdata(dev); char *state_string[] = { "PREQUALIFICATION MODE", /* 0X0 */ "FAST CONSTANT CURRENT MODE", /* 0X1 */ "FAST CONSTANT VOLTAGE MODE", /* 0X2 */ "TOP OFF MODE", /* 0X3 */ "DONE MODE", /* 0X4 */ "HIGH TEMP CHG MODE", /* 0X5 */ "TIME FAULT MODE", /* 0X6 */ "THERMISTOR SUSPEND FAULT MODE", /* 0X7 */ "CHG OFF INPUT INVALID", /* 0X8 */ "RSVD", /* 0X9 */ "CHG OFF JUNCT TEMP", /* 0XA */ "CHG OFF WDT EXPIRE", /* 0XB */ }; int val; if (0 > max77665_read_reg(charger, MAX77665_CHG_DTLS_01, &val)) return -EINVAL; val = CHG_DTLS_MASK(val); if (val >= ARRAY_SIZE(state_string)) return -EINVAL; return sprintf(buf, "%s(%d)\n", state_string[val], val); } static DEVICE_ATTR(charging_state, 0444, max77665_show_battery_charging_state, NULL); static struct attribute *max77665_chg_attributes[] = { &dev_attr_oc_threshold.attr, &dev_attr_oc_state.attr, &dev_attr_oc_count.attr, &dev_attr_charging_state.attr, NULL, }; static const struct attribute_group max77665_chg_attr_group = { .attrs = max77665_chg_attributes, }; static int max77665_add_sysfs_entry(struct device *dev) { return sysfs_create_group(&dev->kobj, &max77665_chg_attr_group); } static void max77665_remove_sysfs_entry(struct device *dev) { sysfs_remove_group(&dev->kobj, &max77665_chg_attr_group); } static __devinit int max77665_battery_probe(struct platform_device *pdev) { int ret = 0; struct max77665_charger *charger; charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); if (!charger) { dev_err(&pdev->dev, "failed to allocate memory status\n"); return -ENOMEM; } mutex_init(&charger->current_limit_mutex); charger->dev = &pdev->dev; charger->plat_data = pdev->dev.platform_data; dev_set_drvdata(&pdev->dev, charger); /* unmask all the interrupt */ max77665_write_reg(charger, MAX77665_CHG_INT_MASK, 0x0); charger->irq = platform_get_irq(pdev, 0); ret = request_threaded_irq(charger->irq, NULL, max77665_charger_irq_handler, 0, "charger_irq", charger); if (ret) { dev_err(&pdev->dev, "failed: irq request error :%d)\n", ret); goto free_mutex; } ret = max77665_add_sysfs_entry(&pdev->dev); if (ret < 0) { dev_err(charger->dev, "sysfs create failed %d\n", ret); goto free_irq; } /* Set OC threshold */ ret = max77665_update_bits(charger->dev->parent, MAX77665_I2C_SLAVE_PMIC, MAX77665_CHG_CNFG_12, BAT_TO_SYS_OVERCURRENT_MASK, charger->plat_data->oc_alert); if (ret < 0) { dev_err(charger->dev, "CHG_CNFG_12 update failed: %d\n", ret); goto remove_sysfs; } if (!charger->plat_data->is_battery_present) goto skip_charger_init; wake_lock_init(&charger->wdt_wake_lock, WAKE_LOCK_SUSPEND, "max77665-charger-wdt"); alarm_init(&charger->wdt_alarm, ALARM_BOOTTIME, max77665_charger_wdt_timer); INIT_DELAYED_WORK(&charger->wdt_ack_work, max77665_charger_wdt_ack_work_handler); INIT_DELAYED_WORK(&charger->set_max_current_work, max77665_set_ideal_input_current_work); /* modify OTP setting of input current limit to 100ma */ ret = max77665_set_max_input_current(charger, 100); if (ret < 0) goto free_lock; ret = max77665_charger_regulator_init(charger, charger->plat_data); if (ret < 0) { dev_err(&pdev->dev, "Charger regulator init failed\n"); goto free_lock; } ret = max77665_charger_init(charger); if (ret < 0) { dev_err(charger->dev, "failed to initialize charger\n"); goto free_reg; } ret = max77665_charging_disable(charger); if (ret < 0) { dev_err(charger->dev, "Disable charging failed\n"); goto free_reg; } skip_charger_init: dev_info(&pdev->dev, "%s() get success\n", __func__); return 0; free_reg: regulator_unregister(charger->reg_info.rdev); free_lock: wake_lock_destroy(&charger->wdt_wake_lock); remove_sysfs: max77665_remove_sysfs_entry(&pdev->dev); free_irq: free_irq(charger->irq, charger); free_mutex: mutex_destroy(&charger->current_limit_mutex); return ret; } static int __devexit max77665_battery_remove(struct platform_device *pdev) { struct max77665_charger *charger = platform_get_drvdata(pdev); max77665_remove_sysfs_entry(&pdev->dev); free_irq(charger->irq, charger); if (charger->plat_data->is_battery_present) { regulator_unregister(charger->reg_info.rdev); wake_lock_destroy(&charger->wdt_wake_lock); } mutex_destroy(&charger->current_limit_mutex); return 0; } #ifdef CONFIG_PM_SLEEP static int max77665_suspend(struct device *dev) { return 0; } static int max77665_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct max77665_charger *charger = platform_get_drvdata(pdev); int ret; ret = max77665_update_charger_status(charger); if (ret < 0) dev_err(charger->dev, "error occured in resume\n"); return ret; } static const struct dev_pm_ops max77665_pm = { .suspend = max77665_suspend, .resume = max77665_resume, }; #define MAX77665_PM (&max77665_pm) #else #define MAX77665_PM NULL #endif static struct platform_driver max77665_battery_driver = { .driver = { .name = "max77665-charger", .owner = THIS_MODULE, .pm = MAX77665_PM, }, .probe = max77665_battery_probe, .remove = __devexit_p(max77665_battery_remove), }; static int __init max77665_battery_init(void) { return platform_driver_register(&max77665_battery_driver); } static void __exit max77665_battery_exit(void) { platform_driver_unregister(&max77665_battery_driver); } subsys_initcall_sync(max77665_battery_init); module_exit(max77665_battery_exit); MODULE_DESCRIPTION("MAXIM MAX77665 battery charging driver"); MODULE_AUTHOR("Syed Rafiuddin "); MODULE_LICENSE("GPL v2");