From patchwork Mon Feb 24 10:10:39 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Krzysztof Kozlowski X-Patchwork-Id: 3708691 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 41D78BF13A for ; Mon, 24 Feb 2014 11:15:25 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 0AEAD2013A for ; Mon, 24 Feb 2014 11:15:24 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2333420149 for ; Mon, 24 Feb 2014 11:15:22 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WHsZG-0000pf-Tk; Mon, 24 Feb 2014 10:15:23 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WHsYi-0006fV-An; Mon, 24 Feb 2014 10:14:48 +0000 Received: from mailout1.w1.samsung.com ([210.118.77.11]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WHsWS-0006ID-3G for linux-arm-kernel@lists.infradead.org; Mon, 24 Feb 2014 10:13:03 +0000 Received: from eucpsbgm2.samsung.com (unknown [203.254.199.245]) by mailout1.w1.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0N1H00A5JWAZAO30@mailout1.w1.samsung.com> for linux-arm-kernel@lists.infradead.org; Mon, 24 Feb 2014 10:11:23 +0000 (GMT) X-AuditID: cbfec7f5-b7fc96d000004885-fd-530b1ac969f5 Received: from eusync1.samsung.com ( [203.254.199.211]) by eucpsbgm2.samsung.com (EUCPMTA) with SMTP id 5E.1D.18565.9CA1B035; Mon, 24 Feb 2014 10:11:21 +0000 (GMT) Received: from AMDC1943.digital.local ([106.116.151.171]) by eusync1.samsung.com (Oracle Communications Messaging Server 7u4-23.01(7.0.4.23.0) 64bit (built Aug 10 2011)) with ESMTPA id <0N1H00JSEWAG6E50@eusync1.samsung.com>; Mon, 24 Feb 2014 10:11:21 +0000 (GMT) From: Krzysztof Kozlowski To: Chanwoo Choi , Samuel Ortiz , Lee Jones , Mark Brown , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Dmitry Eremin-Solenikov , David Woodhouse Subject: [PATCH v4 14/16] charger: max14577: Configure battery-dependent settings from DTS Date: Mon, 24 Feb 2014 11:10:39 +0100 Message-id: <1393236641-14977-15-git-send-email-k.kozlowski@samsung.com> X-Mailer: git-send-email 1.7.9.5 In-reply-to: <1393236641-14977-1-git-send-email-k.kozlowski@samsung.com> References: <1393236641-14977-1-git-send-email-k.kozlowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrOLMWRmVeSWpSXmKPExsVy+t/xy7onpbiDDVbPtrbYOGM9q8XUh0/Y LK5/ec5qMenJe2aLiSsnM1us/drDbvH6haHF2aY37Bb3vx5ltNj0+BqrxeVdc9gs1h65y25x upvVYv2M1ywOfB47Z91l99i8Qstj8Z6XTB6bVnWyedy5tofNY97JQI/NS+o9+rasYvT4vEku gDOKyyYlNSezLLVI3y6BK2P3wsssBYsTK27PWMLewHg2oIuRk0NCwESi92orM4QtJnHh3nq2 LkYuDiGBpYwSH9deY4Jw+pgkunbfYwOpYhMwlti8fAlYlYjAFiaJ3g9fGEESzAJtTBKLPpmD 2MICMRJL7i9nAbFZBFQlPv2fDFTDwcEr4CEx40IRiCkhoCAxZ5INSAUnUPRuywNWEFtIwF3i 27zrLBMYeRcwMqxiFE0tTS4oTkrPNdIrTswtLs1L10vOz93ECAncrzsYlx6zOsQowMGoxMMr Uc0VLMSaWFZcmXuIUYKDWUmE14yXO1iINyWxsiq1KD++qDQntfgQIxMHp1QDY6TnEhdTT1Wu +mX7OyqibbY3M135mpUrlWf8yu9AeIxlwLJD6dfZeQKrKiOmFX5p3Gq+3Hj9dzGfA0prbiYn x0SdXnmu2ae9WfgUw8YbV5t2e0UVCnImmy7/9PfWIo4bt5h5m1LlNteckJVNEpQo4Xj90ic1 /VyOkVx3+u1Hx/ymd93a1ntViaU4I9FQi7moOBEAApLEezoCAAA= X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140224_051228_308654_6C1E74B5 X-CRM114-Status: GOOD ( 22.94 ) X-Spam-Score: -3.8 (---) Cc: Krzysztof Kozlowski , Bartlomiej Zolnierkiewicz , Tomasz Figa , Kyungmin Park , Jenny Tc , Marek Szyprowski X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-1.1 required=5.0 tests=BAYES_00,KHOP_BIG_TO_CC, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Remove hard-coded values for: - Fast Charge current, - End Of Charge current, - Fast Charge timer, - Overvoltage Protection Threshold, - Battery Constant Voltage, and use DTS to configure them. This allows using the max14577 charger driver with different batteries. Now the charger driver requires valid configuration data from DTS. In case of wrong configuration data it fails during probe. Patch adds of_compatible to the charger mfd cell in MFD driver core. Signed-off-by: Krzysztof Kozlowski Cc: Kyungmin Park Cc: Marek Szyprowski Cc: Dmitry Eremin-Solenikov Cc: David Woodhouse Cc: Jenny Tc Acked-by: Lee Jones --- drivers/mfd/max14577.c | 5 +- drivers/power/max14577_charger.c | 235 +++++++++++++++++++++++++++++----- include/linux/mfd/max14577-private.h | 16 +++ include/linux/mfd/max14577.h | 8 ++ 4 files changed, 234 insertions(+), 30 deletions(-) diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index 03fde3e5d1fb..1017d562b09d 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -115,7 +115,10 @@ static struct mfd_cell max14577_devs[] = { .name = "max14577-regulator", .of_compatible = "maxim,max14577-regulator", }, - { .name = "max14577-charger", }, + { + .name = "max14577-charger", + .of_compatible = "maxim,max14577-charger", + }, }; static struct mfd_cell max77836_devs[] = { diff --git a/drivers/power/max14577_charger.c b/drivers/power/max14577_charger.c index 405f4d736337..bdad6d42f33e 100644 --- a/drivers/power/max14577_charger.c +++ b/drivers/power/max14577_charger.c @@ -19,6 +19,7 @@ #include #include #include +#include struct max14577_charger { struct device *dev; @@ -27,6 +28,8 @@ struct max14577_charger { unsigned int charging_state; unsigned int battery_state; + + struct max14577_charger_platform_data *pdata; }; /* @@ -180,15 +183,107 @@ static int max14577_get_present(struct max14577_charger *chg) return 1; } +static inline int max14577_init_constant_voltage(struct max14577_charger *chg, + unsigned int uvolt) +{ + u8 reg_data; + + if (uvolt < MAXIM_CHARGER_CONSTANT_VOLTAGE_MIN || + uvolt > MAXIM_CHARGER_CONSTANT_VOLTAGE_MAX) + return -EINVAL; + + if (uvolt == 4200000) + reg_data = 0x0; + else if (uvolt == MAXIM_CHARGER_CONSTANT_VOLTAGE_MAX) + reg_data = 0x1f; + else if (uvolt <= 4280000) { + unsigned int val = uvolt; + + val -= MAXIM_CHARGER_CONSTANT_VOLTAGE_MIN; + val /= MAXIM_CHARGER_CONSTANT_VOLTAGE_STEP; + if (uvolt <= 4180000) + reg_data = 0x1 + val; + else + reg_data = val; /* Fix for gap between 4.18V and 4.22V */ + } else + return -EINVAL; + + reg_data <<= MAXIM_CHGCTRL3_MBCCVWRC_SHIFT; + + return max14577_write_reg(chg->maxim_core->regmap_muic, + MAXIM_CHG_REG_CHGCTRL3, reg_data); +} + +static inline int max14577_init_eoc(struct max14577_charger *chg, + unsigned int uamp) +{ + unsigned int current_bits = 0xf; + u8 reg_data; + + switch (chg->maxim_core->dev_type) { + case MAXIM_DEVICE_TYPE_MAX77836: + if (uamp < 5000) + return -EINVAL; /* Requested current is too low */ + + if (uamp >= 7500 && uamp < 10000) + current_bits = 0x0; + else if (uamp <= 50000) { + /* <5000, 7499> and <10000, 50000> */ + current_bits = uamp / 5000; + } else { + uamp = min(uamp, 100000U) - 50000U; + current_bits = 0xa + uamp / 10000; + } + break; + + case MAXIM_DEVICE_TYPE_MAX14577: + default: + if (uamp < MAX14577_CHARGER_EOC_CURRENT_LIMIT_MIN) + return -EINVAL; /* Requested current is too low */ + + uamp = min(uamp, MAX14577_CHARGER_EOC_CURRENT_LIMIT_MAX); + uamp -= MAX14577_CHARGER_EOC_CURRENT_LIMIT_MIN; + current_bits = uamp / MAX14577_CHARGER_EOC_CURRENT_LIMIT_STEP; + break; + } + + reg_data = current_bits << MAXIM_CHGCTRL5_EOCS_SHIFT; + + return max14577_update_reg(chg->maxim_core->regmap_muic, + MAXIM_CHG_REG_CHGCTRL5, MAXIM_CHGCTRL5_EOCS_MASK, + reg_data); +} + +static inline int max14577_init_fast_charge(struct max14577_charger *chg, + unsigned int uamp) +{ + u8 reg_data; + int ret; + const struct maxim_charger_current *limits = + &maxim_charger_currents[chg->maxim_core->dev_type]; + + ret = maxim_charger_calc_reg_current(limits, uamp, uamp, ®_data); + if (ret) { + dev_err(chg->dev, "Wrong value for fast charge: %u\n", uamp); + return ret; + } + + return max14577_update_reg(chg->maxim_core->regmap_muic, + MAXIM_CHG_REG_CHGCTRL4, + MAXIM_CHGCTRL4_MBCICHWRCL_MASK | MAXIM_CHGCTRL4_MBCICHWRCH_MASK, + reg_data); +} + /* * Sets charger registers to proper and safe default values. * Some of these values are equal to defaults in MAX14577E * data sheet but there are minor differences. */ -static void max14577_charger_reg_init(struct max14577_charger *chg) +static int max14577_charger_reg_init(struct max14577_charger *chg) { struct regmap *rmap = chg->maxim_core->regmap_muic; u8 reg_data; + int ret; /* * Charger-Type Manual Detection, default off (set CHGTYPMAN to 0) @@ -198,12 +293,7 @@ static void max14577_charger_reg_init(struct max14577_charger *chg) reg_data = 0x1 << MAXIM_CDETCTRL1_CHGDETEN_SHIFT; max14577_update_reg(rmap, MAXIM_MUIC_REG_CDETCTRL1, MAXIM_CDETCTRL1_CHGDETEN_MASK | - MAXIM_CDETCTRL1_CHGTYPMAN_MASK, - reg_data); - - /* Battery Fast-Charge Timer, set to: 6hrs */ - reg_data = 0x3 << MAXIM_CHGCTRL1_TCHW_SHIFT; - max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL1, reg_data); + MAXIM_CDETCTRL1_CHGTYPMAN_MASK, reg_data); /* * Wall-Adapter Rapid Charge, default on @@ -213,32 +303,57 @@ static void max14577_charger_reg_init(struct max14577_charger *chg) reg_data |= 0x1 << MAXIM_CHGCTRL2_MBCHOSTEN_SHIFT; max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL2, reg_data); - /* Battery-Charger Constant Voltage (CV) Mode, set to: 4.35V */ - reg_data = 0xf << MAXIM_CHGCTRL3_MBCCVWRC_SHIFT; - max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL3, reg_data); - - /* - * Fast Battery-Charge Current Low, - * default 200-950mA (max14577) / 100-475mA (max77836) - * - * Fast Battery-Charge Current High, - * set to 450mA (max14577) / 225mA (max77836) - */ - reg_data = 0x1 << MAXIM_CHGCTRL4_MBCICHWRCL_SHIFT; - reg_data |= 0x5 << MAXIM_CHGCTRL4_MBCICHWRCH_SHIFT; - max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL4, reg_data); - - /* End-of-Charge Current, set to 50mA (max14577) / 7.5mA (max77836) */ - reg_data = 0x0 << MAXIM_CHGCTRL5_EOCS_SHIFT; - max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL5, reg_data); - /* Auto Charging Stop, default off */ reg_data = 0x0 << MAXIM_CHGCTRL6_AUTOSTOP_SHIFT; max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL6, reg_data); - /* Overvoltage-Protection Threshold, set to 6.5V */ - reg_data = 0x2 << MAXIM_CHGCTRL7_OTPCGHCVS_SHIFT; + ret = max14577_init_constant_voltage(chg, chg->pdata->constant_uvolt); + if (ret) + return ret; + + ret = max14577_init_eoc(chg, chg->pdata->eoc_uamp); + if (ret) + return ret; + + ret = max14577_init_fast_charge(chg, chg->pdata->fast_charge_uamp); + if (ret) + return ret; + + /* Initialize Battery Fast-Charge Timer */ + switch (chg->pdata->fast_charge_timer) { + case 5 ... 7: + reg_data = chg->pdata->fast_charge_timer - 3; + break; + case 0: + /* Disable */ + reg_data = 0x7; + default: + dev_err(chg->dev, "Wrong value for Fast-Charge Timer: %u\n", + chg->pdata->fast_charge_timer); + return -EINVAL; + } + reg_data <<= MAXIM_CHGCTRL1_TCHW_SHIFT; + max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL1, reg_data); + + /* Initialize Overvoltage-Protection Threshold */ + switch (chg->pdata->ovp_uvolt) { + case 7500000: + reg_data = 0x0; + break; + case 6000000: + case 6500000: + case 7000000: + reg_data = 0x1 + (chg->pdata->ovp_uvolt - 6000000) / 500000; + break; + default: + dev_err(chg->dev, "Wrong value for OVP: %u\n", + chg->pdata->ovp_uvolt); + return -EINVAL; + } + reg_data <<= MAXIM_CHGCTRL7_OTPCGHCVS_SHIFT; max14577_write_reg(rmap, MAXIM_CHG_REG_CHGCTRL7, reg_data); + + return 0; } /* Support property from charger */ @@ -298,6 +413,58 @@ static int max14577_charger_get_property(struct power_supply *psy, return ret; } +#ifdef CONFIG_OF +static struct max14577_charger_platform_data *max14577_charger_dt_init( + struct platform_device *pdev) +{ + struct max14577_charger_platform_data *pdata; + struct device_node *np = pdev->dev.of_node; + int ret; + + if (!np) { + dev_err(&pdev->dev, "No charger OF node\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "Memory alloc for charger pdata failed\n"); + return ERR_PTR(-ENOMEM); + } + + ret = of_property_read_u32(np, "maxim,fast-charge-timer", + &pdata->fast_charge_timer); + if (ret) + return ERR_PTR(ret); + + ret = of_property_read_u32(np, "maxim,constant-uvolt", + &pdata->constant_uvolt); + if (ret) + return ERR_PTR(ret); + + ret = of_property_read_u32(np, "maxim,fast-charge-uamp", + &pdata->fast_charge_uamp); + if (ret) + return ERR_PTR(ret); + + ret = of_property_read_u32(np, "maxim,eoc-uamp", &pdata->eoc_uamp); + if (ret) + return ERR_PTR(ret); + + ret = of_property_read_u32(np, "maxim,ovp-uvolt", &pdata->ovp_uvolt); + if (ret) + return ERR_PTR(ret); + + return pdata; +} +#else /* CONFIG_OF */ +static struct max14577_charger_platform_data *max14577_charger_dt_init( + struct platform_device *pdev) +{ + return NULL; +} +#endif /* CONFIG_OF */ + static int max14577_charger_probe(struct platform_device *pdev) { struct max14577_charger *chg; @@ -312,7 +479,13 @@ static int max14577_charger_probe(struct platform_device *pdev) chg->dev = &pdev->dev; chg->maxim_core = maxim_core; - max14577_charger_reg_init(chg); + chg->pdata = max14577_charger_dt_init(pdev); + if (IS_ERR_OR_NULL(chg->pdata)) + return PTR_ERR(chg->pdata); + + ret = max14577_charger_reg_init(chg); + if (ret) + return ret; chg->charger.name = "max14577-charger", chg->charger.type = POWER_SUPPLY_TYPE_BATTERY, @@ -326,6 +499,10 @@ static int max14577_charger_probe(struct platform_device *pdev) return ret; } + /* Check for valid values for charger */ + BUILD_BUG_ON(MAX14577_CHARGER_EOC_CURRENT_LIMIT_MIN + + MAX14577_CHARGER_EOC_CURRENT_LIMIT_STEP * 0xf != + MAX14577_CHARGER_EOC_CURRENT_LIMIT_MAX); return 0; } diff --git a/include/linux/mfd/max14577-private.h b/include/linux/mfd/max14577-private.h index a8cd7de3526a..33700662fbb4 100644 --- a/include/linux/mfd/max14577-private.h +++ b/include/linux/mfd/max14577-private.h @@ -269,6 +269,22 @@ enum maxim_muic_charger_type { #define MAX77836_CHARGER_CURRENT_LIMIT_HIGH_STEP 25000U #define MAX77836_CHARGER_CURRENT_LIMIT_MAX 475000U +/* + * MAX14577 charger End-Of-Charge current limits + * (as in MAXIM_CHGCTRL5 register), uA + */ +#define MAX14577_CHARGER_EOC_CURRENT_LIMIT_MIN 50000U +#define MAX14577_CHARGER_EOC_CURRENT_LIMIT_STEP 10000U +#define MAX14577_CHARGER_EOC_CURRENT_LIMIT_MAX 200000U + +/* + * MAX14577/MAX77836 Battery Constant Voltage + * (as in MAXIM_CHGCTRL3 register), uV + */ +#define MAXIM_CHARGER_CONSTANT_VOLTAGE_MIN 4000000U +#define MAXIM_CHARGER_CONSTANT_VOLTAGE_STEP 20000U +#define MAXIM_CHARGER_CONSTANT_VOLTAGE_MAX 4350000U + /* MAX14577 regulator SFOUT LDO voltage, fixed, uV */ #define MAX14577_REGULATOR_SAFEOUT_VOLTAGE 4900000 diff --git a/include/linux/mfd/max14577.h b/include/linux/mfd/max14577.h index 0df2fe329b83..b60febd6c53f 100644 --- a/include/linux/mfd/max14577.h +++ b/include/linux/mfd/max14577.h @@ -54,6 +54,14 @@ struct max14577_regulator_platform_data { struct device_node *of_node; }; +struct max14577_charger_platform_data { + unsigned int fast_charge_timer; + unsigned int constant_uvolt; + unsigned int fast_charge_uamp; + unsigned int eoc_uamp; + unsigned int ovp_uvolt; +}; + /* * MAX14577 MFD platform data */