From patchwork Thu Oct 12 13:18:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maciej Purski X-Patchwork-Id: 10001919 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 1D9C96028A for ; Thu, 12 Oct 2017 13:18:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0EC0328DC1 for ; Thu, 12 Oct 2017 13:18:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0351E28DC7; Thu, 12 Oct 2017 13:18:27 +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 739C028DC1 for ; Thu, 12 Oct 2017 13:18:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757193AbdJLNSY (ORCPT ); Thu, 12 Oct 2017 09:18:24 -0400 Received: from mailout2.w1.samsung.com ([210.118.77.12]:48524 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752791AbdJLNSU (ORCPT ); Thu, 12 Oct 2017 09:18:20 -0400 Received: from eucas1p2.samsung.com (unknown [182.198.249.207]) by mailout2.w1.samsung.com (KnoxPortal) with ESMTP id 20171012131817euoutp0273c76d069bf2b6526d207f61539b33b4~s1R1PFVIG3109631096euoutp02d; Thu, 12 Oct 2017 13:18:17 +0000 (GMT) Received: from eusmges3.samsung.com (unknown [203.254.199.242]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20171012131816eucas1p20d2eb73dc1fff51c952cfd0e7e2f12a5~s1R0PW7B22177021770eucas1p2_; Thu, 12 Oct 2017 13:18:16 +0000 (GMT) Received: from eucas1p2.samsung.com ( [182.198.249.207]) by eusmges3.samsung.com (EUCPMTA) with SMTP id 9C.06.12867.79B6FD95; Thu, 12 Oct 2017 14:18:15 +0100 (BST) Received: from eusmgms2.samsung.com (unknown [182.198.249.180]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20171012131815eucas1p22e1d5859c59f11f73d8ccd0a74514c16~s1Rzjki4o1916919169eucas1p27; Thu, 12 Oct 2017 13:18:15 +0000 (GMT) X-AuditID: cbfec7f2-f793b6d000003243-2f-59df6b976fce Received: from eusync4.samsung.com ( [203.254.199.214]) by eusmgms2.samsung.com (EUCPMTA) with SMTP id 56.93.20118.79B6FD95; Thu, 12 Oct 2017 14:18:15 +0100 (BST) Received: from AMDC2075.DIGITAL.local ([106.120.51.25]) by eusync4.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0OXP0071YOY5COB0@eusync4.samsung.com>; Thu, 12 Oct 2017 14:18:15 +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 v3 2/4] hwmon: (ina2xx) Make max expected current configurable Date: Thu, 12 Oct 2017 15:18:00 +0200 Message-id: <1507814282-1486-3-git-send-email-m.purski@samsung.com> X-Mailer: git-send-email 2.7.4 In-reply-to: <1507814282-1486-1-git-send-email-m.purski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAAzWSe0hTcRTH/e3eu3s1V5c184eWxEoywUfYHz8yo8ji9kdhoJVK2ciLmk92 NTKj5qOZBmobqVD4qCm1NHVO0ZESY/nIxzKbYeKjjEw3YyqSImrNa/99zjnf8z2/3+FQmFhD eFAJKemsPEWWJBW64K1dq2a/ssTJyMD2vgDUVN5AoB/v8gGqNA0SaKDkIprK0QpQ8bQVQ4ZN G4bM5kYSadSVBNJNjxCoWqnBUb61BaAK028clZs7Bcj4pAOgH9X9AlQ1+xVH9aZxEtV8GRKg NUMXiR50mMiTbkxdRR1ghkeGMMa+cI3RaQuETLPmPvOiSE0wGpuRYMy5JsC0/1GQTJFeC5gG vQVnlnReYa5RLsdj2aSEW6w84MR1l/hZ+wiRVoxuq/PWcQVQ+hUCZwrSR2HPSh7B8x74caJB WAhcKDFdA+BIYwHGB0sA9v7sJ/53dFaUknyhFkDL48+ADzYBbM1W4oWAooS0L6zLj3HkJXQn gMMrn7Z8MdqMw9qOUsxhtZsOg08qV7YYp73h1Ks8gYNF9GmoLmjD+XFecHTQ8Q6KcqZD4YIK OXwgrSWhfe0XxmtC4eIbw7Z+N5zr1pM874XD6kfb+Sw4tGwQ8nwXZo81bmuC4ZJKv+WD0Tuh qrVsaxakRfChUsxLGFhS27Ldegp2FuYQ/IfL/u2o6RleAjyrgJMWSNgMLjmO5YL8OVkyl5ES 538jNVkH/t1O30b3YhtY7jlmBDQFpK6itPmJSDEhu8VlJhsBpDCpRHQ+fjJSLIqVZd5h5akx 8owkljMCTwqXuotCopSRYjpOls4msmwaK/9fFVDOHgqwy7k8OBgbVhTd1O+bH3g6OkFK2kp3 +D+7tOG97mM5aJ0JlATY7Odc/bMtqmhZRITR5hN0IFwzs7Z/Qvty9fW5qxZr45nLuWX3hrLs F5rf+hyaDo/u5dy7eufGbc/NH9wSF1UhBaGHo668//4NjifoMsbkifVp+dNnnQbavd53EFKc i5cd8cXknOwvF+BFFTcDAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrJLMWRmVeSWpSXmKPExsVy+t/xa7rTs+9HGrR+E7DYOGM9q8WTA+2M FvOPnGO1ODsh0OJB0yomi/7Hr5ktdv1/w2xx/vwGdoslk+ezWmx6fI3VYmHbEhaL9tdbGS3m HXnHYjHj/D4mi0NT9zJaPFl4hsliwctbLBZrj9xlt1h6/SKTxe9dx9gtWvceYXcQ9Vgzbw2j x+VrF5k9PnyM89i0qpPNY/OSeo/FfZNZPZa8OcTqcb75CKPHzu8N7B59W1YxeqzfcpXF4/Mm uQCeKC6blNSczLLUIn27BK6Mlx+usRb0W1RMbvnL0sDYptvFyMkhIWAisW/eNHYIW0ziwr31 bF2MXBxCAksYJb7dm8UC4TQySezb8Yy5i5GDg01AS2JNezxIXERgH6PE6cdzGUEcZoGLLBJn 9qxjARklLOAnce9DEzOIzSKgKvFgZQsTiM0r4CwxuXMHC8Q6OYmb5zrBhnIKuEh8nGQBEhYC Kml73ME6gZF3ASPDKkaR1NLi3PTcYiO94sTc4tK8dL3k/NxNjMAI2Xbs55YdjF3vgg8xCnAw KvHwWrLfjxRiTSwrrsw9xCjBwawkwuubARTiTUmsrEotyo8vKs1JLT7EKM3BoiTO27tndaSQ QHpiSWp2ampBahFMlomDU6qB8dLHGTf67Z8J3Gc39DCZLCV9Z7JHfGzAkSt/dd9t/fQgy/iv UbTQAeaYIwkfFpwIkQ28fzNvb7th5o5KO4f3e35maNgL/PHq3C4ZYmqmvWXt+892yy4c4pr1 uvth9UYd1ob1v7xUqi8u+hZ395/cdJMjTk3tM3oucm1XX3ag+YxB+5c53yWBDmQpzkg01GIu Kk4EAItAlmKMAgAA X-CMS-MailID: 20171012131815eucas1p22e1d5859c59f11f73d8ccd0a74514c16 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: 20171012131815eucas1p22e1d5859c59f11f73d8ccd0a74514c16 X-RootMTR: 20171012131815eucas1p22e1d5859c59f11f73d8ccd0a74514c16 References: <1507814282-1486-1-git-send-email-m.purski@samsung.com> Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@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: current_lsb = max_expected_current / 2^15 calibration_register = 0.00512 / (current_lsb * r_shunt) power_lsb = 25 * current_lsb (for ina231, 230, 226) power_lsb = 20 * current_lsb (for older ones) 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, but users have no impact on the precision of the device. Make max expected current configurable from device tree or platform_data. Allow changing it from sysfs as currX_max attribute. Update calibration register and power_lsb value on each currX_max change. Signed-off-by: Maciej Purski --- drivers/hwmon/ina2xx.c | 107 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 95 insertions(+), 12 deletions(-) diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 62e38fa..04648f6 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -80,6 +80,8 @@ /* common attrs, ina226 attrs and NULL */ #define INA2XX_MAX_ATTRIBUTE_GROUPS 3 +#define INA2XX_MAX_EXPECTED_MA_DEFAULT BIT(15) /* current_lsb = 1 mA */ + /* * Both bus voltage and shunt voltage conversion times for ina226 are set * to 0b0100 on POR, which translates to 2200 microseconds in total. @@ -100,13 +102,16 @@ struct ina2xx_config { int shunt_div; int bus_voltage_shift; int bus_voltage_lsb; /* uV */ - int power_lsb; /* uW */ + int power_lsb_factor; }; struct ina2xx_data { const struct ina2xx_config *config; - long rshunt; + long rshunt; /* uOhms */ + unsigned int max_expected_current; /* mA */ + int current_lsb; /* uA */ + int power_lsb; /* uW */ struct mutex config_lock; struct regmap *regmap; @@ -121,7 +126,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, }, [ina226] = { .config_default = INA226_CONFIG_DEFAULT, @@ -130,7 +135,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, }, }; @@ -169,10 +174,17 @@ static u16 ina226_interval_to_reg(int interval) return INA226_SHIFT_AVG(avg_bits); } +/* + * 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 in order to keep + * calibration value scaled RShunt must be converted to mOhms. + */ static int ina2xx_calibrate(struct ina2xx_data *data) { + int r_shunt = DIV_ROUND_CLOSEST(data->rshunt, 1000); u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor, - data->rshunt); + data->current_lsb * r_shunt); return regmap_write(data->regmap, INA2XX_CALIBRATION, val); } @@ -187,13 +199,29 @@ static int ina2xx_init(struct ina2xx_data *data) if (ret < 0) return ret; - /* - * Set current LSB to 1mA, shunt is in uOhms - * (equation 13 in datasheet). - */ return ina2xx_calibrate(data); } +/* + * 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 ina2xx_set_max_expected_current(struct ina2xx_data *data, + unsigned int val) +{ + if (val <= 0 || val > data->config->calibration_factor) + return -EINVAL; + + data->max_expected_current = val; + data->current_lsb = DIV_ROUND_CLOSEST(data->max_expected_current * 1000, + 1 << 15); + data->power_lsb = data->current_lsb * data->config->power_lsb_factor; + + return 0; +} + static int ina2xx_read_reg(struct device *dev, int reg, unsigned int *regval) { struct ina2xx_data *data = dev_get_drvdata(dev); @@ -268,11 +296,11 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg, val = DIV_ROUND_CLOSEST(val, 1000); break; case INA2XX_POWER: - val = regval * data->config->power_lsb; + val = regval * data->power_lsb; break; case INA2XX_CURRENT: - /* signed register, LSB=1mA (selected), in mA */ - val = (s16)regval; + val = (s16)regval * data->current_lsb; + val = DIV_ROUND_CLOSEST(val, 1000); break; case INA2XX_CALIBRATION: val = DIV_ROUND_CLOSEST(data->config->calibration_factor, @@ -369,6 +397,39 @@ static ssize_t ina226_show_interval(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", ina226_reg_to_interval(regval)); } +static ssize_t ina2xx_max_current_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ina2xx_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", data->max_expected_current); +} + +static ssize_t ina2xx_max_current_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct ina2xx_data *data = dev_get_drvdata(dev); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + ret = ina2xx_set_max_expected_current(data, val); + if (ret) + return ret; + + /* Update the Calibration register */ + ret = ina2xx_calibrate(data); + if (ret) + return ret; + + return len; +} + /* shunt voltage */ static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE); @@ -390,6 +451,11 @@ static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR, ina2xx_show_value, ina2xx_set_shunt, INA2XX_CALIBRATION); +/* max expected current */ +static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR, + ina2xx_max_current_show, + ina2xx_max_current_store, 0); + /* update interval (ina226 only) */ static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, ina226_show_interval, ina226_set_interval, 0); @@ -401,6 +467,7 @@ static struct attribute *ina2xx_attrs[] = { &sensor_dev_attr_curr1_input.dev_attr.attr, &sensor_dev_attr_power1_input.dev_attr.attr, &sensor_dev_attr_shunt_resistor.dev_attr.attr, + &sensor_dev_attr_curr1_max.dev_attr.attr, NULL, }; @@ -453,6 +520,22 @@ static int ina2xx_probe(struct i2c_client *client, data->rshunt = val; + if (of_property_read_u32(dev->of_node, + "ti-max-expected-current-milliamp", + &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_MA_DEFAULT; + } + + ret = ina2xx_set_max_expected_current(data, val); + if (ret < 0) + return ret; + ina2xx_regmap_config.max_register = data->config->registers; data->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config);