diff options
Diffstat (limited to 'drivers/power/max77665-charger.c')
-rw-r--r-- | drivers/power/max77665-charger.c | 293 |
1 files changed, 11 insertions, 282 deletions
diff --git a/drivers/power/max77665-charger.c b/drivers/power/max77665-charger.c index 5d2821e89f8e..cf1a186c7c1e 100644 --- a/drivers/power/max77665-charger.c +++ b/drivers/power/max77665-charger.c @@ -37,8 +37,6 @@ #include <linux/mutex.h> #include <linux/delay.h> -#define CHARGER_TYPE_DETECTION_DEBOUNCE_TIME_MS 500 - /* fast charge current in mA */ static const uint32_t chg_cc[] = { 0, 33, 66, 99, 133, 166, 199, 233, 266, 299, @@ -75,15 +73,9 @@ struct max77665_charger { enum max77665_mode mode; struct device *dev; int irq; - struct power_supply ac; - struct power_supply usb; struct max77665_charger_plat_data *plat_data; struct mutex current_limit_mutex; int max_current_mA; - uint8_t ac_online; - uint8_t usb_online; - uint8_t num_cables; - struct extcon_dev *edev; struct alarm wdt_alarm; struct delayed_work wdt_ack_work; struct delayed_work set_max_current_work; @@ -92,11 +84,6 @@ struct max77665_charger { struct max77665_regulator_info reg_info; }; -static enum power_supply_property max77665_charger_props[] = { - POWER_SUPPLY_PROP_ONLINE, - POWER_SUPPLY_PROP_CURRENT_MAX, -}; - static int max77665_write_reg(struct max77665_charger *charger, uint8_t reg, int value) { @@ -185,59 +172,6 @@ int max77665_get_max_input_current(struct max77665_charger *charger, int *mA) return ret; } -static int max77665_charger_set_property(struct power_supply *psy, - enum power_supply_property psp, - const union power_supply_propval *val) -{ - struct max77665_charger *chip = container_of(psy, - struct max77665_charger, ac); - - if (psp == POWER_SUPPLY_PROP_CURRENT_MAX) - /* passed value is uA */ - return max77665_set_max_input_current(chip, val->intval / 1000); - - return -EINVAL; -} - -static int max77665_charger_get_property(struct power_supply *psy, - enum power_supply_property psp, union power_supply_propval *val) -{ - int online; - int ret; - struct max77665_charger *charger; - - if (psy->type == POWER_SUPPLY_TYPE_MAINS) { - charger = container_of(psy, struct max77665_charger, ac); - online = charger->ac_online; - } else if (psy->type == POWER_SUPPLY_TYPE_USB) { - charger = container_of(psy, struct max77665_charger, usb); - online = charger->usb_online; - } else { - return -EINVAL; - } - - ret = 0; - switch (psp) { - case POWER_SUPPLY_PROP_ONLINE: - val->intval = online; - break; - case POWER_SUPPLY_PROP_CURRENT_MAX: - ret = max77665_get_max_input_current(charger, &val->intval); - break; - default: - return -EINVAL; - } - return ret; -} - -static int max77665_charger_property_is_writeable(struct power_supply *psy, - enum power_supply_property psp) -{ - if (psp == POWER_SUPPLY_PROP_CURRENT_MAX) - return 1; - return 0; -} - static int max77665_enable_write(struct max77665_charger *charger, bool access) { int ret = 0; @@ -553,85 +487,6 @@ static int max77665_charging_enable(struct max77665_charger *charger) return ret; } -static int max77665_disable_charger(struct max77665_charger *charger, - struct extcon_dev *edev) -{ - int ret; - - charger->max_current_mA = 0; - ret = max77665_charging_disable(charger); - - charger->ac_online = 0; - charger->usb_online = 0; - power_supply_changed(&charger->usb); - power_supply_changed(&charger->ac); - - return ret; -} - -static int max77665_enable_charger(struct max77665_charger *charger, - struct extcon_dev *edev) -{ - int ret = 0; - int ilim; - enum max77665_mode mode; - - charger->usb_online = 0; - charger->ac_online = 0; - - if (charger->plat_data->update_status) - charger->plat_data->update_status(0); - - mode = CHARGER; - if (true == extcon_get_cable_state(edev, "USB-Host")) { - mode = OTG; - charger->max_current_mA = 0; - } else if (true == extcon_get_cable_state(edev, "USB")) { - charger->usb_online = 1; - charger->max_current_mA = 500; - } else if (true == extcon_get_cable_state(edev, "Charge-downstream")) { - charger->usb_online = 1; - charger->max_current_mA = 1500; - } else if (true == extcon_get_cable_state(edev, "TA")) { - charger->ac_online = 1; - charger->max_current_mA = 2000; - } else if (true == extcon_get_cable_state(edev, "Fast-charger")) { - charger->ac_online = 1; - charger->max_current_mA = 2200; - } else if (true == extcon_get_cable_state(edev, "Slow-charger")) { - charger->ac_online = 1; - charger->max_current_mA = 500; - } else { - /* no cable connected */ - goto done; - } - - ret = max77665_set_charger_mode(charger, mode); - if (ret < 0) { - dev_err(charger->dev, "failed to set device to charger mode\n"); - goto done; - } - - /* 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) { - ret = max77665_get_max_input_current(charger, &ilim); - if (0 > ret) - goto done; - charger->plat_data->update_status(ilim); - } - -done: - if (charger->usb_online) - power_supply_changed(&charger->usb); - if (charger->ac_online) - power_supply_changed(&charger->ac); - - return ret; -} - static int max77665_set_charging_current(struct regulator_dev *rdev, int min_uA, int max_uA) { @@ -732,56 +587,6 @@ static int max77665_charger_regulator_init( return 0; } -static void charger_extcon_handle_notifier(struct work_struct *w) -{ - struct max77665_charger_cable *cable = container_of(to_delayed_work(w), - struct max77665_charger_cable, extcon_notifier_work); - struct max77665_charger *charger = cable->charger; - int val; - - mutex_lock(&charger->current_limit_mutex); - if (0 > max77665_read_reg(cable->charger, MAX77665_CHG_DTLS_01, &val)) - goto error; - - dev_dbg(charger->dev, "cable is %s, charging is %s\n", - cable->event ? "attached" : "disconnected", - charging_is_on(val) ? "on" : "off"); - /* - * 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. - */ - if (cable->event == 0 && !charging_is_on(val)) - max77665_disable_charger(charger, cable->extcon_dev->edev); - else if (cable->event == 1 && !charging_is_on(val)) - max77665_enable_charger(charger, cable->extcon_dev->edev); - -error: - mutex_unlock(&charger->current_limit_mutex); - -} - -static int max77665_reset_charger(struct max77665_charger *charger, - struct extcon_dev *edev) -{ - int ret; - - mutex_lock(&charger->current_limit_mutex); - - ret = max77665_disable_charger(charger, charger->edev); - if (ret < 0) - goto error; - - ret = max77665_enable_charger(charger, charger->edev); - if (ret < 0) - goto error; -error: - mutex_unlock(&charger->current_limit_mutex); - return 0; -} - static void max77665_charger_wdt_ack_work_handler(struct work_struct *w) { struct max77665_charger *charger = container_of(to_delayed_work(w), @@ -806,20 +611,6 @@ static enum alarmtimer_restart max77665_charger_wdt_timer(struct alarm *alarm, return ALARMTIMER_NORESTART; } -static int charger_extcon_notifier(struct notifier_block *self, - unsigned long event, void *ptr) -{ - struct max77665_charger_cable *cable = container_of(self, - struct max77665_charger_cable, nb); - - cable->event = event; - cancel_delayed_work(&cable->extcon_notifier_work); - schedule_delayed_work(&cable->extcon_notifier_work, - msecs_to_jiffies(CHARGER_TYPE_DETECTION_DEBOUNCE_TIME_MS)); - - return NOTIFY_DONE; -} - static int max77665_update_charger_status(struct max77665_charger *charger) { int ret; @@ -1011,7 +802,6 @@ static void max77665_remove_sysfs_entry(struct device *dev) static __devinit int max77665_battery_probe(struct platform_device *pdev) { int ret = 0; - uint8_t j; struct max77665_charger *charger; charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); @@ -1041,67 +831,13 @@ static __devinit int max77665_battery_probe(struct platform_device *pdev) /* modify OTP setting of input current limit to 100ma */ ret = max77665_set_max_input_current(charger, 100); if (ret < 0) - goto remove_charging; - - dev_info(&pdev->dev, "Initializing battery charger code\n"); - - charger->ac.name = "ac"; - charger->ac.type = POWER_SUPPLY_TYPE_MAINS; - charger->ac.get_property = max77665_charger_get_property; - charger->ac.set_property = max77665_charger_set_property; - charger->ac.properties = max77665_charger_props; - charger->ac.num_properties = ARRAY_SIZE(max77665_charger_props); - charger->ac.property_is_writeable = - max77665_charger_property_is_writeable; - ret = power_supply_register(charger->dev, &charger->ac); - if (ret) { - dev_err(charger->dev, "failed: power supply register\n"); - return ret; - } - - charger->usb = charger->ac; - charger->usb.name = "usb"; - charger->usb.type = POWER_SUPPLY_TYPE_USB; - ret = power_supply_register(charger->dev, &charger->usb); - if (ret) { - dev_err(charger->dev, "failed: power supply register\n"); - goto pwr_sply_error; - } - - for (j = 0 ; j < charger->plat_data->num_cables; j++) { - struct max77665_charger_cable *cable = - &charger->plat_data->cables[j]; - cable->extcon_dev = devm_kzalloc(&pdev->dev, - sizeof(struct extcon_specific_cable_nb), - GFP_KERNEL); - if (!cable->extcon_dev) { - dev_err(&pdev->dev, "failed to allocate memory for extcon dev\n"); - goto chrg_error; - } - - INIT_DELAYED_WORK(&cable->extcon_notifier_work, - charger_extcon_handle_notifier); - - cable->charger = charger; - cable->nb.notifier_call = charger_extcon_notifier; - - ret = extcon_register_interest(cable->extcon_dev, - charger->plat_data->extcon_name, - cable->name, &cable->nb); - if (ret < 0) - dev_err(charger->dev, "Cannot register for cable: %s\n", - cable->name); - } - - charger->edev = extcon_get_extcon_dev(charger->plat_data->extcon_name); - if (!charger->edev) - goto chrg_error; + 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 chrg_error; + goto free_lock; } } @@ -1140,10 +876,11 @@ static __devinit int max77665_battery_probe(struct platform_device *pdev) } if (charger->plat_data->is_battery_present) { - /* reset the charging in case cable is already inserted */ - ret = max77665_reset_charger(charger, charger->edev); - if (ret < 0) + ret = max77665_charging_disable(charger); + if (ret < 0) { + dev_err(charger->dev, "Disable charging failed\n"); goto remove_sysfs; + } } dev_info(&pdev->dev, "%s() get success\n", __func__); @@ -1156,16 +893,10 @@ free_irq: reg_err: if (charger->plat_data->is_battery_present) regulator_unregister(charger->reg_info.rdev); -chrg_error: - if (charger->plat_data->is_battery_present) - power_supply_unregister(&charger->usb); -pwr_sply_error: +free_lock: if (charger->plat_data->is_battery_present) - power_supply_unregister(&charger->ac); -remove_charging: + wake_lock_destroy(&charger->wdt_wake_lock); mutex_destroy(&charger->current_limit_mutex); -if (charger->plat_data->is_battery_present) - wake_lock_destroy(&charger->wdt_wake_lock); return ret; } @@ -1178,10 +909,8 @@ static int __devexit max77665_battery_remove(struct platform_device *pdev) max77665_remove_sysfs_entry(&pdev->dev); free_irq(charger->irq, charger); if (charger->plat_data->is_battery_present) - power_supply_unregister(&charger->ac); - if (charger->plat_data->is_battery_present) - power_supply_unregister(&charger->usb); - + wake_lock_destroy(&charger->wdt_wake_lock); + mutex_destroy(&charger->current_limit_mutex); return 0; } #ifdef CONFIG_PM_SLEEP @@ -1230,7 +959,7 @@ static void __exit max77665_battery_exit(void) platform_driver_unregister(&max77665_battery_driver); } -late_initcall(max77665_battery_init); +subsys_initcall_sync(max77665_battery_init); module_exit(max77665_battery_exit); MODULE_DESCRIPTION("MAXIM MAX77665 battery charging driver"); |