From f5bbc91c88c18a4c518f066cc4e784d7b5fb9735 Mon Sep 17 00:00:00 2001 From: Anda-Maria Nicolae Date: Tue, 7 Jul 2015 15:25:53 +0300 Subject: power_supply: rt9455_charger: Properly notify userspace about charging events Charging events this patch refers to are: - charger is connected to/disconnected from the power source - battery is reconnected to the charger, after it was absent. When the charger is connected to/disconnected from the power source, CHRVPI interrupt occurs and PWR_RDY bit is either set or cleared. PWR_RDY bit is updated after 1-2 seconds CHRVPI interrupt has occurred. power_supply_changed() should be called after PWR_RDY bit is updated. /sys/class/power_supply/rt9455-charger/online file displays the value of PWR_RDY bit. This way, if the userspace is notified that a charging event has occurred and the userspace reads /sys/class/power_supply/rt9455-charger/online file, this file is properly updated when the userspace reads it. This is the reason why power_supply_changed() is called in rt9455_pwr_rdy_work_callback(), instead of being called in interrupt handler. Since no interrupt is triggered when the battery is reconnected to the charger, the userspace is never notified that the battery is reconnected. This is why power_supply_changed() is called in rt9455_max_charging_time_work_callback(), so that the userspace is notified that the battery is reconnected. Signed-off-by: Anda-Maria Nicolae Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel diff --git a/drivers/power/rt9455_charger.c b/drivers/power/rt9455_charger.c index 08baac6..a49a9d4 100644 --- a/drivers/power/rt9455_charger.c +++ b/drivers/power/rt9455_charger.c @@ -973,7 +973,6 @@ static int rt9455_irq_handler_check_irq2_register(struct rt9455_info *info, if (irq2 & GET_MASK(F_CHRVPI)) { dev_dbg(dev, "Charger fault occurred\n"); - alert_userspace = true; /* * CHRVPI bit is set in 2 cases: * 1. when the power source is connected to the charger. @@ -981,6 +980,9 @@ static int rt9455_irq_handler_check_irq2_register(struct rt9455_info *info, * To identify the case, PWR_RDY bit is checked. Because * PWR_RDY bit is set / cleared after CHRVPI interrupt is * triggered, it is used delayed_work to later read PWR_RDY bit. + * Also, do not set to true alert_userspace, because there is no + * need to notify userspace when CHRVPI interrupt has occurred. + * Userspace will be notified after PWR_RDY bit is read. */ queue_delayed_work(system_power_efficient_wq, &info->pwr_rdy_work, @@ -1178,7 +1180,7 @@ static irqreturn_t rt9455_irq_handler_thread(int irq, void *data) /* * Sometimes, an interrupt occurs while rt9455_probe() function * is executing and power_supply_register() is not yet called. - * Do not call power_supply_charged() in this case. + * Do not call power_supply_changed() in this case. */ if (info->charger) power_supply_changed(info->charger); @@ -1478,6 +1480,11 @@ static void rt9455_pwr_rdy_work_callback(struct work_struct *work) RT9455_MAX_CHARGING_TIME * HZ); break; } + /* + * Notify userspace that the charger has been either connected to or + * disconnected from the power source. + */ + power_supply_changed(info->charger); } static void rt9455_max_charging_time_work_callback(struct work_struct *work) @@ -1533,6 +1540,11 @@ static void rt9455_batt_presence_work_callback(struct work_struct *work) if (ret) dev_err(dev, "Failed to unmask BATAB interrupt\n"); } + /* + * Notify userspace that the battery is now connected to the + * charger. + */ + power_supply_changed(info->charger); } } -- cgit v0.10.2 From b1a55af2773d5e4d30b748517fedfac26fc5fd81 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:39:22 +0900 Subject: power_supply: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel diff --git a/drivers/power/bq24190_charger.c b/drivers/power/bq24190_charger.c index 052db78..703ebec 100644 --- a/drivers/power/bq24190_charger.c +++ b/drivers/power/bq24190_charger.c @@ -1534,7 +1534,6 @@ static struct i2c_driver bq24190_driver = { .id_table = bq24190_i2c_ids, .driver = { .name = "bq24190-charger", - .owner = THIS_MODULE, .pm = &bq24190_pm_ops, .of_match_table = of_match_ptr(bq24190_of_match), }, diff --git a/drivers/power/bq24735-charger.c b/drivers/power/bq24735-charger.c index 961a189..b017437 100644 --- a/drivers/power/bq24735-charger.c +++ b/drivers/power/bq24735-charger.c @@ -409,7 +409,6 @@ MODULE_DEVICE_TABLE(of, bq24735_match_ids); static struct i2c_driver bq24735_charger_driver = { .driver = { .name = "bq24735-charger", - .owner = THIS_MODULE, .of_match_table = bq24735_match_ids, }, .probe = bq24735_charger_probe, diff --git a/drivers/power/pm2301_charger.c b/drivers/power/pm2301_charger.c index cc0893f..3a45cc0 100644 --- a/drivers/power/pm2301_charger.c +++ b/drivers/power/pm2301_charger.c @@ -1244,7 +1244,6 @@ static struct i2c_driver pm2xxx_charger_driver = { .remove = pm2xxx_wall_charger_remove, .driver = { .name = "pm2xxx-wall_charger", - .owner = THIS_MODULE, .pm = PM2XXX_PM_OPS, }, .id_table = pm2xxx_id, -- cgit v0.10.2 From 1ae25d626cfe7e11adc2c3e71d0de1f882954ef3 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 20 Jul 2015 17:32:05 +0800 Subject: power: reset: at91: add sama5d3 reset function This patch introduces a new compatible string: "atmel,sama5d3-rstc" and new reset function for sama5d3 and later chips. As in sama5d3 or later chips, we don't have to shutdown the DDR controller before reset. Shutdown the DDR controller before reset is a workaround to avoid DDR signal driving the bus, but since sama5d3 and later chips there is no such a conflict. So in this patch: 1. the sama5d3 reset function only need to write the rstc register and return. 2. we can remove the code related with sama5d3 DDR controller as we don't use it at all. Signed-off-by: Josh Wu Acked-by: Nicolas Ferre Acked-by: Alexandre Belloni Reviewed-by: Guenter Roeck Signed-off-by: Sebastian Reichel diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 424ac8c..dd998b9 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -87,7 +87,7 @@ One interrupt per TC channel in a TC block: RSTC Reset Controller required properties: - compatible: Should be "atmel,-rstc". - can be "at91sam9260" or "at91sam9g45" + can be "at91sam9260" or "at91sam9g45" or "sama5d3" - reg: Should contain registers location and length Example: diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 36dc52f..c378d4e 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -123,6 +123,15 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, return NOTIFY_DONE; } +static int sama5d3_restart(struct notifier_block *this, unsigned long mode, + void *cmd) +{ + writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST), + at91_rstc_base); + + return NOTIFY_DONE; +} + static void __init at91_reset_status(struct platform_device *pdev) { u32 reg = readl(at91_rstc_base + AT91_RSTC_SR); @@ -155,13 +164,13 @@ static void __init at91_reset_status(struct platform_device *pdev) static const struct of_device_id at91_ramc_of_match[] = { { .compatible = "atmel,at91sam9260-sdramc", }, { .compatible = "atmel,at91sam9g45-ddramc", }, - { .compatible = "atmel,sama5d3-ddramc", }, { /* sentinel */ } }; static const struct of_device_id at91_reset_of_match[] = { { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9260_restart }, { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart }, + { .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart }, { /* sentinel */ } }; @@ -181,13 +190,16 @@ static int at91_reset_of_probe(struct platform_device *pdev) return -ENODEV; } - for_each_matching_node(np, at91_ramc_of_match) { - at91_ramc_base[idx] = of_iomap(np, 0); - if (!at91_ramc_base[idx]) { - dev_err(&pdev->dev, "Could not map ram controller address\n"); - return -ENODEV; + if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) { + /* we need to shutdown the ddr controller, so get ramc base */ + for_each_matching_node(np, at91_ramc_of_match) { + at91_ramc_base[idx] = of_iomap(np, 0); + if (!at91_ramc_base[idx]) { + dev_err(&pdev->dev, "Could not map ram controller address\n"); + return -ENODEV; + } + idx++; } - idx++; } match = of_match_node(at91_reset_of_match, pdev->dev.of_node); -- cgit v0.10.2 From 1b7cac23419e1398eac4c28368da6671c9c4ce9d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 23 Mar 2015 10:20:28 +1100 Subject: twl4030_charger: use devm_request_threaded_irq This simplifies the error paths. Signed-off-by: NeilBrown Acked-by: Pavel Machek Signed-off-by: Sebastian Reichel diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 022b891..4c779ae 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -619,21 +619,21 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) goto fail_register_usb; } - ret = request_threaded_irq(bci->irq_chg, NULL, + ret = devm_request_threaded_irq(&pdev->dev, bci->irq_chg, NULL, twl4030_charger_interrupt, IRQF_ONESHOT, pdev->name, bci); if (ret < 0) { dev_err(&pdev->dev, "could not request irq %d, status %d\n", bci->irq_chg, ret); - goto fail_chg_irq; + goto fail; } - ret = request_threaded_irq(bci->irq_bci, NULL, + ret = devm_request_threaded_irq(&pdev->dev, bci->irq_bci, NULL, twl4030_bci_interrupt, IRQF_ONESHOT, pdev->name, bci); if (ret < 0) { dev_err(&pdev->dev, "could not request irq %d, status %d\n", bci->irq_bci, ret); - goto fail_bci_irq; + goto fail; } INIT_WORK(&bci->work, twl4030_bci_usb_work); @@ -656,7 +656,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) TWL4030_INTERRUPTS_BCIIMR1A); if (ret < 0) { dev_err(&pdev->dev, "failed to unmask interrupts: %d\n", ret); - goto fail_unmask_interrupts; + goto fail; } reg = ~(u32)(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV); @@ -675,11 +675,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) return 0; -fail_unmask_interrupts: - free_irq(bci->irq_bci, bci); -fail_bci_irq: - free_irq(bci->irq_chg, bci); -fail_chg_irq: +fail: power_supply_unregister(bci->usb); fail_register_usb: power_supply_unregister(bci->ac); @@ -704,8 +700,6 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, TWL4030_INTERRUPTS_BCIIMR2A); - free_irq(bci->irq_bci, bci); - free_irq(bci->irq_chg, bci); power_supply_unregister(bci->usb); power_supply_unregister(bci->ac); kfree(bci); -- cgit v0.10.2 From 325b50aa5d1c7dae57d1e44defdbacd1e2bcabde Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 23 Mar 2015 10:20:28 +1100 Subject: twl4030_charger: use devres for power_supply_register and kzalloc. Final allocations/registrations are now managed by devres. Signed-off-by: NeilBrown Acked-by: Pavel Machek Signed-off-by: Sebastian Reichel diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 4c779ae..709d90d 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -581,7 +581,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) int ret; u32 reg; - bci = kzalloc(sizeof(*bci), GFP_KERNEL); + bci = devm_kzalloc(&pdev->dev, sizeof(*bci), GFP_KERNEL); if (bci == NULL) return -ENOMEM; @@ -596,27 +596,27 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) ret = twl4030_is_battery_present(bci); if (ret) { dev_crit(&pdev->dev, "Battery was not detected:%d\n", ret); - goto fail_no_battery; + return ret; } platform_set_drvdata(pdev, bci); - bci->ac = power_supply_register(&pdev->dev, &twl4030_bci_ac_desc, - NULL); + bci->ac = devm_power_supply_register(&pdev->dev, &twl4030_bci_ac_desc, + NULL); if (IS_ERR(bci->ac)) { ret = PTR_ERR(bci->ac); dev_err(&pdev->dev, "failed to register ac: %d\n", ret); - goto fail_register_ac; + return ret; } bci->usb_reg = regulator_get(bci->dev, "bci3v1"); - bci->usb = power_supply_register(&pdev->dev, &twl4030_bci_usb_desc, - NULL); + bci->usb = devm_power_supply_register(&pdev->dev, &twl4030_bci_usb_desc, + NULL); if (IS_ERR(bci->usb)) { ret = PTR_ERR(bci->usb); dev_err(&pdev->dev, "failed to register usb: %d\n", ret); - goto fail_register_usb; + return ret; } ret = devm_request_threaded_irq(&pdev->dev, bci->irq_chg, NULL, @@ -625,7 +625,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "could not request irq %d, status %d\n", bci->irq_chg, ret); - goto fail; + return ret; } ret = devm_request_threaded_irq(&pdev->dev, bci->irq_bci, NULL, @@ -633,7 +633,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "could not request irq %d, status %d\n", bci->irq_bci, ret); - goto fail; + return ret; } INIT_WORK(&bci->work, twl4030_bci_usb_work); @@ -656,7 +656,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) TWL4030_INTERRUPTS_BCIIMR1A); if (ret < 0) { dev_err(&pdev->dev, "failed to unmask interrupts: %d\n", ret); - goto fail; + return ret; } reg = ~(u32)(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV); @@ -674,16 +674,6 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) twl4030_charger_enable_backup(0, 0); return 0; - -fail: - power_supply_unregister(bci->usb); -fail_register_usb: - power_supply_unregister(bci->ac); -fail_register_ac: -fail_no_battery: - kfree(bci); - - return ret; } static int __exit twl4030_bci_remove(struct platform_device *pdev) @@ -700,10 +690,6 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, TWL4030_INTERRUPTS_BCIIMR2A); - power_supply_unregister(bci->usb); - power_supply_unregister(bci->ac); - kfree(bci); - return 0; } -- cgit v0.10.2 From 377b641ac84c573bcea06aec47f7ad1ba4047e1c Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Wed, 1 Jul 2015 11:40:53 +0200 Subject: power/ltc2941-battery-gauge.c: Use the devicetree node name as supply name Make it possible to set the name of the supply from the devicetree. Like other power supply drivers just use the node name. This makes the code smaller as well, as it doesn't need to allocate memory to hold the name and allocate a unique ID. Signed-off-by: Mike Looijmans Signed-off-by: Sebastian Reichel diff --git a/drivers/power/ltc2941-battery-gauge.c b/drivers/power/ltc2941-battery-gauge.c index daeb086..4adf2ba 100644 --- a/drivers/power/ltc2941-battery-gauge.c +++ b/drivers/power/ltc2941-battery-gauge.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -63,15 +62,11 @@ struct ltc294x_info { struct power_supply_desc supply_desc; /* Supply description */ struct delayed_work work; /* Work scheduler */ int num_regs; /* Number of registers (chip type) */ - int id; /* Identifier of ltc294x chip */ int charge; /* Last charge register content */ int r_sense; /* mOhm */ int Qlsb; /* nAh */ }; -static DEFINE_IDR(ltc294x_id); -static DEFINE_MUTEX(ltc294x_lock); - static inline int convert_bin_to_uAh( const struct ltc294x_info *info, int Q) { @@ -371,10 +366,6 @@ static int ltc294x_i2c_remove(struct i2c_client *client) cancel_delayed_work(&info->work); power_supply_unregister(info->supply); - kfree(info->supply_desc.name); - mutex_lock(<c294x_lock); - idr_remove(<c294x_id, info->id); - mutex_unlock(<c294x_lock); return 0; } @@ -384,44 +375,28 @@ static int ltc294x_i2c_probe(struct i2c_client *client, struct power_supply_config psy_cfg = {}; struct ltc294x_info *info; int ret; - int num; u32 prescaler_exp; s32 r_sense; struct device_node *np; - mutex_lock(<c294x_lock); - ret = idr_alloc(<c294x_id, client, 0, 0, GFP_KERNEL); - mutex_unlock(<c294x_lock); - if (ret < 0) - goto fail_id; - - num = ret; - info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); - if (info == NULL) { - ret = -ENOMEM; - goto fail_info; - } + if (info == NULL) + return -ENOMEM; i2c_set_clientdata(client, info); - info->num_regs = id->driver_data; - info->supply_desc.name = kasprintf(GFP_KERNEL, "%s-%d", client->name, - num); - if (!info->supply_desc.name) { - ret = -ENOMEM; - goto fail_name; - } - np = of_node_get(client->dev.of_node); + info->num_regs = id->driver_data; + info->supply_desc.name = np->name; + /* r_sense can be negative, when sense+ is connected to the battery * instead of the sense-. This results in reversed measurements. */ ret = of_property_read_u32(np, "lltc,resistor-sense", &r_sense); if (ret < 0) { dev_err(&client->dev, "Could not find lltc,resistor-sense in devicetree\n"); - goto fail_name; + return ret; } info->r_sense = r_sense; @@ -446,7 +421,6 @@ static int ltc294x_i2c_probe(struct i2c_client *client, } info->client = client; - info->id = num; info->supply_desc.type = POWER_SUPPLY_TYPE_BATTERY; info->supply_desc.properties = ltc294x_properties; if (info->num_regs >= LTC294X_REG_TEMPERATURE_LSB) @@ -473,31 +447,19 @@ static int ltc294x_i2c_probe(struct i2c_client *client, ret = ltc294x_reset(info, prescaler_exp); if (ret < 0) { dev_err(&client->dev, "Communication with chip failed\n"); - goto fail_comm; + return ret; } info->supply = power_supply_register(&client->dev, &info->supply_desc, &psy_cfg); if (IS_ERR(info->supply)) { dev_err(&client->dev, "failed to register ltc2941\n"); - ret = PTR_ERR(info->supply); - goto fail_register; + return PTR_ERR(info->supply); } else { schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ); } return 0; - -fail_register: - kfree(info->supply_desc.name); -fail_comm: -fail_name: -fail_info: - mutex_lock(<c294x_lock); - idr_remove(<c294x_id, num); - mutex_unlock(<c294x_lock); -fail_id: - return ret; } #ifdef CONFIG_PM_SLEEP -- cgit v0.10.2 From dd9f1486ae207cd947416f1bdc461edc4880f2df Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Wed, 15 Jul 2015 11:25:58 +0800 Subject: power/reset: zx: Register restart handler Register with kernel restart handler instead of setting arm_pm_restart directly. Signed-off-by: Jun Nie Signed-off-by: Sebastian Reichel diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 17d93a7..5a0189b 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -166,5 +166,12 @@ config POWER_RESET_RMOBILE help Reboot support for Renesas R-Mobile and SH-Mobile SoCs. +config POWER_RESET_ZX + tristate "ZTE SoCs reset driver" + depends on ARCH_ZX || COMPILE_TEST + depends on HAS_IOMEM + help + Reboot support for ZTE SoCs. + endif diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index dbe06c3..096fa67 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o +obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o diff --git a/drivers/power/reset/zx-reboot.c b/drivers/power/reset/zx-reboot.c new file mode 100644 index 0000000..cf4b973 --- /dev/null +++ b/drivers/power/reset/zx-reboot.c @@ -0,0 +1,82 @@ +/* + * ZTE zx296702 SoC reset code + * + * Copyright (c) 2015 Linaro Ltd. + * + * Author: Jun Nie + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static void __iomem *base; +static void __iomem *pcu_base; + +static int zx_restart_handler(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + writel_relaxed(1, base + 0xb0); + writel_relaxed(1, pcu_base + 0x34); + + mdelay(50); + pr_emerg("Unable to restart system\n"); + + return NOTIFY_DONE; +} + +static struct notifier_block zx_restart_nb = { + .notifier_call = zx_restart_handler, + .priority = 128, +}; + +static int zx_reboot_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + int err; + + base = of_iomap(np, 0); + if (!base) { + WARN(1, "failed to map base address"); + return -ENODEV; + } + + np = of_find_compatible_node(NULL, NULL, "zte,zx296702-pcu"); + pcu_base = of_iomap(np, 0); + if (!pcu_base) { + iounmap(base); + WARN(1, "failed to map pcu_base address"); + return -ENODEV; + } + + err = register_restart_handler(&zx_restart_nb); + if (err) + dev_err(&pdev->dev, "Register restart handler failed(err=%d)\n", + err); + + return err; +} + +static const struct of_device_id zx_reboot_of_match[] = { + { .compatible = "zte,sysctrl" }, + {} +}; + +static struct platform_driver zx_reboot_driver = { + .probe = zx_reboot_probe, + .driver = { + .name = "zx-reboot", + .of_match_table = zx_reboot_of_match, + }, +}; +module_platform_driver(zx_reboot_driver); -- cgit v0.10.2 From db04fc5caa79260170a68d58db8fc401f1ab05f5 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 22 Jul 2015 16:51:53 -0500 Subject: power: bq27x00_battery: Add manufacturer property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the manufacturer property to the bq27x00 driver. Signed-off-by: Andrew F. Davis Acked-by: Dan Murphy Acked-by: Pali Rohár Signed-off-by: Sebastian Reichel diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index b6b9837..2257bd4 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -41,6 +41,8 @@ #define DRIVER_VERSION "1.2.0" +#define BQ27XXX_MANUFACTURER "Texas Instruments" + #define BQ27x00_REG_TEMP 0x06 #define BQ27x00_REG_VOLT 0x08 #define BQ27x00_REG_AI 0x14 @@ -142,6 +144,7 @@ static enum power_supply_property bq27x00_battery_props[] = { POWER_SUPPLY_PROP_ENERGY_NOW, POWER_SUPPLY_PROP_POWER_AVG, POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, }; static enum power_supply_property bq27425_battery_props[] = { @@ -156,6 +159,7 @@ static enum power_supply_property bq27425_battery_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_MANUFACTURER, }; static enum power_supply_property bq27742_battery_props[] = { @@ -174,6 +178,7 @@ static enum power_supply_property bq27742_battery_props[] = { POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_POWER_AVG, POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, }; static enum power_supply_property bq27510_battery_props[] = { @@ -192,6 +197,7 @@ static enum power_supply_property bq27510_battery_props[] = { POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_POWER_AVG, POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, }; static unsigned int poll_interval = 360; @@ -749,6 +755,9 @@ static int bq27x00_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_HEALTH: ret = bq27x00_simple_value(di->cache.health, val); break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = BQ27XXX_MANUFACTURER; + break; default: return -EINVAL; } -- cgit v0.10.2 From 6eb207f271478472195cfaa2e59646f7e5036ae8 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 22 Jul 2015 16:51:54 -0500 Subject: power: bq27x00_battery: Fix lines over 80 characters long MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shorted lines over 80 characters long by reducing tab count. Signed-off-by: Andrew F. Davis Acked-by: Pali Rohár Acked-by: Dan Murphy Signed-off-by: Sebastian Reichel diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 2257bd4..203cf61 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -39,49 +39,49 @@ #include -#define DRIVER_VERSION "1.2.0" +#define DRIVER_VERSION "1.2.0" #define BQ27XXX_MANUFACTURER "Texas Instruments" -#define BQ27x00_REG_TEMP 0x06 -#define BQ27x00_REG_VOLT 0x08 -#define BQ27x00_REG_AI 0x14 -#define BQ27x00_REG_FLAGS 0x0A -#define BQ27x00_REG_TTE 0x16 -#define BQ27x00_REG_TTF 0x18 -#define BQ27x00_REG_TTECP 0x26 -#define BQ27x00_REG_NAC 0x0C /* Nominal available capacity */ -#define BQ27x00_REG_LMD 0x12 /* Last measured discharge */ -#define BQ27x00_REG_CYCT 0x2A /* Cycle count total */ -#define BQ27x00_REG_AE 0x22 /* Available energy */ -#define BQ27x00_POWER_AVG 0x24 - -#define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ -#define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ -#define BQ27000_FLAG_EDVF BIT(0) /* Final End-of-Discharge-Voltage flag */ -#define BQ27000_FLAG_EDV1 BIT(1) /* First End-of-Discharge-Voltage flag */ -#define BQ27000_FLAG_CI BIT(4) /* Capacity Inaccurate flag */ -#define BQ27000_FLAG_FC BIT(5) -#define BQ27000_FLAG_CHGS BIT(7) /* Charge state flag */ - -#define BQ27500_REG_SOC 0x2C -#define BQ27500_REG_DCAP 0x3C /* Design capacity */ -#define BQ27500_FLAG_DSC BIT(0) -#define BQ27500_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */ -#define BQ27500_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */ -#define BQ27500_FLAG_FC BIT(9) -#define BQ27500_FLAG_OTC BIT(15) - -#define BQ27742_POWER_AVG 0x76 - -#define BQ27510_REG_SOC 0x20 -#define BQ27510_REG_DCAP 0x2E /* Design capacity */ -#define BQ27510_REG_CYCT 0x1E /* Cycle count total */ +#define BQ27x00_REG_TEMP 0x06 +#define BQ27x00_REG_VOLT 0x08 +#define BQ27x00_REG_AI 0x14 +#define BQ27x00_REG_FLAGS 0x0A +#define BQ27x00_REG_TTE 0x16 +#define BQ27x00_REG_TTF 0x18 +#define BQ27x00_REG_TTECP 0x26 +#define BQ27x00_REG_NAC 0x0C /* Nominal available capacity */ +#define BQ27x00_REG_LMD 0x12 /* Last measured discharge */ +#define BQ27x00_REG_CYCT 0x2A /* Cycle count total */ +#define BQ27x00_REG_AE 0x22 /* Available energy */ +#define BQ27x00_POWER_AVG 0x24 + +#define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ +#define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ +#define BQ27000_FLAG_EDVF BIT(0) /* Final End-of-Discharge-Voltage flag */ +#define BQ27000_FLAG_EDV1 BIT(1) /* First End-of-Discharge-Voltage flag */ +#define BQ27000_FLAG_CI BIT(4) /* Capacity Inaccurate flag */ +#define BQ27000_FLAG_FC BIT(5) +#define BQ27000_FLAG_CHGS BIT(7) /* Charge state flag */ + +#define BQ27500_REG_SOC 0x2C +#define BQ27500_REG_DCAP 0x3C /* Design capacity */ +#define BQ27500_FLAG_DSC BIT(0) +#define BQ27500_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */ +#define BQ27500_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */ +#define BQ27500_FLAG_FC BIT(9) +#define BQ27500_FLAG_OTC BIT(15) + +#define BQ27742_POWER_AVG 0x76 + +#define BQ27510_REG_SOC 0x20 +#define BQ27510_REG_DCAP 0x2E /* Design capacity */ +#define BQ27510_REG_CYCT 0x1E /* Cycle count total */ /* bq27425 register addresses are same as bq27x00 addresses minus 4 */ -#define BQ27425_REG_OFFSET 0x04 +#define BQ27425_REG_OFFSET 0x04 #define BQ27425_REG_SOC (0x1C + BQ27425_REG_OFFSET) -#define BQ27425_REG_DCAP (0x3C + BQ27425_REG_OFFSET) +#define BQ27425_REG_DCAP (0x3C + BQ27425_REG_OFFSET) #define BQ27000_RS 20 /* Resistor sense */ #define BQ27x00_POWER_CONSTANT (256 * 29200 / 1000) -- cgit v0.10.2 From ce33edfa4903d8b8ded2569e880489678f75a85b Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 22 Jul 2015 16:51:55 -0500 Subject: power: bq27x00_battery: Fix function parameter alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the alignment of function parameters on new lines. Signed-off-by: Andrew F. Davis Acked-by: Pali Rohár Acked-by: Dan Murphy Signed-off-by: Sebastian Reichel diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 203cf61..9cdad19 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -210,7 +210,7 @@ MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \ */ static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg, - bool single) + bool single) { if (di->chip == BQ27425) return di->bus.read(di, reg - BQ27425_REG_OFFSET, single); @@ -565,7 +565,7 @@ static void bq27x00_battery_poll(struct work_struct *work) * Or 0 if something fails. */ static int bq27x00_battery_current(struct bq27x00_device_info *di, - union power_supply_propval *val) + union power_supply_propval *val) { int curr; int flags; @@ -593,7 +593,7 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di, } static int bq27x00_battery_status(struct bq27x00_device_info *di, - union power_supply_propval *val) + union power_supply_propval *val) { int status; @@ -621,7 +621,7 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di, } static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di, - union power_supply_propval *val) + union power_supply_propval *val) { int level; @@ -655,7 +655,7 @@ static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di, * Or < 0 if something fails. */ static int bq27x00_battery_voltage(struct bq27x00_device_info *di, - union power_supply_propval *val) + union power_supply_propval *val) { int volt; @@ -671,7 +671,7 @@ static int bq27x00_battery_voltage(struct bq27x00_device_info *di, } static int bq27x00_simple_value(int value, - union power_supply_propval *val) + union power_supply_propval *val) { if (value < 0) return value; @@ -987,7 +987,7 @@ static inline void bq27x00_battery_i2c_exit(void) {}; #ifdef CONFIG_BATTERY_BQ27X00_PLATFORM static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg, - bool single) + bool single) { struct device *dev = di->dev; struct bq27000_platform_data *pdata = dev->platform_data; -- cgit v0.10.2 From 6d0a1815e814ee5eaa0cec17913d5e4abae99ef0 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 22 Jul 2015 16:51:56 -0500 Subject: power: bq27x00_battery: Checkpatch fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove space before tab. Remove unnecessary line continuations. Add braces to else statement. Remove unnecessary parentheses. Remove unneeded blank lines. Remove unnecessary 'out of memory' message. Add missing line after declarations. Change use of printk to pr_err. Signed-off-by: Andrew F. Davis Acked-by: Pali Rohár Acked-by: Dan Murphy Signed-off-by: Sebastian Reichel diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 9cdad19..8287261f 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -108,7 +108,7 @@ struct bq27x00_reg_cache { }; struct bq27x00_device_info { - struct device *dev; + struct device *dev; int id; enum bq27x00_chip chip; @@ -202,8 +202,8 @@ static enum power_supply_property bq27510_battery_props[] = { static unsigned int poll_interval = 360; module_param(poll_interval, uint, 0644); -MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \ - "0 disables polling"); +MODULE_PARM_DESC(poll_interval, + "battery poll interval in seconds - 0 disables polling"); /* * Common code for BQ27x00 devices @@ -319,8 +319,9 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) ilmd = bq27x00_read(di, BQ27510_REG_DCAP, false); else ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false); - } else + } else { ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); + } if (ilmd < 0) { dev_dbg(di->dev, "error reading initial last measured discharge\n"); @@ -451,7 +452,7 @@ static int bq27x00_battery_read_health(struct bq27x00_device_info *di) return tval; } - if ((di->chip == BQ27500)) { + if (di->chip == BQ27500) { if (tval & BQ27500_FLAG_SOCF) tval = POWER_SUPPLY_HEALTH_DEAD; else if (tval & BQ27500_FLAG_OTC) @@ -836,7 +837,6 @@ static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di) mutex_destroy(&di->lock); } - /* i2c specific code */ #ifdef CONFIG_BATTERY_BQ27X00_I2C @@ -897,14 +897,12 @@ static int bq27x00_battery_probe(struct i2c_client *client, name = devm_kasprintf(&client->dev, GFP_KERNEL, "%s-%d", id->name, num); if (!name) { - dev_err(&client->dev, "failed to allocate device name\n"); retval = -ENOMEM; goto batt_failed; } di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL); if (!di) { - dev_err(&client->dev, "failed to allocate device info data\n"); retval = -ENOMEM; goto batt_failed; } @@ -965,8 +963,9 @@ static struct i2c_driver bq27x00_battery_driver = { static inline int bq27x00_battery_i2c_init(void) { int ret = i2c_add_driver(&bq27x00_battery_driver); + if (ret) - printk(KERN_ERR "Unable to register BQ27x00 i2c driver\n"); + pr_err("Unable to register BQ27x00 i2c driver\n"); return ret; } @@ -1037,10 +1036,8 @@ static int bq27000_battery_probe(struct platform_device *pdev) } di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); - if (!di) { - dev_err(&pdev->dev, "failed to allocate device info data\n"); + if (!di) return -ENOMEM; - } platform_set_drvdata(pdev, di); @@ -1073,8 +1070,9 @@ static struct platform_driver bq27000_battery_driver = { static inline int bq27x00_battery_platform_init(void) { int ret = platform_driver_register(&bq27000_battery_driver); + if (ret) - printk(KERN_ERR "Unable to register BQ27000 platform driver\n"); + pr_err("Unable to register BQ27000 platform driver\n"); return ret; } -- cgit v0.10.2 From 3309aa494186b0c5364d812ae000955262590655 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Mon, 27 Jul 2015 14:59:06 +0800 Subject: power/reset: zx: Remove unnecessary include file Including ARM related header file cause build failure in i386 build because COMILE_TEST also involve building zx driver. Remove the unnecessary include file. Signed-off-by: Jun Nie Signed-off-by: Sebastian Reichel diff --git a/drivers/power/reset/zx-reboot.c b/drivers/power/reset/zx-reboot.c index cf4b973..a5b0096 100644 --- a/drivers/power/reset/zx-reboot.c +++ b/drivers/power/reset/zx-reboot.c @@ -18,8 +18,6 @@ #include #include -#include - static void __iomem *base; static void __iomem *pcu_base; -- cgit v0.10.2 From 71a5a508436332ac40f688ef06e61628f25f3e5b Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Sat, 25 Jul 2015 09:23:16 +0530 Subject: power_supply: bq24735: Convert to using managed resources Use managed resource functions like devm_kasprintf and devm_power_supply_register in bq24735_charger_probe. To be compatible with the change, replace various gotos by direct returns and drop unneeded labels. Also, remove bq24735_charger_remove as it is now redundant. Signed-off-by: Vaishali Thakkar Signed-off-by: Sebastian Reichel diff --git a/drivers/power/bq24735-charger.c b/drivers/power/bq24735-charger.c index b017437..eb2b368 100644 --- a/drivers/power/bq24735-charger.c +++ b/drivers/power/bq24735-charger.c @@ -267,8 +267,9 @@ static int bq24735_charger_probe(struct i2c_client *client, name = (char *)charger->pdata->name; if (!name) { - name = kasprintf(GFP_KERNEL, "bq24735@%s", - dev_name(&client->dev)); + name = devm_kasprintf(&client->dev, GFP_KERNEL, + "bq24735@%s", + dev_name(&client->dev)); if (!name) { dev_err(&client->dev, "Failed to alloc device name\n"); return -ENOMEM; @@ -296,23 +297,21 @@ static int bq24735_charger_probe(struct i2c_client *client, if (ret < 0) { dev_err(&client->dev, "Failed to read manufacturer id : %d\n", ret); - goto err_free_name; + return ret; } else if (ret != 0x0040) { dev_err(&client->dev, "manufacturer id mismatch. 0x0040 != 0x%04x\n", ret); - ret = -ENODEV; - goto err_free_name; + return -ENODEV; } ret = bq24735_read_word(client, BQ24735_DEVICE_ID); if (ret < 0) { dev_err(&client->dev, "Failed to read device id : %d\n", ret); - goto err_free_name; + return ret; } else if (ret != 0x000B) { dev_err(&client->dev, "device id mismatch. 0x000b != 0x%04x\n", ret); - ret = -ENODEV; - goto err_free_name; + return -ENODEV; } if (gpio_is_valid(charger->pdata->status_gpio)) { @@ -331,7 +330,7 @@ static int bq24735_charger_probe(struct i2c_client *client, ret = bq24735_config_charger(charger); if (ret < 0) { dev_err(&client->dev, "failed in configuring charger"); - goto err_free_name; + return ret; } /* check for AC adapter presence */ @@ -339,17 +338,17 @@ static int bq24735_charger_probe(struct i2c_client *client, ret = bq24735_enable_charging(charger); if (ret < 0) { dev_err(&client->dev, "Failed to enable charging\n"); - goto err_free_name; + return ret; } } - charger->charger = power_supply_register(&client->dev, supply_desc, - &psy_cfg); + charger->charger = devm_power_supply_register(&client->dev, supply_desc, + &psy_cfg); if (IS_ERR(charger->charger)) { ret = PTR_ERR(charger->charger); dev_err(&client->dev, "Failed to register power supply: %d\n", ret); - goto err_free_name; + return ret; } if (client->irq) { @@ -364,34 +363,11 @@ static int bq24735_charger_probe(struct i2c_client *client, dev_err(&client->dev, "Unable to register IRQ %d err %d\n", client->irq, ret); - goto err_unregister_supply; + return ret; } } return 0; -err_unregister_supply: - power_supply_unregister(charger->charger); -err_free_name: - if (name != charger->pdata->name) - kfree(name); - - return ret; -} - -static int bq24735_charger_remove(struct i2c_client *client) -{ - struct bq24735 *charger = i2c_get_clientdata(client); - - if (charger->client->irq) - devm_free_irq(&charger->client->dev, charger->client->irq, - &charger->charger); - - power_supply_unregister(charger->charger); - - if (charger->charger_desc.name != charger->pdata->name) - kfree(charger->charger_desc.name); - - return 0; } static const struct i2c_device_id bq24735_charger_id[] = { @@ -412,7 +388,6 @@ static struct i2c_driver bq24735_charger_driver = { .of_match_table = bq24735_match_ids, }, .probe = bq24735_charger_probe, - .remove = bq24735_charger_remove, .id_table = bq24735_charger_id, }; -- cgit v0.10.2 From 753f15833c4d782ee41e333f66bfe424a39680e6 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:26:47 +0300 Subject: power: ds2780_battery: clean up eeprom read/write functions The change removes redundant sysfs binary file boundary checks while reading or writing "param_eeprom" or "user_eeprom", the checks are not needed, since this task is done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Sebastian Reichel diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c index a7a0427..d3743d0 100644 --- a/drivers/power/ds2780_battery.c +++ b/drivers/power/ds2780_battery.c @@ -637,10 +637,6 @@ static ssize_t ds2780_read_param_eeprom_bin(struct file *filp, struct power_supply *psy = to_power_supply(dev); struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); - count = min_t(loff_t, count, - DS2780_EEPROM_BLOCK1_END - - DS2780_EEPROM_BLOCK1_START + 1 - off); - return ds2780_read_block(dev_info, buf, DS2780_EEPROM_BLOCK1_START + off, count); } @@ -655,10 +651,6 @@ static ssize_t ds2780_write_param_eeprom_bin(struct file *filp, struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); int ret; - count = min_t(loff_t, count, - DS2780_EEPROM_BLOCK1_END - - DS2780_EEPROM_BLOCK1_START + 1 - off); - ret = ds2780_write(dev_info, buf, DS2780_EEPROM_BLOCK1_START + off, count); if (ret < 0) @@ -676,7 +668,7 @@ static struct bin_attribute ds2780_param_eeprom_bin_attr = { .name = "param_eeprom", .mode = S_IRUGO | S_IWUSR, }, - .size = DS2780_EEPROM_BLOCK1_END - DS2780_EEPROM_BLOCK1_START + 1, + .size = DS2780_PARAM_EEPROM_SIZE, .read = ds2780_read_param_eeprom_bin, .write = ds2780_write_param_eeprom_bin, }; @@ -690,10 +682,6 @@ static ssize_t ds2780_read_user_eeprom_bin(struct file *filp, struct power_supply *psy = to_power_supply(dev); struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); - count = min_t(loff_t, count, - DS2780_EEPROM_BLOCK0_END - - DS2780_EEPROM_BLOCK0_START + 1 - off); - return ds2780_read_block(dev_info, buf, DS2780_EEPROM_BLOCK0_START + off, count); } @@ -708,10 +696,6 @@ static ssize_t ds2780_write_user_eeprom_bin(struct file *filp, struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); int ret; - count = min_t(loff_t, count, - DS2780_EEPROM_BLOCK0_END - - DS2780_EEPROM_BLOCK0_START + 1 - off); - ret = ds2780_write(dev_info, buf, DS2780_EEPROM_BLOCK0_START + off, count); if (ret < 0) @@ -729,7 +713,7 @@ static struct bin_attribute ds2780_user_eeprom_bin_attr = { .name = "user_eeprom", .mode = S_IRUGO | S_IWUSR, }, - .size = DS2780_EEPROM_BLOCK0_END - DS2780_EEPROM_BLOCK0_START + 1, + .size = DS2780_USER_EEPROM_SIZE, .read = ds2780_read_user_eeprom_bin, .write = ds2780_write_user_eeprom_bin, }; -- cgit v0.10.2 From 9f28b86552aef94733387814a57755cb0019cfb9 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:26:48 +0300 Subject: power: ds2781_battery: clean up eeprom read/write functions The change removes redundant calculation of left space on eeprom while reading or writing "param_eeprom" or "user_eeprom", the checks are not needed, since this task is done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Sebastian Reichel diff --git a/drivers/power/ds2781_battery.c b/drivers/power/ds2781_battery.c index 56d583d..c368002 100644 --- a/drivers/power/ds2781_battery.c +++ b/drivers/power/ds2781_battery.c @@ -639,8 +639,6 @@ static ssize_t ds2781_read_param_eeprom_bin(struct file *filp, struct power_supply *psy = to_power_supply(dev); struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); - count = min_t(loff_t, count, DS2781_PARAM_EEPROM_SIZE - off); - return ds2781_read_block(dev_info, buf, DS2781_EEPROM_BLOCK1_START + off, count); } @@ -655,8 +653,6 @@ static ssize_t ds2781_write_param_eeprom_bin(struct file *filp, struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); int ret; - count = min_t(loff_t, count, DS2781_PARAM_EEPROM_SIZE - off); - ret = ds2781_write(dev_info, buf, DS2781_EEPROM_BLOCK1_START + off, count); if (ret < 0) @@ -688,8 +684,6 @@ static ssize_t ds2781_read_user_eeprom_bin(struct file *filp, struct power_supply *psy = to_power_supply(dev); struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); - count = min_t(loff_t, count, DS2781_USER_EEPROM_SIZE - off); - return ds2781_read_block(dev_info, buf, DS2781_EEPROM_BLOCK0_START + off, count); @@ -705,8 +699,6 @@ static ssize_t ds2781_write_user_eeprom_bin(struct file *filp, struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); int ret; - count = min_t(loff_t, count, DS2781_USER_EEPROM_SIZE - off); - ret = ds2781_write(dev_info, buf, DS2781_EEPROM_BLOCK0_START + off, count); if (ret < 0) -- cgit v0.10.2 From 3e1d9c6f241961e2e21b8df9de5ee12e3dc6f177 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:26:49 +0300 Subject: power: olpc_battery: clean up eeprom read function The change removes redundant sysfs binary file boundary check while reading eeprom content from userspace, the check is done on caller side in fs/sysfs/file.c, if binary attribute size is not zero. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Sebastian Reichel diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index a944338..9e29b13 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -521,11 +521,6 @@ static ssize_t olpc_bat_eeprom_read(struct file *filp, struct kobject *kobj, int ret; int i; - if (off >= EEPROM_SIZE) - return 0; - if (off + count > EEPROM_SIZE) - count = EEPROM_SIZE - off; - for (i = 0; i < count; i++) { ec_byte = EEPROM_START + off + i; ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &buf[i], 1); @@ -545,7 +540,7 @@ static struct bin_attribute olpc_bat_eeprom = { .name = "eeprom", .mode = S_IRUGO, }, - .size = 0, + .size = EEPROM_SIZE, .read = olpc_bat_eeprom_read, }; -- cgit v0.10.2 From 26305022e7ffdeff49b15c9ab18e2c0c880356da Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 24 Jul 2015 23:11:28 +0200 Subject: MAINTAINERS: AVS is not maintained via power supply tree The adaptive voltage scaling framework is not maintained via the power supply tree and has its own entry in the MAINTAINERS file, so add an exception in the power supply entry. Signed-off-by: Sebastian Reichel Acked-by: Kevin Hilman diff --git a/MAINTAINERS b/MAINTAINERS index 8133cef..243f76f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8049,6 +8049,7 @@ T: git git://git.infradead.org/battery-2.6.git S: Maintained F: include/linux/power_supply.h F: drivers/power/ +X: drivers/power/avs/ PNP SUPPORT M: "Rafael J. Wysocki" -- cgit v0.10.2 From b5e578631e5c1d77f58727ea0769dd55c462b572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 28 Jul 2015 20:44:41 +0200 Subject: rx51-battery: Set name to rx51-battery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For compatibility between board code and DT, set battery name to same value. Signed-off-by: Pali Rohár Acked-by: Pavel Machek Signed-off-by: Sebastian Reichel diff --git a/drivers/power/rx51_battery.c b/drivers/power/rx51_battery.c index ac62069..af9383d 100644 --- a/drivers/power/rx51_battery.c +++ b/drivers/power/rx51_battery.c @@ -215,7 +215,7 @@ static int rx51_battery_probe(struct platform_device *pdev) platform_set_drvdata(pdev, di); di->dev = &pdev->dev; - di->bat_desc.name = dev_name(&pdev->dev); + di->bat_desc.name = "rx51-battery"; di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY; di->bat_desc.properties = rx51_battery_props; di->bat_desc.num_properties = ARRAY_SIZE(rx51_battery_props); -- cgit v0.10.2 From e57c4a67d71275e4a15b9f0f92a322ea27b26a6e Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: use runtime_pm to keep usb phy active while charging. The twl4030 usb phy needs to be active while we are using the USB VBUS as a current source for charging. In particular, the usb3v1 regulator must be enabled and the PHY_PWR_PHYPWD bit must be set to keep the phy powered. commit ab37813f4093a5f59cb8e083cde277289dc72ed3 twl4030_charger: Allow charger to control the regulator that feeds it gave the charger control over the regulator, but didn't resolve the PHY_PWR_PHYPWD issue. Now that both of these are controlled by runtime_pm in phy-twl4030-usb, we can simply take a runtime_pm reference to the USB phy whenever the charger wants to use it as a current source. So this patch reverts the above commit, and adds the necessary runtime_pm calls. Acked-by: Lee Jones Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 489674a..831696e 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -788,9 +788,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, static struct regulator_consumer_supply usb1v8 = { .supply = "usb1v8", }; - static struct regulator_consumer_supply usb3v1[] = { - { .supply = "usb3v1" }, - { .supply = "bci3v1" }, + static struct regulator_consumer_supply usb3v1 = { + .supply = "usb3v1", }; /* First add the regulators so that they can be used by transceiver */ @@ -818,7 +817,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); child = add_regulator_linked(TWL4030_REG_VUSB3V1, - &usb_fixed, usb3v1, 2, + &usb_fixed, &usb3v1, 1, features); if (IS_ERR(child)) return PTR_ERR(child); @@ -838,7 +837,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) { usb1v5.dev_name = dev_name(child); usb1v8.dev_name = dev_name(child); - usb3v1[0].dev_name = dev_name(child); + usb3v1.dev_name = dev_name(child); } } diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 709d90d..fe71c61 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -22,7 +22,6 @@ #include #include #include -#include #define TWL4030_BCIMSTATEC 0x02 #define TWL4030_BCIICHG 0x08 @@ -94,7 +93,6 @@ struct twl4030_bci { struct work_struct work; int irq_chg; int irq_bci; - struct regulator *usb_reg; int usb_enabled; unsigned long event; @@ -208,7 +206,7 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) { int ret; - if (enable) { + if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { /* Check for USB charger connected */ if (!twl4030_bci_have_vbus(bci)) return -ENODEV; @@ -222,14 +220,9 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) return -EACCES; } - /* Need to keep regulator on */ + /* Need to keep phy powered */ if (!bci->usb_enabled) { - ret = regulator_enable(bci->usb_reg); - if (ret) { - dev_err(bci->dev, - "Failed to enable regulator\n"); - return ret; - } + pm_runtime_get_sync(bci->transceiver->dev); bci->usb_enabled = 1; } @@ -244,7 +237,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) } else { ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0); if (bci->usb_enabled) { - regulator_disable(bci->usb_reg); + pm_runtime_mark_last_busy(bci->transceiver->dev); + pm_runtime_put_autosuspend(bci->transceiver->dev); bci->usb_enabled = 0; } } @@ -609,8 +603,6 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) return ret; } - bci->usb_reg = regulator_get(bci->dev, "bci3v1"); - bci->usb = devm_power_supply_register(&pdev->dev, &twl4030_bci_usb_desc, NULL); if (IS_ERR(bci->usb)) { -- cgit v0.10.2 From 7396f708b9f1d8874dda9c6386c37b065d99b68f Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: convert to module_platform_driver instead of ..._probe. Drivers using module_platform_driver_probe cannot return EPROBE_DEFER from the probe function, which makes them rather useless these days... Convert to module_platform_driver() so EPROBE_DEFER can be used. Signed-off-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index fe71c61..0452383 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -568,7 +568,7 @@ static const struct power_supply_desc twl4030_bci_usb_desc = { .get_property = twl4030_bci_get_property, }; -static int __init twl4030_bci_probe(struct platform_device *pdev) +static int twl4030_bci_probe(struct platform_device *pdev) { struct twl4030_bci *bci; const struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data; @@ -692,14 +692,14 @@ static const struct of_device_id twl_bci_of_match[] = { MODULE_DEVICE_TABLE(of, twl_bci_of_match); static struct platform_driver twl4030_bci_driver = { + .probe = twl4030_bci_probe, .driver = { .name = "twl4030_bci", .of_match_table = of_match_ptr(twl_bci_of_match), }, .remove = __exit_p(twl4030_bci_remove), }; - -module_platform_driver_probe(twl4030_bci_driver, twl4030_bci_probe); +module_platform_driver(twl4030_bci_driver); MODULE_AUTHOR("Gražvydas Ignotas"); MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver"); -- cgit v0.10.2 From 3fc3895e4fe17ee92ae1d1bb9f04da6069e8c370 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: correctly handle -EPROBE_DEFER from devm_usb_get_phy_by_node Now that twl4030_bci_probe can safely return -EPROBE_DEFER, do so when devm_usb_get_phy_by_node returns that error. Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 0452383..ffc123f 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -636,9 +636,13 @@ static int twl4030_bci_probe(struct platform_device *pdev) phynode = of_find_compatible_node(bci->dev->of_node->parent, NULL, "ti,twl4030-usb"); - if (phynode) + if (phynode) { bci->transceiver = devm_usb_get_phy_by_node( bci->dev, phynode, &bci->usb_nb); + if (IS_ERR(bci->transceiver) && + PTR_ERR(bci->transceiver) == -EPROBE_DEFER) + return -EPROBE_DEFER; + } } /* Enable interrupts now. */ -- cgit v0.10.2 From 6e37ec8c77e3e6580cbb844dfeea0fb3970c0a35 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: trust phy to determine when USB power is available. The usb phy driver already determines when VBUS is available, so repeating the test in the charger driver is pointless duplication. On probe, process the last event from the phy, and from then on, do whatever the phy tells us without double-checking. Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index ffc123f..a075216 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -178,28 +178,6 @@ static int twl4030_is_battery_present(struct twl4030_bci *bci) } /* - * Check if VBUS power is present - */ -static int twl4030_bci_have_vbus(struct twl4030_bci *bci) -{ - int ret; - u8 hwsts; - - ret = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &hwsts, - TWL4030_PM_MASTER_STS_HW_CONDITIONS); - if (ret < 0) - return 0; - - dev_dbg(bci->dev, "check_vbus: HW_CONDITIONS %02x\n", hwsts); - - /* in case we also have STS_USB_ID, VBUS is driven by TWL itself */ - if ((hwsts & TWL4030_STS_VBUS) && !(hwsts & TWL4030_STS_USB_ID)) - return 1; - - return 0; -} - -/* * Enable/Disable USB Charge functionality. */ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) @@ -207,10 +185,6 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) int ret; if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { - /* Check for USB charger connected */ - if (!twl4030_bci_have_vbus(bci)) - return -ENODEV; - /* * Until we can find out what current the device can provide, * require a module param to enable USB charging. @@ -662,7 +636,12 @@ static int twl4030_bci_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret); twl4030_charger_enable_ac(true); - twl4030_charger_enable_usb(bci, true); + if (!IS_ERR_OR_NULL(bci->transceiver)) + twl4030_bci_usb_ncb(&bci->usb_nb, + bci->transceiver->last_event, + NULL); + else + twl4030_charger_enable_usb(bci, false); if (pdata) twl4030_charger_enable_backup(pdata->bb_uvolt, pdata->bb_uamp); -- cgit v0.10.2 From 3b542f089dcbdcf1c21a01927fbc6d5116af01f6 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: split uA calculation into a function. We will need this calculation in other places, so create functions to map between register value and uA value. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index a075216..29984b2 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -178,6 +178,40 @@ static int twl4030_is_battery_present(struct twl4030_bci *bci) } /* + * TI provided formulas: + * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85 + * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7 + * Here we use integer approximation of: + * CGAIN == 0: val * 1.6618 - 0.85 * 1000 + * CGAIN == 1: (val * 1.6618 - 0.85 * 1000) * 2 + */ +/* + * convert twl register value for currents into uA + */ +static int regval2ua(int regval, bool cgain) +{ + if (cgain) + return (regval * 16618 - 8500 * 1000) / 5; + else + return (regval * 16618 - 8500 * 1000) / 10; +} + +/* + * convert uA currents into twl register value + */ +static int ua2regval(int ua, bool cgain) +{ + int ret; + if (cgain) + ua /= 2; + ret = (ua * 10 + 8500 * 1000) / 16618; + /* rounding problems */ + if (ret < 512) + ret = 512; + return ret; +} + +/* * Enable/Disable USB Charge functionality. */ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) @@ -366,14 +400,6 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, return NOTIFY_OK; } -/* - * TI provided formulas: - * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85 - * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7 - * Here we use integer approximation of: - * CGAIN == 0: val * 1.6618 - 0.85 - * CGAIN == 1: (val * 1.6618 - 0.85) * 2 - */ static int twl4030_charger_get_current(void) { int curr; @@ -388,11 +414,7 @@ static int twl4030_charger_get_current(void) if (ret) return ret; - ret = (curr * 16618 - 850 * 10000) / 10; - if (bcictl1 & TWL4030_CGAIN) - ret *= 2; - - return ret; + return regval2ua(curr, bcictl1 & TWL4030_CGAIN); } /* -- cgit v0.10.2 From 1098cb58aed8eb4e06302d947a38bbfb69c8b4ba Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: allow fine control of charger current. The twl4030 allows control of the incoming current. Part of this control is a 'CGAIN' setting which doubles the range for half the precision. This control affects several different current setting, so all need to be updated at once when CGAIN is changed. With this patch, all of these current setting are managed by the driver, but most are left at their default settings. The current drawn is set to 500mA if the allow_usb module parameter is set, and to 100mA otherwise. More fine control will appear in later patches. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 29984b2..3b7cc63 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -31,6 +31,11 @@ #define TWL4030_BCIMFSTS4 0x10 #define TWL4030_BCICTL1 0x23 #define TWL4030_BB_CFG 0x12 +#define TWL4030_BCIIREF1 0x27 +#define TWL4030_BCIIREF2 0x28 +#define TWL4030_BCIMFKEY 0x11 +#define TWL4030_BCIMFTH8 0x1d +#define TWL4030_BCIMFTH9 0x1e #define TWL4030_BCIMFSTS1 0x01 @@ -95,6 +100,12 @@ struct twl4030_bci { int irq_bci; int usb_enabled; + /* + * ichg values in uA. If any are 'large', we set CGAIN to + * '1' which doubles the range for half the precision. + */ + unsigned int ichg_eoc, ichg_lo, ichg_hi, cur; + unsigned long event; }; @@ -211,6 +222,146 @@ static int ua2regval(int ua, bool cgain) return ret; } +static int twl4030_charger_update_current(struct twl4030_bci *bci) +{ + int status; + unsigned reg, cur_reg; + u8 bcictl1, oldreg, fullreg; + bool cgain = false; + u8 boot_bci; + + /* First, check thresholds and see if cgain is needed */ + if (bci->ichg_eoc >= 200000) + cgain = true; + if (bci->ichg_lo >= 400000) + cgain = true; + if (bci->ichg_hi >= 820000) + cgain = true; + if (bci->cur > 852000) + cgain = true; + + status = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1); + if (status < 0) + return status; + if (twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &boot_bci, + TWL4030_PM_MASTER_BOOT_BCI) < 0) + boot_bci = 0; + boot_bci &= 7; + + if ((!!cgain) != !!(bcictl1 & TWL4030_CGAIN)) + /* Need to turn for charging while we change the + * CGAIN bit. Leave it off while everything is + * updated. + */ + twl4030_clear_set_boot_bci(boot_bci, 0); + + /* + * For ichg_eoc, the hardware only supports reg values matching + * 100XXXX000, and requires the XXXX be stored in the high nibble + * of TWL4030_BCIMFTH8. + */ + reg = ua2regval(bci->ichg_eoc, cgain); + if (reg > 0x278) + reg = 0x278; + if (reg < 0x200) + reg = 0x200; + reg = (reg >> 3) & 0xf; + fullreg = reg << 4; + + /* + * For ichg_lo, reg value must match 10XXXX0000. + * XXXX is stored in low nibble of TWL4030_BCIMFTH8. + */ + reg = ua2regval(bci->ichg_lo, cgain); + if (reg > 0x2F0) + reg = 0x2F0; + if (reg < 0x200) + reg = 0x200; + reg = (reg >> 4) & 0xf; + fullreg |= reg; + + /* ichg_eoc and ichg_lo live in same register */ + status = twl4030_bci_read(TWL4030_BCIMFTH8, &oldreg); + if (status < 0) + return status; + if (oldreg != fullreg) { + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xF4, + TWL4030_BCIMFKEY); + if (status < 0) + return status; + twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, + fullreg, TWL4030_BCIMFTH8); + } + + /* ichg_hi threshold must be 1XXXX01100 (I think) */ + reg = ua2regval(bci->ichg_hi, cgain); + if (reg > 0x3E0) + reg = 0x3E0; + if (reg < 0x200) + reg = 0x200; + fullreg = (reg >> 5) & 0xF; + fullreg <<= 4; + status = twl4030_bci_read(TWL4030_BCIMFTH9, &oldreg); + if (status < 0) + return status; + if ((oldreg & 0xF0) != fullreg) { + fullreg |= (oldreg & 0x0F); + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xE7, + TWL4030_BCIMFKEY); + if (status < 0) + return status; + twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, + fullreg, TWL4030_BCIMFTH9); + } + + /* + * And finally, set the current. This is stored in + * two registers. + */ + reg = ua2regval(bci->cur, cgain); + /* we have only 10 bits */ + if (reg > 0x3ff) + reg = 0x3ff; + status = twl4030_bci_read(TWL4030_BCIIREF1, &oldreg); + if (status < 0) + return status; + cur_reg = oldreg; + status = twl4030_bci_read(TWL4030_BCIIREF2, &oldreg); + if (status < 0) + return status; + cur_reg |= oldreg << 8; + if (reg != oldreg) { + /* disable write protection for one write access for + * BCIIREF */ + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xE7, + TWL4030_BCIMFKEY); + if (status < 0) + return status; + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, + (reg & 0x100) ? 3 : 2, + TWL4030_BCIIREF2); + if (status < 0) + return status; + /* disable write protection for one write access for + * BCIIREF */ + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xE7, + TWL4030_BCIMFKEY); + if (status < 0) + return status; + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, + reg & 0xff, + TWL4030_BCIIREF1); + } + if ((!!cgain) != !!(bcictl1 & TWL4030_CGAIN)) { + /* Flip CGAIN and re-enable charging */ + bcictl1 ^= TWL4030_CGAIN; + twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, + bcictl1, TWL4030_BCICTL1); + twl4030_clear_set_boot_bci(0, boot_bci); + } + return 0; +} + /* * Enable/Disable USB Charge functionality. */ @@ -219,14 +370,6 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) int ret; if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { - /* - * Until we can find out what current the device can provide, - * require a module param to enable USB charging. - */ - if (!allow_usb) { - dev_warn(bci->dev, "USB charging is disabled.\n"); - return -EACCES; - } /* Need to keep phy powered */ if (!bci->usb_enabled) { @@ -578,6 +721,14 @@ static int twl4030_bci_probe(struct platform_device *pdev) if (!pdata) pdata = twl4030_bci_parse_dt(&pdev->dev); + bci->ichg_eoc = 80100; /* Stop charging when current drops to here */ + bci->ichg_lo = 241000; /* Low threshold */ + bci->ichg_hi = 500000; /* High threshold */ + if (allow_usb) + bci->cur = 500000; /* 500mA */ + else + bci->cur = 100000; /* 100mA */ + bci->dev = &pdev->dev; bci->irq_chg = platform_get_irq(pdev, 0); bci->irq_bci = platform_get_irq(pdev, 1); @@ -657,6 +808,7 @@ static int twl4030_bci_probe(struct platform_device *pdev) if (ret < 0) dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret); + twl4030_charger_update_current(bci); twl4030_charger_enable_ac(true); if (!IS_ERR_OR_NULL(bci->transceiver)) twl4030_bci_usb_ncb(&bci->usb_nb, -- cgit v0.10.2 From e4ae537e0482e99eeaa5373d39932fe65a477c21 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: distinguish between USB current and 'AC' current The twl4030 charger has two current sources, 'USB' and 'AC' (presumably "Accessory Charger" because it isn't Alternating Current). If 'AC' is providing current, we should set the current limit differently to when it isn't (and so USB is used). So split 'cur' into 'usb_cur' and 'ac_cur' and use accordingly. Now we must review the current setting on any interrupt or USB event which might indicate that the charger-source has changed. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 3b7cc63..982675d 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -22,6 +22,7 @@ #include #include #include +#include #define TWL4030_BCIMSTATEC 0x02 #define TWL4030_BCIICHG 0x08 @@ -101,10 +102,13 @@ struct twl4030_bci { int usb_enabled; /* - * ichg values in uA. If any are 'large', we set CGAIN to - * '1' which doubles the range for half the precision. + * ichg_* and *_cur values in uA. If any are 'large', we set + * CGAIN to '1' which doubles the range for half the + * precision. */ - unsigned int ichg_eoc, ichg_lo, ichg_hi, cur; + unsigned int ichg_eoc, ichg_lo, ichg_hi; + unsigned int usb_cur, ac_cur; + bool ac_is_active; unsigned long event; }; @@ -225,11 +229,24 @@ static int ua2regval(int ua, bool cgain) static int twl4030_charger_update_current(struct twl4030_bci *bci) { int status; + int cur; unsigned reg, cur_reg; u8 bcictl1, oldreg, fullreg; bool cgain = false; u8 boot_bci; + /* + * If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11) + * and AC is enabled, set current for 'ac' + */ + if (twl4030_get_madc_conversion(11) > 4500) { + cur = bci->ac_cur; + bci->ac_is_active = true; + } else { + cur = bci->usb_cur; + bci->ac_is_active = false; + } + /* First, check thresholds and see if cgain is needed */ if (bci->ichg_eoc >= 200000) cgain = true; @@ -237,7 +254,7 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci) cgain = true; if (bci->ichg_hi >= 820000) cgain = true; - if (bci->cur > 852000) + if (cur > 852000) cgain = true; status = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1); @@ -318,7 +335,7 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci) * And finally, set the current. This is stored in * two registers. */ - reg = ua2regval(bci->cur, cgain); + reg = ua2regval(cur, cgain); /* we have only 10 bits */ if (reg > 0x3ff) reg = 0x3ff; @@ -371,6 +388,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { + twl4030_charger_update_current(bci); + /* Need to keep phy powered */ if (!bci->usb_enabled) { pm_runtime_get_sync(bci->transceiver->dev); @@ -463,6 +482,7 @@ static irqreturn_t twl4030_charger_interrupt(int irq, void *arg) struct twl4030_bci *bci = arg; dev_dbg(bci->dev, "CHG_PRES irq\n"); + twl4030_charger_update_current(bci); power_supply_changed(bci->ac); power_supply_changed(bci->usb); @@ -495,6 +515,7 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg) power_supply_changed(bci->ac); power_supply_changed(bci->usb); } + twl4030_charger_update_current(bci); /* various monitoring events, for now we just log them here */ if (irqs1 & (TWL4030_TBATOR2 | TWL4030_TBATOR1)) @@ -724,10 +745,11 @@ static int twl4030_bci_probe(struct platform_device *pdev) bci->ichg_eoc = 80100; /* Stop charging when current drops to here */ bci->ichg_lo = 241000; /* Low threshold */ bci->ichg_hi = 500000; /* High threshold */ + bci->ac_cur = 500000; /* 500mA */ if (allow_usb) - bci->cur = 500000; /* 500mA */ + bci->usb_cur = 500000; /* 500mA */ else - bci->cur = 100000; /* 100mA */ + bci->usb_cur = 100000; /* 100mA */ bci->dev = &pdev->dev; bci->irq_chg = platform_get_irq(pdev, 0); -- cgit v0.10.2 From aca3c3546396b305fff79f09883cff48a908aac0 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: allow max_current to be managed via sysfs. 'max_current' sysfs attributes are created which allow the max to be set. Whenever a current source changes, the default is restored. This will be followed by a uevent, so user-space can decide to update again. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 b/Documentation/ABI/testing/sysfs-class-power-twl4030 new file mode 100644 index 0000000..0331bba --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-power-twl4030 @@ -0,0 +1,15 @@ +What: /sys/class/power_supply/twl4030_ac/max_current + /sys/class/power_supply/twl4030_usb/max_current +Description: + Read/Write limit on current which may + be drawn from the ac (Accessory Charger) or + USB port. + + Value is in micro-Amps. + + Value is set automatically to an appropriate + value when a cable is plugged or unplugged. + + Value can the set by writing to the attribute. + The change will only persist until the next + plug event. These event are reported via udev. diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 982675d..b0a50ad 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -482,6 +482,8 @@ static irqreturn_t twl4030_charger_interrupt(int irq, void *arg) struct twl4030_bci *bci = arg; dev_dbg(bci->dev, "CHG_PRES irq\n"); + /* reset current on each 'plug' event */ + bci->ac_cur = 500000; twl4030_charger_update_current(bci); power_supply_changed(bci->ac); power_supply_changed(bci->usb); @@ -536,6 +538,63 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg) return IRQ_HANDLED; } +/* + * Provide "max_current" attribute in sysfs. + */ +static ssize_t +twl4030_bci_max_current_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct twl4030_bci *bci = dev_get_drvdata(dev->parent); + int cur = 0; + int status = 0; + status = kstrtoint(buf, 10, &cur); + if (status) + return status; + if (cur < 0) + return -EINVAL; + if (dev == &bci->ac->dev) + bci->ac_cur = cur; + else + bci->usb_cur = cur; + + twl4030_charger_update_current(bci); + return n; +} + +/* + * sysfs max_current show + */ +static ssize_t twl4030_bci_max_current_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int status = 0; + int cur = -1; + u8 bcictl1; + struct twl4030_bci *bci = dev_get_drvdata(dev->parent); + + if (dev == &bci->ac->dev) { + if (!bci->ac_is_active) + cur = bci->ac_cur; + } else { + if (bci->ac_is_active) + cur = bci->usb_cur; + } + if (cur < 0) { + cur = twl4030bci_read_adc_val(TWL4030_BCIIREF1); + if (cur < 0) + return cur; + status = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1); + if (status < 0) + return status; + cur = regval2ua(cur, bcictl1 & TWL4030_CGAIN); + } + return scnprintf(buf, PAGE_SIZE, "%u\n", cur); +} + +static DEVICE_ATTR(max_current, 0644, twl4030_bci_max_current_show, + twl4030_bci_max_current_store); + static void twl4030_bci_usb_work(struct work_struct *data) { struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work); @@ -558,6 +617,12 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, dev_dbg(bci->dev, "OTG notify %lu\n", val); + /* reset current on each 'plug' event */ + if (allow_usb) + bci->usb_cur = 500000; + else + bci->usb_cur = 100000; + bci->event = val; schedule_work(&bci->work); @@ -831,6 +896,11 @@ static int twl4030_bci_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret); twl4030_charger_update_current(bci); + if (device_create_file(&bci->usb->dev, &dev_attr_max_current)) + dev_warn(&pdev->dev, "could not create sysfs file\n"); + if (device_create_file(&bci->ac->dev, &dev_attr_max_current)) + dev_warn(&pdev->dev, "could not create sysfs file\n"); + twl4030_charger_enable_ac(true); if (!IS_ERR_OR_NULL(bci->transceiver)) twl4030_bci_usb_ncb(&bci->usb_nb, @@ -855,6 +925,8 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) twl4030_charger_enable_usb(bci, false); twl4030_charger_enable_backup(0, 0); + device_remove_file(&bci->usb->dev, &dev_attr_max_current); + device_remove_file(&bci->ac->dev, &dev_attr_max_current); /* mask interrupts */ twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, TWL4030_INTERRUPTS_BCIIMR1A); -- cgit v0.10.2 From 22d4c33f7335ddf6deda26630c78650e133bfe72 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: enable manual enable/disable of usb charging. 'off' or 'auto' to /sys/class/power/twl4030_usb/mode will now enable or disable charging from USB port. Normally this is enabled on 'plug' and disabled on 'unplug'. Unplug will still disable charging. 'plug' will only enable it if 'auto' if selected. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 b/Documentation/ABI/testing/sysfs-class-power-twl4030 index 0331bba..40e0f91 100644 --- a/Documentation/ABI/testing/sysfs-class-power-twl4030 +++ b/Documentation/ABI/testing/sysfs-class-power-twl4030 @@ -13,3 +13,14 @@ Description: Value can the set by writing to the attribute. The change will only persist until the next plug event. These event are reported via udev. + + +What: /sys/class/power_supply/twl4030_usb/mode +Description: + Changing mode for USB port. + Writing to this can disable charging. + + Possible values are: + "auto" - draw power as appropriate for detected + power source and battery status. + "off" - do not draw any power. diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index b0a50ad..6fa928e 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -109,10 +109,16 @@ struct twl4030_bci { unsigned int ichg_eoc, ichg_lo, ichg_hi; unsigned int usb_cur, ac_cur; bool ac_is_active; + int usb_mode; /* charging mode requested */ +#define CHARGE_OFF 0 +#define CHARGE_AUTO 1 unsigned long event; }; +/* strings for 'usb_mode' values */ +static char *modes[] = { "off", "auto" }; + /* * clear and set bits on an given register on a given module */ @@ -386,6 +392,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) { int ret; + if (bci->usb_mode == CHARGE_OFF) + enable = false; if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { twl4030_charger_update_current(bci); @@ -629,6 +637,53 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, return NOTIFY_OK; } +/* + * sysfs charger enabled store + */ +static ssize_t +twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct twl4030_bci *bci = dev_get_drvdata(dev->parent); + int mode; + int status; + + if (sysfs_streq(buf, modes[0])) + mode = 0; + else if (sysfs_streq(buf, modes[1])) + mode = 1; + else + return -EINVAL; + twl4030_charger_enable_usb(bci, false); + bci->usb_mode = mode; + status = twl4030_charger_enable_usb(bci, true); + return (status == 0) ? n : status; +} + +/* + * sysfs charger enabled show + */ +static ssize_t +twl4030_bci_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct twl4030_bci *bci = dev_get_drvdata(dev->parent); + int len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(modes); i++) + if (bci->usb_mode == i) + len += snprintf(buf+len, PAGE_SIZE-len, + "[%s] ", modes[i]); + else + len += snprintf(buf+len, PAGE_SIZE-len, + "%s ", modes[i]); + buf[len-1] = '\n'; + return len; +} +static DEVICE_ATTR(mode, 0644, twl4030_bci_mode_show, + twl4030_bci_mode_store); + static int twl4030_charger_get_current(void) { int curr; @@ -815,6 +870,7 @@ static int twl4030_bci_probe(struct platform_device *pdev) bci->usb_cur = 500000; /* 500mA */ else bci->usb_cur = 100000; /* 100mA */ + bci->usb_mode = CHARGE_AUTO; bci->dev = &pdev->dev; bci->irq_chg = platform_get_irq(pdev, 0); @@ -898,6 +954,8 @@ static int twl4030_bci_probe(struct platform_device *pdev) twl4030_charger_update_current(bci); if (device_create_file(&bci->usb->dev, &dev_attr_max_current)) dev_warn(&pdev->dev, "could not create sysfs file\n"); + if (device_create_file(&bci->usb->dev, &dev_attr_mode)) + dev_warn(&pdev->dev, "could not create sysfs file\n"); if (device_create_file(&bci->ac->dev, &dev_attr_max_current)) dev_warn(&pdev->dev, "could not create sysfs file\n"); @@ -926,6 +984,7 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) twl4030_charger_enable_backup(0, 0); device_remove_file(&bci->usb->dev, &dev_attr_max_current); + device_remove_file(&bci->usb->dev, &dev_attr_mode); device_remove_file(&bci->ac->dev, &dev_attr_max_current); /* mask interrupts */ twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, -- cgit v0.10.2 From 7f4a633d21331155ee06c5ee44749ed35a3a3cc5 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: add software controlled linear charging mode. Add a 'continuous' option for usb charging which enables the "linear" charging mode of the twl4030. Linear charging does a good job with not-so-reliable power sources. Auto mode does not work well as it switches off when voltage drops momentarily. Care must be taken not to over-charge. It was used with a bike hub dynamo since a year or so. In that case there are automatically charging stops when the cyclist needs a break. Original-by: Andreas Kemnade Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 b/Documentation/ABI/testing/sysfs-class-power-twl4030 index 40e0f91..e8baa36 100644 --- a/Documentation/ABI/testing/sysfs-class-power-twl4030 +++ b/Documentation/ABI/testing/sysfs-class-power-twl4030 @@ -24,3 +24,12 @@ Description: "auto" - draw power as appropriate for detected power source and battery status. "off" - do not draw any power. + "continuous" + - activate mode described as "linear" in + TWL data sheets. This uses whatever + current is available and doesn't switch off + when voltage drops. + + This is useful for unstable power sources + such as bicycle dynamo, but care should + be taken that battery is not over-charged. diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 6fa928e..de5430d 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -24,6 +24,8 @@ #include #include +#define TWL4030_BCIMDEN 0x00 +#define TWL4030_BCIMDKEY 0x01 #define TWL4030_BCIMSTATEC 0x02 #define TWL4030_BCIICHG 0x08 #define TWL4030_BCIVAC 0x0a @@ -35,13 +37,16 @@ #define TWL4030_BCIIREF1 0x27 #define TWL4030_BCIIREF2 0x28 #define TWL4030_BCIMFKEY 0x11 +#define TWL4030_BCIMFEN3 0x14 #define TWL4030_BCIMFTH8 0x1d #define TWL4030_BCIMFTH9 0x1e +#define TWL4030_BCIWDKEY 0x21 #define TWL4030_BCIMFSTS1 0x01 #define TWL4030_BCIAUTOWEN BIT(5) #define TWL4030_CONFIG_DONE BIT(4) +#define TWL4030_CVENAC BIT(2) #define TWL4030_BCIAUTOUSB BIT(1) #define TWL4030_BCIAUTOAC BIT(0) #define TWL4030_CGAIN BIT(5) @@ -112,12 +117,13 @@ struct twl4030_bci { int usb_mode; /* charging mode requested */ #define CHARGE_OFF 0 #define CHARGE_AUTO 1 +#define CHARGE_LINEAR 2 unsigned long event; }; /* strings for 'usb_mode' values */ -static char *modes[] = { "off", "auto" }; +static char *modes[] = { "off", "auto", "continuous" }; /* * clear and set bits on an given register on a given module @@ -404,16 +410,42 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) bci->usb_enabled = 1; } - /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */ - ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB); - if (ret < 0) - return ret; + if (bci->usb_mode == CHARGE_AUTO) + /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */ + ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB); /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */ ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE, 0, TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4); + if (bci->usb_mode == CHARGE_LINEAR) { + twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC|TWL4030_CVENAC, 0); + /* Watch dog key: WOVF acknowledge */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33, + TWL4030_BCIWDKEY); + /* 0x24 + EKEY6: off mode */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a, + TWL4030_BCIMDKEY); + /* EKEY2: Linear charge: USB path */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x26, + TWL4030_BCIMDKEY); + /* WDKEY5: stop watchdog count */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf3, + TWL4030_BCIWDKEY); + /* enable MFEN3 access */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x9c, + TWL4030_BCIMFKEY); + /* ICHGEOCEN - end-of-charge monitor (current < 80mA) + * (charging continues) + * ICHGLOWEN - current level monitor (charge continues) + * don't monitor over-current or heat save + */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf0, + TWL4030_BCIMFEN3); + } } else { ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0); + ret |= twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a, + TWL4030_BCIMDKEY); if (bci->usb_enabled) { pm_runtime_mark_last_busy(bci->transceiver->dev); pm_runtime_put_autosuspend(bci->transceiver->dev); @@ -652,6 +684,8 @@ twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr, mode = 0; else if (sysfs_streq(buf, modes[1])) mode = 1; + else if (sysfs_streq(buf, modes[2])) + mode = 2; else return -EINVAL; twl4030_charger_enable_usb(bci, false); @@ -750,6 +784,17 @@ static int twl4030_bci_get_property(struct power_supply *psy, is_charging = state & TWL4030_MSTATEC_USB; else is_charging = state & TWL4030_MSTATEC_AC; + if (!is_charging) { + u8 s; + twl4030_bci_read(TWL4030_BCIMDEN, &s); + if (psy->desc->type == POWER_SUPPLY_TYPE_USB) + is_charging = s & 1; + else + is_charging = s & 2; + if (is_charging) + /* A little white lie */ + state = TWL4030_MSTATEC_QUICK1; + } switch (psp) { case POWER_SUPPLY_PROP_STATUS: -- cgit v0.10.2 From b04b908d8a2901c2cc59db87defd9c08bd4293cc Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: add ac/mode to match usb/mode This allows AC charging to be turned off, much like usb charging. "continuous" mode is not available though. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 b/Documentation/ABI/testing/sysfs-class-power-twl4030 index e8baa36..be26af0 100644 --- a/Documentation/ABI/testing/sysfs-class-power-twl4030 +++ b/Documentation/ABI/testing/sysfs-class-power-twl4030 @@ -33,3 +33,13 @@ Description: This is useful for unstable power sources such as bicycle dynamo, but care should be taken that battery is not over-charged. + +What: /sys/class/power_supply/twl4030_ac/mode +Description: + Changing mode for 'ac' port. + Writing to this can disable charging. + + Possible values are: + "auto" - draw power as appropriate for detected + power source and battery status. + "off" - do not draw any power. diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index de5430d..68117ad 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -114,7 +114,7 @@ struct twl4030_bci { unsigned int ichg_eoc, ichg_lo, ichg_hi; unsigned int usb_cur, ac_cur; bool ac_is_active; - int usb_mode; /* charging mode requested */ + int usb_mode, ac_mode; /* charging mode requested */ #define CHARGE_OFF 0 #define CHARGE_AUTO 1 #define CHARGE_LINEAR 2 @@ -459,10 +459,13 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) /* * Enable/Disable AC Charge funtionality. */ -static int twl4030_charger_enable_ac(bool enable) +static int twl4030_charger_enable_ac(struct twl4030_bci *bci, bool enable) { int ret; + if (bci->ac_mode == CHARGE_OFF) + enable = false; + if (enable) ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOAC); else @@ -688,9 +691,17 @@ twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr, mode = 2; else return -EINVAL; - twl4030_charger_enable_usb(bci, false); - bci->usb_mode = mode; - status = twl4030_charger_enable_usb(bci, true); + if (dev == &bci->ac->dev) { + if (mode == 2) + return -EINVAL; + twl4030_charger_enable_ac(bci, false); + bci->ac_mode = mode; + status = twl4030_charger_enable_ac(bci, true); + } else { + twl4030_charger_enable_usb(bci, false); + bci->usb_mode = mode; + status = twl4030_charger_enable_usb(bci, true); + } return (status == 0) ? n : status; } @@ -704,9 +715,13 @@ twl4030_bci_mode_show(struct device *dev, struct twl4030_bci *bci = dev_get_drvdata(dev->parent); int len = 0; int i; + int mode = bci->usb_mode; + + if (dev == &bci->ac->dev) + mode = bci->ac_mode; for (i = 0; i < ARRAY_SIZE(modes); i++) - if (bci->usb_mode == i) + if (mode == i) len += snprintf(buf+len, PAGE_SIZE-len, "[%s] ", modes[i]); else @@ -916,6 +931,7 @@ static int twl4030_bci_probe(struct platform_device *pdev) else bci->usb_cur = 100000; /* 100mA */ bci->usb_mode = CHARGE_AUTO; + bci->ac_mode = CHARGE_AUTO; bci->dev = &pdev->dev; bci->irq_chg = platform_get_irq(pdev, 0); @@ -1001,10 +1017,12 @@ static int twl4030_bci_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "could not create sysfs file\n"); if (device_create_file(&bci->usb->dev, &dev_attr_mode)) dev_warn(&pdev->dev, "could not create sysfs file\n"); + if (device_create_file(&bci->ac->dev, &dev_attr_mode)) + dev_warn(&pdev->dev, "could not create sysfs file\n"); if (device_create_file(&bci->ac->dev, &dev_attr_max_current)) dev_warn(&pdev->dev, "could not create sysfs file\n"); - twl4030_charger_enable_ac(true); + twl4030_charger_enable_ac(bci, true); if (!IS_ERR_OR_NULL(bci->transceiver)) twl4030_bci_usb_ncb(&bci->usb_nb, bci->transceiver->last_event, @@ -1024,13 +1042,14 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) { struct twl4030_bci *bci = platform_get_drvdata(pdev); - twl4030_charger_enable_ac(false); + twl4030_charger_enable_ac(bci, false); twl4030_charger_enable_usb(bci, false); twl4030_charger_enable_backup(0, 0); device_remove_file(&bci->usb->dev, &dev_attr_max_current); device_remove_file(&bci->usb->dev, &dev_attr_mode); device_remove_file(&bci->ac->dev, &dev_attr_max_current); + device_remove_file(&bci->ac->dev, &dev_attr_mode); /* mask interrupts */ twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, TWL4030_INTERRUPTS_BCIIMR1A); -- cgit v0.10.2 From 21ae40404f3ca66fb37dd26e7b67eb109f2453ab Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: Increase current carefully while watching voltage. The USB Battery Charging spec (BC1.2) suggests a dedicated charging port can deliver from 0.5 to 5.0A at between 4.75 and 5.25 volts. To choose the "correct" current voltage setting requires a trial and error approach: try to draw current and see if the voltage drops too low. Even with a configured Standard Downstream Port, it may not be possible to reliably pull 500mA - depending on cable quality and source quality I have reports of charging failure due to the voltage dropping too low. To address both these concerns, this patch introduce incremental current setting. The current pull from VBUS is increased in steps of 20mA every 100ms until the target is reached or until the measure voltage drops below 4.75V. If the voltage does go too low, the target current is reduced by 20mA and kept there. This applies to currents selected automatically, or to values set via sysfs. So setting a large value will cause the maximum available to be used - up to the limit of 1.7A imposed by the hardware. Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 68117ad..2c537ee 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -119,6 +119,18 @@ struct twl4030_bci { #define CHARGE_AUTO 1 #define CHARGE_LINEAR 2 + /* When setting the USB current we slowly increase the + * requested current until target is reached or the voltage + * drops below 4.75V. In the latter case we step back one + * step. + */ + unsigned int usb_cur_target; + struct delayed_work current_worker; +#define USB_CUR_STEP 20000 /* 20mA at a time */ +#define USB_MIN_VOLT 4750000 /* 4.75V */ +#define USB_CUR_DELAY msecs_to_jiffies(100) +#define USB_MAX_CURRENT 1700000 /* TWL4030 caps at 1.7A */ + unsigned long event; }; @@ -257,6 +269,12 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci) } else { cur = bci->usb_cur; bci->ac_is_active = false; + if (cur > bci->usb_cur_target) { + cur = bci->usb_cur_target; + bci->usb_cur = cur; + } + if (cur < bci->usb_cur_target) + schedule_delayed_work(&bci->current_worker, USB_CUR_DELAY); } /* First, check thresholds and see if cgain is needed */ @@ -391,6 +409,41 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci) return 0; } +static int twl4030_charger_get_current(void); + +static void twl4030_current_worker(struct work_struct *data) +{ + int v, curr; + int res; + struct twl4030_bci *bci = container_of(data, struct twl4030_bci, + current_worker.work); + + res = twl4030bci_read_adc_val(TWL4030_BCIVBUS); + if (res < 0) + v = 0; + else + /* BCIVBUS uses ADCIN8, 7/1023 V/step */ + v = res * 6843; + curr = twl4030_charger_get_current(); + + dev_dbg(bci->dev, "v=%d cur=%d limit=%d target=%d\n", v, curr, + bci->usb_cur, bci->usb_cur_target); + + if (v < USB_MIN_VOLT) { + /* Back up and stop adjusting. */ + bci->usb_cur -= USB_CUR_STEP; + bci->usb_cur_target = bci->usb_cur; + } else if (bci->usb_cur >= bci->usb_cur_target || + bci->usb_cur + USB_CUR_STEP > USB_MAX_CURRENT) { + /* Reached target and voltage is OK - stop */ + return; + } else { + bci->usb_cur += USB_CUR_STEP; + schedule_delayed_work(&bci->current_worker, USB_CUR_DELAY); + } + twl4030_charger_update_current(bci); +} + /* * Enable/Disable USB Charge functionality. */ @@ -451,6 +504,7 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) pm_runtime_put_autosuspend(bci->transceiver->dev); bci->usb_enabled = 0; } + bci->usb_cur = 0; } return ret; @@ -599,7 +653,7 @@ twl4030_bci_max_current_store(struct device *dev, struct device_attribute *attr, if (dev == &bci->ac->dev) bci->ac_cur = cur; else - bci->usb_cur = cur; + bci->usb_cur_target = cur; twl4030_charger_update_current(bci); return n; @@ -621,7 +675,7 @@ static ssize_t twl4030_bci_max_current_show(struct device *dev, cur = bci->ac_cur; } else { if (bci->ac_is_active) - cur = bci->usb_cur; + cur = bci->usb_cur_target; } if (cur < 0) { cur = twl4030bci_read_adc_val(TWL4030_BCIIREF1); @@ -662,9 +716,9 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, /* reset current on each 'plug' event */ if (allow_usb) - bci->usb_cur = 500000; + bci->usb_cur_target = 500000; else - bci->usb_cur = 100000; + bci->usb_cur_target = 100000; bci->event = val; schedule_work(&bci->work); @@ -927,9 +981,9 @@ static int twl4030_bci_probe(struct platform_device *pdev) bci->ichg_hi = 500000; /* High threshold */ bci->ac_cur = 500000; /* 500mA */ if (allow_usb) - bci->usb_cur = 500000; /* 500mA */ + bci->usb_cur_target = 500000; /* 500mA */ else - bci->usb_cur = 100000; /* 100mA */ + bci->usb_cur_target = 100000; /* 100mA */ bci->usb_mode = CHARGE_AUTO; bci->ac_mode = CHARGE_AUTO; @@ -980,6 +1034,7 @@ static int twl4030_bci_probe(struct platform_device *pdev) } INIT_WORK(&bci->work, twl4030_bci_usb_work); + INIT_DELAYED_WORK(&bci->current_worker, twl4030_current_worker); bci->usb_nb.notifier_call = twl4030_bci_usb_ncb; if (bci->dev->of_node) { -- cgit v0.10.2 From 63369b2b99d718ca2777bf8d71360de75888f05b Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 18:18:33 +0200 Subject: power: Export I2C module alias information in missing drivers The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Sebastian Reichel diff --git a/drivers/power/bq24190_charger.c b/drivers/power/bq24190_charger.c index 703ebec..bb6d85b 100644 --- a/drivers/power/bq24190_charger.c +++ b/drivers/power/bq24190_charger.c @@ -1515,6 +1515,7 @@ static const struct i2c_device_id bq24190_i2c_ids[] = { { "bq24190", BQ24190_REG_VPRS_PN_24190 }, { }, }; +MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids); #ifdef CONFIG_OF static const struct of_device_id bq24190_of_match[] = { diff --git a/drivers/power/rt5033_battery.c b/drivers/power/rt5033_battery.c index a7a6877..bcdd830 100644 --- a/drivers/power/rt5033_battery.c +++ b/drivers/power/rt5033_battery.c @@ -165,7 +165,7 @@ static const struct i2c_device_id rt5033_battery_id[] = { { "rt5033-battery", }, { } }; -MODULE_DEVICE_TABLE(platform, rt5033_battery_id); +MODULE_DEVICE_TABLE(i2c, rt5033_battery_id); static struct i2c_driver rt5033_battery_driver = { .driver = { -- cgit v0.10.2 From 1e8b82c1ff3bc52c5e4265d66fe5c6da9a66e2e6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 2 Aug 2015 11:09:50 +0200 Subject: power: Allow compile test of GPIO consumers if !GPIOLIB The GPIO subsystem provides dummy GPIO consumer functions if GPIOLIB is not enabled. Hence drivers that depend on GPIOLIB, but use GPIO consumer functionality only, can still be compiled if GPIOLIB is not enabled. Relax the dependency on GPIOLIB if COMPILE_TEST is enabled, where appropriate. Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Signed-off-by: Sebastian Reichel diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 08beeed..f8758d6 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -333,7 +333,7 @@ config CHARGER_LP8788 config CHARGER_GPIO tristate "GPIO charger" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Say Y to include support for chargers which report their online status through a GPIO pin. @@ -391,26 +391,30 @@ config CHARGER_BQ2415X config CHARGER_BQ24190 tristate "TI BQ24190 battery charger driver" - depends on I2C && GPIOLIB + depends on I2C + depends on GPIOLIB || COMPILE_TEST help Say Y to enable support for the TI BQ24190 battery charger. config CHARGER_BQ24257 tristate "TI BQ24257 battery charger driver" - depends on I2C && GPIOLIB + depends on I2C + depends on GPIOLIB || COMPILE_TEST depends on REGMAP_I2C help Say Y to enable support for the TI BQ24257 battery charger. config CHARGER_BQ24735 tristate "TI BQ24735 battery charger support" - depends on I2C && GPIOLIB + depends on I2C + depends on GPIOLIB || COMPILE_TEST help Say Y to enable support for the TI BQ24735 battery charger. config CHARGER_BQ25890 tristate "TI BQ25890 battery charger driver" - depends on I2C && GPIOLIB + depends on I2C + depends on GPIOLIB || COMPILE_TEST select REGMAP_I2C help Say Y to enable support for the TI BQ25890 battery charger. @@ -462,7 +466,8 @@ config BATTERY_RT5033 config CHARGER_RT9455 tristate "Richtek RT9455 battery charger driver" - depends on I2C && GPIOLIB + depends on I2C + depends on GPIOLIB || COMPILE_TEST select REGMAP_I2C help Say Y to enable support for Richtek RT9455 battery charger. -- cgit v0.10.2 From c9f85a90d41476aca2d3b60f98ab87d7ae1b8612 Mon Sep 17 00:00:00 2001 From: Andreas Dannenberg Date: Tue, 4 Aug 2015 11:36:17 -0500 Subject: power: bq24190_charger: Fix charge type sysfs property Access to the BQ24190's configurable charge type property (none, trickle, fast) is being masked by an incorrect power_supply_property entry. After applying this patch a new 'charge_type' property will appear in the bq24190-charger sysfs folder backed up by getters/setters already present in the driver. Signed-off-by: Andreas Dannenberg Acked-by: Dan Murphy Acked-by: Andrew F. Davis Signed-off-by: Sebastian Reichel diff --git a/drivers/power/bq24190_charger.c b/drivers/power/bq24190_charger.c index bb6d85b..469a452 100644 --- a/drivers/power/bq24190_charger.c +++ b/drivers/power/bq24190_charger.c @@ -902,7 +902,7 @@ static int bq24190_charger_property_is_writeable(struct power_supply *psy, } static enum power_supply_property bq24190_charger_properties[] = { - POWER_SUPPLY_PROP_TYPE, + POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, -- cgit v0.10.2 From b49d15d138aa4632f35a2db93dee775d920f3653 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 7 Aug 2015 13:45:25 +1000 Subject: twl4030_charger: fix compile error when TWL4030_MADC not available. We can only use the madc to check for 'ac' availability if the madc has been compiled in. If not: assume always using USB. Reported-by: Tony Lindgren Signed-off-by: NeilBrown Acked-by: Tony Lindgren Signed-off-by: Sebastian Reichel diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 2c537ee..f4f2c1f 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -91,6 +91,21 @@ #define TWL4030_MSTATEC_COMPLETE1 0x0b #define TWL4030_MSTATEC_COMPLETE4 0x0e +#if IS_ENABLED(CONFIG_TWL4030_MADC) +/* + * If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11) + * then AC is available. + */ +static inline int ac_available(void) +{ + return twl4030_get_madc_conversion(11) > 4500; +} +#else +static inline int ac_available(void) +{ + return 0; +} +#endif static bool allow_usb; module_param(allow_usb, bool, 0644); MODULE_PARM_DESC(allow_usb, "Allow USB charge drawing default current"); @@ -263,7 +278,7 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci) * If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11) * and AC is enabled, set current for 'ac' */ - if (twl4030_get_madc_conversion(11) > 4500) { + if (ac_available()) { cur = bci->ac_cur; bci->ac_is_active = true; } else { -- cgit v0.10.2 From b68c3161430a4c7c0a001e658188bfea6a2fe5bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 11 Aug 2015 13:22:19 +0200 Subject: bq2415x_charger: Allow to load and use driver even if notify device is not registered yet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Driver bq2415x_charger works also without notify power supply device for charger detection. But when charger detection is specified in DT, then bq2415x_charger refused to loaded with -EPROBE_DEFER. This patch rewrites code so that notify device for charger detection is checked when power supply event is received and not when registering power supply device. So this patch allows to use bq2415x_charger driver also when kernel is compiled without driver for notify power supply device. Now after this patch scheduled workqueue is called after INIT_DELAYED_WORK, so it also fix problem when scheduled workqueue was called before init. Signed-off-by: Pali Rohár Signed-off-by: Sebastian Reichel diff --git a/drivers/power/bq2415x_charger.c b/drivers/power/bq2415x_charger.c index e98dcb6..ec212b5 100644 --- a/drivers/power/bq2415x_charger.c +++ b/drivers/power/bq2415x_charger.c @@ -170,7 +170,7 @@ struct bq2415x_device { struct power_supply *charger; struct power_supply_desc charger_desc; struct delayed_work work; - struct power_supply *notify_psy; + struct device_node *notify_node; struct notifier_block nb; enum bq2415x_mode reported_mode;/* mode reported by hook function */ enum bq2415x_mode mode; /* currently configured mode */ @@ -792,22 +792,47 @@ static int bq2415x_set_mode(struct bq2415x_device *bq, enum bq2415x_mode mode) } +static bool bq2415x_update_reported_mode(struct bq2415x_device *bq, int mA) +{ + enum bq2415x_mode mode; + + if (mA == 0) + mode = BQ2415X_MODE_OFF; + else if (mA < 500) + mode = BQ2415X_MODE_NONE; + else if (mA < 1800) + mode = BQ2415X_MODE_HOST_CHARGER; + else + mode = BQ2415X_MODE_DEDICATED_CHARGER; + + if (bq->reported_mode == mode) + return false; + + bq->reported_mode = mode; + return true; +} + static int bq2415x_notifier_call(struct notifier_block *nb, unsigned long val, void *v) { struct bq2415x_device *bq = container_of(nb, struct bq2415x_device, nb); struct power_supply *psy = v; - enum bq2415x_mode mode; union power_supply_propval prop; int ret; - int mA; if (val != PSY_EVENT_PROP_CHANGED) return NOTIFY_OK; - if (psy != bq->notify_psy) - return NOTIFY_OK; + /* Ignore event if it was not send by notify_node/notify_device */ + if (bq->notify_node) { + if (!psy->dev.parent || + psy->dev.parent->of_node != bq->notify_node) + return NOTIFY_OK; + } else if (bq->init_data.notify_device) { + if (strcmp(psy->desc->name, bq->init_data.notify_device) != 0) + return NOTIFY_OK; + } dev_dbg(bq->dev, "notifier call was called\n"); @@ -816,22 +841,9 @@ static int bq2415x_notifier_call(struct notifier_block *nb, if (ret != 0) return NOTIFY_OK; - mA = prop.intval; - - if (mA == 0) - mode = BQ2415X_MODE_OFF; - else if (mA < 500) - mode = BQ2415X_MODE_NONE; - else if (mA < 1800) - mode = BQ2415X_MODE_HOST_CHARGER; - else - mode = BQ2415X_MODE_DEDICATED_CHARGER; - - if (bq->reported_mode == mode) + if (!bq2415x_update_reported_mode(bq, prop.intval)) return NOTIFY_OK; - bq->reported_mode = mode; - /* if automode is not enabled do not tell about reported_mode */ if (bq->automode < 1) return NOTIFY_OK; @@ -1536,6 +1548,8 @@ static int bq2415x_probe(struct i2c_client *client, struct device_node *np = client->dev.of_node; struct bq2415x_platform_data *pdata = client->dev.platform_data; const struct acpi_device_id *acpi_id = NULL; + struct power_supply *notify_psy = NULL; + union power_supply_propval prop; if (!np && !pdata && !ACPI_HANDLE(&client->dev)) { dev_err(&client->dev, "Neither devicetree, nor platform data, nor ACPI support\n"); @@ -1569,25 +1583,6 @@ static int bq2415x_probe(struct i2c_client *client, goto error_2; } - if (np) { - bq->notify_psy = power_supply_get_by_phandle(np, - "ti,usb-charger-detection"); - - if (IS_ERR(bq->notify_psy)) { - dev_info(&client->dev, - "no 'ti,usb-charger-detection' property (err=%ld)\n", - PTR_ERR(bq->notify_psy)); - bq->notify_psy = NULL; - } else if (!bq->notify_psy) { - ret = -EPROBE_DEFER; - goto error_2; - } - } else if (pdata && pdata->notify_device) { - bq->notify_psy = power_supply_get_by_name(pdata->notify_device); - } else { - bq->notify_psy = NULL; - } - i2c_set_clientdata(client, bq); bq->id = num; @@ -1607,32 +1602,35 @@ static int bq2415x_probe(struct i2c_client *client, "ti,current-limit", &bq->init_data.current_limit); if (ret) - goto error_3; + goto error_2; ret = device_property_read_u32(bq->dev, "ti,weak-battery-voltage", &bq->init_data.weak_battery_voltage); if (ret) - goto error_3; + goto error_2; ret = device_property_read_u32(bq->dev, "ti,battery-regulation-voltage", &bq->init_data.battery_regulation_voltage); if (ret) - goto error_3; + goto error_2; ret = device_property_read_u32(bq->dev, "ti,charge-current", &bq->init_data.charge_current); if (ret) - goto error_3; + goto error_2; ret = device_property_read_u32(bq->dev, "ti,termination-current", &bq->init_data.termination_current); if (ret) - goto error_3; + goto error_2; ret = device_property_read_u32(bq->dev, "ti,resistor-sense", &bq->init_data.resistor_sense); if (ret) - goto error_3; + goto error_2; + if (np) + bq->notify_node = of_parse_phandle(np, + "ti,usb-charger-detection", 0); } else { memcpy(&bq->init_data, pdata, sizeof(bq->init_data)); } @@ -1642,56 +1640,72 @@ static int bq2415x_probe(struct i2c_client *client, ret = bq2415x_power_supply_init(bq); if (ret) { dev_err(bq->dev, "failed to register power supply: %d\n", ret); - goto error_3; + goto error_2; } ret = bq2415x_sysfs_init(bq); if (ret) { dev_err(bq->dev, "failed to create sysfs entries: %d\n", ret); - goto error_4; + goto error_3; } ret = bq2415x_set_defaults(bq); if (ret) { dev_err(bq->dev, "failed to set default values: %d\n", ret); - goto error_5; + goto error_4; } - if (bq->notify_psy) { + if (bq->notify_node || bq->init_data.notify_device) { bq->nb.notifier_call = bq2415x_notifier_call; ret = power_supply_reg_notifier(&bq->nb); if (ret) { dev_err(bq->dev, "failed to reg notifier: %d\n", ret); - goto error_6; + goto error_4; } - /* Query for initial reported_mode and set it */ - bq2415x_notifier_call(&bq->nb, PSY_EVENT_PROP_CHANGED, - bq->notify_psy); - bq2415x_set_mode(bq, bq->reported_mode); - bq->automode = 1; - dev_info(bq->dev, "automode enabled\n"); + dev_info(bq->dev, "automode supported, waiting for events\n"); } else { bq->automode = -1; dev_info(bq->dev, "automode not supported\n"); } + /* Query for initial reported_mode and set it */ + if (bq->nb.notifier_call) { + if (np) { + notify_psy = power_supply_get_by_phandle(np, + "ti,usb-charger-detection"); + if (IS_ERR(notify_psy)) + notify_psy = NULL; + } else if (bq->init_data.notify_device) { + notify_psy = power_supply_get_by_name( + bq->init_data.notify_device); + } + } + if (notify_psy) { + ret = power_supply_get_property(notify_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &prop); + power_supply_put(notify_psy); + + if (ret == 0) { + bq2415x_update_reported_mode(bq, prop.intval); + bq2415x_set_mode(bq, bq->reported_mode); + } + } + INIT_DELAYED_WORK(&bq->work, bq2415x_timer_work); bq2415x_set_autotimer(bq, 1); dev_info(bq->dev, "driver registered\n"); return 0; -error_6: -error_5: - bq2415x_sysfs_exit(bq); error_4: - bq2415x_power_supply_exit(bq); + bq2415x_sysfs_exit(bq); error_3: - if (bq->notify_psy) - power_supply_put(bq->notify_psy); + bq2415x_power_supply_exit(bq); error_2: + if (bq->notify_node) + of_node_put(bq->notify_node); kfree(name); error_1: mutex_lock(&bq2415x_id_mutex); @@ -1707,10 +1721,11 @@ static int bq2415x_remove(struct i2c_client *client) { struct bq2415x_device *bq = i2c_get_clientdata(client); - if (bq->notify_psy) { + if (bq->nb.notifier_call) power_supply_unreg_notifier(&bq->nb); - power_supply_put(bq->notify_psy); - } + + if (bq->notify_node) + of_node_put(bq->notify_node); bq2415x_sysfs_exit(bq); bq2415x_power_supply_exit(bq); -- cgit v0.10.2