From patchwork Tue Jan 31 00:02:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Lindgren X-Patchwork-Id: 9546209 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A484260425 for ; Tue, 31 Jan 2017 00:02:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 964BB283F9 for ; Tue, 31 Jan 2017 00:02:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8AF8128407; Tue, 31 Jan 2017 00:02:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E5073283F9 for ; Tue, 31 Jan 2017 00:02:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754660AbdAaAC0 (ORCPT ); Mon, 30 Jan 2017 19:02:26 -0500 Received: from muru.com ([72.249.23.125]:32952 "EHLO muru.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754598AbdAaACY (ORCPT ); Mon, 30 Jan 2017 19:02:24 -0500 Received: from sampyla.muru.com. (localhost [127.0.0.1]) by muru.com (Postfix) with ESMTP id C6AC98419; Tue, 31 Jan 2017 00:03:23 +0000 (UTC) From: Tony Lindgren To: Sebastian Reichel Cc: Liam Breck , "Mark A . Greer" , linux-pm@vger.kernel.org, linux-omap@vger.kernel.org Subject: [PATCH 2/2] power: bq24190_charger: Use PM runtime autosuspend Date: Mon, 30 Jan 2017 16:02:10 -0800 Message-Id: <20170131000210.5442-3-tony@atomide.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170131000210.5442-1-tony@atomide.com> References: <20170131000210.5442-1-tony@atomide.com> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP We can get quite a few interrupts when the battery is trickle charging. Let's enable PM runtime autosuspend to avoid constantly toggling device driver PM runtime state. Let's use a 600 ms timeout as that's how long the USB chager detection might take. Cc: Liam Breck Acked-by: Mark Greer Acked-by: Liam Breck Signed-off-by: Tony Lindgren --- drivers/power/supply/bq24190_charger.c | 153 ++++++++++++++++++++++++--------- 1 file changed, 111 insertions(+), 42 deletions(-) diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -420,6 +420,7 @@ static ssize_t bq24190_sysfs_show(struct device *dev, struct power_supply *psy = dev_get_drvdata(dev); struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy); struct bq24190_sysfs_field_info *info; + ssize_t count; int ret; u8 v; @@ -427,11 +428,20 @@ static ssize_t bq24190_sysfs_show(struct device *dev, if (!info) return -EINVAL; + ret = pm_runtime_get_sync(bdi->dev); + if (ret < 0) + return ret; + ret = bq24190_read_mask(bdi, info->reg, info->mask, info->shift, &v); if (ret) - return ret; + count = ret; + else + count = scnprintf(buf, PAGE_SIZE, "%hhx\n", v); - return scnprintf(buf, PAGE_SIZE, "%hhx\n", v); + pm_runtime_mark_last_busy(bdi->dev); + pm_runtime_put_autosuspend(bdi->dev); + + return count; } static ssize_t bq24190_sysfs_store(struct device *dev, @@ -451,9 +461,16 @@ static ssize_t bq24190_sysfs_store(struct device *dev, if (ret < 0) return ret; + ret = pm_runtime_get_sync(bdi->dev); + if (ret < 0) + return ret; + ret = bq24190_write_mask(bdi, info->reg, info->mask, info->shift, v); if (ret) - return ret; + count = ret; + + pm_runtime_mark_last_busy(bdi->dev); + pm_runtime_put_autosuspend(bdi->dev); return count; } @@ -795,7 +812,9 @@ static int bq24190_charger_get_property(struct power_supply *psy, dev_dbg(bdi->dev, "prop: %d\n", psp); - pm_runtime_get_sync(bdi->dev); + ret = pm_runtime_get_sync(bdi->dev); + if (ret < 0) + return ret; switch (psp) { case POWER_SUPPLY_PROP_CHARGE_TYPE: @@ -835,7 +854,9 @@ static int bq24190_charger_get_property(struct power_supply *psy, ret = -ENODATA; } - pm_runtime_put_sync(bdi->dev); + pm_runtime_mark_last_busy(bdi->dev); + pm_runtime_put_autosuspend(bdi->dev); + return ret; } @@ -848,7 +869,9 @@ static int bq24190_charger_set_property(struct power_supply *psy, dev_dbg(bdi->dev, "prop: %d\n", psp); - pm_runtime_get_sync(bdi->dev); + ret = pm_runtime_get_sync(bdi->dev); + if (ret < 0) + return ret; switch (psp) { case POWER_SUPPLY_PROP_CHARGE_TYPE: @@ -864,7 +887,9 @@ static int bq24190_charger_set_property(struct power_supply *psy, ret = -EINVAL; } - pm_runtime_put_sync(bdi->dev); + pm_runtime_mark_last_busy(bdi->dev); + pm_runtime_put_autosuspend(bdi->dev); + return ret; } @@ -1065,7 +1090,9 @@ static int bq24190_battery_get_property(struct power_supply *psy, dev_dbg(bdi->dev, "prop: %d\n", psp); - pm_runtime_get_sync(bdi->dev); + ret = pm_runtime_get_sync(bdi->dev); + if (ret < 0) + return ret; switch (psp) { case POWER_SUPPLY_PROP_STATUS: @@ -1093,7 +1120,9 @@ static int bq24190_battery_get_property(struct power_supply *psy, ret = -ENODATA; } - pm_runtime_put_sync(bdi->dev); + pm_runtime_mark_last_busy(bdi->dev); + pm_runtime_put_autosuspend(bdi->dev); + return ret; } @@ -1106,7 +1135,9 @@ static int bq24190_battery_set_property(struct power_supply *psy, dev_dbg(bdi->dev, "prop: %d\n", psp); - pm_runtime_get_sync(bdi->dev); + ret = pm_runtime_get_sync(bdi->dev); + if (ret < 0) + return ret; switch (psp) { case POWER_SUPPLY_PROP_ONLINE: @@ -1119,7 +1150,9 @@ static int bq24190_battery_set_property(struct power_supply *psy, ret = -EINVAL; } - pm_runtime_put_sync(bdi->dev); + pm_runtime_mark_last_busy(bdi->dev); + pm_runtime_put_autosuspend(bdi->dev); + return ret; } @@ -1234,11 +1267,15 @@ static void bq24190_check_status(struct bq24190_dev_info *bdi) static irqreturn_t bq24190_irq_handler_thread(int irq, void *data) { struct bq24190_dev_info *bdi = data; + int ret; bdi->irq_event = true; - pm_runtime_get_sync(bdi->dev); + ret = pm_runtime_get_sync(bdi->dev); + if (ret < 0) + return ret; bq24190_check_status(bdi); - pm_runtime_put_sync(bdi->dev); + pm_runtime_mark_last_busy(bdi->dev); + pm_runtime_put_autosuspend(bdi->dev); bdi->irq_event = false; return IRQ_HANDLED; @@ -1249,33 +1286,26 @@ static int bq24190_hw_init(struct bq24190_dev_info *bdi) u8 v; int ret; - pm_runtime_get_sync(bdi->dev); - /* First check that the device really is what its supposed to be */ ret = bq24190_read_mask(bdi, BQ24190_REG_VPRS, BQ24190_REG_VPRS_PN_MASK, BQ24190_REG_VPRS_PN_SHIFT, &v); if (ret < 0) - goto out; + return ret; - if (v != bdi->model) { - ret = -ENODEV; - goto out; - } + if (v != bdi->model) + return -ENODEV; ret = bq24190_register_reset(bdi); if (ret < 0) - goto out; + return ret; ret = bq24190_set_mode_host(bdi); if (ret < 0) - goto out; + return ret; - ret = bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg); -out: - pm_runtime_put_sync(bdi->dev); - return ret; + return bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg); } #ifdef CONFIG_OF @@ -1364,12 +1394,16 @@ static int bq24190_probe(struct i2c_client *client, } pm_runtime_enable(dev); - pm_runtime_resume(dev); + pm_runtime_set_autosuspend_delay(dev, 600); + pm_runtime_use_autosuspend(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) + goto out1; ret = bq24190_hw_init(bdi); if (ret < 0) { dev_err(dev, "Hardware init failed\n"); - goto out1; + goto out2; } charger_cfg.drv_data = bdi; @@ -1380,7 +1414,7 @@ static int bq24190_probe(struct i2c_client *client, if (IS_ERR(bdi->charger)) { dev_err(dev, "Can't register charger\n"); ret = PTR_ERR(bdi->charger); - goto out1; + goto out2; } battery_cfg.drv_data = bdi; @@ -1389,13 +1423,13 @@ static int bq24190_probe(struct i2c_client *client, if (IS_ERR(bdi->battery)) { dev_err(dev, "Can't register battery\n"); ret = PTR_ERR(bdi->battery); - goto out2; + goto out3; } ret = bq24190_sysfs_create_group(bdi); if (ret) { dev_err(dev, "Can't create sysfs entries\n"); - goto out3; + goto out4; } bdi->initialized = true; @@ -1406,21 +1440,30 @@ static int bq24190_probe(struct i2c_client *client, "bq24190-charger", bdi); if (ret < 0) { dev_err(dev, "Can't set up irq handler\n"); - goto out4; + goto out5; } + enable_irq_wake(bdi->irq); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return 0; -out4: +out5: bq24190_sysfs_remove_group(bdi); -out3: +out4: power_supply_unregister(bdi->battery); -out2: +out3: power_supply_unregister(bdi->charger); +out2: + pm_runtime_put_sync(dev); + out1: + pm_runtime_dont_use_autosuspend(dev); pm_runtime_disable(dev); if (bdi->gpio_int) gpio_free(bdi->gpio_int); @@ -1430,14 +1473,20 @@ static int bq24190_probe(struct i2c_client *client, static int bq24190_remove(struct i2c_client *client) { struct bq24190_dev_info *bdi = i2c_get_clientdata(client); + int error; - pm_runtime_get_sync(bdi->dev); - bq24190_register_reset(bdi); - pm_runtime_put_sync(bdi->dev); + error = pm_runtime_get_sync(bdi->dev); + if (error < 0) { + dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", error); + pm_runtime_put_noidle(bdi->dev); + } + bq24190_register_reset(bdi); bq24190_sysfs_remove_group(bdi); power_supply_unregister(bdi->battery); power_supply_unregister(bdi->charger); + pm_runtime_dont_use_autosuspend(bdi->dev); + pm_runtime_put_sync(bdi->dev); pm_runtime_disable(bdi->dev); if (bdi->gpio_int) @@ -1480,10 +1529,20 @@ static int bq24190_pm_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct bq24190_dev_info *bdi = i2c_get_clientdata(client); + int error; + + error = pm_runtime_get_sync(bdi->dev); + if (error < 0) { + dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", error); + pm_runtime_put_noidle(bdi->dev); + } - pm_runtime_get_sync(bdi->dev); bq24190_register_reset(bdi); - pm_runtime_put_sync(bdi->dev); + + if (!error) { + pm_runtime_mark_last_busy(bdi->dev); + pm_runtime_put_autosuspend(bdi->dev); + } return 0; } @@ -1492,15 +1551,25 @@ static int bq24190_pm_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct bq24190_dev_info *bdi = i2c_get_clientdata(client); + int error; bdi->f_reg = 0; bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */ - pm_runtime_get_sync(bdi->dev); + error = pm_runtime_get_sync(bdi->dev); + if (error < 0) { + pm_runtime_put_noidle(bdi->dev); + dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", error); + } + bq24190_register_reset(bdi); bq24190_set_mode_host(bdi); bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg); - pm_runtime_put_sync(bdi->dev); + + if (!error) { + pm_runtime_mark_last_busy(bdi->dev); + pm_runtime_put_autosuspend(bdi->dev); + } /* Things may have changed while suspended so alert upper layer */ power_supply_changed(bdi->charger);