diff options
Diffstat (limited to 'drivers/power')
35 files changed, 805 insertions, 173 deletions
diff --git a/drivers/power/88pm860x_charger.c b/drivers/power/88pm860x_charger.c index 4b37a5af8deb..36fb4b5a4b0d 100644 --- a/drivers/power/88pm860x_charger.c +++ b/drivers/power/88pm860x_charger.c @@ -714,7 +714,6 @@ out_irq: while (--i >= 0) free_irq(info->irq[i], info); out: - kfree(info); return ret; } @@ -728,7 +727,6 @@ static int pm860x_charger_remove(struct platform_device *pdev) free_irq(info->irq[0], info); for (i = 0; i < info->irq_nums; i++) free_irq(info->irq[i], info); - kfree(info); return 0; } diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 07e1a8f8d03e..0d0b5d7d19d0 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -254,7 +254,7 @@ config BATTERY_RX51 config CHARGER_ISP1704 tristate "ISP1704 USB Charger Detection" - depends on USB_OTG_UTILS + depends on USB_PHY help Say Y to enable support for USB Charger Detection with ISP1707/ISP1704 USB transceivers. @@ -340,6 +340,13 @@ config CHARGER_SMB347 Say Y to include support for Summit Microelectronics SMB347 Battery Charger. +config CHARGER_TPS65090 + tristate "TPS65090 battery charger driver" + depends on MFD_TPS65090 + help + Say Y here to enable support for battery charging with TPS65090 + PMIC chips. + config AB8500_BM bool "AB8500 Battery Management Driver" depends on AB8500_CORE && AB8500_GPADC diff --git a/drivers/power/Makefile b/drivers/power/Makefile index eb520ea74970..653bf6ceff30 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -52,4 +52,5 @@ obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_POWER_AVS) += avs/ obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o +obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o obj-$(CONFIG_POWER_RESET) += reset/ diff --git a/drivers/power/ab8500_bmdata.c b/drivers/power/ab8500_bmdata.c index 85742a6d29ff..d29864533093 100644 --- a/drivers/power/ab8500_bmdata.c +++ b/drivers/power/ab8500_bmdata.c @@ -11,7 +11,7 @@ * Note that the res_to_temp table must be strictly sorted by falling resistance * values to work. */ -static struct abx500_res_to_temp temp_tbl_A_thermistor[] = { +const struct abx500_res_to_temp ab8500_temp_tbl_a_thermistor[] = { {-5, 53407}, { 0, 48594}, { 5, 43804}, @@ -28,8 +28,12 @@ static struct abx500_res_to_temp temp_tbl_A_thermistor[] = { {60, 13437}, {65, 12500}, }; +EXPORT_SYMBOL(ab8500_temp_tbl_a_thermistor); -static struct abx500_res_to_temp temp_tbl_B_thermistor[] = { +const int ab8500_temp_tbl_a_size = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor); +EXPORT_SYMBOL(ab8500_temp_tbl_a_size); + +const struct abx500_res_to_temp ab8500_temp_tbl_b_thermistor[] = { {-5, 200000}, { 0, 159024}, { 5, 151921}, @@ -46,8 +50,12 @@ static struct abx500_res_to_temp temp_tbl_B_thermistor[] = { {60, 85461}, {65, 82869}, }; +EXPORT_SYMBOL(ab8500_temp_tbl_b_thermistor); + +const int ab8500_temp_tbl_b_size = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor); +EXPORT_SYMBOL(ab8500_temp_tbl_b_size); -static struct abx500_v_to_cap cap_tbl_A_thermistor[] = { +static const struct abx500_v_to_cap cap_tbl_a_thermistor[] = { {4171, 100}, {4114, 95}, {4009, 83}, @@ -70,7 +78,7 @@ static struct abx500_v_to_cap cap_tbl_A_thermistor[] = { {3247, 0}, }; -static struct abx500_v_to_cap cap_tbl_B_thermistor[] = { +static const struct abx500_v_to_cap cap_tbl_b_thermistor[] = { {4161, 100}, {4124, 98}, {4044, 90}, @@ -93,7 +101,7 @@ static struct abx500_v_to_cap cap_tbl_B_thermistor[] = { {3250, 0}, }; -static struct abx500_v_to_cap cap_tbl[] = { +static const struct abx500_v_to_cap cap_tbl[] = { {4186, 100}, {4163, 99}, {4114, 95}, @@ -124,7 +132,7 @@ static struct abx500_v_to_cap cap_tbl[] = { * Note that the res_to_temp table must be strictly sorted by falling * resistance values to work. */ -static struct abx500_res_to_temp temp_tbl[] = { +static const struct abx500_res_to_temp temp_tbl[] = { {-5, 214834}, { 0, 162943}, { 5, 124820}, @@ -146,7 +154,7 @@ static struct abx500_res_to_temp temp_tbl[] = { * Note that the batres_vs_temp table must be strictly sorted by falling * temperature values to work. */ -static struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { +static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { { 40, 120}, { 30, 135}, { 20, 165}, @@ -160,7 +168,7 @@ static struct batres_vs_temp temp_to_batres_tbl_thermistor[] = { * Note that the batres_vs_temp table must be strictly sorted by falling * temperature values to work. */ -static struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = { +static const struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = { { 60, 300}, { 30, 300}, { 20, 300}, @@ -171,7 +179,7 @@ static struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = { }; /* battery resistance table for LI ION 9100 battery */ -static struct batres_vs_temp temp_to_batres_tbl_9100[] = { +static const struct batres_vs_temp temp_to_batres_tbl_9100[] = { { 60, 180}, { 30, 180}, { 20, 180}, @@ -230,10 +238,10 @@ static struct abx500_battery_type bat_type_thermistor[] = { .maint_b_chg_timer_h = 200, .low_high_cur_lvl = 300, .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_A_thermistor), - .r_to_t_tbl = temp_tbl_A_thermistor, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_A_thermistor), - .v_to_cap_tbl = cap_tbl_A_thermistor, + .n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor), + .r_to_t_tbl = ab8500_temp_tbl_a_thermistor, + .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_a_thermistor), + .v_to_cap_tbl = cap_tbl_a_thermistor, .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), .batres_tbl = temp_to_batres_tbl_thermistor, @@ -258,10 +266,10 @@ static struct abx500_battery_type bat_type_thermistor[] = { .maint_b_chg_timer_h = 200, .low_high_cur_lvl = 300, .low_high_vol_lvl = 4000, - .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_B_thermistor), - .r_to_t_tbl = temp_tbl_B_thermistor, - .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_B_thermistor), - .v_to_cap_tbl = cap_tbl_B_thermistor, + .n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor), + .r_to_t_tbl = ab8500_temp_tbl_b_thermistor, + .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_b_thermistor), + .v_to_cap_tbl = cap_tbl_b_thermistor, .n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor), .batres_tbl = temp_to_batres_tbl_thermistor, }, @@ -547,7 +555,7 @@ int ab8500_bm_of_probe(struct device *dev, struct device_node *np, struct abx500_bm_data *bm) { - struct batres_vs_temp *tmp_batres_tbl; + const struct batres_vs_temp *tmp_batres_tbl; struct device_node *battery_node; const char *btech; int i; diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index a9486f1a1b5b..d412d34bf3df 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -131,6 +131,7 @@ struct ab8500_btemp *ab8500_btemp_get(void) return btemp; } +EXPORT_SYMBOL(ab8500_btemp_get); /** * ab8500_btemp_batctrl_volt_to_res() - convert batctrl voltage to resistance @@ -815,7 +816,7 @@ static void ab8500_btemp_periodic(struct ab8500_btemp *di, * * Returns battery temperature */ -static int ab8500_btemp_get_temp(struct ab8500_btemp *di) +int ab8500_btemp_get_temp(struct ab8500_btemp *di) { int temp = 0; @@ -851,6 +852,7 @@ static int ab8500_btemp_get_temp(struct ab8500_btemp *di) } return temp; } +EXPORT_SYMBOL(ab8500_btemp_get_temp); /** * ab8500_btemp_get_batctrl_temp() - get the temperature @@ -862,6 +864,7 @@ int ab8500_btemp_get_batctrl_temp(struct ab8500_btemp *btemp) { return btemp->bat_temp * 1000; } +EXPORT_SYMBOL(ab8500_btemp_get_batctrl_temp); /** * ab8500_btemp_get_property() - get the btemp properties diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 1601d27ce5d4..c5391f5c372d 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -863,7 +863,7 @@ static int ab8500_fg_bat_voltage(struct ab8500_fg *di) static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage) { int i, tbl_size; - struct abx500_v_to_cap *tbl; + const struct abx500_v_to_cap *tbl; int cap = 0; tbl = di->bm->bat_type[di->bm->batt_id].v_to_cap_tbl, @@ -915,7 +915,7 @@ static int ab8500_fg_uncomp_volt_to_capacity(struct ab8500_fg *di) static int ab8500_fg_battery_resistance(struct ab8500_fg *di) { int i, tbl_size; - struct batres_vs_temp *tbl; + const struct batres_vs_temp *tbl; int resist = 0; tbl = di->bm->bat_type[di->bm->batt_id].batres_tbl; diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index 8acc3f8d303c..fefc39fe42be 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c @@ -1485,13 +1485,12 @@ static int charger_manager_probe(struct platform_device *pdev) /* Basic Values. Unspecified are Null or 0 */ cm->dev = &pdev->dev; - cm->desc = kzalloc(sizeof(struct charger_desc), GFP_KERNEL); + cm->desc = kmemdup(desc, sizeof(struct charger_desc), GFP_KERNEL); if (!cm->desc) { dev_err(&pdev->dev, "Cannot allocate memory.\n"); ret = -ENOMEM; goto err_alloc_desc; } - memcpy(cm->desc, desc, sizeof(struct charger_desc)); cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */ /* diff --git a/drivers/power/da9030_battery.c b/drivers/power/da9030_battery.c index e8c5a391a498..ae6c41835ee6 100644 --- a/drivers/power/da9030_battery.c +++ b/drivers/power/da9030_battery.c @@ -505,7 +505,7 @@ static int da9030_battery_probe(struct platform_device *pdev) pdata->charge_millivolt > 4350) return -EINVAL; - charger = kzalloc(sizeof(*charger), GFP_KERNEL); + charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); if (charger == NULL) return -ENOMEM; @@ -557,8 +557,6 @@ err_notifier: cancel_delayed_work(&charger->work); err_charger_init: - kfree(charger); - return ret; } @@ -575,8 +573,6 @@ static int da9030_battery_remove(struct platform_device *dev) da9030_set_charge(charger, 0); power_supply_unregister(&charger->psy); - kfree(charger); - return 0; } diff --git a/drivers/power/da9052-battery.c b/drivers/power/da9052-battery.c index 08193feb3b08..f8f4c0f7c17d 100644 --- a/drivers/power/da9052-battery.c +++ b/drivers/power/da9052-battery.c @@ -594,7 +594,8 @@ static s32 da9052_bat_probe(struct platform_device *pdev) int ret; int i; - bat = kzalloc(sizeof(struct da9052_battery), GFP_KERNEL); + bat = devm_kzalloc(&pdev->dev, sizeof(struct da9052_battery), + GFP_KERNEL); if (!bat) return -ENOMEM; @@ -635,7 +636,6 @@ err: while (--i >= 0) da9052_free_irq(bat->da9052, da9052_bat_irq_bits[i], bat); - kfree(bat); return ret; } static int da9052_bat_remove(struct platform_device *pdev) @@ -647,7 +647,6 @@ static int da9052_bat_remove(struct platform_device *pdev) da9052_free_irq(bat->da9052, da9052_bat_irq_bits[i], bat); power_supply_unregister(&bat->psy); - kfree(bat); return 0; } diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c index 704e652072be..85b4e6eca0b1 100644 --- a/drivers/power/ds2760_battery.c +++ b/drivers/power/ds2760_battery.c @@ -512,7 +512,7 @@ static int ds2760_battery_probe(struct platform_device *pdev) int retval = 0; struct ds2760_device_info *di; - di = kzalloc(sizeof(*di), GFP_KERNEL); + di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); if (!di) { retval = -ENOMEM; goto di_alloc_failed; @@ -576,7 +576,6 @@ static int ds2760_battery_probe(struct platform_device *pdev) workqueue_failed: power_supply_unregister(&di->bat); batt_failed: - kfree(di); di_alloc_failed: success: return retval; @@ -590,7 +589,6 @@ static int ds2760_battery_remove(struct platform_device *pdev) cancel_delayed_work_sync(&di->set_charged_work); destroy_workqueue(di->monitor_wqueue); power_supply_unregister(&di->bat); - kfree(di); return 0; } diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c index 8b6c4539e7f4..9f418fa879e5 100644 --- a/drivers/power/ds2780_battery.c +++ b/drivers/power/ds2780_battery.c @@ -760,7 +760,7 @@ static int ds2780_battery_probe(struct platform_device *pdev) int ret = 0; struct ds2780_device_info *dev_info; - dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL); + dev_info = devm_kzalloc(&pdev->dev, sizeof(*dev_info), GFP_KERNEL); if (!dev_info) { ret = -ENOMEM; goto fail; @@ -779,7 +779,7 @@ static int ds2780_battery_probe(struct platform_device *pdev) ret = power_supply_register(&pdev->dev, &dev_info->bat); if (ret) { dev_err(dev_info->dev, "failed to register battery\n"); - goto fail_free_info; + goto fail; } ret = sysfs_create_group(&dev_info->bat.dev->kobj, &ds2780_attr_group); @@ -813,8 +813,6 @@ fail_remove_group: sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group); fail_unregister: power_supply_unregister(&dev_info->bat); -fail_free_info: - kfree(dev_info); fail: return ret; } @@ -828,7 +826,6 @@ static int ds2780_battery_remove(struct platform_device *pdev) power_supply_unregister(&dev_info->bat); - kfree(dev_info); return 0; } diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c index c09e7726c96c..563174891c90 100644 --- a/drivers/power/ds2782_battery.c +++ b/drivers/power/ds2782_battery.c @@ -332,32 +332,32 @@ static int ds278x_battery_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP -static int ds278x_suspend(struct i2c_client *client, - pm_message_t state) +static int ds278x_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct ds278x_info *info = i2c_get_clientdata(client); cancel_delayed_work(&info->bat_work); return 0; } -static int ds278x_resume(struct i2c_client *client) +static int ds278x_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct ds278x_info *info = i2c_get_clientdata(client); schedule_delayed_work(&info->bat_work, DS278x_DELAY); return 0; } -#else - -#define ds278x_suspend NULL -#define ds278x_resume NULL - -#endif /* CONFIG_PM */ +static SIMPLE_DEV_PM_OPS(ds278x_battery_pm_ops, ds278x_suspend, ds278x_resume); +#define DS278X_BATTERY_PM_OPS (&ds278x_battery_pm_ops) +#else +#define DS278X_BATTERY_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ enum ds278x_num_id { DS2782 = 0, @@ -460,11 +460,10 @@ MODULE_DEVICE_TABLE(i2c, ds278x_id); static struct i2c_driver ds278x_battery_driver = { .driver = { .name = "ds2782-battery", + .pm = DS278X_BATTERY_PM_OPS, }, .probe = ds278x_battery_probe, .remove = ds278x_battery_remove, - .suspend = ds278x_suspend, - .resume = ds278x_resume, .id_table = ds278x_id, }; module_i2c_driver(ds278x_battery_driver); diff --git a/drivers/power/goldfish_battery.c b/drivers/power/goldfish_battery.c index c10f460f986f..29eba88a2963 100644 --- a/drivers/power/goldfish_battery.c +++ b/drivers/power/goldfish_battery.c @@ -178,7 +178,7 @@ static int goldfish_battery_probe(struct platform_device *pdev) return -ENODEV; } - data->reg_base = devm_ioremap(&pdev->dev, r->start, r->end - r->start + 1); + data->reg_base = devm_ioremap(&pdev->dev, r->start, resource_size(r)); if (data->reg_base == NULL) { dev_err(&pdev->dev, "unable to remap MMIO\n"); return -ENOMEM; diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c index e3e40a9f3af2..e9883eeeee76 100644 --- a/drivers/power/gpio-charger.c +++ b/drivers/power/gpio-charger.c @@ -86,7 +86,8 @@ static int gpio_charger_probe(struct platform_device *pdev) return -EINVAL; } - gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL); + gpio_charger = devm_kzalloc(&pdev->dev, sizeof(*gpio_charger), + GFP_KERNEL); if (!gpio_charger) { dev_err(&pdev->dev, "Failed to alloc driver structure\n"); return -ENOMEM; @@ -140,7 +141,6 @@ static int gpio_charger_probe(struct platform_device *pdev) err_gpio_free: gpio_free(pdata->gpio); err_free: - kfree(gpio_charger); return ret; } @@ -156,7 +156,6 @@ static int gpio_charger_remove(struct platform_device *pdev) gpio_free(gpio_charger->pdata->gpio); platform_set_drvdata(pdev, NULL); - kfree(gpio_charger); return 0; } diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c index 176ad59d99f5..fc04d191579b 100644 --- a/drivers/power/isp1704_charger.c +++ b/drivers/power/isp1704_charger.c @@ -411,7 +411,7 @@ static int isp1704_charger_probe(struct platform_device *pdev) struct isp1704_charger *isp; int ret = -ENODEV; - isp = kzalloc(sizeof *isp, GFP_KERNEL); + isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); if (!isp) return -ENOMEM; @@ -477,8 +477,6 @@ fail1: isp1704_charger_set_power(isp, 0); usb_put_phy(isp->phy); fail0: - kfree(isp); - dev_err(&pdev->dev, "failed to register isp1704 with error %d\n", ret); return ret; @@ -492,7 +490,6 @@ static int isp1704_charger_remove(struct platform_device *pdev) power_supply_unregister(&isp->psy); usb_put_phy(isp->phy); isp1704_charger_set_power(isp, 0); - kfree(isp); return 0; } diff --git a/drivers/power/lp8788-charger.c b/drivers/power/lp8788-charger.c index 6d1f452810b8..ed49b50b220b 100644 --- a/drivers/power/lp8788-charger.c +++ b/drivers/power/lp8788-charger.c @@ -49,7 +49,6 @@ #define LP8788_CHG_START 0x11 #define LP8788_CHG_END 0x1C -#define LP8788_BUF_SIZE 40 #define LP8788_ISEL_MAX 23 #define LP8788_ISEL_STEP 50 #define LP8788_VTERM_MIN 4100 @@ -633,7 +632,7 @@ static ssize_t lp8788_show_charger_status(struct device *dev, lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data); state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S; - return scnprintf(buf, LP8788_BUF_SIZE, "%s\n", desc[state]); + return scnprintf(buf, PAGE_SIZE, "%s\n", desc[state]); } static ssize_t lp8788_show_eoc_time(struct device *dev, @@ -647,7 +646,7 @@ static ssize_t lp8788_show_eoc_time(struct device *dev, lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val); val = (val & LP8788_CHG_EOC_TIME_M) >> LP8788_CHG_EOC_TIME_S; - return scnprintf(buf, LP8788_BUF_SIZE, "End Of Charge Time: %s\n", + return scnprintf(buf, PAGE_SIZE, "End Of Charge Time: %s\n", stime[val]); } @@ -667,8 +666,7 @@ static ssize_t lp8788_show_eoc_level(struct device *dev, val = (val & LP8788_CHG_EOC_LEVEL_M) >> LP8788_CHG_EOC_LEVEL_S; level = mode ? abs_level[val] : relative_level[val]; - return scnprintf(buf, LP8788_BUF_SIZE, "End Of Charge Level: %s\n", - level); + return scnprintf(buf, PAGE_SIZE, "End Of Charge Level: %s\n", level); } static DEVICE_ATTR(charger_status, S_IRUSR, lp8788_show_charger_status, NULL); diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c index 74a0bd9bc162..c7ff6d67f158 100644 --- a/drivers/power/max17040_battery.c +++ b/drivers/power/max17040_battery.c @@ -246,31 +246,34 @@ static int max17040_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP -static int max17040_suspend(struct i2c_client *client, - pm_message_t state) +static int max17040_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct max17040_chip *chip = i2c_get_clientdata(client); cancel_delayed_work(&chip->work); return 0; } -static int max17040_resume(struct i2c_client *client) +static int max17040_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct max17040_chip *chip = i2c_get_clientdata(client); schedule_delayed_work(&chip->work, MAX17040_DELAY); return 0; } +static SIMPLE_DEV_PM_OPS(max17040_pm_ops, max17040_suspend, max17040_resume); +#define MAX17040_PM_OPS (&max17040_pm_ops) + #else -#define max17040_suspend NULL -#define max17040_resume NULL +#define MAX17040_PM_OPS NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ static const struct i2c_device_id max17040_id[] = { { "max17040", 0 }, @@ -281,11 +284,10 @@ MODULE_DEVICE_TABLE(i2c, max17040_id); static struct i2c_driver max17040_i2c_driver = { .driver = { .name = "max17040", + .pm = MAX17040_PM_OPS, }, .probe = max17040_probe, .remove = max17040_remove, - .suspend = max17040_suspend, - .resume = max17040_resume, .id_table = max17040_id, }; module_i2c_driver(max17040_i2c_driver); diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c index 14e2b96d93b0..08f0d7909b6b 100644 --- a/drivers/power/max8903_charger.c +++ b/drivers/power/max8903_charger.c @@ -189,7 +189,7 @@ static int max8903_probe(struct platform_device *pdev) int ta_in = 0; int usb_in = 0; - data = kzalloc(sizeof(struct max8903_data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL); if (data == NULL) { dev_err(dev, "Cannot allocate memory.\n"); return -ENOMEM; @@ -341,7 +341,6 @@ err_dc_irq: err_psy: power_supply_unregister(&data->psy); err: - kfree(data); return ret; } @@ -359,7 +358,6 @@ static int max8903_remove(struct platform_device *pdev) if (pdata->dc_valid) free_irq(gpio_to_irq(pdata->dok), data); power_supply_unregister(&data->psy); - kfree(data); } return 0; diff --git a/drivers/power/max8925_power.c b/drivers/power/max8925_power.c index 665cdc76c265..0ee1e14f76e9 100644 --- a/drivers/power/max8925_power.c +++ b/drivers/power/max8925_power.c @@ -489,7 +489,8 @@ static int max8925_power_probe(struct platform_device *pdev) return -EINVAL; } - info = kzalloc(sizeof(struct max8925_power_info), GFP_KERNEL); + info = devm_kzalloc(&pdev->dev, sizeof(struct max8925_power_info), + GFP_KERNEL); if (!info) return -ENOMEM; info->chip = chip; @@ -546,7 +547,6 @@ out_battery: out_usb: power_supply_unregister(&info->ac); out: - kfree(info); return ret; } @@ -559,7 +559,6 @@ static int max8925_power_remove(struct platform_device *pdev) power_supply_unregister(&info->usb); power_supply_unregister(&info->battery); max8925_deinit_charger(info); - kfree(info); } return 0; } diff --git a/drivers/power/max8997_charger.c b/drivers/power/max8997_charger.c index e757885b620c..4bdedfed936d 100644 --- a/drivers/power/max8997_charger.c +++ b/drivers/power/max8997_charger.c @@ -138,7 +138,8 @@ static int max8997_battery_probe(struct platform_device *pdev) return ret; } - charger = kzalloc(sizeof(struct charger_data), GFP_KERNEL); + charger = devm_kzalloc(&pdev->dev, sizeof(struct charger_data), + GFP_KERNEL); if (charger == NULL) { dev_err(&pdev->dev, "Cannot allocate memory.\n"); return -ENOMEM; @@ -158,13 +159,10 @@ static int max8997_battery_probe(struct platform_device *pdev) ret = power_supply_register(&pdev->dev, &charger->battery); if (ret) { dev_err(&pdev->dev, "failed: power supply register\n"); - goto err; + return ret; } return 0; -err: - kfree(charger); - return ret; } static int max8997_battery_remove(struct platform_device *pdev) @@ -172,7 +170,6 @@ static int max8997_battery_remove(struct platform_device *pdev) struct charger_data *charger = platform_get_drvdata(pdev); power_supply_unregister(&charger->battery); - kfree(charger); return 0; } diff --git a/drivers/power/max8998_charger.c b/drivers/power/max8998_charger.c index bf677e3daec9..5017470c2fc9 100644 --- a/drivers/power/max8998_charger.c +++ b/drivers/power/max8998_charger.c @@ -88,7 +88,8 @@ static int max8998_battery_probe(struct platform_device *pdev) return -ENODEV; } - max8998 = kzalloc(sizeof(struct max8998_battery_data), GFP_KERNEL); + max8998 = devm_kzalloc(&pdev->dev, sizeof(struct max8998_battery_data), + GFP_KERNEL); if (!max8998) return -ENOMEM; @@ -174,7 +175,6 @@ static int max8998_battery_probe(struct platform_device *pdev) return 0; err: - kfree(max8998); return ret; } @@ -183,7 +183,6 @@ static int max8998_battery_remove(struct platform_device *pdev) struct max8998_battery_data *max8998 = platform_get_drvdata(pdev); power_supply_unregister(&max8998->battery); - kfree(max8998); return 0; } diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c index c2122a7ad065..17fd77f24b2a 100644 --- a/drivers/power/pcf50633-charger.c +++ b/drivers/power/pcf50633-charger.c @@ -373,7 +373,7 @@ static int pcf50633_mbc_probe(struct platform_device *pdev) int i; u8 mbcs1; - mbc = kzalloc(sizeof(*mbc), GFP_KERNEL); + mbc = devm_kzalloc(&pdev->dev, sizeof(*mbc), GFP_KERNEL); if (!mbc) return -ENOMEM; @@ -413,7 +413,6 @@ static int pcf50633_mbc_probe(struct platform_device *pdev) ret = power_supply_register(&pdev->dev, &mbc->adapter); if (ret) { dev_err(mbc->pcf->dev, "failed to register adapter\n"); - kfree(mbc); return ret; } @@ -421,7 +420,6 @@ static int pcf50633_mbc_probe(struct platform_device *pdev) if (ret) { dev_err(mbc->pcf->dev, "failed to register usb\n"); power_supply_unregister(&mbc->adapter); - kfree(mbc); return ret; } @@ -430,7 +428,6 @@ static int pcf50633_mbc_probe(struct platform_device *pdev) dev_err(mbc->pcf->dev, "failed to register ac\n"); power_supply_unregister(&mbc->adapter); power_supply_unregister(&mbc->usb); - kfree(mbc); return ret; } @@ -461,8 +458,6 @@ static int pcf50633_mbc_remove(struct platform_device *pdev) power_supply_unregister(&mbc->adapter); power_supply_unregister(&mbc->ac); - kfree(mbc); - return 0; } diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index 7df7c5facc10..0c52e2a0d90c 100644 --- a/drivers/power/pda_power.c +++ b/drivers/power/pda_power.c @@ -35,7 +35,7 @@ static struct timer_list supply_timer; static struct timer_list polling_timer; static int polling; -#ifdef CONFIG_USB_OTG_UTILS +#if IS_ENABLED(CONFIG_USB_PHY) static struct usb_phy *transceiver; static struct notifier_block otg_nb; #endif @@ -218,7 +218,7 @@ static void polling_timer_func(unsigned long unused) jiffies + msecs_to_jiffies(pdata->polling_interval)); } -#ifdef CONFIG_USB_OTG_UTILS +#if IS_ENABLED(CONFIG_USB_PHY) static int otg_is_usb_online(void) { return (transceiver->last_event == USB_EVENT_VBUS || @@ -315,7 +315,7 @@ static int pda_power_probe(struct platform_device *pdev) pda_psy_usb.num_supplicants = pdata->num_supplicants; } -#ifdef CONFIG_USB_OTG_UTILS +#if IS_ENABLED(CONFIG_USB_PHY) transceiver = usb_get_phy(USB_PHY_TYPE_USB2); if (!IS_ERR_OR_NULL(transceiver)) { if (!pdata->is_usb_online) @@ -367,7 +367,7 @@ static int pda_power_probe(struct platform_device *pdev) } } -#ifdef CONFIG_USB_OTG_UTILS +#if IS_ENABLED(CONFIG_USB_PHY) if (!IS_ERR_OR_NULL(transceiver) && pdata->use_otg_notifier) { otg_nb.notifier_call = otg_handle_notification; ret = usb_register_notifier(transceiver, &otg_nb); @@ -391,7 +391,7 @@ static int pda_power_probe(struct platform_device *pdev) return 0; -#ifdef CONFIG_USB_OTG_UTILS +#if IS_ENABLED(CONFIG_USB_PHY) otg_reg_notifier_failed: if (pdata->is_usb_online && usb_irq) free_irq(usb_irq->start, &pda_psy_usb); @@ -402,7 +402,7 @@ usb_irq_failed: usb_supply_failed: if (pdata->is_ac_online && ac_irq) free_irq(ac_irq->start, &pda_psy_ac); -#ifdef CONFIG_USB_OTG_UTILS +#if IS_ENABLED(CONFIG_USB_PHY) if (!IS_ERR_OR_NULL(transceiver)) usb_put_phy(transceiver); #endif @@ -437,7 +437,7 @@ static int pda_power_remove(struct platform_device *pdev) power_supply_unregister(&pda_psy_usb); if (pdata->is_ac_online) power_supply_unregister(&pda_psy_ac); -#ifdef CONFIG_USB_OTG_UTILS +#if IS_ENABLED(CONFIG_USB_PHY) if (!IS_ERR_OR_NULL(transceiver)) usb_put_phy(transceiver); #endif diff --git a/drivers/power/pm2301_charger.c b/drivers/power/pm2301_charger.c index 618c46d25a3b..a44175139bbf 100644 --- a/drivers/power/pm2301_charger.c +++ b/drivers/power/pm2301_charger.c @@ -26,6 +26,7 @@ #include <linux/pm2301_charger.h> #include <linux/gpio.h> #include <linux/pm_runtime.h> +#include <linux/pm.h> #include "pm2301_charger.h" @@ -225,7 +226,7 @@ static int pm2xxx_charger_ovv_mngt(struct pm2xxx_charger *pm2, int val) static int pm2xxx_charger_wd_exp_mngt(struct pm2xxx_charger *pm2, int val) { - dev_dbg(pm2->dev , "20 minutes watchdog occured\n"); + dev_dbg(pm2->dev , "20 minutes watchdog expired\n"); pm2->ac.wd_expired = true; power_supply_changed(&pm2->ac_chg.psy); @@ -906,8 +907,13 @@ static struct pm2xxx_irq pm2xxx_charger_irq[] = { {"PM2XXX_IRQ_INT", pm2xxx_irq_int}, }; -static int pm2xxx_wall_charger_resume(struct i2c_client *i2c_client) +#ifdef CONFIG_PM + +#ifdef CONFIG_PM_SLEEP + +static int pm2xxx_wall_charger_resume(struct device *dev) { + struct i2c_client *i2c_client = to_i2c_client(dev); struct pm2xxx_charger *pm2; pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(i2c_client); @@ -921,9 +927,9 @@ static int pm2xxx_wall_charger_resume(struct i2c_client *i2c_client) return 0; } -static int pm2xxx_wall_charger_suspend(struct i2c_client *i2c_client, - pm_message_t state) +static int pm2xxx_wall_charger_suspend(struct device *dev) { + struct i2c_client *i2c_client = to_i2c_client(dev); struct pm2xxx_charger *pm2; pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(i2c_client); @@ -939,7 +945,10 @@ static int pm2xxx_wall_charger_suspend(struct i2c_client *i2c_client, return 0; } -#ifdef CONFIG_PM +#endif + +#ifdef CONFIG_PM_RUNTIME + static int pm2xxx_runtime_suspend(struct device *dev) { struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev); @@ -977,9 +986,12 @@ static int pm2xxx_runtime_resume(struct device *dev) return ret; } +#endif + static const struct dev_pm_ops pm2xxx_pm_ops = { - .runtime_suspend = pm2xxx_runtime_suspend, - .runtime_resume = pm2xxx_runtime_resume, + SET_SYSTEM_SLEEP_PM_OPS(pm2xxx_wall_charger_suspend, + pm2xxx_wall_charger_resume) + SET_RUNTIME_PM_OPS(pm2xxx_runtime_suspend, pm2xxx_runtime_resume, NULL) }; #define PM2XXX_PM_OPS (&pm2xxx_pm_ops) #else @@ -1234,8 +1246,6 @@ MODULE_DEVICE_TABLE(i2c, pm2xxx_id); static struct i2c_driver pm2xxx_charger_driver = { .probe = pm2xxx_wall_charger_probe, .remove = pm2xxx_wall_charger_remove, - .suspend = pm2xxx_wall_charger_suspend, - .resume = pm2xxx_wall_charger_resume, .driver = { .name = "pm2xxx-wall_charger", .owner = THIS_MODULE, diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 5deac432e2ae..1c517c34e4be 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -26,17 +26,42 @@ EXPORT_SYMBOL_GPL(power_supply_class); static struct device_type power_supply_dev_type; +static bool __power_supply_is_supplied_by(struct power_supply *supplier, + struct power_supply *supply) +{ + int i; + + if (!supply->supplied_from && !supplier->supplied_to) + return false; + + /* Support both supplied_to and supplied_from modes */ + if (supply->supplied_from) { + if (!supplier->name) + return false; + for (i = 0; i < supply->num_supplies; i++) + if (!strcmp(supplier->name, supply->supplied_from[i])) + return true; + } else { + if (!supply->name) + return false; + for (i = 0; i < supplier->num_supplicants; i++) + if (!strcmp(supplier->supplied_to[i], supply->name)) + return true; + } + + return false; +} + static int __power_supply_changed_work(struct device *dev, void *data) { struct power_supply *psy = (struct power_supply *)data; struct power_supply *pst = dev_get_drvdata(dev); - int i; - for (i = 0; i < psy->num_supplicants; i++) - if (!strcmp(psy->supplied_to[i], pst->name)) { - if (pst->external_power_changed) - pst->external_power_changed(pst); - } + if (__power_supply_is_supplied_by(psy, pst)) { + if (pst->external_power_changed) + pst->external_power_changed(pst); + } + return 0; } @@ -63,22 +88,151 @@ void power_supply_changed(struct power_supply *psy) } EXPORT_SYMBOL_GPL(power_supply_changed); +#ifdef CONFIG_OF +#include <linux/of.h> + +static int __power_supply_populate_supplied_from(struct device *dev, + void *data) +{ + struct power_supply *psy = (struct power_supply *)data; + struct power_supply *epsy = dev_get_drvdata(dev); + struct device_node *np; + int i = 0; + + do { + np = of_parse_phandle(psy->of_node, "power-supplies", i++); + if (!np) + continue; + + if (np == epsy->of_node) { + dev_info(psy->dev, "%s: Found supply : %s\n", + psy->name, epsy->name); + psy->supplied_from[i-1] = (char *)epsy->name; + psy->num_supplies++; + break; + } + } while (np); + + return 0; +} + +static int power_supply_populate_supplied_from(struct power_supply *psy) +{ + int error; + + error = class_for_each_device(power_supply_class, NULL, psy, + __power_supply_populate_supplied_from); + + dev_dbg(psy->dev, "%s %d\n", __func__, error); + + return error; +} + +static int __power_supply_find_supply_from_node(struct device *dev, + void *data) +{ + struct device_node *np = (struct device_node *)data; + struct power_supply *epsy = dev_get_drvdata(dev); + + /* return error breaks out of class_for_each_device loop */ + if (epsy->of_node == np) + return -EINVAL; + + return 0; +} + +static int power_supply_find_supply_from_node(struct device_node *supply_node) +{ + int error; + struct device *dev; + struct class_dev_iter iter; + + /* + * Use iterator to see if any other device is registered. + * This is required since class_for_each_device returns 0 + * if there are no devices registered. + */ + class_dev_iter_init(&iter, power_supply_class, NULL, NULL); + dev = class_dev_iter_next(&iter); + + if (!dev) + return -EPROBE_DEFER; + + /* + * We have to treat the return value as inverted, because if + * we return error on not found, then it won't continue looking. + * So we trick it by returning error on success to stop looking + * once the matching device is found. + */ + error = class_for_each_device(power_supply_class, NULL, supply_node, + __power_supply_find_supply_from_node); + + return error ? 0 : -EPROBE_DEFER; +} + +static int power_supply_check_supplies(struct power_supply *psy) +{ + struct device_node *np; + int cnt = 0; + + /* If there is already a list honor it */ + if (psy->supplied_from && psy->num_supplies > 0) + return 0; + + /* No device node found, nothing to do */ + if (!psy->of_node) + return 0; + + do { + int ret; + + np = of_parse_phandle(psy->of_node, "power-supplies", cnt++); + if (!np) + continue; + + ret = power_supply_find_supply_from_node(np); + if (ret) { + dev_dbg(psy->dev, "Failed to find supply, defer!\n"); + return -EPROBE_DEFER; + } + } while (np); + + /* All supplies found, allocate char ** array for filling */ + psy->supplied_from = devm_kzalloc(psy->dev, sizeof(psy->supplied_from), + GFP_KERNEL); + if (!psy->supplied_from) { + dev_err(psy->dev, "Couldn't allocate memory for supply list\n"); + return -ENOMEM; + } + + *psy->supplied_from = devm_kzalloc(psy->dev, sizeof(char *) * cnt, + GFP_KERNEL); + if (!*psy->supplied_from) { + dev_err(psy->dev, "Couldn't allocate memory for supply list\n"); + return -ENOMEM; + } + + return power_supply_populate_supplied_from(psy); +} +#else +static inline int power_supply_check_supplies(struct power_supply *psy) +{ + return 0; +} +#endif + static int __power_supply_am_i_supplied(struct device *dev, void *data) { union power_supply_propval ret = {0,}; struct power_supply *psy = (struct power_supply *)data; struct power_supply *epsy = dev_get_drvdata(dev); - int i; - for (i = 0; i < epsy->num_supplicants; i++) { - if (!strcmp(epsy->supplied_to[i], psy->name)) { - if (epsy->get_property(epsy, - POWER_SUPPLY_PROP_ONLINE, &ret)) - continue; + if (__power_supply_is_supplied_by(epsy, psy)) + if (!epsy->get_property(epsy, POWER_SUPPLY_PROP_ONLINE, &ret)) { if (ret.intval) return ret.intval; } - } + return 0; } @@ -336,6 +490,12 @@ int power_supply_register(struct device *parent, struct power_supply *psy) INIT_WORK(&psy->changed_work, power_supply_changed_work); + rc = power_supply_check_supplies(psy); + if (rc) { + dev_info(dev, "Not all required supplies found, defer probe\n"); + goto check_supplies_failed; + } + rc = kobject_set_name(&dev->kobj, "%s", psy->name); if (rc) goto kobject_set_name_failed; @@ -368,6 +528,7 @@ register_thermal_failed: device_del(dev); kobject_set_name_failed: device_add_failed: +check_supplies_failed: put_device(dev); success: return rc; diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 1ae65b822864..349e9ae8090a 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -30,3 +30,10 @@ config POWER_RESET_RESTART Some boards don't actually have the ability to power off. Instead they restart, and u-boot holds the SoC until the user presses a key. u-boot then boots into Linux. + +config POWER_RESET_VEXPRESS + bool + depends on POWER_RESET + help + Power off and reset support for the ARM Ltd. Versatile + Express boards. diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 0f317f50c56f..372807fd83f7 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o -obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
\ No newline at end of file +obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o +obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o diff --git a/drivers/power/reset/vexpress-poweroff.c b/drivers/power/reset/vexpress-poweroff.c new file mode 100644 index 000000000000..469e6962b2cf --- /dev/null +++ b/drivers/power/reset/vexpress-poweroff.c @@ -0,0 +1,146 @@ +/* + * 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. + * + * Copyright (C) 2012 ARM Limited + */ + +#include <linux/jiffies.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/stat.h> +#include <linux/vexpress.h> + +#include <asm/system_misc.h> + +static void vexpress_reset_do(struct device *dev, const char *what) +{ + int err = -ENOENT; + struct vexpress_config_func *func = + vexpress_config_func_get_by_dev(dev); + + if (func) { + unsigned long timeout; + + err = vexpress_config_write(func, 0, 0); + + timeout = jiffies + HZ; + while (time_before(jiffies, timeout)) + cpu_relax(); + } + + dev_emerg(dev, "Unable to %s (%d)\n", what, err); +} + +static struct device *vexpress_power_off_device; + +static void vexpress_power_off(void) +{ + vexpress_reset_do(vexpress_power_off_device, "power off"); +} + +static struct device *vexpress_restart_device; + +static void vexpress_restart(char str, const char *cmd) +{ + vexpress_reset_do(vexpress_restart_device, "restart"); +} + +static ssize_t vexpress_reset_active_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", vexpress_restart_device == dev); +} + +static ssize_t vexpress_reset_active_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + long value; + int err = kstrtol(buf, 0, &value); + + if (!err && value) + vexpress_restart_device = dev; + + return err ? err : count; +} + +DEVICE_ATTR(active, S_IRUGO | S_IWUSR, vexpress_reset_active_show, + vexpress_reset_active_store); + + +enum vexpress_reset_func { FUNC_RESET, FUNC_SHUTDOWN, FUNC_REBOOT }; + +static struct of_device_id vexpress_reset_of_match[] = { + { + .compatible = "arm,vexpress-reset", + .data = (void *)FUNC_RESET, + }, { + .compatible = "arm,vexpress-shutdown", + .data = (void *)FUNC_SHUTDOWN + }, { + .compatible = "arm,vexpress-reboot", + .data = (void *)FUNC_REBOOT + }, + {} +}; + +static int vexpress_reset_probe(struct platform_device *pdev) +{ + enum vexpress_reset_func func; + const struct of_device_id *match = + of_match_device(vexpress_reset_of_match, &pdev->dev); + + if (match) + func = (enum vexpress_reset_func)match->data; + else + func = pdev->id_entry->driver_data; + + switch (func) { + case FUNC_SHUTDOWN: + vexpress_power_off_device = &pdev->dev; + pm_power_off = vexpress_power_off; + break; + case FUNC_RESET: + if (!vexpress_restart_device) + vexpress_restart_device = &pdev->dev; + arm_pm_restart = vexpress_restart; + device_create_file(&pdev->dev, &dev_attr_active); + break; + case FUNC_REBOOT: + vexpress_restart_device = &pdev->dev; + arm_pm_restart = vexpress_restart; + device_create_file(&pdev->dev, &dev_attr_active); + break; + }; + + return 0; +} + +static const struct platform_device_id vexpress_reset_id_table[] = { + { .name = "vexpress-reset", .driver_data = FUNC_RESET, }, + { .name = "vexpress-shutdown", .driver_data = FUNC_SHUTDOWN, }, + { .name = "vexpress-reboot", .driver_data = FUNC_REBOOT, }, + {} +}; + +static struct platform_driver vexpress_reset_driver = { + .probe = vexpress_reset_probe, + .driver = { + .name = "vexpress-reset", + .of_match_table = vexpress_reset_of_match, + }, + .id_table = vexpress_reset_id_table, +}; + +static int __init vexpress_reset_init(void) +{ + return platform_driver_register(&vexpress_reset_driver); +} +device_initcall(vexpress_reset_init); diff --git a/drivers/power/rx51_battery.c b/drivers/power/rx51_battery.c index 35f625e18ba6..cbde1d6d3228 100644 --- a/drivers/power/rx51_battery.c +++ b/drivers/power/rx51_battery.c @@ -120,7 +120,7 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di) /* First check for temperature in first direct table */ if (raw < ARRAY_SIZE(rx51_temp_table1)) - return rx51_temp_table1[raw] * 100; + return rx51_temp_table1[raw] * 10; /* Binary search RAW value in second inverse table */ while (max - min > 1) { @@ -133,7 +133,7 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di) break; } - return (rx51_temp_table2_first - min) * 100; + return (rx51_temp_table2_first - min) * 10; } /* @@ -203,7 +203,7 @@ static int rx51_battery_probe(struct platform_device *pdev) struct rx51_device_info *di; int ret; - di = kzalloc(sizeof(*di), GFP_KERNEL); + di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); if (!di) return -ENOMEM; @@ -218,7 +218,6 @@ static int rx51_battery_probe(struct platform_device *pdev) ret = power_supply_register(di->dev, &di->bat); if (ret) { platform_set_drvdata(pdev, NULL); - kfree(di); return ret; } @@ -231,7 +230,6 @@ static int rx51_battery_remove(struct platform_device *pdev) power_supply_unregister(&di->bat); platform_set_drvdata(pdev, NULL); - kfree(di); return 0; } diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c index d2ca989dcbdc..5948ce058bdd 100644 --- a/drivers/power/s3c_adc_battery.c +++ b/drivers/power/s3c_adc_battery.c @@ -145,14 +145,17 @@ static int s3c_adc_bat_get_property(struct power_supply *psy, int new_level; int full_volt; - const struct s3c_adc_bat_thresh *lut = bat->pdata->lut_noac; - unsigned int lut_size = bat->pdata->lut_noac_cnt; + const struct s3c_adc_bat_thresh *lut; + unsigned int lut_size; if (!bat) { dev_err(psy->dev, "no battery infos ?!\n"); return -EINVAL; } + lut = bat->pdata->lut_noac; + lut_size = bat->pdata->lut_noac_cnt; + if (bat->volt_value < 0 || bat->cur_value < 0 || jiffies_to_msecs(jiffies - bat->timestamp) > BAT_POLL_INTERVAL) { diff --git a/drivers/power/sbs-battery.c b/drivers/power/sbs-battery.c index 3960f0b2afe9..c8c78a74e75a 100644 --- a/drivers/power/sbs-battery.c +++ b/drivers/power/sbs-battery.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/gpio.h> +#include <linux/of.h> #include <linux/power/sbs-battery.h> @@ -667,7 +668,6 @@ of_out: return pdata; } #else -#define sbs_dt_ids NULL static struct sbs_platform_data *sbs_of_populate_pdata( struct i2c_client *client) { @@ -820,10 +820,11 @@ static int sbs_remove(struct i2c_client *client) return 0; } -#if defined CONFIG_PM -static int sbs_suspend(struct i2c_client *client, - pm_message_t state) +#if defined CONFIG_PM_SLEEP + +static int sbs_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct sbs_info *chip = i2c_get_clientdata(client); s32 ret; @@ -838,11 +839,13 @@ static int sbs_suspend(struct i2c_client *client, return 0; } + +static SIMPLE_DEV_PM_OPS(sbs_pm_ops, sbs_suspend, NULL); +#define SBS_PM_OPS (&sbs_pm_ops) + #else -#define sbs_suspend NULL +#define SBS_PM_OPS NULL #endif -/* any smbus transaction will wake up sbs */ -#define sbs_resume NULL static const struct i2c_device_id sbs_id[] = { { "bq20z75", 0 }, @@ -854,12 +857,11 @@ MODULE_DEVICE_TABLE(i2c, sbs_id); static struct i2c_driver sbs_battery_driver = { .probe = sbs_probe, .remove = sbs_remove, - .suspend = sbs_suspend, - .resume = sbs_resume, .id_table = sbs_id, .driver = { .name = "sbs-battery", - .of_match_table = sbs_dt_ids, + .of_match_table = of_match_ptr(sbs_dt_ids), + .pm = SBS_PM_OPS, }, }; module_i2c_driver(sbs_battery_driver); diff --git a/drivers/power/test_power.c b/drivers/power/test_power.c index b99a452a4fda..0152f35dca5c 100644 --- a/drivers/power/test_power.c +++ b/drivers/power/test_power.c @@ -30,6 +30,8 @@ static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION; static int battery_capacity = 50; static int battery_voltage = 3300; +static bool module_initialized; + static int test_power_get_ac_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -185,6 +187,7 @@ static int __init test_power_init(void) } } + module_initialized = true; return 0; failed: while (--i >= 0) @@ -209,6 +212,8 @@ static void __exit test_power_exit(void) for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) power_supply_unregister(&test_power_supplies[i]); + + module_initialized = false; } module_exit(test_power_exit); @@ -221,8 +226,8 @@ struct battery_property_map { }; static struct battery_property_map map_ac_online[] = { - { 0, "on" }, - { 1, "off" }, + { 0, "off" }, + { 1, "on" }, { -1, NULL }, }; @@ -295,10 +300,16 @@ static const char *map_get_key(struct battery_property_map *map, int value, return def_key; } +static inline void signal_power_supply_changed(struct power_supply *psy) +{ + if (module_initialized) + power_supply_changed(psy); +} + static int param_set_ac_online(const char *key, const struct kernel_param *kp) { ac_online = map_get_value(map_ac_online, key, ac_online); - power_supply_changed(&test_power_supplies[0]); + signal_power_supply_changed(&test_power_supplies[0]); return 0; } @@ -311,7 +322,7 @@ static int param_get_ac_online(char *buffer, const struct kernel_param *kp) static int param_set_usb_online(const char *key, const struct kernel_param *kp) { usb_online = map_get_value(map_ac_online, key, usb_online); - power_supply_changed(&test_power_supplies[2]); + signal_power_supply_changed(&test_power_supplies[2]); return 0; } @@ -325,7 +336,7 @@ static int param_set_battery_status(const char *key, const struct kernel_param *kp) { battery_status = map_get_value(map_status, key, battery_status); - power_supply_changed(&test_power_supplies[1]); + signal_power_supply_changed(&test_power_supplies[1]); return 0; } @@ -339,7 +350,7 @@ static int param_set_battery_health(const char *key, const struct kernel_param *kp) { battery_health = map_get_value(map_health, key, battery_health); - power_supply_changed(&test_power_supplies[1]); + signal_power_supply_changed(&test_power_supplies[1]); return 0; } @@ -353,7 +364,7 @@ static int param_set_battery_present(const char *key, const struct kernel_param *kp) { battery_present = map_get_value(map_present, key, battery_present); - power_supply_changed(&test_power_supplies[0]); + signal_power_supply_changed(&test_power_supplies[0]); return 0; } @@ -369,7 +380,7 @@ static int param_set_battery_technology(const char *key, { battery_technology = map_get_value(map_technology, key, battery_technology); - power_supply_changed(&test_power_supplies[1]); + signal_power_supply_changed(&test_power_supplies[1]); return 0; } @@ -390,7 +401,7 @@ static int param_set_battery_capacity(const char *key, return -EINVAL; battery_capacity = tmp; - power_supply_changed(&test_power_supplies[1]); + signal_power_supply_changed(&test_power_supplies[1]); return 0; } @@ -405,7 +416,7 @@ static int param_set_battery_voltage(const char *key, return -EINVAL; battery_voltage = tmp; - power_supply_changed(&test_power_supplies[1]); + signal_power_supply_changed(&test_power_supplies[1]); return 0; } diff --git a/drivers/power/tps65090-charger.c b/drivers/power/tps65090-charger.c new file mode 100644 index 000000000000..9fbca310a2ad --- /dev/null +++ b/drivers/power/tps65090-charger.c @@ -0,0 +1,320 @@ +/* + * Battery charger driver for TI's tps65090 + * + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>. + */ +#include <linux/err.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/mfd/tps65090.h> + +#define TPS65090_REG_INTR_STS 0x00 +#define TPS65090_REG_CG_CTRL0 0x04 +#define TPS65090_REG_CG_CTRL1 0x05 +#define TPS65090_REG_CG_CTRL2 0x06 +#define TPS65090_REG_CG_CTRL3 0x07 +#define TPS65090_REG_CG_CTRL4 0x08 +#define TPS65090_REG_CG_CTRL5 0x09 +#define TPS65090_REG_CG_STATUS1 0x0a +#define TPS65090_REG_CG_STATUS2 0x0b + +#define TPS65090_CHARGER_ENABLE BIT(0) +#define TPS65090_VACG BIT(1) +#define TPS65090_NOITERM BIT(5) + +struct tps65090_charger { + struct device *dev; + int ac_online; + int prev_ac_online; + int irq; + struct power_supply ac; + struct tps65090_platform_data *pdata; +}; + +static enum power_supply_property tps65090_ac_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static int tps65090_low_chrg_current(struct tps65090_charger *charger) +{ + int ret; + + ret = tps65090_write(charger->dev->parent, TPS65090_REG_CG_CTRL5, + TPS65090_NOITERM); + if (ret < 0) { + dev_err(charger->dev, "%s(): error reading in register 0x%x\n", + __func__, TPS65090_REG_CG_CTRL5); + return ret; + } + return 0; +} + +static int tps65090_enable_charging(struct tps65090_charger *charger, + uint8_t enable) +{ + int ret; + uint8_t ctrl0 = 0; + + ret = tps65090_read(charger->dev->parent, TPS65090_REG_CG_CTRL0, + &ctrl0); + if (ret < 0) { + dev_err(charger->dev, "%s(): error reading in register 0x%x\n", + __func__, TPS65090_REG_CG_CTRL0); + return ret; + } + + ret = tps65090_write(charger->dev->parent, TPS65090_REG_CG_CTRL0, + (ctrl0 | TPS65090_CHARGER_ENABLE)); + if (ret < 0) { + dev_err(charger->dev, "%s(): error reading in register 0x%x\n", + __func__, TPS65090_REG_CG_CTRL0); + return ret; + } + return 0; +} + +static int tps65090_config_charger(struct tps65090_charger *charger) +{ + int ret; + + if (charger->pdata->enable_low_current_chrg) { + ret = tps65090_low_chrg_current(charger); + if (ret < 0) { + dev_err(charger->dev, + "error configuring low charge current\n"); + return ret; + } + } + + return 0; +} + +static int tps65090_ac_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct tps65090_charger *charger = container_of(psy, + struct tps65090_charger, ac); + + if (psp == POWER_SUPPLY_PROP_ONLINE) { + val->intval = charger->ac_online; + charger->prev_ac_online = charger->ac_online; + return 0; + } + return -EINVAL; +} + +static irqreturn_t tps65090_charger_isr(int irq, void *dev_id) +{ + struct tps65090_charger *charger = dev_id; + int ret; + uint8_t status1 = 0; + uint8_t intrsts = 0; + + ret = tps65090_read(charger->dev->parent, TPS65090_REG_CG_STATUS1, + &status1); + if (ret < 0) { + dev_err(charger->dev, "%s(): Error in reading reg 0x%x\n", + __func__, TPS65090_REG_CG_STATUS1); + return IRQ_HANDLED; + } + msleep(75); + ret = tps65090_read(charger->dev->parent, TPS65090_REG_INTR_STS, + &intrsts); + if (ret < 0) { + dev_err(charger->dev, "%s(): Error in reading reg 0x%x\n", + __func__, TPS65090_REG_INTR_STS); + return IRQ_HANDLED; + } + + if (intrsts & TPS65090_VACG) { + ret = tps65090_enable_charging(charger, 1); + if (ret < 0) + return IRQ_HANDLED; + charger->ac_online = 1; + } else { + charger->ac_online = 0; + } + + if (charger->prev_ac_online != charger->ac_online) + power_supply_changed(&charger->ac); + + return IRQ_HANDLED; +} + +#if defined(CONFIG_OF) + +#include <linux/of_device.h> + +static struct tps65090_platform_data * + tps65090_parse_dt_charger_data(struct platform_device *pdev) +{ + struct tps65090_platform_data *pdata; + struct device_node *np = pdev->dev.of_node; + unsigned int prop; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n"); + return NULL; + } + + prop = of_property_read_bool(np, "ti,enable-low-current-chrg"); + pdata->enable_low_current_chrg = prop; + + pdata->irq_base = -1; + + return pdata; + +} +#else +static struct tps65090_platform_data * + tps65090_parse_dt_charger_data(struct platform_device *pdev) +{ + return NULL; +} +#endif + +static int tps65090_charger_probe(struct platform_device *pdev) +{ + struct tps65090_charger *cdata; + struct tps65090_platform_data *pdata; + uint8_t status1 = 0; + int ret; + int irq; + + pdata = dev_get_platdata(pdev->dev.parent); + + if (!pdata && pdev->dev.of_node) + pdata = tps65090_parse_dt_charger_data(pdev); + + if (!pdata) { + dev_err(&pdev->dev, "%s():no platform data available\n", + __func__); + return -ENODEV; + } + + cdata = devm_kzalloc(&pdev->dev, sizeof(*cdata), GFP_KERNEL); + if (!cdata) { + dev_err(&pdev->dev, "failed to allocate memory status\n"); + return -ENOMEM; + } + + dev_set_drvdata(&pdev->dev, cdata); + + cdata->dev = &pdev->dev; + cdata->pdata = pdata; + + cdata->ac.name = "tps65090-ac"; + cdata->ac.type = POWER_SUPPLY_TYPE_MAINS; + cdata->ac.get_property = tps65090_ac_get_property; + cdata->ac.properties = tps65090_ac_props; + cdata->ac.num_properties = ARRAY_SIZE(tps65090_ac_props); + cdata->ac.supplied_to = pdata->supplied_to; + cdata->ac.num_supplicants = pdata->num_supplicants; + + ret = power_supply_register(&pdev->dev, &cdata->ac); + if (ret) { + dev_err(&pdev->dev, "failed: power supply register\n"); + return ret; + } + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_warn(&pdev->dev, "Unable to get charger irq = %d\n", irq); + ret = irq; + goto fail_unregister_supply; + } + + cdata->irq = irq; + + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + tps65090_charger_isr, 0, "tps65090-charger", cdata); + if (ret) { + dev_err(cdata->dev, "Unable to register irq %d err %d\n", irq, + ret); + goto fail_free_irq; + } + + ret = tps65090_config_charger(cdata); + if (ret < 0) { + dev_err(&pdev->dev, "charger config failed, err %d\n", ret); + goto fail_free_irq; + } + + /* Check for charger presence */ + ret = tps65090_read(cdata->dev->parent, TPS65090_REG_CG_STATUS1, + &status1); + if (ret < 0) { + dev_err(cdata->dev, "%s(): Error in reading reg 0x%x", __func__, + TPS65090_REG_CG_STATUS1); + goto fail_free_irq; + } + + if (status1 != 0) { + ret = tps65090_enable_charging(cdata, 1); + if (ret < 0) { + dev_err(cdata->dev, "error enabling charger\n"); + goto fail_free_irq; + } + cdata->ac_online = 1; + power_supply_changed(&cdata->ac); + } + + return 0; + +fail_free_irq: + devm_free_irq(cdata->dev, irq, cdata); +fail_unregister_supply: + power_supply_unregister(&cdata->ac); + + return ret; +} + +static int tps65090_charger_remove(struct platform_device *pdev) +{ + struct tps65090_charger *cdata = dev_get_drvdata(&pdev->dev); + + devm_free_irq(cdata->dev, cdata->irq, cdata); + power_supply_unregister(&cdata->ac); + + return 0; +} + +static struct of_device_id of_tps65090_charger_match[] = { + { .compatible = "ti,tps65090-charger", }, + { /* end */ } +}; + +static struct platform_driver tps65090_charger_driver = { + .driver = { + .name = "tps65090-charger", + .of_match_table = of_tps65090_charger_match, + .owner = THIS_MODULE, + }, + .probe = tps65090_charger_probe, + .remove = tps65090_charger_remove, +}; +module_platform_driver(tps65090_charger_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Syed Rafiuddin <srafiuddin@nvidia.com>"); +MODULE_DESCRIPTION("tps65090 battery charger driver"); diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index a69d0d11b540..bed458172dd2 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -636,17 +636,7 @@ static struct platform_driver twl4030_bci_driver = { .remove = __exit_p(twl4030_bci_remove), }; -static int __init twl4030_bci_init(void) -{ - return platform_driver_probe(&twl4030_bci_driver, twl4030_bci_probe); -} -module_init(twl4030_bci_init); - -static void __exit twl4030_bci_exit(void) -{ - platform_driver_unregister(&twl4030_bci_driver); -} -module_exit(twl4030_bci_exit); +module_platform_driver_probe(twl4030_bci_driver, twl4030_bci_probe); MODULE_AUTHOR("GraÅžvydas Ignotas"); MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver"); diff --git a/drivers/power/wm831x_backup.c b/drivers/power/wm831x_backup.c index d9cc169f1424..58cbb009b74f 100644 --- a/drivers/power/wm831x_backup.c +++ b/drivers/power/wm831x_backup.c @@ -169,7 +169,8 @@ static int wm831x_backup_probe(struct platform_device *pdev) struct power_supply *backup; int ret; - devdata = kzalloc(sizeof(struct wm831x_backup), GFP_KERNEL); + devdata = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_backup), + GFP_KERNEL); if (devdata == NULL) return -ENOMEM; @@ -197,14 +198,8 @@ static int wm831x_backup_probe(struct platform_device *pdev) backup->num_properties = ARRAY_SIZE(wm831x_backup_props); backup->get_property = wm831x_backup_get_prop; ret = power_supply_register(&pdev->dev, backup); - if (ret) - goto err_kmalloc; return ret; - -err_kmalloc: - kfree(devdata); - return ret; } static int wm831x_backup_remove(struct platform_device *pdev) @@ -213,7 +208,6 @@ static int wm831x_backup_remove(struct platform_device *pdev) power_supply_unregister(&devdata->backup); kfree(devdata->backup.name); - kfree(devdata); return 0; } |