From patchwork Mon Jan 21 12:03:55 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lee Jones X-Patchwork-Id: 2011801 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id 5D3A83FD1A for ; Mon, 21 Jan 2013 12:14:42 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TxGDn-0001bJ-5q; Mon, 21 Jan 2013 12:11:27 +0000 Received: from mail-wi0-f176.google.com ([209.85.212.176]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1TxG8W-0006ZU-Kh for linux-arm-kernel@lists.infradead.org; Mon, 21 Jan 2013 12:06:18 +0000 Received: by mail-wi0-f176.google.com with SMTP id hm6so7065389wib.15 for ; Mon, 21 Jan 2013 04:04:56 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:x-gm-message-state; bh=JboUGrxbeYrbMeexa8Ogt1Q4Irgpu0Ron78eYEVhXJM=; b=YIXcNw7lR5aQSVvszOKZxgXVffNYI5bTj7r8MVHgTdm3BvE9L/9vupKDpp5egV+9Y9 81OieV42I4K4NGnwqKk3YzALPo7yvEm7l2i8aIvYWqJS7o5wDpSxfeLS0u9snrNDtyB2 gN6Kh7iSi8Hl4h0MZClRUQr0LkLLlW3BG2dMsxQppawKZ14X7k4vHqsI78k8Uy4yJ5Nx vVYNKtFU2abRt+KJQC+Il4QM6t3HPQCGOspqnz0LMkwX6mBXBoM8MHYFoPAj1RlF+qoj M/9Vv3DNiINtDRsz0Eox4A6CBqvnjNjlkRaUfC7I9WeMBrWXTEZuRoOLNVxZSTGVi6LX eGzg== X-Received: by 10.180.20.109 with SMTP id m13mr15050818wie.16.1358769896259; Mon, 21 Jan 2013 04:04:56 -0800 (PST) Received: from localhost.localdomain (cpc34-aztw25-2-0-cust250.18-1.cable.virginmedia.com. [86.16.136.251]) by mx.google.com with ESMTPS id i2sm16575305wiw.3.2013.01.21.04.04.54 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 21 Jan 2013 04:04:55 -0800 (PST) From: Lee Jones To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH 19/24] pm2301: LPN mode control support Date: Mon, 21 Jan 2013 12:03:55 +0000 Message-Id: <1358769840-4763-20-git-send-email-lee.jones@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1358769840-4763-1-git-send-email-lee.jones@linaro.org> References: <1358769840-4763-1-git-send-email-lee.jones@linaro.org> X-Gm-Message-State: ALoCoQkNSfpLZeV71s9u3GE5Y5VWXp2btzFO7aOEV0AGYgCzUuaJ+pWUROTvO54ON33Irkpbl6HX X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130121_070601_017167_C71772D8 X-CRM114-Status: GOOD ( 17.87 ) X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.212.176 listed in list.dnswl.org] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: linus.walleij@stericsson.com, arnd@arndb.de, cbou@mail.ru, Rupesh Kumar , anton.vorontsov@linaro.org, Lee Jones X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Rupesh Kumar The AC charger plug-in detection while booting causes I2C read failure if AC charger is not connected. Now the LPN pin is enabled for every PM2301 register access, which solves the issue. Signed-off-by: Lee Jones Signed-off-by: Rupesh Kumar Reviewed-by: Marcus COOPER Reviewed-by: Vijaya Kumar K-1 Reviewed-by: Rabin VINCENT Reviewed-by: Jonas ABERG Tested-by: Jonas ABERG --- drivers/power/pm2301_charger.c | 72 ++++++++++++++++++++++++++++++++++++++-- drivers/power/pm2301_charger.h | 1 + include/linux/pm2301_charger.h | 1 + 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/drivers/power/pm2301_charger.c b/drivers/power/pm2301_charger.c index c7d92b3..14e37b2 100644 --- a/drivers/power/pm2301_charger.c +++ b/drivers/power/pm2301_charger.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "pm2301_charger.h" @@ -110,9 +111,35 @@ static const struct i2c_device_id pm2xxx_ident[] = { { } }; +static void set_lpn_pin(struct pm2xxx_charger *pm2) +{ + if (pm2->ac.charger_connected) + return; + gpio_set_value(pm2->lpn_pin, 1); + + return; +} + +static void clear_lpn_pin(struct pm2xxx_charger *pm2) +{ + if (pm2->ac.charger_connected) + return; + gpio_set_value(pm2->lpn_pin, 0); + + return; +} + int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val) { int ret; + /* + * When AC adaptor is unplugged, the host + * must put LPN high to be able to + * communicate by I2C with PM2301 + * and receive I2C "acknowledge" from PM2301. + */ + mutex_lock(&pm2->lock); + set_lpn_pin(pm2); ret = i2c_smbus_read_i2c_block_data(pm2->config.pm2xxx_i2c, reg, 1, val); @@ -120,6 +147,8 @@ int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val) dev_err(pm2->dev, "Error reading register at 0x%x\n", reg); else ret = 0; + clear_lpn_pin(pm2); + mutex_unlock(&pm2->lock); return ret; } @@ -127,6 +156,14 @@ int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val) int pm2xxx_reg_write(struct pm2xxx_charger *pm2, int reg, u8 val) { int ret; + /* + * When AC adaptor is unplugged, the host + * must put LPN high to be able to + * communicate by I2C with PM2301 + * and receive I2C "acknowledge" from PM2301. + */ + mutex_lock(&pm2->lock); + set_lpn_pin(pm2); ret = i2c_smbus_write_i2c_block_data(pm2->config.pm2xxx_i2c, reg, 1, &val); @@ -134,6 +171,8 @@ int pm2xxx_reg_write(struct pm2xxx_charger *pm2, int reg, u8 val) dev_err(pm2->dev, "Error writing register at 0x%x\n", reg); else ret = 0; + clear_lpn_pin(pm2); + mutex_unlock(&pm2->lock); return ret; } @@ -850,6 +889,14 @@ static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client, pm2->bat = pl_data->battery; + /*get lpn GPIO from platform data*/ + if (!pm2->pdata->lpn_gpio) { + dev_err(pm2->dev, "no lpn gpio data supplied\n"); + ret = -EINVAL; + goto free_device_info; + } + pm2->lpn_pin = pm2->pdata->lpn_gpio; + if (!i2c_check_functionality(i2c_client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_READ_WORD_DATA)) { @@ -929,10 +976,25 @@ static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client, goto unregister_pm2xxx_charger; } + /*Initialize lock*/ + mutex_init(&pm2->lock); + /* - * I2C Read/Write will fail, if AC adaptor is not connected. - * fix the charger detection mechanism. + * Charger detection mechanism requires pulling up the LPN pin + * while i2c communication if Charger is not connected + * LPN pin of PM2301 is GPIO60 of AB9540 */ + ret = gpio_request(pm2->lpn_pin, "pm2301_lpm_gpio"); + if (ret < 0) { + dev_err(pm2->dev, "pm2301_lpm_gpio request failed\n"); + goto unregister_pm2xxx_charger; + } + ret = gpio_direction_output(pm2->lpn_pin, 0); + if (ret < 0) { + dev_err(pm2->dev, "pm2301_lpm_gpio direction failed\n"); + goto free_gpio; + } + ret = pm2xxx_charger_detection(pm2, &val); if ((ret == 0) && val) { @@ -951,7 +1013,8 @@ static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client, err_deep_debug: /* disable interrupt */ free_irq(pm2->pdata->irq_number, pm2); - +free_gpio: + gpio_free(pm2->lpn_pin); unregister_pm2xxx_charger: /* unregister power supply */ power_supply_unregister(&pm2->ac_chg.psy); @@ -987,6 +1050,9 @@ static int __devexit pm2xxx_wall_charger_remove(struct i2c_client *i2c_client) power_supply_unregister(&pm2->ac_chg.psy); + /*Free GPIO60*/ + gpio_free(pm2->lpn_pin); + kfree(pm2); return 0; diff --git a/drivers/power/pm2301_charger.h b/drivers/power/pm2301_charger.h index 5ae3573..c28babc 100644 --- a/drivers/power/pm2301_charger.h +++ b/drivers/power/pm2301_charger.h @@ -493,6 +493,7 @@ struct pm2xxx_charger { int old_vbat; int failure_case; int failure_input_ovv; + unsigned int lpn_pin; struct pm2xxx_interrupts *pm2_int; struct ab8500_gpadc *gpadc; struct regulator *regu; diff --git a/include/linux/pm2301_charger.h b/include/linux/pm2301_charger.h index 16bb1d3..fc3f026 100644 --- a/include/linux/pm2301_charger.h +++ b/include/linux/pm2301_charger.h @@ -49,6 +49,7 @@ struct pm2xxx_charger_platform_data { int i2c_bus; const char *label; int irq_number; + unsigned int lpn_gpio; int irq_type; };