xref: /openbmc/linux/drivers/hwmon/ina3221.c (revision ead21c77)
17cb6dcffSAndrew F. Davis /*
27cb6dcffSAndrew F. Davis  * INA3221 Triple Current/Voltage Monitor
37cb6dcffSAndrew F. Davis  *
47cb6dcffSAndrew F. Davis  * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
57cb6dcffSAndrew F. Davis  *	Andrew F. Davis <afd@ti.com>
67cb6dcffSAndrew F. Davis  *
77cb6dcffSAndrew F. Davis  * This program is free software; you can redistribute it and/or modify
87cb6dcffSAndrew F. Davis  * it under the terms of the GNU General Public License version 2 as
97cb6dcffSAndrew F. Davis  * published by the Free Software Foundation.
107cb6dcffSAndrew F. Davis  *
117cb6dcffSAndrew F. Davis  * This program is distributed in the hope that it will be useful, but
127cb6dcffSAndrew F. Davis  * WITHOUT ANY WARRANTY; without even the implied warranty of
137cb6dcffSAndrew F. Davis  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
147cb6dcffSAndrew F. Davis  * General Public License for more details.
157cb6dcffSAndrew F. Davis  */
167cb6dcffSAndrew F. Davis 
177cb6dcffSAndrew F. Davis #include <linux/hwmon.h>
187cb6dcffSAndrew F. Davis #include <linux/hwmon-sysfs.h>
197cb6dcffSAndrew F. Davis #include <linux/i2c.h>
207cb6dcffSAndrew F. Davis #include <linux/module.h>
217cb6dcffSAndrew F. Davis #include <linux/of.h>
227cb6dcffSAndrew F. Davis #include <linux/regmap.h>
237cb6dcffSAndrew F. Davis 
247cb6dcffSAndrew F. Davis #define INA3221_DRIVER_NAME		"ina3221"
257cb6dcffSAndrew F. Davis 
267cb6dcffSAndrew F. Davis #define INA3221_CONFIG			0x00
277cb6dcffSAndrew F. Davis #define INA3221_SHUNT1			0x01
287cb6dcffSAndrew F. Davis #define INA3221_BUS1			0x02
297cb6dcffSAndrew F. Davis #define INA3221_SHUNT2			0x03
307cb6dcffSAndrew F. Davis #define INA3221_BUS2			0x04
317cb6dcffSAndrew F. Davis #define INA3221_SHUNT3			0x05
327cb6dcffSAndrew F. Davis #define INA3221_BUS3			0x06
337cb6dcffSAndrew F. Davis #define INA3221_CRIT1			0x07
347cb6dcffSAndrew F. Davis #define INA3221_WARN1			0x08
357cb6dcffSAndrew F. Davis #define INA3221_CRIT2			0x09
367cb6dcffSAndrew F. Davis #define INA3221_WARN2			0x0a
377cb6dcffSAndrew F. Davis #define INA3221_CRIT3			0x0b
387cb6dcffSAndrew F. Davis #define INA3221_WARN3			0x0c
397cb6dcffSAndrew F. Davis #define INA3221_MASK_ENABLE		0x0f
407cb6dcffSAndrew F. Davis 
4159d608e1SNicolin Chen #define INA3221_CONFIG_MODE_MASK	GENMASK(2, 0)
4259d608e1SNicolin Chen #define INA3221_CONFIG_MODE_POWERDOWN	0
43791ebc9dSNicolin Chen #define INA3221_CONFIG_MODE_SHUNT	BIT(0)
44791ebc9dSNicolin Chen #define INA3221_CONFIG_MODE_BUS		BIT(1)
45791ebc9dSNicolin Chen #define INA3221_CONFIG_MODE_CONTINUOUS	BIT(2)
46a9e9dd9cSNicolin Chen #define INA3221_CONFIG_CHx_EN(x)	BIT(14 - (x))
477cb6dcffSAndrew F. Davis 
487cb6dcffSAndrew F. Davis #define INA3221_RSHUNT_DEFAULT		10000
497cb6dcffSAndrew F. Davis 
507cb6dcffSAndrew F. Davis enum ina3221_fields {
517cb6dcffSAndrew F. Davis 	/* Configuration */
527cb6dcffSAndrew F. Davis 	F_RST,
537cb6dcffSAndrew F. Davis 
547cb6dcffSAndrew F. Davis 	/* Alert Flags */
557cb6dcffSAndrew F. Davis 	F_WF3, F_WF2, F_WF1,
567cb6dcffSAndrew F. Davis 	F_CF3, F_CF2, F_CF1,
577cb6dcffSAndrew F. Davis 
587cb6dcffSAndrew F. Davis 	/* sentinel */
597cb6dcffSAndrew F. Davis 	F_MAX_FIELDS
607cb6dcffSAndrew F. Davis };
617cb6dcffSAndrew F. Davis 
627cb6dcffSAndrew F. Davis static const struct reg_field ina3221_reg_fields[] = {
637cb6dcffSAndrew F. Davis 	[F_RST] = REG_FIELD(INA3221_CONFIG, 15, 15),
647cb6dcffSAndrew F. Davis 
657cb6dcffSAndrew F. Davis 	[F_WF3] = REG_FIELD(INA3221_MASK_ENABLE, 3, 3),
667cb6dcffSAndrew F. Davis 	[F_WF2] = REG_FIELD(INA3221_MASK_ENABLE, 4, 4),
677cb6dcffSAndrew F. Davis 	[F_WF1] = REG_FIELD(INA3221_MASK_ENABLE, 5, 5),
687cb6dcffSAndrew F. Davis 	[F_CF3] = REG_FIELD(INA3221_MASK_ENABLE, 7, 7),
697cb6dcffSAndrew F. Davis 	[F_CF2] = REG_FIELD(INA3221_MASK_ENABLE, 8, 8),
707cb6dcffSAndrew F. Davis 	[F_CF1] = REG_FIELD(INA3221_MASK_ENABLE, 9, 9),
717cb6dcffSAndrew F. Davis };
727cb6dcffSAndrew F. Davis 
737cb6dcffSAndrew F. Davis enum ina3221_channels {
747cb6dcffSAndrew F. Davis 	INA3221_CHANNEL1,
757cb6dcffSAndrew F. Davis 	INA3221_CHANNEL2,
767cb6dcffSAndrew F. Davis 	INA3221_CHANNEL3,
777cb6dcffSAndrew F. Davis 	INA3221_NUM_CHANNELS
787cb6dcffSAndrew F. Davis };
797cb6dcffSAndrew F. Davis 
807cb6dcffSAndrew F. Davis static const unsigned int register_channel[] = {
81a9e9dd9cSNicolin Chen 	[INA3221_BUS1] = INA3221_CHANNEL1,
82a9e9dd9cSNicolin Chen 	[INA3221_BUS2] = INA3221_CHANNEL2,
83a9e9dd9cSNicolin Chen 	[INA3221_BUS3] = INA3221_CHANNEL3,
847cb6dcffSAndrew F. Davis 	[INA3221_SHUNT1] = INA3221_CHANNEL1,
857cb6dcffSAndrew F. Davis 	[INA3221_SHUNT2] = INA3221_CHANNEL2,
867cb6dcffSAndrew F. Davis 	[INA3221_SHUNT3] = INA3221_CHANNEL3,
877cb6dcffSAndrew F. Davis 	[INA3221_CRIT1] = INA3221_CHANNEL1,
887cb6dcffSAndrew F. Davis 	[INA3221_CRIT2] = INA3221_CHANNEL2,
897cb6dcffSAndrew F. Davis 	[INA3221_CRIT3] = INA3221_CHANNEL3,
907cb6dcffSAndrew F. Davis 	[INA3221_WARN1] = INA3221_CHANNEL1,
917cb6dcffSAndrew F. Davis 	[INA3221_WARN2] = INA3221_CHANNEL2,
927cb6dcffSAndrew F. Davis 	[INA3221_WARN3] = INA3221_CHANNEL3,
937cb6dcffSAndrew F. Davis };
947cb6dcffSAndrew F. Davis 
957cb6dcffSAndrew F. Davis /**
96a9e9dd9cSNicolin Chen  * struct ina3221_input - channel input source specific information
97a9e9dd9cSNicolin Chen  * @label: label of channel input source
98a9e9dd9cSNicolin Chen  * @shunt_resistor: shunt resistor value of channel input source
99a9e9dd9cSNicolin Chen  * @disconnected: connection status of channel input source
100a9e9dd9cSNicolin Chen  */
101a9e9dd9cSNicolin Chen struct ina3221_input {
102a9e9dd9cSNicolin Chen 	const char *label;
103a9e9dd9cSNicolin Chen 	int shunt_resistor;
104a9e9dd9cSNicolin Chen 	bool disconnected;
105a9e9dd9cSNicolin Chen };
106a9e9dd9cSNicolin Chen 
107a9e9dd9cSNicolin Chen /**
1087cb6dcffSAndrew F. Davis  * struct ina3221_data - device specific information
1097cb6dcffSAndrew F. Davis  * @regmap: Register map of the device
1107cb6dcffSAndrew F. Davis  * @fields: Register fields of the device
111a9e9dd9cSNicolin Chen  * @inputs: Array of channel input source specific structures
11259d608e1SNicolin Chen  * @reg_config: Register value of INA3221_CONFIG
1137cb6dcffSAndrew F. Davis  */
1147cb6dcffSAndrew F. Davis struct ina3221_data {
1157cb6dcffSAndrew F. Davis 	struct regmap *regmap;
1167cb6dcffSAndrew F. Davis 	struct regmap_field *fields[F_MAX_FIELDS];
117a9e9dd9cSNicolin Chen 	struct ina3221_input inputs[INA3221_NUM_CHANNELS];
11859d608e1SNicolin Chen 	u32 reg_config;
1197cb6dcffSAndrew F. Davis };
1207cb6dcffSAndrew F. Davis 
121a9e9dd9cSNicolin Chen static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel)
122a9e9dd9cSNicolin Chen {
123a9e9dd9cSNicolin Chen 	return ina->reg_config & INA3221_CONFIG_CHx_EN(channel);
124a9e9dd9cSNicolin Chen }
125a9e9dd9cSNicolin Chen 
126a9e9dd9cSNicolin Chen static ssize_t ina3221_show_label(struct device *dev,
127a9e9dd9cSNicolin Chen 				  struct device_attribute *attr, char *buf)
128a9e9dd9cSNicolin Chen {
129a9e9dd9cSNicolin Chen 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
130a9e9dd9cSNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
131a9e9dd9cSNicolin Chen 	unsigned int channel = sd_attr->index;
132a9e9dd9cSNicolin Chen 	struct ina3221_input *input = &ina->inputs[channel];
133a9e9dd9cSNicolin Chen 
134a9e9dd9cSNicolin Chen 	return snprintf(buf, PAGE_SIZE, "%s\n", input->label);
135a9e9dd9cSNicolin Chen }
136a9e9dd9cSNicolin Chen 
137a9e9dd9cSNicolin Chen static ssize_t ina3221_show_enable(struct device *dev,
138a9e9dd9cSNicolin Chen 				   struct device_attribute *attr, char *buf)
139a9e9dd9cSNicolin Chen {
140a9e9dd9cSNicolin Chen 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
141a9e9dd9cSNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
142a9e9dd9cSNicolin Chen 	unsigned int channel = sd_attr->index;
143a9e9dd9cSNicolin Chen 
144a9e9dd9cSNicolin Chen 	return snprintf(buf, PAGE_SIZE, "%d\n",
145a9e9dd9cSNicolin Chen 			ina3221_is_enabled(ina, channel));
146a9e9dd9cSNicolin Chen }
147a9e9dd9cSNicolin Chen 
148a9e9dd9cSNicolin Chen static ssize_t ina3221_set_enable(struct device *dev,
149a9e9dd9cSNicolin Chen 				  struct device_attribute *attr,
150a9e9dd9cSNicolin Chen 				  const char *buf, size_t count)
151a9e9dd9cSNicolin Chen {
152a9e9dd9cSNicolin Chen 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
153a9e9dd9cSNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
154a9e9dd9cSNicolin Chen 	unsigned int channel = sd_attr->index;
155a9e9dd9cSNicolin Chen 	u16 config, mask = INA3221_CONFIG_CHx_EN(channel);
156a9e9dd9cSNicolin Chen 	bool enable;
157a9e9dd9cSNicolin Chen 	int ret;
158a9e9dd9cSNicolin Chen 
159a9e9dd9cSNicolin Chen 	ret = kstrtobool(buf, &enable);
160a9e9dd9cSNicolin Chen 	if (ret)
161a9e9dd9cSNicolin Chen 		return ret;
162a9e9dd9cSNicolin Chen 
163a9e9dd9cSNicolin Chen 	config = enable ? mask : 0;
164a9e9dd9cSNicolin Chen 
165a9e9dd9cSNicolin Chen 	/* Enable or disable the channel */
166a9e9dd9cSNicolin Chen 	ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, mask, config);
167a9e9dd9cSNicolin Chen 	if (ret)
168a9e9dd9cSNicolin Chen 		return ret;
169a9e9dd9cSNicolin Chen 
170a9e9dd9cSNicolin Chen 	/* Cache the latest config register value */
171a9e9dd9cSNicolin Chen 	ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config);
172a9e9dd9cSNicolin Chen 	if (ret)
173a9e9dd9cSNicolin Chen 		return ret;
174a9e9dd9cSNicolin Chen 
175a9e9dd9cSNicolin Chen 	return count;
176a9e9dd9cSNicolin Chen }
177a9e9dd9cSNicolin Chen 
1787cb6dcffSAndrew F. Davis static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg,
1797cb6dcffSAndrew F. Davis 			      int *val)
1807cb6dcffSAndrew F. Davis {
1817cb6dcffSAndrew F. Davis 	unsigned int regval;
1827cb6dcffSAndrew F. Davis 	int ret;
1837cb6dcffSAndrew F. Davis 
1847cb6dcffSAndrew F. Davis 	ret = regmap_read(ina->regmap, reg, &regval);
1857cb6dcffSAndrew F. Davis 	if (ret)
1867cb6dcffSAndrew F. Davis 		return ret;
1877cb6dcffSAndrew F. Davis 
1887cb6dcffSAndrew F. Davis 	*val = sign_extend32(regval >> 3, 12);
1897cb6dcffSAndrew F. Davis 
1907cb6dcffSAndrew F. Davis 	return 0;
1917cb6dcffSAndrew F. Davis }
1927cb6dcffSAndrew F. Davis 
1937cb6dcffSAndrew F. Davis static ssize_t ina3221_show_bus_voltage(struct device *dev,
1947cb6dcffSAndrew F. Davis 					struct device_attribute *attr,
1957cb6dcffSAndrew F. Davis 					char *buf)
1967cb6dcffSAndrew F. Davis {
1977cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
1987cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
1997cb6dcffSAndrew F. Davis 	unsigned int reg = sd_attr->index;
200a9e9dd9cSNicolin Chen 	unsigned int channel = register_channel[reg];
2017cb6dcffSAndrew F. Davis 	int val, voltage_mv, ret;
2027cb6dcffSAndrew F. Davis 
203a9e9dd9cSNicolin Chen 	/* No data for read-only attribute if channel is disabled */
204a9e9dd9cSNicolin Chen 	if (!attr->store && !ina3221_is_enabled(ina, channel))
205a9e9dd9cSNicolin Chen 		return -ENODATA;
206a9e9dd9cSNicolin Chen 
2077cb6dcffSAndrew F. Davis 	ret = ina3221_read_value(ina, reg, &val);
2087cb6dcffSAndrew F. Davis 	if (ret)
2097cb6dcffSAndrew F. Davis 		return ret;
2107cb6dcffSAndrew F. Davis 
2117cb6dcffSAndrew F. Davis 	voltage_mv = val * 8;
2127cb6dcffSAndrew F. Davis 
2137cb6dcffSAndrew F. Davis 	return snprintf(buf, PAGE_SIZE, "%d\n", voltage_mv);
2147cb6dcffSAndrew F. Davis }
2157cb6dcffSAndrew F. Davis 
2167cb6dcffSAndrew F. Davis static ssize_t ina3221_show_shunt_voltage(struct device *dev,
2177cb6dcffSAndrew F. Davis 					  struct device_attribute *attr,
2187cb6dcffSAndrew F. Davis 					  char *buf)
2197cb6dcffSAndrew F. Davis {
2207cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
2217cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
2227cb6dcffSAndrew F. Davis 	unsigned int reg = sd_attr->index;
223a9e9dd9cSNicolin Chen 	unsigned int channel = register_channel[reg];
2247cb6dcffSAndrew F. Davis 	int val, voltage_uv, ret;
2257cb6dcffSAndrew F. Davis 
226a9e9dd9cSNicolin Chen 	/* No data for read-only attribute if channel is disabled */
227a9e9dd9cSNicolin Chen 	if (!attr->store && !ina3221_is_enabled(ina, channel))
228a9e9dd9cSNicolin Chen 		return -ENODATA;
229a9e9dd9cSNicolin Chen 
2307cb6dcffSAndrew F. Davis 	ret = ina3221_read_value(ina, reg, &val);
2317cb6dcffSAndrew F. Davis 	if (ret)
2327cb6dcffSAndrew F. Davis 		return ret;
2337cb6dcffSAndrew F. Davis 	voltage_uv = val * 40;
2347cb6dcffSAndrew F. Davis 
2357cb6dcffSAndrew F. Davis 	return snprintf(buf, PAGE_SIZE, "%d\n", voltage_uv);
2367cb6dcffSAndrew F. Davis }
2377cb6dcffSAndrew F. Davis 
2387cb6dcffSAndrew F. Davis static ssize_t ina3221_show_current(struct device *dev,
2397cb6dcffSAndrew F. Davis 				    struct device_attribute *attr, char *buf)
2407cb6dcffSAndrew F. Davis {
2417cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
2427cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
2437cb6dcffSAndrew F. Davis 	unsigned int reg = sd_attr->index;
2447cb6dcffSAndrew F. Davis 	unsigned int channel = register_channel[reg];
245a9e9dd9cSNicolin Chen 	struct ina3221_input *input = &ina->inputs[channel];
246a9e9dd9cSNicolin Chen 	int resistance_uo = input->shunt_resistor;
2477cb6dcffSAndrew F. Davis 	int val, current_ma, voltage_nv, ret;
2487cb6dcffSAndrew F. Davis 
249a9e9dd9cSNicolin Chen 	/* No data for read-only attribute if channel is disabled */
250a9e9dd9cSNicolin Chen 	if (!attr->store && !ina3221_is_enabled(ina, channel))
251a9e9dd9cSNicolin Chen 		return -ENODATA;
252a9e9dd9cSNicolin Chen 
2537cb6dcffSAndrew F. Davis 	ret = ina3221_read_value(ina, reg, &val);
2547cb6dcffSAndrew F. Davis 	if (ret)
2557cb6dcffSAndrew F. Davis 		return ret;
2567cb6dcffSAndrew F. Davis 	voltage_nv = val * 40000;
2577cb6dcffSAndrew F. Davis 
2587cb6dcffSAndrew F. Davis 	current_ma = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo);
2597cb6dcffSAndrew F. Davis 
2607cb6dcffSAndrew F. Davis 	return snprintf(buf, PAGE_SIZE, "%d\n", current_ma);
2617cb6dcffSAndrew F. Davis }
2627cb6dcffSAndrew F. Davis 
2637cb6dcffSAndrew F. Davis static ssize_t ina3221_set_current(struct device *dev,
2647cb6dcffSAndrew F. Davis 				   struct device_attribute *attr,
2657cb6dcffSAndrew F. Davis 				   const char *buf, size_t count)
2667cb6dcffSAndrew F. Davis {
2677cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
2687cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
2697cb6dcffSAndrew F. Davis 	unsigned int reg = sd_attr->index;
2707cb6dcffSAndrew F. Davis 	unsigned int channel = register_channel[reg];
271a9e9dd9cSNicolin Chen 	struct ina3221_input *input = &ina->inputs[channel];
272a9e9dd9cSNicolin Chen 	int resistance_uo = input->shunt_resistor;
2737cb6dcffSAndrew F. Davis 	int val, current_ma, voltage_uv, ret;
2747cb6dcffSAndrew F. Davis 
2757cb6dcffSAndrew F. Davis 	ret = kstrtoint(buf, 0, &current_ma);
2767cb6dcffSAndrew F. Davis 	if (ret)
2777cb6dcffSAndrew F. Davis 		return ret;
2787cb6dcffSAndrew F. Davis 
2797cb6dcffSAndrew F. Davis 	/* clamp current */
2807cb6dcffSAndrew F. Davis 	current_ma = clamp_val(current_ma,
2817cb6dcffSAndrew F. Davis 			       INT_MIN / resistance_uo,
2827cb6dcffSAndrew F. Davis 			       INT_MAX / resistance_uo);
2837cb6dcffSAndrew F. Davis 
2847cb6dcffSAndrew F. Davis 	voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000);
2857cb6dcffSAndrew F. Davis 
2867cb6dcffSAndrew F. Davis 	/* clamp voltage */
2877cb6dcffSAndrew F. Davis 	voltage_uv = clamp_val(voltage_uv, -163800, 163800);
2887cb6dcffSAndrew F. Davis 
2897cb6dcffSAndrew F. Davis 	/* 1 / 40uV(scale) << 3(register shift) = 5 */
2907cb6dcffSAndrew F. Davis 	val = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8;
2917cb6dcffSAndrew F. Davis 
2927cb6dcffSAndrew F. Davis 	ret = regmap_write(ina->regmap, reg, val);
2937cb6dcffSAndrew F. Davis 	if (ret)
2947cb6dcffSAndrew F. Davis 		return ret;
2957cb6dcffSAndrew F. Davis 
2967cb6dcffSAndrew F. Davis 	return count;
2977cb6dcffSAndrew F. Davis }
2987cb6dcffSAndrew F. Davis 
2997cb6dcffSAndrew F. Davis static ssize_t ina3221_show_shunt(struct device *dev,
3007cb6dcffSAndrew F. Davis 				  struct device_attribute *attr, char *buf)
3017cb6dcffSAndrew F. Davis {
3027cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
3037cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
3047cb6dcffSAndrew F. Davis 	unsigned int channel = sd_attr->index;
305a9e9dd9cSNicolin Chen 	struct ina3221_input *input = &ina->inputs[channel];
3067cb6dcffSAndrew F. Davis 
307a9e9dd9cSNicolin Chen 	return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor);
3087cb6dcffSAndrew F. Davis }
3097cb6dcffSAndrew F. Davis 
3107cb6dcffSAndrew F. Davis static ssize_t ina3221_set_shunt(struct device *dev,
3117cb6dcffSAndrew F. Davis 				 struct device_attribute *attr,
3127cb6dcffSAndrew F. Davis 				 const char *buf, size_t count)
3137cb6dcffSAndrew F. Davis {
3147cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
3157cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
3167cb6dcffSAndrew F. Davis 	unsigned int channel = sd_attr->index;
317a9e9dd9cSNicolin Chen 	struct ina3221_input *input = &ina->inputs[channel];
3189ad0df1aSGuenter Roeck 	int val;
3197cb6dcffSAndrew F. Davis 	int ret;
3207cb6dcffSAndrew F. Davis 
3219ad0df1aSGuenter Roeck 	ret = kstrtoint(buf, 0, &val);
3227cb6dcffSAndrew F. Davis 	if (ret)
3237cb6dcffSAndrew F. Davis 		return ret;
3247cb6dcffSAndrew F. Davis 
3259ad0df1aSGuenter Roeck 	val = clamp_val(val, 1, INT_MAX);
3267cb6dcffSAndrew F. Davis 
327a9e9dd9cSNicolin Chen 	input->shunt_resistor = val;
3287cb6dcffSAndrew F. Davis 
3297cb6dcffSAndrew F. Davis 	return count;
3307cb6dcffSAndrew F. Davis }
3317cb6dcffSAndrew F. Davis 
3327cb6dcffSAndrew F. Davis static ssize_t ina3221_show_alert(struct device *dev,
3337cb6dcffSAndrew F. Davis 				  struct device_attribute *attr, char *buf)
3347cb6dcffSAndrew F. Davis {
3357cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
3367cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
3377cb6dcffSAndrew F. Davis 	unsigned int field = sd_attr->index;
3387cb6dcffSAndrew F. Davis 	unsigned int regval;
3397cb6dcffSAndrew F. Davis 	int ret;
3407cb6dcffSAndrew F. Davis 
3417cb6dcffSAndrew F. Davis 	ret = regmap_field_read(ina->fields[field], &regval);
3427cb6dcffSAndrew F. Davis 	if (ret)
3437cb6dcffSAndrew F. Davis 		return ret;
3447cb6dcffSAndrew F. Davis 
3457cb6dcffSAndrew F. Davis 	return snprintf(buf, PAGE_SIZE, "%d\n", regval);
3467cb6dcffSAndrew F. Davis }
3477cb6dcffSAndrew F. Davis 
348a9e9dd9cSNicolin Chen /* input channel label */
349a9e9dd9cSNicolin Chen static SENSOR_DEVICE_ATTR(in1_label, 0444,
350a9e9dd9cSNicolin Chen 		ina3221_show_label, NULL, INA3221_CHANNEL1);
351a9e9dd9cSNicolin Chen static SENSOR_DEVICE_ATTR(in2_label, 0444,
352a9e9dd9cSNicolin Chen 		ina3221_show_label, NULL, INA3221_CHANNEL2);
353a9e9dd9cSNicolin Chen static SENSOR_DEVICE_ATTR(in3_label, 0444,
354a9e9dd9cSNicolin Chen 		ina3221_show_label, NULL, INA3221_CHANNEL3);
355a9e9dd9cSNicolin Chen 
356a9e9dd9cSNicolin Chen /* voltage channel enable */
357a9e9dd9cSNicolin Chen static SENSOR_DEVICE_ATTR(in1_enable, 0644,
358a9e9dd9cSNicolin Chen 		ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL1);
359a9e9dd9cSNicolin Chen static SENSOR_DEVICE_ATTR(in2_enable, 0644,
360a9e9dd9cSNicolin Chen 		ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL2);
361a9e9dd9cSNicolin Chen static SENSOR_DEVICE_ATTR(in3_enable, 0644,
362a9e9dd9cSNicolin Chen 		ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL3);
363a9e9dd9cSNicolin Chen 
3647cb6dcffSAndrew F. Davis /* bus voltage */
3657cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO,
3667cb6dcffSAndrew F. Davis 		ina3221_show_bus_voltage, NULL, INA3221_BUS1);
3677cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO,
3687cb6dcffSAndrew F. Davis 		ina3221_show_bus_voltage, NULL, INA3221_BUS2);
3697cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO,
3707cb6dcffSAndrew F. Davis 		ina3221_show_bus_voltage, NULL, INA3221_BUS3);
3717cb6dcffSAndrew F. Davis 
3727cb6dcffSAndrew F. Davis /* calculated current */
3737cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO,
3747cb6dcffSAndrew F. Davis 		ina3221_show_current, NULL, INA3221_SHUNT1);
3757cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO,
3767cb6dcffSAndrew F. Davis 		ina3221_show_current, NULL, INA3221_SHUNT2);
3777cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO,
3787cb6dcffSAndrew F. Davis 		ina3221_show_current, NULL, INA3221_SHUNT3);
3797cb6dcffSAndrew F. Davis 
3807cb6dcffSAndrew F. Davis /* shunt resistance */
3817cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(shunt1_resistor, S_IRUGO | S_IWUSR,
3827cb6dcffSAndrew F. Davis 		ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL1);
3837cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(shunt2_resistor, S_IRUGO | S_IWUSR,
3847cb6dcffSAndrew F. Davis 		ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL2);
3857cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(shunt3_resistor, S_IRUGO | S_IWUSR,
3867cb6dcffSAndrew F. Davis 		ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL3);
3877cb6dcffSAndrew F. Davis 
3887cb6dcffSAndrew F. Davis /* critical current */
3897cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr1_crit, S_IRUGO | S_IWUSR,
3907cb6dcffSAndrew F. Davis 		ina3221_show_current, ina3221_set_current, INA3221_CRIT1);
3917cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr2_crit, S_IRUGO | S_IWUSR,
3927cb6dcffSAndrew F. Davis 		ina3221_show_current, ina3221_set_current, INA3221_CRIT2);
3937cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr3_crit, S_IRUGO | S_IWUSR,
3947cb6dcffSAndrew F. Davis 		ina3221_show_current, ina3221_set_current, INA3221_CRIT3);
3957cb6dcffSAndrew F. Davis 
3967cb6dcffSAndrew F. Davis /* critical current alert */
3977cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr1_crit_alarm, S_IRUGO,
3987cb6dcffSAndrew F. Davis 		ina3221_show_alert, NULL, F_CF1);
3997cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr2_crit_alarm, S_IRUGO,
4007cb6dcffSAndrew F. Davis 		ina3221_show_alert, NULL, F_CF2);
4017cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr3_crit_alarm, S_IRUGO,
4027cb6dcffSAndrew F. Davis 		ina3221_show_alert, NULL, F_CF3);
4037cb6dcffSAndrew F. Davis 
4047cb6dcffSAndrew F. Davis /* warning current */
4057cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR,
4067cb6dcffSAndrew F. Davis 		ina3221_show_current, ina3221_set_current, INA3221_WARN1);
4077cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr2_max, S_IRUGO | S_IWUSR,
4087cb6dcffSAndrew F. Davis 		ina3221_show_current, ina3221_set_current, INA3221_WARN2);
4097cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr3_max, S_IRUGO | S_IWUSR,
4107cb6dcffSAndrew F. Davis 		ina3221_show_current, ina3221_set_current, INA3221_WARN3);
4117cb6dcffSAndrew F. Davis 
4127cb6dcffSAndrew F. Davis /* warning current alert */
4137cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO,
4147cb6dcffSAndrew F. Davis 		ina3221_show_alert, NULL, F_WF1);
4157cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr2_max_alarm, S_IRUGO,
4167cb6dcffSAndrew F. Davis 		ina3221_show_alert, NULL, F_WF2);
4177cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr3_max_alarm, S_IRUGO,
4187cb6dcffSAndrew F. Davis 		ina3221_show_alert, NULL, F_WF3);
4197cb6dcffSAndrew F. Davis 
4207cb6dcffSAndrew F. Davis /* shunt voltage */
4217cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO,
4227cb6dcffSAndrew F. Davis 		ina3221_show_shunt_voltage, NULL, INA3221_SHUNT1);
4237cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO,
4247cb6dcffSAndrew F. Davis 		ina3221_show_shunt_voltage, NULL, INA3221_SHUNT2);
4257cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO,
4267cb6dcffSAndrew F. Davis 		ina3221_show_shunt_voltage, NULL, INA3221_SHUNT3);
4277cb6dcffSAndrew F. Davis 
4287cb6dcffSAndrew F. Davis static struct attribute *ina3221_attrs[] = {
429a9e9dd9cSNicolin Chen 	/* channel 1 -- make sure label at first */
430a9e9dd9cSNicolin Chen 	&sensor_dev_attr_in1_label.dev_attr.attr,
431a9e9dd9cSNicolin Chen 	&sensor_dev_attr_in1_enable.dev_attr.attr,
4327cb6dcffSAndrew F. Davis 	&sensor_dev_attr_in1_input.dev_attr.attr,
4337cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr1_input.dev_attr.attr,
4347cb6dcffSAndrew F. Davis 	&sensor_dev_attr_shunt1_resistor.dev_attr.attr,
4357cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr1_crit.dev_attr.attr,
4367cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr1_crit_alarm.dev_attr.attr,
4377cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr1_max.dev_attr.attr,
4387cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
4397cb6dcffSAndrew F. Davis 	&sensor_dev_attr_in4_input.dev_attr.attr,
4407cb6dcffSAndrew F. Davis 
441a9e9dd9cSNicolin Chen 	/* channel 2 -- make sure label at first */
442a9e9dd9cSNicolin Chen 	&sensor_dev_attr_in2_label.dev_attr.attr,
443a9e9dd9cSNicolin Chen 	&sensor_dev_attr_in2_enable.dev_attr.attr,
4447cb6dcffSAndrew F. Davis 	&sensor_dev_attr_in2_input.dev_attr.attr,
4457cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr2_input.dev_attr.attr,
4467cb6dcffSAndrew F. Davis 	&sensor_dev_attr_shunt2_resistor.dev_attr.attr,
4477cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr2_crit.dev_attr.attr,
4487cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr2_crit_alarm.dev_attr.attr,
4497cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr2_max.dev_attr.attr,
4507cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
4517cb6dcffSAndrew F. Davis 	&sensor_dev_attr_in5_input.dev_attr.attr,
4527cb6dcffSAndrew F. Davis 
453a9e9dd9cSNicolin Chen 	/* channel 3 -- make sure label at first */
454a9e9dd9cSNicolin Chen 	&sensor_dev_attr_in3_label.dev_attr.attr,
455a9e9dd9cSNicolin Chen 	&sensor_dev_attr_in3_enable.dev_attr.attr,
4567cb6dcffSAndrew F. Davis 	&sensor_dev_attr_in3_input.dev_attr.attr,
4577cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr3_input.dev_attr.attr,
4587cb6dcffSAndrew F. Davis 	&sensor_dev_attr_shunt3_resistor.dev_attr.attr,
4597cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr3_crit.dev_attr.attr,
4607cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr3_crit_alarm.dev_attr.attr,
4617cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr3_max.dev_attr.attr,
4627cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr3_max_alarm.dev_attr.attr,
4637cb6dcffSAndrew F. Davis 	&sensor_dev_attr_in6_input.dev_attr.attr,
4647cb6dcffSAndrew F. Davis 
4657cb6dcffSAndrew F. Davis 	NULL,
4667cb6dcffSAndrew F. Davis };
467a9e9dd9cSNicolin Chen 
468a9e9dd9cSNicolin Chen static umode_t ina3221_attr_is_visible(struct kobject *kobj,
469a9e9dd9cSNicolin Chen 				       struct attribute *attr, int n)
470a9e9dd9cSNicolin Chen {
471a9e9dd9cSNicolin Chen 	const int max_attrs = ARRAY_SIZE(ina3221_attrs) - 1;
472a9e9dd9cSNicolin Chen 	const int num_attrs = max_attrs / INA3221_NUM_CHANNELS;
473a9e9dd9cSNicolin Chen 	struct device *dev = kobj_to_dev(kobj);
474a9e9dd9cSNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
475a9e9dd9cSNicolin Chen 	enum ina3221_channels channel = n / num_attrs;
476a9e9dd9cSNicolin Chen 	struct ina3221_input *input = &ina->inputs[channel];
477a9e9dd9cSNicolin Chen 	int index = n % num_attrs;
478a9e9dd9cSNicolin Chen 
479a9e9dd9cSNicolin Chen 	/* Hide label node if label is not provided */
480a9e9dd9cSNicolin Chen 	if (index == 0 && !input->label)
481a9e9dd9cSNicolin Chen 		return 0;
482a9e9dd9cSNicolin Chen 
483a9e9dd9cSNicolin Chen 	return attr->mode;
484a9e9dd9cSNicolin Chen }
485a9e9dd9cSNicolin Chen 
486a9e9dd9cSNicolin Chen static const struct attribute_group ina3221_group = {
487a9e9dd9cSNicolin Chen 	.is_visible = ina3221_attr_is_visible,
488a9e9dd9cSNicolin Chen 	.attrs = ina3221_attrs,
489a9e9dd9cSNicolin Chen };
490a9e9dd9cSNicolin Chen __ATTRIBUTE_GROUPS(ina3221);
4917cb6dcffSAndrew F. Davis 
4927cb6dcffSAndrew F. Davis static const struct regmap_range ina3221_yes_ranges[] = {
493c20217b3SNicolin Chen 	regmap_reg_range(INA3221_CONFIG, INA3221_BUS3),
4947cb6dcffSAndrew F. Davis 	regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE),
4957cb6dcffSAndrew F. Davis };
4967cb6dcffSAndrew F. Davis 
4977cb6dcffSAndrew F. Davis static const struct regmap_access_table ina3221_volatile_table = {
4987cb6dcffSAndrew F. Davis 	.yes_ranges = ina3221_yes_ranges,
4997cb6dcffSAndrew F. Davis 	.n_yes_ranges = ARRAY_SIZE(ina3221_yes_ranges),
5007cb6dcffSAndrew F. Davis };
5017cb6dcffSAndrew F. Davis 
5027cb6dcffSAndrew F. Davis static const struct regmap_config ina3221_regmap_config = {
5037cb6dcffSAndrew F. Davis 	.reg_bits = 8,
5047cb6dcffSAndrew F. Davis 	.val_bits = 16,
5057cb6dcffSAndrew F. Davis 
5067cb6dcffSAndrew F. Davis 	.cache_type = REGCACHE_RBTREE,
5077cb6dcffSAndrew F. Davis 	.volatile_table = &ina3221_volatile_table,
5087cb6dcffSAndrew F. Davis };
5097cb6dcffSAndrew F. Davis 
510a9e9dd9cSNicolin Chen static int ina3221_probe_child_from_dt(struct device *dev,
511a9e9dd9cSNicolin Chen 				       struct device_node *child,
512a9e9dd9cSNicolin Chen 				       struct ina3221_data *ina)
513a9e9dd9cSNicolin Chen {
514a9e9dd9cSNicolin Chen 	struct ina3221_input *input;
515a9e9dd9cSNicolin Chen 	u32 val;
516a9e9dd9cSNicolin Chen 	int ret;
517a9e9dd9cSNicolin Chen 
518a9e9dd9cSNicolin Chen 	ret = of_property_read_u32(child, "reg", &val);
519a9e9dd9cSNicolin Chen 	if (ret) {
520a9e9dd9cSNicolin Chen 		dev_err(dev, "missing reg property of %s\n", child->name);
521a9e9dd9cSNicolin Chen 		return ret;
522a9e9dd9cSNicolin Chen 	} else if (val > INA3221_CHANNEL3) {
523a9e9dd9cSNicolin Chen 		dev_err(dev, "invalid reg %d of %s\n", val, child->name);
524a9e9dd9cSNicolin Chen 		return ret;
525a9e9dd9cSNicolin Chen 	}
526a9e9dd9cSNicolin Chen 
527a9e9dd9cSNicolin Chen 	input = &ina->inputs[val];
528a9e9dd9cSNicolin Chen 
529a9e9dd9cSNicolin Chen 	/* Log the disconnected channel input */
530a9e9dd9cSNicolin Chen 	if (!of_device_is_available(child)) {
531a9e9dd9cSNicolin Chen 		input->disconnected = true;
532a9e9dd9cSNicolin Chen 		return 0;
533a9e9dd9cSNicolin Chen 	}
534a9e9dd9cSNicolin Chen 
535a9e9dd9cSNicolin Chen 	/* Save the connected input label if available */
536a9e9dd9cSNicolin Chen 	of_property_read_string(child, "label", &input->label);
537a9e9dd9cSNicolin Chen 
538a9e9dd9cSNicolin Chen 	/* Overwrite default shunt resistor value optionally */
539a9e9dd9cSNicolin Chen 	if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val))
540a9e9dd9cSNicolin Chen 		input->shunt_resistor = val;
541a9e9dd9cSNicolin Chen 
542a9e9dd9cSNicolin Chen 	return 0;
543a9e9dd9cSNicolin Chen }
544a9e9dd9cSNicolin Chen 
545a9e9dd9cSNicolin Chen static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina)
546a9e9dd9cSNicolin Chen {
547a9e9dd9cSNicolin Chen 	const struct device_node *np = dev->of_node;
548a9e9dd9cSNicolin Chen 	struct device_node *child;
549a9e9dd9cSNicolin Chen 	int ret;
550a9e9dd9cSNicolin Chen 
551a9e9dd9cSNicolin Chen 	/* Compatible with non-DT platforms */
552a9e9dd9cSNicolin Chen 	if (!np)
553a9e9dd9cSNicolin Chen 		return 0;
554a9e9dd9cSNicolin Chen 
555a9e9dd9cSNicolin Chen 	for_each_child_of_node(np, child) {
556a9e9dd9cSNicolin Chen 		ret = ina3221_probe_child_from_dt(dev, child, ina);
557a9e9dd9cSNicolin Chen 		if (ret)
558a9e9dd9cSNicolin Chen 			return ret;
559a9e9dd9cSNicolin Chen 	}
560a9e9dd9cSNicolin Chen 
561a9e9dd9cSNicolin Chen 	return 0;
562a9e9dd9cSNicolin Chen }
563a9e9dd9cSNicolin Chen 
5647cb6dcffSAndrew F. Davis static int ina3221_probe(struct i2c_client *client,
5657cb6dcffSAndrew F. Davis 			 const struct i2c_device_id *id)
5667cb6dcffSAndrew F. Davis {
5677cb6dcffSAndrew F. Davis 	struct device *dev = &client->dev;
5687cb6dcffSAndrew F. Davis 	struct ina3221_data *ina;
5697cb6dcffSAndrew F. Davis 	struct device *hwmon_dev;
5707cb6dcffSAndrew F. Davis 	int i, ret;
5717cb6dcffSAndrew F. Davis 
5727cb6dcffSAndrew F. Davis 	ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL);
5737cb6dcffSAndrew F. Davis 	if (!ina)
5747cb6dcffSAndrew F. Davis 		return -ENOMEM;
5757cb6dcffSAndrew F. Davis 
5767cb6dcffSAndrew F. Davis 	ina->regmap = devm_regmap_init_i2c(client, &ina3221_regmap_config);
5777cb6dcffSAndrew F. Davis 	if (IS_ERR(ina->regmap)) {
5787cb6dcffSAndrew F. Davis 		dev_err(dev, "Unable to allocate register map\n");
5797cb6dcffSAndrew F. Davis 		return PTR_ERR(ina->regmap);
5807cb6dcffSAndrew F. Davis 	}
5817cb6dcffSAndrew F. Davis 
5827cb6dcffSAndrew F. Davis 	for (i = 0; i < F_MAX_FIELDS; i++) {
5837cb6dcffSAndrew F. Davis 		ina->fields[i] = devm_regmap_field_alloc(dev,
5847cb6dcffSAndrew F. Davis 							 ina->regmap,
5857cb6dcffSAndrew F. Davis 							 ina3221_reg_fields[i]);
5867cb6dcffSAndrew F. Davis 		if (IS_ERR(ina->fields[i])) {
5877cb6dcffSAndrew F. Davis 			dev_err(dev, "Unable to allocate regmap fields\n");
5887cb6dcffSAndrew F. Davis 			return PTR_ERR(ina->fields[i]);
5897cb6dcffSAndrew F. Davis 		}
5907cb6dcffSAndrew F. Davis 	}
5917cb6dcffSAndrew F. Davis 
5927cb6dcffSAndrew F. Davis 	for (i = 0; i < INA3221_NUM_CHANNELS; i++)
593a9e9dd9cSNicolin Chen 		ina->inputs[i].shunt_resistor = INA3221_RSHUNT_DEFAULT;
594a9e9dd9cSNicolin Chen 
595a9e9dd9cSNicolin Chen 	ret = ina3221_probe_from_dt(dev, ina);
596a9e9dd9cSNicolin Chen 	if (ret) {
597a9e9dd9cSNicolin Chen 		dev_err(dev, "Unable to probe from device tree\n");
598a9e9dd9cSNicolin Chen 		return ret;
599a9e9dd9cSNicolin Chen 	}
6007cb6dcffSAndrew F. Davis 
6017cb6dcffSAndrew F. Davis 	ret = regmap_field_write(ina->fields[F_RST], true);
6027cb6dcffSAndrew F. Davis 	if (ret) {
6037cb6dcffSAndrew F. Davis 		dev_err(dev, "Unable to reset device\n");
6047cb6dcffSAndrew F. Davis 		return ret;
6057cb6dcffSAndrew F. Davis 	}
6067cb6dcffSAndrew F. Davis 
607a9e9dd9cSNicolin Chen 	/* Sync config register after reset */
608a9e9dd9cSNicolin Chen 	ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config);
609a9e9dd9cSNicolin Chen 	if (ret)
610a9e9dd9cSNicolin Chen 		return ret;
611a9e9dd9cSNicolin Chen 
612a9e9dd9cSNicolin Chen 	/* Disable channels if their inputs are disconnected */
613a9e9dd9cSNicolin Chen 	for (i = 0; i < INA3221_NUM_CHANNELS; i++) {
614a9e9dd9cSNicolin Chen 		if (ina->inputs[i].disconnected)
615a9e9dd9cSNicolin Chen 			ina->reg_config &= ~INA3221_CONFIG_CHx_EN(i);
616a9e9dd9cSNicolin Chen 	}
617a9e9dd9cSNicolin Chen 	ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config);
618a9e9dd9cSNicolin Chen 	if (ret)
619a9e9dd9cSNicolin Chen 		return ret;
620a9e9dd9cSNicolin Chen 
62159d608e1SNicolin Chen 	dev_set_drvdata(dev, ina);
62259d608e1SNicolin Chen 
6237cb6dcffSAndrew F. Davis 	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
6247cb6dcffSAndrew F. Davis 							   client->name,
6257cb6dcffSAndrew F. Davis 							   ina, ina3221_groups);
6267cb6dcffSAndrew F. Davis 	if (IS_ERR(hwmon_dev)) {
6277cb6dcffSAndrew F. Davis 		dev_err(dev, "Unable to register hwmon device\n");
6287cb6dcffSAndrew F. Davis 		return PTR_ERR(hwmon_dev);
6297cb6dcffSAndrew F. Davis 	}
6307cb6dcffSAndrew F. Davis 
6317cb6dcffSAndrew F. Davis 	return 0;
6327cb6dcffSAndrew F. Davis }
6337cb6dcffSAndrew F. Davis 
634ead21c77SArnd Bergmann static int __maybe_unused ina3221_suspend(struct device *dev)
63559d608e1SNicolin Chen {
63659d608e1SNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
63759d608e1SNicolin Chen 	int ret;
63859d608e1SNicolin Chen 
63959d608e1SNicolin Chen 	/* Save config register value and enable cache-only */
64059d608e1SNicolin Chen 	ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config);
64159d608e1SNicolin Chen 	if (ret)
64259d608e1SNicolin Chen 		return ret;
64359d608e1SNicolin Chen 
64459d608e1SNicolin Chen 	/* Set to power-down mode for power saving */
64559d608e1SNicolin Chen 	ret = regmap_update_bits(ina->regmap, INA3221_CONFIG,
64659d608e1SNicolin Chen 				 INA3221_CONFIG_MODE_MASK,
64759d608e1SNicolin Chen 				 INA3221_CONFIG_MODE_POWERDOWN);
64859d608e1SNicolin Chen 	if (ret)
64959d608e1SNicolin Chen 		return ret;
65059d608e1SNicolin Chen 
65159d608e1SNicolin Chen 	regcache_cache_only(ina->regmap, true);
65259d608e1SNicolin Chen 	regcache_mark_dirty(ina->regmap);
65359d608e1SNicolin Chen 
65459d608e1SNicolin Chen 	return 0;
65559d608e1SNicolin Chen }
65659d608e1SNicolin Chen 
657ead21c77SArnd Bergmann static int __maybe_unused ina3221_resume(struct device *dev)
65859d608e1SNicolin Chen {
65959d608e1SNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
66059d608e1SNicolin Chen 	int ret;
66159d608e1SNicolin Chen 
66259d608e1SNicolin Chen 	regcache_cache_only(ina->regmap, false);
66359d608e1SNicolin Chen 
66459d608e1SNicolin Chen 	/* Software reset the chip */
66559d608e1SNicolin Chen 	ret = regmap_field_write(ina->fields[F_RST], true);
66659d608e1SNicolin Chen 	if (ret) {
66759d608e1SNicolin Chen 		dev_err(dev, "Unable to reset device\n");
66859d608e1SNicolin Chen 		return ret;
66959d608e1SNicolin Chen 	}
67059d608e1SNicolin Chen 
67159d608e1SNicolin Chen 	/* Restore cached register values to hardware */
67259d608e1SNicolin Chen 	ret = regcache_sync(ina->regmap);
67359d608e1SNicolin Chen 	if (ret)
67459d608e1SNicolin Chen 		return ret;
67559d608e1SNicolin Chen 
67659d608e1SNicolin Chen 	/* Restore config register value to hardware */
67759d608e1SNicolin Chen 	ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config);
67859d608e1SNicolin Chen 	if (ret)
67959d608e1SNicolin Chen 		return ret;
68059d608e1SNicolin Chen 
68159d608e1SNicolin Chen 	return 0;
68259d608e1SNicolin Chen }
68359d608e1SNicolin Chen 
68459d608e1SNicolin Chen static const struct dev_pm_ops ina3221_pm = {
68559d608e1SNicolin Chen 	SET_SYSTEM_SLEEP_PM_OPS(ina3221_suspend, ina3221_resume)
68659d608e1SNicolin Chen };
68759d608e1SNicolin Chen 
6887cb6dcffSAndrew F. Davis static const struct of_device_id ina3221_of_match_table[] = {
6897cb6dcffSAndrew F. Davis 	{ .compatible = "ti,ina3221", },
6907cb6dcffSAndrew F. Davis 	{ /* sentinel */ }
6917cb6dcffSAndrew F. Davis };
6927cb6dcffSAndrew F. Davis MODULE_DEVICE_TABLE(of, ina3221_of_match_table);
6937cb6dcffSAndrew F. Davis 
6947cb6dcffSAndrew F. Davis static const struct i2c_device_id ina3221_ids[] = {
6957cb6dcffSAndrew F. Davis 	{ "ina3221", 0 },
6967cb6dcffSAndrew F. Davis 	{ /* sentinel */ }
6977cb6dcffSAndrew F. Davis };
6987cb6dcffSAndrew F. Davis MODULE_DEVICE_TABLE(i2c, ina3221_ids);
6997cb6dcffSAndrew F. Davis 
7007cb6dcffSAndrew F. Davis static struct i2c_driver ina3221_i2c_driver = {
7017cb6dcffSAndrew F. Davis 	.probe = ina3221_probe,
7027cb6dcffSAndrew F. Davis 	.driver = {
7037cb6dcffSAndrew F. Davis 		.name = INA3221_DRIVER_NAME,
7047cb6dcffSAndrew F. Davis 		.of_match_table = ina3221_of_match_table,
70559d608e1SNicolin Chen 		.pm = &ina3221_pm,
7067cb6dcffSAndrew F. Davis 	},
7077cb6dcffSAndrew F. Davis 	.id_table = ina3221_ids,
7087cb6dcffSAndrew F. Davis };
7097cb6dcffSAndrew F. Davis module_i2c_driver(ina3221_i2c_driver);
7107cb6dcffSAndrew F. Davis 
7117cb6dcffSAndrew F. Davis MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
7127cb6dcffSAndrew F. Davis MODULE_DESCRIPTION("Texas Instruments INA3221 HWMon Driver");
7137cb6dcffSAndrew F. Davis MODULE_LICENSE("GPL v2");
714