From patchwork Thu Oct 12 12:36:03 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maciej Purski X-Patchwork-Id: 10001831 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 4AC916028A for ; Thu, 12 Oct 2017 12:36:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3C9D428DAE for ; Thu, 12 Oct 2017 12:36:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3164528DB6; Thu, 12 Oct 2017 12:36:46 +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 A22E028DAE for ; Thu, 12 Oct 2017 12:36:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755928AbdJLMgm (ORCPT ); Thu, 12 Oct 2017 08:36:42 -0400 Received: from mailout2.w1.samsung.com ([210.118.77.12]:42965 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752620AbdJLMgi (ORCPT ); Thu, 12 Oct 2017 08:36:38 -0400 Received: from eucas1p1.samsung.com (unknown [182.198.249.206]) by mailout2.w1.samsung.com (KnoxPortal) with ESMTP id 20171012123635euoutp02f5601ec5044256aa77a36a7f07706a71~s0tbUhTlG1982119821euoutp02S; Thu, 12 Oct 2017 12:36:35 +0000 (GMT) Received: from eusmges2.samsung.com (unknown [203.254.199.241]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20171012123634eucas1p192d143e9ddcf8ba4ea3a1703735a4b1e~s0taiB8991309813098eucas1p1R; Thu, 12 Oct 2017 12:36:34 +0000 (GMT) Received: from eucas1p1.samsung.com ( [182.198.249.206]) by eusmges2.samsung.com (EUCPMTA) with SMTP id 72.B4.12907.2D16FD95; Thu, 12 Oct 2017 13:36:34 +0100 (BST) Received: from eusmgms2.samsung.com (unknown [182.198.249.180]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20171012123633eucas1p2b76006dfc295beab89de68cbfe8839ad~s0tZ0mzEz0103501035eucas1p21; Thu, 12 Oct 2017 12:36:33 +0000 (GMT) X-AuditID: cbfec7f1-f793a6d00000326b-bd-59df61d2ece7 Received: from eusync4.samsung.com ( [203.254.199.214]) by eusmgms2.samsung.com (EUCPMTA) with SMTP id C2.3D.20118.1D16FD95; Thu, 12 Oct 2017 13:36:33 +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 <0OXP00DU9N0HRK20@eusync4.samsung.com>; Thu, 12 Oct 2017 13:36:33 +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 v2 2/4] hwmon: (ina2xx) Make max expected current configurable Date: Thu, 12 Oct 2017 14:36:03 +0200 Message-id: <1507811765-31005-3-git-send-email-m.purski@samsung.com> X-Mailer: git-send-email 2.7.4 In-reply-to: <1507811765-31005-1-git-send-email-m.purski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAAzWSa0hTYRzGe3fO2TkOp6dp9aJdZDAIS8sweimL8gLnQ5BGH9IP6rDTtNyM nawsLS84L4GaYlqJl5zDhqbNZTVSbE2NrG0q2o20UkJNcmKhoWluZ317/s/7ex7+f3gpTHKf 8KNSVBdZtUqeKhWK8M6+P9agIfl47N6a1o3oUXUbgSZ7CgCqs1gJ9LYsBn3J1QtQ6cQPDJnW ZjFks7WTSFtRRyDDxCiBGjRaHBX8eAxQreUnjqpt3QJkruwCaLLhjQDVT3/EUavlM4ma3g0K 0LKpj0T5XRby6CampbYFMMOjgxjjmI9nDPoiIdOhvcE0llQQjHbWTDC2PAtgni1mk0yJUQ+Y NuMIziwYtkd7xonCzrCpKZdY9Z4jiaJkm3kKv1CKrqy2vsGygSaoGHhQkA6Ftc9f47zeDO1j bcJiIKIkdBOAvSsP3cPC+mAeEBQDypVYtiicAQmtA7DydhTPrAHoWBvBnIyQDoQtBQlO35fu BnB4achVhNE2HOq6bmPOtA8dDVtvVZFOjdMyqG/KdvliOhLqzIvulbbDD9Yil+9BR8Hmxk8E 7+tJaK/05nUk7JizunkfONNvJHm9FQ5X3HT71+Dgb5OQ15kw51O7mzkEF8qNrn6M9oLlnVUY f6QYFmokPMJA/TeDu+YYLHy2RPIHVwNo1H0ny4B/PdigB75sOqdUsNy+YE6u5NJViuCkNKUB rP+cgdX++adg7tVBM6ApIPUUv/87Fish5Je4DKUZQAqT+opt8eOxEvEZecZVVp2WoE5PZTkz 8Kdw6Rbx4ThNrIRWyC+y51n2Aqv+/yqgPPyygQIVbxvKCf360h53eeLkqnfijElncmS9OKfx CjjbdKc32QHzdwZ0tITdO6H217ZJUbdjdFcPK01aI5OeNCfIZNE+I7mRmWFdQeHtOaoQgV21 e7hGFl69P2aay1MJVh5MrciOH1DaO4xq6S/dXOgO6lS5NaLydMTd6/4pA1kiKc4ly0MCMTUn /wco8b8SNQMAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrJLMWRmVeSWpSXmKPExsVy+t/xa7oXE+9HGtw7omuxccZ6VosnB9oZ LeYfOcdqcXZCoMWDplVMFv2PXzNb7Pr/htni/PkN7BZLJs9ntdj0+BqrxcK2JSwW7a+3MlrM O/KOxWLG+X1MFoem7mW0eLLwDJPFgpe3WCzWHrnLbrH0+kUmi9+7jrFbtO49wu4g6rFm3hpG j8vXLjJ7fPgY57FpVSebx+Yl9R6L+yazeix5c4jV43zzEUaPnd8b2D36tqxi9Fi/5SqLx+dN cgE8UVw2Kak5mWWpRfp2CVwZ5w+9YCnot6j4t/YMcwNjm24XIweHhICJxO8j6V2MnECmmMSF e+vZuhi5OIQEljBKPJ9zgBXCaWSS2N51iRWkgU1AS2JNezxIXERgH6PE6cdzGUEcZoGLLBJn 9qxjARklLOAncXRLCxuIzSKgKrFqaQMziM0r4CKx7NB3Foh1chI3z3WCxTkFXCVWLL7NCmIL AdW0XlzLOIGRdwEjwypGkdTS4tz03GIjveLE3OLSvHS95PzcTYzACNl27OeWHYxd74IPMQpw MCrx8Fqy348UYk0sK67MPcQowcGsJMJ7Pg4oxJuSWFmVWpQfX1Sak1p8iFGag0VJnLd3z+pI IYH0xJLU7NTUgtQimCwTB6dUAyPTHu3cFJZHS9OZpi/JWpyyRvVZwoHDK1Um9HuoHfP4/HvL bk/jmOy28H65VoeCtmD/LhOdxadUbXVCrY48M7IoqVgStu29uLwC44d7JbK7QiwPflTxdTrZ 8LenOMf20GueSRYrxP+6176+IqTgw2Dx+NZUoQIBg5lmR6vm8p/V7l65j+MfixJLcUaioRZz UXEiAHjso+mMAgAA X-CMS-MailID: 20171012123633eucas1p2b76006dfc295beab89de68cbfe8839ad 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: 20171012123633eucas1p2b76006dfc295beab89de68cbfe8839ad X-RootMTR: 20171012123633eucas1p2b76006dfc295beab89de68cbfe8839ad References: <1507811765-31005-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..bcaf814 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-microamp", + &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);