From patchwork Thu Jun 5 09:07:09 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonghwa Lee X-Patchwork-Id: 4304111 Return-Path: X-Original-To: patchwork-linux-pm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 3B0A99F1D6 for ; Thu, 5 Jun 2014 09:07:32 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 091B42034C for ; Thu, 5 Jun 2014 09:07:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 06CC320251 for ; Thu, 5 Jun 2014 09:07:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751221AbaFEJH0 (ORCPT ); Thu, 5 Jun 2014 05:07:26 -0400 Received: from mailout1.samsung.com ([203.254.224.24]:32897 "EHLO mailout1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751159AbaFEJHW (ORCPT ); Thu, 5 Jun 2014 05:07:22 -0400 Received: from epcpsbgr3.samsung.com (u143.gpu120.samsung.co.kr [203.254.230.143]) by mailout1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0N6O002HIUO887B0@mailout1.samsung.com> for linux-pm@vger.kernel.org; Thu, 05 Jun 2014 18:07:20 +0900 (KST) Received: from epcpsbgm1.samsung.com ( [172.20.52.113]) by epcpsbgr3.samsung.com (EPCPMTA) with SMTP id 48.28.14704.84330935; Thu, 05 Jun 2014 18:07:20 +0900 (KST) X-AuditID: cbfee68f-b7fef6d000003970-ea-53903348bb8a Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 53.90.08203.84330935; Thu, 05 Jun 2014 18:07:20 +0900 (KST) Received: from localhost.localdomain ([10.252.82.199]) by mmp2.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0N6O00ICXUO5QXJ0@mmp2.samsung.com>; Thu, 05 Jun 2014 18:07:20 +0900 (KST) From: Jonghwa Lee To: linux-pm@vger.kernel.org Cc: dbaryshkov@gmail.com, dwmw2@infradead.org, cw00.choi@samsung.com, myungjoo.ham@samsung.com, Jonghwa Lee Subject: [PATCH v2 1/4] power: max17042_battery: Specifies operation mode of max17042 fuelgauge Date: Thu, 05 Jun 2014 18:07:09 +0900 Message-id: <1401959231-20940-1-git-send-email-jonghwa3.lee@samsung.com> X-Mailer: git-send-email 1.7.9.5 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrMLMWRmVeSWpSXmKPExsWyRsSkUNfDeEKwwcZGSYvrX56zWkx68p7Z YuLKycwWnWefMFt87j3CaHG7cQWbA5vHzll32T02r9Dy6NuyitHj8ya5AJYoLpuU1JzMstQi fbsEroyOhxOZCyZ6VXyccZitgbHHpouRk0NCwERiwZ5GZghbTOLCvfVsXYxcHEICSxklpi36 zwhTNLF7ETtEYjqjxN0Ln9hBEkICbUwS29+mgthsAjoS//fdBIuLCMhITL2ynxWkgVmgg1Fi w50+JpCEsECixM3H59lAbBYBVYlbR4+ygti8Ah4S20+uBqrhANqmIDFnkg1Ir4TAdzaJ5ecm MULUC0h8m3yIBaJGVmLTAairJSUOrrjBMoFRcAEjwypG0dSC5ILipPQiY73ixNzi0rx0veT8 3E2MwAA9/e9Z/w7GuwesDzEmA42byCwlmpwPDPC8knhDYzMjC1MTU2Mjc0sz0oSVxHnvP0wK EhJITyxJzU5NLUgtii8qzUktPsTIxMEp1cDIIKRfvOrqxbpbpxfnSu31X8g6Y/nxpTOb3te9 qbl62fDnF9cc/z75RW3Oc5bfKgk4df/NIsdw/Qa1B+t44mcUv/34slfabHvprgyRpxxH+mwC zZbtOK9s09fw7F5rxM+F2nsVJ5nVHZKV/mFdccJyX+qMWqfHvQZHhLR+fFhna+X0JCVp64J2 JZbijERDLeai4kQAevP0X2YCAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrAIsWRmVeSWpSXmKPExsVy+t9jQV0P4wnBBm+b+S2uf3nOajHpyXtm i4krJzNbdJ59wmzxufcIo8XtxhVsDmweO2fdZffYvELLo2/LKkaPz5vkAliiGhhtMlITU1KL FFLzkvNTMvPSbZW8g+Od403NDAx1DS0tzJUU8hJzU22VXHwCdN0yc4CWKymUJeaUAoUCEouL lfTtME0IDXHTtYBpjND1DQmC6zEyQAMJaxgzOh5OZC6Y6FXxccZhtgbGHpsuRk4OCQETiYnd i9ghbDGJC/fWs3UxcnEICUxnlLh74RNYQkigjUli+9tUEJtNQEfi/76bYHERARmJqVf2s4I0 MAt0MEpsuNPHBJIQFkiUuPn4PBuIzSKgKnHr6FFWEJtXwENi+8nVQDUcQNsUJOZMspnAyL2A kWEVo2hqQXJBcVJ6rqFecWJucWleul5yfu4mRnD4P5PawbiyweIQowAHoxIP74SA/mAh1sSy 4srcQ4wSHMxKIrxLdScEC/GmJFZWpRblxxeV5qQWH2JMBlo+kVlKNDkfGJt5JfGGxiZmRpZG 5oYWRsbmpAkrifMeaLUOFBJITyxJzU5NLUgtgtnCxMEp1cAYF/01rOA5p/n7gtKWyAfS1fea J264paW1+oNIeSOHDuPUJ9XXNl6d9UdES/lEmYu2SoHt6abgJzlfvutW7Mu+ytdvsrc5XF5o 84LLATyvd7fK7p798ZV64DvjEJ1fXAq3VN7cMXkU7xzbte4OZ3yVhBbb/0UL+4M6Knje9KVo cv+6u0vxSbESS3FGoqEWc1FxIgAg87IGwwIAAA== DLP-Filter: Pass X-MTR: 20000000000000000@CPGS X-CFilter-Loop: Reflected Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable 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 Fuelgauge max17042 chip and its successors, max17047, max17050 has different operation mode, 'ModelGague M1' and 'ModelGauge M3'. Each mode is selectable depends on its implementation via register control. M1 mode can measure battery's capacity only according to voltage information while M3 needs current and temperature at once. Therefore, its properties which is showed to users can be also differed. This patch supports mode selection in max17042 driver and proper working for each mode. Signed-off-by: Jonghwa Lee Acked-by: Chanwoo Choi Acked-by: MyungJoo Ham --- .../bindings/power_supply/max17042_battery.txt | 3 + drivers/power/max17042_battery.c | 116 ++++++++++++-------- include/linux/power/max17042_battery.h | 7 +- 3 files changed, 77 insertions(+), 49 deletions(-) diff --git a/Documentation/devicetree/bindings/power_supply/max17042_battery.txt b/Documentation/devicetree/bindings/power_supply/max17042_battery.txt index 5bc9b68..8ac9405 100644 --- a/Documentation/devicetree/bindings/power_supply/max17042_battery.txt +++ b/Documentation/devicetree/bindings/power_supply/max17042_battery.txt @@ -3,6 +3,9 @@ max17042_battery Required properties : - compatible : "maxim,max17042" + - maxim,operation-mode : Defined fuelgauge operation mode + <0> : ModelGauge m1, fuelgauge based on voltage only + <1> : ModelGauge m3, fuelgauge with mixing algorithm Optional properties : - maxim,rsns-microohm : Resistance of rsns resistor in micro Ohms diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c index 66da691..c1d3ae5 100644 --- a/drivers/power/max17042_battery.c +++ b/drivers/power/max17042_battery.c @@ -49,6 +49,9 @@ /* Interrupt mask bits */ #define CONFIG_ALRT_BIT_ENBL (1 << 2) +#define CONFIG_ETHERM_BIT (1 << 4) +#define CONFIG_TEX_BIT (1 << 8) +#define CONFIG_TEN_BIT (1 << 9) #define STATUS_INTR_SOCMIN_BIT (1 << 10) #define STATUS_INTR_SOCMAX_BIT (1 << 14) @@ -71,6 +74,7 @@ struct max17042_chip { struct regmap *regmap; struct power_supply battery; enum max170xx_chip_type chip_type; + enum max17042_operation_mode mode; struct max17042_platform_data *pdata; struct work_struct work; int init_complete; @@ -91,6 +95,8 @@ static enum power_supply_property max17042_battery_props[] = { POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CURRENT_AVG, }; +#define MODELGAUGE_M1_PROPS 8 +#define MODELGAUGE_M3_PROPS 13 static int max17042_get_property(struct power_supply *psy, enum power_supply_property psp, @@ -164,13 +170,19 @@ static int max17042_get_property(struct power_supply *psy, val->intval = data * 625 / 8; break; case POWER_SUPPLY_PROP_CAPACITY: - ret = regmap_read(map, MAX17042_RepSOC, &data); + if (chip->mode == MODELGAUGE_M3) + ret = regmap_read(map, MAX17042_RepSOC, &data); + else + ret = regmap_read(map, MAX17042_VFSOC, &data); if (ret < 0) return ret; val->intval = data >> 8; break; case POWER_SUPPLY_PROP_CHARGE_FULL: + if (chip->mode == MODELGAUGE_M1) + return -EINVAL; + ret = regmap_read(map, MAX17042_FullCAP, &data); if (ret < 0) return ret; @@ -178,6 +190,9 @@ static int max17042_get_property(struct power_supply *psy, val->intval = data * 1000 / 2; break; case POWER_SUPPLY_PROP_CHARGE_COUNTER: + if (chip->mode == MODELGAUGE_M1) + return -EINVAL; + ret = regmap_read(map, MAX17042_QH, &data); if (ret < 0) return ret; @@ -185,6 +200,9 @@ static int max17042_get_property(struct power_supply *psy, val->intval = data * 1000 / 2; break; case POWER_SUPPLY_PROP_TEMP: + if (chip->mode == MODELGAUGE_M1) + return -EINVAL; + ret = regmap_read(map, MAX17042_TEMP, &data); if (ret < 0) return ret; @@ -200,40 +218,38 @@ static int max17042_get_property(struct power_supply *psy, val->intval = val->intval * 10 / 256; break; case POWER_SUPPLY_PROP_CURRENT_NOW: - if (chip->pdata->enable_current_sense) { - ret = regmap_read(map, MAX17042_Current, &data); - if (ret < 0) - return ret; - - val->intval = data; - if (val->intval & 0x8000) { - /* Negative */ - val->intval = ~val->intval & 0x7fff; - val->intval++; - val->intval *= -1; - } - val->intval *= 1562500 / chip->pdata->r_sns; - } else { + if (chip->mode == MODELGAUGE_M1) return -EINVAL; + + ret = regmap_read(map, MAX17042_Current, &data); + if (ret < 0) + return ret; + + val->intval = data; + if (val->intval & 0x8000) { + /* Negative */ + val->intval = ~val->intval & 0x7fff; + val->intval++; + val->intval *= -1; } + val->intval *= 1562500 / chip->pdata->r_sns; break; case POWER_SUPPLY_PROP_CURRENT_AVG: - if (chip->pdata->enable_current_sense) { - ret = regmap_read(map, MAX17042_AvgCurrent, &data); - if (ret < 0) - return ret; - - val->intval = data; - if (val->intval & 0x8000) { - /* Negative */ - val->intval = ~val->intval & 0x7fff; - val->intval++; - val->intval *= -1; - } - val->intval *= 1562500 / chip->pdata->r_sns; - } else { + if (chip->mode == MODELGAUGE_M1) return -EINVAL; + + ret = regmap_read(map, MAX17042_AvgCurrent, &data); + if (ret < 0) + return ret; + + val->intval = data; + if (val->intval & 0x8000) { + /* Negative */ + val->intval = ~val->intval & 0x7fff; + val->intval++; + val->intval *= -1; } + val->intval *= 1562500 / chip->pdata->r_sns; break; default: return -EINVAL; @@ -629,7 +645,6 @@ static struct max17042_platform_data * max17042_get_pdata(struct device *dev) { struct device_node *np = dev->of_node; - u32 prop; struct max17042_platform_data *pdata; if (!np) @@ -639,14 +654,14 @@ max17042_get_pdata(struct device *dev) if (!pdata) return NULL; + of_property_read_u32(np, "maxim,operation-mode", &pdata->mode); + /* * Require current sense resistor value to be specified for * current-sense functionality to be enabled at all. */ - if (of_property_read_u32(np, "maxim,rsns-microohm", &prop) == 0) { - pdata->r_sns = prop; - pdata->enable_current_sense = true; - } + if (pdata->mode == MODELGAUGE_M3) + of_property_read_u32(np, "maxim,rsns-microohm", &pdata->r_sns); return pdata; } @@ -706,20 +721,31 @@ static int max17042_probe(struct i2c_client *client, dev_err(&client->dev, "device version mismatch: %x\n", val); return -EIO; } + chip->mode = chip->pdata->mode; + dev_dbg(&client->dev, "operates as modelgauge %s\n", + chip->mode == MODELGAUGE_M1 ? "M1" : "M3"); chip->battery.name = "max170xx_battery"; chip->battery.type = POWER_SUPPLY_TYPE_BATTERY; chip->battery.get_property = max17042_get_property; chip->battery.properties = max17042_battery_props; - chip->battery.num_properties = ARRAY_SIZE(max17042_battery_props); - - /* When current is not measured, - * CURRENT_NOW and CURRENT_AVG properties should be invisible. */ - if (!chip->pdata->enable_current_sense) - chip->battery.num_properties -= 2; + if (chip->mode == MODELGAUGE_M3) { + /* ModelGauge m3 */ + chip->battery.num_properties = MODELGAUGE_M3_PROPS; + if (chip->pdata->r_sns == 0) + chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR; + } else { + /* ModelGauge m1 */ + chip->battery.num_properties = MODELGAUGE_M1_PROPS; + regmap_write(chip->regmap, MAX17042_CGAIN, 0x0000); + regmap_write(chip->regmap, MAX17042_MiscCFG, 0x0003); + regmap_write(chip->regmap, MAX17042_LearnCFG, 0x0007); - if (chip->pdata->r_sns == 0) - chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR; + /* Off thermistor - temperature may be externally given */ + regmap_update_bits(chip->regmap, MAX17042_CONFIG, + CONFIG_ETHERM_BIT | CONFIG_TEX_BIT | CONFIG_TEN_BIT, + CONFIG_TEX_BIT); + } if (chip->pdata->init_data) for (i = 0; i < chip->pdata->num_init_data; i++) @@ -727,12 +753,6 @@ static int max17042_probe(struct i2c_client *client, chip->pdata->init_data[i].addr, chip->pdata->init_data[i].data); - if (!chip->pdata->enable_current_sense) { - regmap_write(chip->regmap, MAX17042_CGAIN, 0x0000); - regmap_write(chip->regmap, MAX17042_MiscCFG, 0x0003); - regmap_write(chip->regmap, MAX17042_LearnCFG, 0x0007); - } - ret = power_supply_register(&client->dev, &chip->battery); if (ret) { dev_err(&client->dev, "failed: power supply register\n"); diff --git a/include/linux/power/max17042_battery.h b/include/linux/power/max17042_battery.h index 89dd84f..f8c03c2 100644 --- a/include/linux/power/max17042_battery.h +++ b/include/linux/power/max17042_battery.h @@ -195,13 +195,18 @@ struct max17042_config_data { u16 cell_char_tbl[MAX17042_CHARACTERIZATION_DATA_SIZE]; } __packed; +enum max17042_operation_mode { + MODELGAUGE_M1, + MODELGAUGE_M3, +}; + struct max17042_platform_data { struct max17042_reg_data *init_data; struct max17042_config_data *config_data; int num_init_data; /* Number of enties in init_data array */ - bool enable_current_sense; bool enable_por_init; /* Use POR init from Maxim appnote */ + enum max17042_operation_mode mode; /* * R_sns in micro-ohms. * default 10000 (if r_sns = 0) as it is the recommended value by