From patchwork Thu Sep 28 12:50:12 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maciej Purski X-Patchwork-Id: 9975929 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 041E76034B for ; Thu, 28 Sep 2017 12:51:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E8D50295B3 for ; Thu, 28 Sep 2017 12:51:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E7401295B8; Thu, 28 Sep 2017 12:51:01 +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=ham 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 CFC7F295B3 for ; Thu, 28 Sep 2017 12:51:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753097AbdI1MvA (ORCPT ); Thu, 28 Sep 2017 08:51:00 -0400 Received: from mailout2.w1.samsung.com ([210.118.77.12]:54192 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753090AbdI1Mu5 (ORCPT ); Thu, 28 Sep 2017 08:50:57 -0400 Received: from eucas1p2.samsung.com (unknown [182.198.249.207]) by mailout2.w1.samsung.com (KnoxPortal) with ESMTP id 20170928125054euoutp0209e7ddc10d3ddaed8b457a6e3a5b8bcd~oh38C0iQw0068300683euoutp02T; Thu, 28 Sep 2017 12:50:54 +0000 (GMT) Received: from eusmges4.samsung.com (unknown [203.254.199.244]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20170928125054eucas1p1ee6d42bea7edc6dbb00ace06d4b3edcb~oh37ZWtl72111621116eucas1p1Y; Thu, 28 Sep 2017 12:50:54 +0000 (GMT) Received: from eucas1p2.samsung.com ( [182.198.249.207]) by eusmges4.samsung.com (EUCPMTA) with SMTP id C7.57.12944.D20FCC95; Thu, 28 Sep 2017 13:50:53 +0100 (BST) Received: from eusmgms2.samsung.com (unknown [182.198.249.180]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20170928125053eucas1p19e757ac5c3774f54c7cd0ee4525decbe~oh36t6umu3077030770eucas1p1D; Thu, 28 Sep 2017 12:50:53 +0000 (GMT) X-AuditID: cbfec7f4-f79ab6d000003290-83-59ccf02d8250 Received: from eusync3.samsung.com ( [203.254.199.213]) by eusmgms2.samsung.com (EUCPMTA) with SMTP id 5A.4C.20118.D20FCC95; Thu, 28 Sep 2017 13:50:53 +0100 (BST) Received: from AMDC2075.DIGITAL.local ([106.120.51.25]) by eusync3.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0OWZ00K1TQC79Y00@eusync3.samsung.com>; Thu, 28 Sep 2017 13:50:53 +0100 (BST) From: Maciej Purski To: devicetree@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, linux-iio@vger.kernel.org Cc: Rob Herring , Mark Rutland , Guenter Roeck , Jean Delvare , Jonathan Corbet , Russell King , Kukjin Kim , Krzysztof Kozlowski , Jonathan Cameron , Hartmut Knaack , Lars-Peter Clausen , Peter Meerwald-Stadler , Bartlomiej Zolnierkiewicz , Marek Szyprowski , Maciej Purski Subject: [PATCH 1/4] iio: adc: ina2xx: Make max expected current configurable Date: Thu, 28 Sep 2017 14:50:12 +0200 Message-id: <1506603015-27202-2-git-send-email-m.purski@samsung.com> X-Mailer: git-send-email 2.7.4 In-reply-to: <1506603015-27202-1-git-send-email-m.purski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAAzWSWUwTURSGvbN0BkL1WkAvYEisURADSmzMjYLBuM2TywMPLIoVJkBskXQo EZdYQUFQgYBLVSw0LQQbFKyVAAIxTUMfipQl7qgkoAIligEV41ItA2//Of9/vnMeDkvKjHQo m52Tx2tylCq5xJ9q7fnpjo6e7k3a9N21DT/QN9N47EkJwLWOPho/rTyIRwotBK4Y9ZC4wztF Yre7hcHm6loaW0ef09hYbKZwiecRwAbHZwrr3d0Etl/rAnjM2EvguonXFL7neMvg+hcDBP7V 0cPgC10OJiGYazI0AW7o+QDJTX89zFktpRLuofksZyqvpjnzlJ3m3EUOwLX/0DFcuc0CuGbb M4qbsYYfCEj2j8vgVdn5vGbj9iP+WS4DlzuZcKJ2xEvogHdzGfBjEVSgP/W/gahXoP53zZIy 4M/KYD1AtqJntFjMANT5+DOxONF/00yIRgNAzolBIBZegGo+jfx3WFYCo1BTSZqvHwS7ARqa G5znktBNoYau66QPFQj3o5fv9YxvgIJrUb9hmU9K4S40dyVQXBaOXvWVzqf94G5U6DSRPgyC FgbNecyMGNqFPrY7F64LRJNO20J/FRqqvkSJ+hQa+NYhEfVpdO5Ny0JmG5qpss0vIOFSVNV6 g/TdgKAUXSyWiREOlddXLeB3oMHO0XmkDOoB+jKcWgnC6sASCwjitYI6kxcUMYJSLWhzMmPS j6ut4P/juP46Z9uAqWerHUAWyAOkmyyuJBmtzBcK1HaAWFIeJFVN9ibJpBnKgpO85niaRqvi BTsIYyn5Sml8cnGSDGYq8/hjPJ/LaxZdgvUL1YGIdFvk3lOJWan9nW2zCWB4SDEWogje7V3N aPeUXB0P/3Dl/ZrG23d46n4lXTz+7kwAuHR2/T549KWJqghPuaWLuBurl86G5CzRn4+btl1u XL4y9k2vNa2GMG7x2FLcw7m3szPjtTtbC80oMvF6xg1XGIxzB6/asO6j7lCIx1Mhp4QsZWwU qRGU/wC99votNAMAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrOLMWRmVeSWpSXmKPExsVy+t/xq7q6H85EGuxdKWuxccZ6VosnB9oZ LeYfOcdqcXZCoMWDplVMFv2PXzNb7Pr/htni/PkN7BZLJs9ntdj0+BqrxcK2JSwW7a+3MlrM O/KOxWLG+X1MFoem7mW0eLLwDJPFgpe3WCzWHrnLbrH0+kUmi9+7jrFbtO49wu4g6rFm3hpG j8vXLjJ7fPgY57FpVSebx+Yl9R6L+yazeix5c4jV43zzEUaPnd8b2D36tqxi9Fi/5SqLx+dN cgE8UVw2Kak5mWWpRfp2CVwZp+d5FLxyqJj/4D9TA+N/4y5GTg4JAROJCzOXMEHYYhIX7q1n 62Lk4hASWMIosXFbJyuE08gksXr6K/YuRg4ONgEtiTXt8SBxEYF9jBKnH89lBHGYBS6ySJzZ s44FZJSwgK/EzsVbWEAaWARUJS7M4wcxeQVcJH70CkMsk5O4ea6TGcTmFHCVaDq+GMwWAipZ 9LiTdQIj7wJGhlWMIqmlxbnpucVGesWJucWleel6yfm5mxiB0bHt2M8tOxi73gUfYhTgYFTi 4V1w8HSkEGtiWXFl7iFGCQ5mJRHenFdnIoV4UxIrq1KL8uOLSnNSiw8xSnOwKInz9u5ZHSkk kJ5YkpqdmlqQWgSTZeLglGpgjGueGrts3b1TFVP2223ZsI7rd/sXs7um7ceDO5WNFZIWtXHK Pf0snc1mmxb9ia1n7785ynxZOewrJkjvXRq1VlGS+dnTSQ1XLuWuruk0SPL0mh6tsnbCbolT WZ5PfvTE1e3L4mjZc8auarld/NWOTVc5MhxOz1gSsKWJy+Ji2jSdLX5uLQZ3lViKMxINtZiL ihMBMqHa+ooCAAA= X-CMS-MailID: 20170928125053eucas1p19e757ac5c3774f54c7cd0ee4525decbe X-Msg-Generator: CA X-Sender-IP: 182.198.249.180 X-Local-Sender: =?UTF-8?B?TWFjaWVqIFB1cnNraRtTZWN1cml0eSAoVFApG1NhbXN1bmcg?= =?UTF-8?B?RWxlY3Ryb25pY3MbVHJhaW5lZSAoKQ==?= X-Global-Sender: =?UTF-8?B?TWFjaWVqIFB1cnNraRtTZWN1cml0eSAoVFApG1NhbXN1bmcg?= =?UTF-8?B?RWxlY3Ryb25pY3MbVHJhaW5lZSAoKQ==?= X-Sender-Code: =?UTF-8?B?QzEwG0VIURtDMTBDRDAyQ0QwMjczOTU=?= CMS-TYPE: 201P X-CMS-RootMailID: 20170928125053eucas1p19e757ac5c3774f54c7cd0ee4525decbe X-RootMTR: 20170928125053eucas1p19e757ac5c3774f54c7cd0ee4525decbe References: <1506603015-27202-1-git-send-email-m.purski@samsung.com> Sender: linux-hwmon-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-hwmon@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Max expected current is used for calculating calibration register value, Current LSB and Power LSB according to equations found in ina datasheet. Max expected current is now implicitly set to default value, which is 2^15, thanks to which Current LSB is equal to 1 mA and Power LSB is equal to 20000 uW or 25000 uW depending on ina model. Make max expected current configurable, just like it's already done with shunt resistance: from device tree, platform_data or later from sysfs. On each max_expected_current change, calculate new values for Current LSB and Power LSB. According to datasheet Current LSB should be calculated by dividing max expected current by 2^15, as values read from device registers are in this case 16-bit integers. Power LSB is calculated by multiplying Current LSB by a factor, which is defined in ina documentation. Signed-off-by: Maciej Purski --- drivers/iio/adc/ina2xx-adc.c | 110 ++++++++++++++++++++++++++++++----- include/linux/platform_data/ina2xx.h | 2 + 2 files changed, 98 insertions(+), 14 deletions(-) diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index f387b97..883fede 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -56,6 +56,7 @@ #define INA226_DEFAULT_IT 1110 #define INA2XX_RSHUNT_DEFAULT 10000 +#define INA2XX_MAX_EXPECTED_A_DEFAULT (1 << 15) /* current_lsb = 1 mA */ /* * bit masks for reading the settings in the configuration register @@ -114,7 +115,7 @@ struct ina2xx_config { int shunt_div; int bus_voltage_shift; int bus_voltage_lsb; /* uV */ - int power_lsb; /* uW */ + int power_lsb_factor; enum ina2xx_ids chip_id; }; @@ -123,7 +124,10 @@ struct ina2xx_chip_info { struct task_struct *task; const struct ina2xx_config *config; struct mutex state_lock; - unsigned int shunt_resistor; + unsigned int shunt_resistor; /* uOhms */ + unsigned int max_expected_current; /* mA */ + int current_lsb; /* uA */ + int power_lsb; /* uW */ int avg; int int_time_vbus; /* Bus voltage integration time uS */ int int_time_vshunt; /* Shunt voltage integration time uS */ @@ -137,7 +141,7 @@ static const struct ina2xx_config ina2xx_config[] = { .shunt_div = 100, .bus_voltage_shift = 3, .bus_voltage_lsb = 4000, - .power_lsb = 20000, + .power_lsb_factor = 20, .chip_id = ina219, }, [ina226] = { @@ -146,7 +150,7 @@ static const struct ina2xx_config ina2xx_config[] = { .shunt_div = 400, .bus_voltage_shift = 0, .bus_voltage_lsb = 1250, - .power_lsb = 25000, + .power_lsb_factor = 25, .chip_id = ina226, }, }; @@ -210,14 +214,15 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev, case INA2XX_POWER: /* processed (mW) = raw*lsb (uW) / 1000 */ - *val = chip->config->power_lsb; + *val = chip->power_lsb; *val2 = 1000; return IIO_VAL_FRACTIONAL; case INA2XX_CURRENT: - /* processed (mA) = raw (mA) */ - *val = 1; - return IIO_VAL_INT; + /* processed (mA) = raw*lsb (uA) / 1000 */ + *val = chip->current_lsb; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; } } @@ -434,24 +439,47 @@ static ssize_t ina2xx_allow_async_readout_store(struct device *dev, } /* - * Set current LSB to 1mA, shunt is in uOhms - * (equation 13 in datasheet). We hardcode a Current_LSB - * of 1.0 x10-6. The only remaining parameter is RShunt. + * Calculate calibration value according to equation 1 in ina226 datasheet + * http://www.ti.com/lit/ds/symlink/ina226.pdf. + * Current LSB is in uA and RShunt is in uOhms, so RShunt should be + * converted to mOhms in order to keep the scale. * There is no need to expose the CALIBRATION register * to the user for now. But we need to reset this register - * if the user updates RShunt after driver init, e.g upon - * reading an EEPROM/Probe-type value. + * if the user updates RShunt or max expected current after driver + * init, e.g upon reading an EEPROM/Probe-type value. */ static int ina2xx_set_calibration(struct ina2xx_chip_info *chip) { + unsigned int rshunt = DIV_ROUND_CLOSEST(chip->shunt_resistor, 1000); u16 regval = DIV_ROUND_CLOSEST(chip->config->calibration_factor, - chip->shunt_resistor); + chip->current_lsb * rshunt); return regmap_write(chip->regmap, INA2XX_CALIBRATION, regval); } +/* + * Set max_expected_current (mA) and calculate current_lsb (uA), + * according to equation 2 in ina226 datasheet. Power LSB is calculated + * by multiplying Current LSB by a given factor, which may vary depending + * on ina version. + */ +static int set_max_expected_current(struct ina2xx_chip_info *chip, + unsigned int val) +{ + if (val <= 0 || val > chip->config->calibration_factor) + return -EINVAL; + + chip->max_expected_current = val; + chip->current_lsb = DIV_ROUND_CLOSEST(chip->max_expected_current * 1000, + 1 << 15); + chip->power_lsb = chip->current_lsb * chip->config->power_lsb_factor; + + return 0; +} + static int set_shunt_resistor(struct ina2xx_chip_info *chip, unsigned int val) { + if (val <= 0 || val > chip->config->calibration_factor) return -EINVAL; @@ -493,6 +521,39 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev, return len; } +static ssize_t ina2xx_max_expected_current_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ina2xx_chip_info *chip = iio_priv(dev_to_iio_dev(dev)); + + return sprintf(buf, "%d\n", chip->max_expected_current); +} + +static ssize_t ina2xx_max_expected_current_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct ina2xx_chip_info *chip = iio_priv(dev_to_iio_dev(dev)); + unsigned long val; + int ret; + + ret = kstrtoul((const char *) buf, 10, &val); + if (ret) + return ret; + + ret = set_max_expected_current(chip, val); + if (ret) + return ret; + + /* Update the Calibration register */ + ret = ina2xx_set_calibration(chip); + if (ret) + return ret; + + return len; +} + #define INA219_CHAN(_type, _index, _address) { \ .type = (_type), \ .address = (_address), \ @@ -755,10 +816,15 @@ static IIO_DEVICE_ATTR(in_shunt_resistor, S_IRUGO | S_IWUSR, ina2xx_shunt_resistor_show, ina2xx_shunt_resistor_store, 0); +static IIO_DEVICE_ATTR(in_max_expected_current, S_IRUGO | S_IWUSR, + ina2xx_max_expected_current_show, + ina2xx_max_expected_current_store, 0); + static struct attribute *ina219_attributes[] = { &iio_dev_attr_in_allow_async_readout.dev_attr.attr, &iio_const_attr_ina219_integration_time_available.dev_attr.attr, &iio_dev_attr_in_shunt_resistor.dev_attr.attr, + &iio_dev_attr_in_max_expected_current.dev_attr.attr, NULL, }; @@ -766,6 +832,7 @@ static struct attribute *ina226_attributes[] = { &iio_dev_attr_in_allow_async_readout.dev_attr.attr, &iio_const_attr_ina226_integration_time_available.dev_attr.attr, &iio_dev_attr_in_shunt_resistor.dev_attr.attr, + &iio_dev_attr_in_max_expected_current.dev_attr.attr, NULL, }; @@ -851,6 +918,21 @@ static int ina2xx_probe(struct i2c_client *client, if (ret) return ret; + if (of_property_read_u32(client->dev.of_node, + "max-expected-current", &val) < 0) { + struct ina2xx_platform_data *pdata = + dev_get_platdata(&client->dev); + + if (pdata && pdata->max_mA != 0) + val = pdata->max_mA; + else + val = INA2XX_MAX_EXPECTED_A_DEFAULT; + } + + ret = set_max_expected_current(chip, val); + if (ret) + return ret; + /* Patch the current config register with default. */ val = chip->config->config_default; diff --git a/include/linux/platform_data/ina2xx.h b/include/linux/platform_data/ina2xx.h index 9abc0ca..f02b1d8 100644 --- a/include/linux/platform_data/ina2xx.h +++ b/include/linux/platform_data/ina2xx.h @@ -13,7 +13,9 @@ /** * struct ina2xx_platform_data - ina2xx info * @shunt_uohms shunt resistance in microohms + * @max_mA max expected current in mA */ struct ina2xx_platform_data { long shunt_uohms; + int max_mA; };