From patchwork Thu Sep 28 12:50:13 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maciej Purski X-Patchwork-Id: 9975939 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 C81716034B for ; Thu, 28 Sep 2017 12:51:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B9BA4295A4 for ; Thu, 28 Sep 2017 12:51:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AE044295B4; Thu, 28 Sep 2017 12:51:06 +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 1B392295A4 for ; Thu, 28 Sep 2017 12:51:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753017AbdI1MvF (ORCPT ); Thu, 28 Sep 2017 08:51:05 -0400 Received: from mailout2.w1.samsung.com ([210.118.77.12]:54204 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753094AbdI1MvB (ORCPT ); Thu, 28 Sep 2017 08:51:01 -0400 Received: from eucas1p1.samsung.com (unknown [182.198.249.206]) by mailout2.w1.samsung.com (KnoxPortal) with ESMTP id 20170928125058euoutp026179aaa42571ebbbe3b271a8b8030ad8~oh3-r3JkD0068300683euoutp02V; Thu, 28 Sep 2017 12:50:58 +0000 (GMT) Received: from eusmges5.samsung.com (unknown [203.254.199.245]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20170928125058eucas1p1be3e5017128c06cf05dacece9507455e~oh3-T5zPZ2364923649eucas1p1x; Thu, 28 Sep 2017 12:50:58 +0000 (GMT) Received: from eucas1p1.samsung.com ( [182.198.249.206]) by eusmges5.samsung.com (EUCPMTA) with SMTP id 18.37.12743.230FCC95; Thu, 28 Sep 2017 13:50:58 +0100 (BST) Received: from eusmgms1.samsung.com (unknown [182.198.249.179]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20170928125057eucas1p2e8a2db5db29e7d7886c3906c7fffd390~oh3_raAqy3123831238eucas1p2Z; Thu, 28 Sep 2017 12:50:57 +0000 (GMT) X-AuditID: cbfec7f5-f79d06d0000031c7-de-59ccf0328bc6 Received: from eusync3.samsung.com ( [203.254.199.213]) by eusmgms1.samsung.com (EUCPMTA) with SMTP id 63.EA.18832.130FCC95; Thu, 28 Sep 2017 13:50:57 +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:57 +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 2/4] hwmon: (ina2xx) Make max expected current configurable Date: Thu, 28 Sep 2017 14:50:13 +0200 Message-id: <1506603015-27202-3-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: H4sIAAAAAAAAAzWSe0hTcRTH+93Hdp1euWymPzSFBkFJakbFr4dSYHXJjPonUCodeVPLqWxq WUFmufnI9yOtmIpTahrqnGKakmNq5GMuUVHJIsV8EZpaiqDprv73Oed8z/ecA4fCxVrSmYqI iuUUUbJIqUBENHau9XkcXegJPNLwQoTqimpINPlJDVCJqY9EvdnX0I8kHYayJuZw1Lw5jyOz uVaItHklJNJPDJGoTKUlkHquASCN6TeBisxtGDIWtAI0WdaDodKZUQK9N30ToophC4bWmzuF KLnVJDy7l63WVAN2YMiCswuLt1i9LlXA1mufsOWZeSSrnTeSrPmZCbAf/iUK2UyDDrA1hkGC XdK7XbULEp0J5SIj4jmFl2+IKHwurQTE9KMHr41aLBF0e6QBGwoyx+DG32TAsyPsH68RpAER JWYqAPw4ko5tF8TMEoBNKs/dhpL2KoIXVQKYWKvC+WATwPw3X7YCihIw7rBaHbydd2DaABxY /Wq1xRkzAStbC/FtKwnjD3XPM6xMMAfgpKbYugfN+MHOnF8kP84NjvSlWjU2zHmY1FVunQYZ nRBOda3tLO4HDcV/cJ4lcLbLIOR5H0xNacd4fgQtK80Cnh/Dp2O1O5rTcCnXYO3FGXuY2/jS egFkaJiiEvMSFq52dO/Yn4OajXqSv7gIQGPzgCAbuJSCPTrgwMUp5WGc8rinUiZXxkWFed6O luvB1u90b3StNIGKzlNGwFBAakejuu5AMSmLVybIjQBSuNSBjpztCRTTobKEh5wiOlgRF8kp jcCFIqROtE+QKlDMhMliuXscF8MpdqsYZeOcCFxXfOs2lgsOc+zJxjzHK77uvbk3sw59jrXV z2TWxrHXvf2XL7iqLdi6JEA7/F0iTr9vvDT4ShIUmut+0SfFpY+mM+RqJ3PM3dRFlePbWGgb MNPybrowJySkJ9nr56RXwdi4y9BoR1uV/XTdQUtV4x06f//lE+umgJZKTfSNsikpoQyXebvj CqXsPyR/8K43AwAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrFLMWRmVeSWpSXmKPExsVy+t/xq7qGH85EGqxt0rHYOGM9q8WTA+2M FvOPnGO1ODsh0OJB0yomi/7Hr5ktdv1/w2xx/vwGdoslk+ezWmx6fI3VYmHbEhaL9tdbGS3m HXnHYjHj/D4mi0NT9zJaPFl4hsliwctbLBZrj9xlt1h6/SKTxe9dx9gtWvceYXcQ9Vgzbw2j x+VrF5k9PnyM89i0qpPNY/OSeo/FfZNZPZa8OcTqcb75CKPHzu8N7B59W1YxeqzfcpXF4/Mm uQCeKC6blNSczLLUIn27BK6M113zGQsuWFTMPrSEqYHxtG4XIyeHhICJxPyDq1kgbDGJC/fW s3UxcnEICSxhlHjypIkdwmlkkvhxdCVQhoODTUBLYk17PEhcRGAfo8Tpx3MZQRxmgYssEmf2 rAMbJSzgLbGqpZcZxGYRUJV4Mm8mI4jNK+AicWzic1aIdXISN891gtVwCrhKNB1fDGYLAdUs etzJOoGRdwEjwypGkdTS4tz03GJDveLE3OLSvHS95PzcTYzAGNl27OfmHYyXNgYfYhTgYFTi 4dVYfDpSiDWxrLgy9xCjBAezkghvzqszkUK8KYmVValF+fFFpTmpxYcYpTlYlMR5e/esjhQS SE8sSc1OTS1ILYLJMnFwSjUwsltrrTNjrqutuXkyqPX6j49hDK5nJnvFXDXeULplk87NrZuP KvBYHp374aWabbpvy+cZtsvUtTUvr7Ga2222M95ZaKu7kekHxhMXd0u4ccqqbfojNkPlybF5 ISEiT+wnVEnWTE5lm33l0ce0Wbxu8TZCGf2CM6P61tq5fIv6Wr/NeNv8g5vfK7EUZyQaajEX FScCAJgeQHCNAgAA X-CMS-MailID: 20170928125057eucas1p2e8a2db5db29e7d7886c3906c7fffd390 X-Msg-Generator: CA X-Sender-IP: 182.198.249.179 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: 20170928125057eucas1p2e8a2db5db29e7d7886c3906c7fffd390 X-RootMTR: 20170928125057eucas1p2e8a2db5db29e7d7886c3906c7fffd390 References: <1506603015-27202-1-git-send-email-m.purski@samsung.com> Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@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/hwmon/ina2xx.c | 105 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 93 insertions(+), 12 deletions(-) diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 62e38fa..d956013 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_A_DEFAULT (1 << 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,28 @@ 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 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 +295,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 +396,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_expected_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_expected_current_set(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((const char *) buf, 10, &val); + if (ret) + return ret; + + ret = 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 +450,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(max_expected_current, S_IRUGO | S_IWUSR, + ina2xx_max_expected_current_show, + ina2xx_max_expected_current_set, 0); + /* update interval (ina226 only) */ static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, ina226_show_interval, ina226_set_interval, 0); @@ -401,6 +466,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_max_expected_current.dev_attr.attr, NULL, }; @@ -453,6 +519,21 @@ static int ina2xx_probe(struct i2c_client *client, data->rshunt = val; + if (of_property_read_u32(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(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);