Received: by 2002:ac0:a5a6:0:0:0:0:0 with SMTP id m35-v6csp2434778imm; Thu, 27 Sep 2018 12:49:50 -0700 (PDT) X-Google-Smtp-Source: ACcGV62QDjj6r11n0ts9IfbhHtETHeLmU/TARBGrvGhF0HXU1q9bOoY/ezPpzhD9ez5da6LRxK54 X-Received: by 2002:a63:1e19:: with SMTP id e25-v6mr11777320pge.44.1538077790592; Thu, 27 Sep 2018 12:49:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1538077790; cv=none; d=google.com; s=arc-20160816; b=dj+BTAPGc93PBKiVkPpKt5kKejlicXN8v/hV1vFOOsDP9X4q/x6PfNX43gvXuCK+an yHTYtc/FOCNwuBGaWzzXEmervy+Gkv2WqhFC2oTkaaQQtlJxkG2gMFCj+xSZIl38FWCE xEIOJpHdya94rIZLqMIBFmnpJ76UFj5WVkgDmo79EtccCCmnPPYJuTy3GjLqAhL6jq3R S8DYJkv5haycB5L5vbXdTkO7zNkZOZLWeYsU5F7TlHmj+HLUy9HxWayWGxkZOeLnS8d3 NTLBGUUoiFSBCidLJ67JI2K5/B81q5cpYOjuVvujVHtJnPGQ6Ab/fv7tZueFVwJvTWS1 F6ew== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature; bh=VpCVBrQo6SsrzXDwOcXayzQcuay/1iBMWp+hcrPvScA=; b=cMrp2DV9/bjG/6TNBBvrwfAOvsvpXPNF8+BLOLQtz5x4cnm99h90lQ6EPb3abEdGu0 X7RPQwLAPo+d2ukTqPta/qsKjvzthsUPKF22jaBhZZgDqZHT5NRT0zqkZnXPyba0gelh behvFdRMKsNcya1/QyT4Fqlfm8+qc31uPEjTvJf7JmYovZudE0vN2pvc19ZOKKwl0z3m QawLo/tz4LNspnXX7g61P2Mfx5thrxct51jC0pQ+2twwq4FaiO5jL61YVTp+tl5xA6PW tzm7B33zT2EQ8z5KhfyothKAdSGId0gZkF933LB7bpZJlsagPJJxahNOB5ddI/5PKTF2 UiGw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=Ja0nGWQP; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 34-v6si2778505pgt.95.2018.09.27.12.49.34; Thu, 27 Sep 2018 12:49:50 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=Ja0nGWQP; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728414AbeI1CJN (ORCPT + 99 others); Thu, 27 Sep 2018 22:09:13 -0400 Received: from mail-pg1-f193.google.com ([209.85.215.193]:46161 "EHLO mail-pg1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728343AbeI1CJN (ORCPT ); Thu, 27 Sep 2018 22:09:13 -0400 Received: by mail-pg1-f193.google.com with SMTP id b129-v6so2671154pga.13; Thu, 27 Sep 2018 12:49:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=VpCVBrQo6SsrzXDwOcXayzQcuay/1iBMWp+hcrPvScA=; b=Ja0nGWQPB6Aiq7y61m7k+dvQIeAO0+1aJpzcKYj5IGwqNu+AuZucVi2Aqp3B0IYkLA GWcSmugpmSy8eEbHLYF90BWtzIZiqxO2wHc0KlnB2BKrPQDF2uGeZSG72FWZtIxlYk+y jOluDG6vil6LLo3L4I7jizHEXLIYsoOUF4YQmpIXMkESvjn01Do6X+Z5RlLcQ4P2JiES 1b+h0lEjJo72i/ivupLTGm+v2QCgA9Skg1NDXYnsyeHOfOZga+emyviq8NDoJeq1kUx/ +7HutYhvQ0yX0i2SilQEEYY/x84GGHP2zOvmBl49ep/2+OogNQ9MbdsacOWRBQeRmkAS 72Qw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=VpCVBrQo6SsrzXDwOcXayzQcuay/1iBMWp+hcrPvScA=; b=dmVfHhm7DhWyWQrOY0Z+zfwNx32GkYbkpoq9hoRNiMUVQ8E8CXtYOSIWSv93b6uIai tvHKtli0zKDmdwgwUMh97KjS/m92JSmlAtZ2bO/mRzdd1/o5sGhhdpv13L0JWnXY+qMc 75YjmcC604Yc998fBNhdtxKInEoTT81WwlmGIcK1iFMoQHwmYFZUbGVv+0O8h2zskY55 hzcAYaqTMoyk6kSNnavoloJG5o0onN+v44K4D0i++d+ZBQRRRVo6MDJ4kCYv4KlyQFp4 NKOGKulk6fyKTzqACJC7dDuY/QDbsVFbIClcbRigXtAWR1RmMz5yspzS6olZoGu05/gS 34bw== X-Gm-Message-State: ABuFfohP/dacTQ23ms+1ikENYBZHmuQFnjLYKAzvEzoCYb1GR1Kb7YDj tXuDhJsTP4GtjYv4uORTOpY= X-Received: by 2002:a62:f58a:: with SMTP id b10-v6mr13219401pfm.253.1538077758227; Thu, 27 Sep 2018 12:49:18 -0700 (PDT) Received: from Asurada-Nvidia.nvidia.com (thunderhill.nvidia.com. [216.228.112.22]) by smtp.gmail.com with ESMTPSA id g65-v6sm1449850pfg.98.2018.09.27.12.49.17 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 27 Sep 2018 12:49:17 -0700 (PDT) From: Nicolin Chen To: jdelvare@suse.com, linux@roeck-us.net, robh+dt@kernel.org, mark.rutland@arm.com, corbet@lwn.net Cc: afd@ti.com, linux-hwmon@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org Subject: [PATCH v6 2/2] hwmon: ina3221: Read channel input source info from DT Date: Thu, 27 Sep 2018 12:49:10 -0700 Message-Id: <20180927194910.18464-3-nicoleotsuka@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180927194910.18464-1-nicoleotsuka@gmail.com> References: <20180927194910.18464-1-nicoleotsuka@gmail.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org An ina3221 chip has three input ports. Each port is used to measure the voltage and current of its input source. The DT binding now has defined bindings for their input sources, so the driver should read these information and handle accordingly. This patch adds a new structure of input source specific information including input source label, shunt resistor value and its connection status. It exposes these labels via in[123]_label sysfs nodes upon available, and also disables those channels where there are no input source being connected. Meanwhile, it also adds in[123]_enable sysfs nodes for users to get control of three channels, and returns -ENODATA code for any sensor read according to hwmon ABI. Signed-off-by: Nicolin Chen --- Changelog v5->v6: * Removed the code of hiding disconnected channels * Added in[123]_label sysfs nodes to control channels * Added -ENODATA return for sensor read at disabled channels v4->v5: * Replaced "shunt-resistor" with "shunt-resistor-micro-ohms" * Replaced "input-label" with "label" * Replaced "input-id" with "reg" * Simplified is_visible() by using index of the attr * Moved inX_label to index-0 and added comments for safety v3->v4: * Added is_visible callback function to hide sysfs nodes v2->v3: * N/A v1->v2: * Added a structure for input source corresponding to DT bindings * Moved shunt resistor value to the structure * Defined in[123]_label sysfs nodes instead of name[123]_input * Updated probe() function to get information from DT * Updated ina3221 hwmon documentation for the labels * Dropped dynamical group definition to keep all groups as they were Documentation/hwmon/ina3221 | 2 + drivers/hwmon/ina3221.c | 237 +++++++++++++++++++++++++++++++++--- 2 files changed, 225 insertions(+), 14 deletions(-) diff --git a/Documentation/hwmon/ina3221 b/Documentation/hwmon/ina3221 index 0ff74854cb2e..4b82cbfb551c 100644 --- a/Documentation/hwmon/ina3221 +++ b/Documentation/hwmon/ina3221 @@ -21,6 +21,8 @@ and power are calculated host-side from these. Sysfs entries ------------- +in[123]_label Voltage channel labels +in[123]_enable Voltage channel enable controls in[123]_input Bus voltage(mV) channels curr[123]_input Current(mA) measurement channels shunt[123]_resistor Shunt resistance(uOhm) channels diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index e6b49500c52a..5c16d78e7482 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -41,6 +41,7 @@ #define INA3221_CONFIG_MODE_SHUNT BIT(1) #define INA3221_CONFIG_MODE_BUS BIT(2) #define INA3221_CONFIG_MODE_CONTINUOUS BIT(3) +#define INA3221_CONFIG_CHx_EN(x) BIT(14 - (x)) #define INA3221_RSHUNT_DEFAULT 10000 @@ -75,6 +76,9 @@ enum ina3221_channels { }; static const unsigned int register_channel[] = { + [INA3221_BUS1] = INA3221_CHANNEL1, + [INA3221_BUS2] = INA3221_CHANNEL2, + [INA3221_BUS3] = INA3221_CHANNEL3, [INA3221_SHUNT1] = INA3221_CHANNEL1, [INA3221_SHUNT2] = INA3221_CHANNEL2, [INA3221_SHUNT3] = INA3221_CHANNEL3, @@ -86,18 +90,93 @@ static const unsigned int register_channel[] = { [INA3221_WARN3] = INA3221_CHANNEL3, }; +/** + * struct ina3221_input - channel input source specific information + * @label: label of channel input source + * @shunt_resistor: shunt resistor value of channel input source + * @disconnected: connection status of channel input source + */ +struct ina3221_input { + const char *label; + int shunt_resistor; + bool disconnected; +}; + /** * struct ina3221_data - device specific information * @regmap: Register map of the device * @fields: Register fields of the device - * @shunt_resistors: Array of resistor values per channel + * @inputs: Array of channel input source specific structures */ struct ina3221_data { struct regmap *regmap; struct regmap_field *fields[F_MAX_FIELDS]; - int shunt_resistors[INA3221_NUM_CHANNELS]; + struct ina3221_input inputs[INA3221_NUM_CHANNELS]; }; +static inline bool ina3221_is_enable(struct ina3221_data *ina, int channel) +{ + unsigned int config; + int ret; + + /* Return false to reject further read */ + ret = regmap_read(ina->regmap, INA3221_CONFIG, &config); + if (ret) + return false; + + return (config & INA3221_CONFIG_CHx_EN(channel)) > 0; +} + +static ssize_t ina3221_show_label(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int channel = sd_attr->index; + struct ina3221_input *input = &ina->inputs[channel]; + + return snprintf(buf, PAGE_SIZE, "%s\n", input->label); +} + +static ssize_t ina3221_show_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int channel = sd_attr->index; + + return snprintf(buf, PAGE_SIZE, "%d\n", + ina3221_is_enable(ina, channel)); +} + +static ssize_t ina3221_set_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); + struct ina3221_data *ina = dev_get_drvdata(dev); + unsigned int channel = sd_attr->index; + unsigned int mask = INA3221_CONFIG_CHx_EN(channel); + unsigned int config; + int val, ret; + + ret = kstrtoint(buf, 0, &val); + if (ret) + return ret; + + /* inX_enable only accepts 1 for enabling or 0 for disabling */ + if (val != 0 && val != 1) + return -EINVAL; + + config = val ? mask : 0; + + ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, mask, config); + if (ret) + return ret; + + return count; +} + static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, int *val) { @@ -120,8 +199,13 @@ static ssize_t ina3221_show_bus_voltage(struct device *dev, struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int reg = sd_attr->index; + unsigned int channel = register_channel[reg]; int val, voltage_mv, ret; + /* No data for read-only attribute if channel is disabled */ + if (!attr->store && !ina3221_is_enable(ina, channel)) + return -ENODATA; + ret = ina3221_read_value(ina, reg, &val); if (ret) return ret; @@ -138,8 +222,13 @@ static ssize_t ina3221_show_shunt_voltage(struct device *dev, struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int reg = sd_attr->index; + unsigned int channel = register_channel[reg]; int val, voltage_uv, ret; + /* No data for read-only attribute if channel is disabled */ + if (!attr->store && !ina3221_is_enable(ina, channel)) + return -ENODATA; + ret = ina3221_read_value(ina, reg, &val); if (ret) return ret; @@ -155,9 +244,14 @@ static ssize_t ina3221_show_current(struct device *dev, struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int reg = sd_attr->index; unsigned int channel = register_channel[reg]; - int resistance_uo = ina->shunt_resistors[channel]; + struct ina3221_input *input = &ina->inputs[channel]; + int resistance_uo = input->shunt_resistor; int val, current_ma, voltage_nv, ret; + /* No data for read-only attribute if channel is disabled */ + if (!attr->store && !ina3221_is_enable(ina, channel)) + return -ENODATA; + ret = ina3221_read_value(ina, reg, &val); if (ret) return ret; @@ -176,7 +270,8 @@ static ssize_t ina3221_set_current(struct device *dev, struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int reg = sd_attr->index; unsigned int channel = register_channel[reg]; - int resistance_uo = ina->shunt_resistors[channel]; + struct ina3221_input *input = &ina->inputs[channel]; + int resistance_uo = input->shunt_resistor; int val, current_ma, voltage_uv, ret; ret = kstrtoint(buf, 0, ¤t_ma); @@ -209,11 +304,9 @@ static ssize_t ina3221_show_shunt(struct device *dev, struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int channel = sd_attr->index; - unsigned int resistance_uo; - - resistance_uo = ina->shunt_resistors[channel]; + struct ina3221_input *input = &ina->inputs[channel]; - return snprintf(buf, PAGE_SIZE, "%d\n", resistance_uo); + return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor); } static ssize_t ina3221_set_shunt(struct device *dev, @@ -223,6 +316,7 @@ static ssize_t ina3221_set_shunt(struct device *dev, struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); struct ina3221_data *ina = dev_get_drvdata(dev); unsigned int channel = sd_attr->index; + struct ina3221_input *input = &ina->inputs[channel]; int val; int ret; @@ -232,7 +326,7 @@ static ssize_t ina3221_set_shunt(struct device *dev, val = clamp_val(val, 1, INT_MAX); - ina->shunt_resistors[channel] = val; + input->shunt_resistor = val; return count; } @@ -253,6 +347,22 @@ static ssize_t ina3221_show_alert(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", regval); } +/* input channel label */ +static SENSOR_DEVICE_ATTR(in1_label, 0444, + ina3221_show_label, NULL, INA3221_CHANNEL1); +static SENSOR_DEVICE_ATTR(in2_label, 0444, + ina3221_show_label, NULL, INA3221_CHANNEL2); +static SENSOR_DEVICE_ATTR(in3_label, 0444, + ina3221_show_label, NULL, INA3221_CHANNEL3); + +/* voltage channel enable */ +static SENSOR_DEVICE_ATTR(in1_enable, 0644, + ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL1); +static SENSOR_DEVICE_ATTR(in2_enable, 0644, + ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL2); +static SENSOR_DEVICE_ATTR(in3_enable, 0644, + ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL3); + /* bus voltage */ static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina3221_show_bus_voltage, NULL, INA3221_BUS1); @@ -318,7 +428,9 @@ static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ina3221_show_shunt_voltage, NULL, INA3221_SHUNT3); static struct attribute *ina3221_attrs[] = { - /* channel 1 */ + /* channel 1 -- make sure label at first */ + &sensor_dev_attr_in1_label.dev_attr.attr, + &sensor_dev_attr_in1_enable.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_curr1_input.dev_attr.attr, &sensor_dev_attr_shunt1_resistor.dev_attr.attr, @@ -328,7 +440,9 @@ static struct attribute *ina3221_attrs[] = { &sensor_dev_attr_curr1_max_alarm.dev_attr.attr, &sensor_dev_attr_in4_input.dev_attr.attr, - /* channel 2 */ + /* channel 2 -- make sure label at first */ + &sensor_dev_attr_in2_label.dev_attr.attr, + &sensor_dev_attr_in2_enable.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, &sensor_dev_attr_curr2_input.dev_attr.attr, &sensor_dev_attr_shunt2_resistor.dev_attr.attr, @@ -338,7 +452,9 @@ static struct attribute *ina3221_attrs[] = { &sensor_dev_attr_curr2_max_alarm.dev_attr.attr, &sensor_dev_attr_in5_input.dev_attr.attr, - /* channel 3 */ + /* channel 3 -- make sure label at first */ + &sensor_dev_attr_in3_label.dev_attr.attr, + &sensor_dev_attr_in3_enable.dev_attr.attr, &sensor_dev_attr_in3_input.dev_attr.attr, &sensor_dev_attr_curr3_input.dev_attr.attr, &sensor_dev_attr_shunt3_resistor.dev_attr.attr, @@ -350,7 +466,30 @@ static struct attribute *ina3221_attrs[] = { NULL, }; -ATTRIBUTE_GROUPS(ina3221); + +static umode_t ina3221_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + const int max_attrs = ARRAY_SIZE(ina3221_attrs) - 1; + const int num_attrs = max_attrs / INA3221_NUM_CHANNELS; + struct device *dev = kobj_to_dev(kobj); + struct ina3221_data *ina = dev_get_drvdata(dev); + enum ina3221_channels channel = n / num_attrs; + struct ina3221_input *input = &ina->inputs[channel]; + int index = n % num_attrs; + + /* Hide label node if label is not provided */ + if (index == 0 && !input->label) + return 0; + + return attr->mode; +} + +static const struct attribute_group ina3221_group = { + .is_visible = ina3221_attr_is_visible, + .attrs = ina3221_attrs, +}; +__ATTRIBUTE_GROUPS(ina3221); static const struct regmap_range ina3221_yes_ranges[] = { regmap_reg_range(INA3221_SHUNT1, INA3221_BUS3), @@ -370,6 +509,60 @@ static const struct regmap_config ina3221_regmap_config = { .volatile_table = &ina3221_volatile_table, }; +static int ina3221_probe_child_from_dt(struct device *dev, + struct device_node *child, + struct ina3221_data *ina) +{ + struct ina3221_input *input; + u32 val; + int ret; + + ret = of_property_read_u32(child, "reg", &val); + if (ret) { + dev_err(dev, "missing reg property of %s\n", child->name); + return ret; + } else if (val > INA3221_CHANNEL3) { + dev_err(dev, "invalid reg %d of %s\n", val, child->name); + return ret; + } + + input = &ina->inputs[val]; + + /* Log the disconnected channel input */ + if (!of_device_is_available(child)) { + input->disconnected = true; + return 0; + } + + /* Save the connected input label if available */ + of_property_read_string(child, "label", &input->label); + + /* Overwrite default shunt resistor value optionally */ + if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) + input->shunt_resistor = val; + + return 0; +} + +static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina) +{ + const struct device_node *np = dev->of_node; + struct device_node *child; + int ret; + + /* Compatible with non-DT platforms */ + if (!np) + return 0; + + for_each_child_of_node(np, child) { + ret = ina3221_probe_child_from_dt(dev, child, ina); + if (ret) + return ret; + } + + return 0; +} + static int ina3221_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -377,6 +570,7 @@ static int ina3221_probe(struct i2c_client *client, struct ina3221_data *ina; struct device *hwmon_dev; int i, ret; + u16 mask; ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL); if (!ina) @@ -399,7 +593,13 @@ static int ina3221_probe(struct i2c_client *client, } for (i = 0; i < INA3221_NUM_CHANNELS; i++) - ina->shunt_resistors[i] = INA3221_RSHUNT_DEFAULT; + ina->inputs[i].shunt_resistor = INA3221_RSHUNT_DEFAULT; + + ret = ina3221_probe_from_dt(dev, ina); + if (ret) { + dev_err(dev, "Unable to probe from device treee\n"); + return ret; + } ret = regmap_field_write(ina->fields[F_RST], true); if (ret) { @@ -407,6 +607,15 @@ static int ina3221_probe(struct i2c_client *client, return ret; } + /* Disable channels if their inputs are disconnected */ + for (i = 0, mask = 0; i < INA3221_NUM_CHANNELS; i++) { + if (ina->inputs[i].disconnected) + mask |= INA3221_CONFIG_CHx_EN(i); + } + ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, mask, 0); + if (ret) + return ret; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, ina, ina3221_groups); -- 2.17.1