xref: /openbmc/linux/drivers/hwmon/ina3221.c (revision 1975d167)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27cb6dcffSAndrew F. Davis /*
37cb6dcffSAndrew F. Davis  * INA3221 Triple Current/Voltage Monitor
47cb6dcffSAndrew F. Davis  *
5ad736c1aSAlexander A. Klimov  * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/
67cb6dcffSAndrew F. Davis  *	Andrew F. Davis <afd@ti.com>
77cb6dcffSAndrew F. Davis  */
87cb6dcffSAndrew F. Davis 
97cb6dcffSAndrew F. Davis #include <linux/hwmon.h>
107cb6dcffSAndrew F. Davis #include <linux/hwmon-sysfs.h>
117cb6dcffSAndrew F. Davis #include <linux/i2c.h>
127cb6dcffSAndrew F. Davis #include <linux/module.h>
1387625b24SNicolin Chen #include <linux/mutex.h>
147cb6dcffSAndrew F. Davis #include <linux/of.h>
15323aeb0eSNicolin Chen #include <linux/pm_runtime.h>
167cb6dcffSAndrew F. Davis #include <linux/regmap.h>
175c090abfSNicolin Chen #include <linux/util_macros.h>
187cb6dcffSAndrew F. Davis 
197cb6dcffSAndrew F. Davis #define INA3221_DRIVER_NAME		"ina3221"
207cb6dcffSAndrew F. Davis 
217cb6dcffSAndrew F. Davis #define INA3221_CONFIG			0x00
227cb6dcffSAndrew F. Davis #define INA3221_SHUNT1			0x01
237cb6dcffSAndrew F. Davis #define INA3221_BUS1			0x02
247cb6dcffSAndrew F. Davis #define INA3221_SHUNT2			0x03
257cb6dcffSAndrew F. Davis #define INA3221_BUS2			0x04
267cb6dcffSAndrew F. Davis #define INA3221_SHUNT3			0x05
277cb6dcffSAndrew F. Davis #define INA3221_BUS3			0x06
287cb6dcffSAndrew F. Davis #define INA3221_CRIT1			0x07
297cb6dcffSAndrew F. Davis #define INA3221_WARN1			0x08
307cb6dcffSAndrew F. Davis #define INA3221_CRIT2			0x09
317cb6dcffSAndrew F. Davis #define INA3221_WARN2			0x0a
327cb6dcffSAndrew F. Davis #define INA3221_CRIT3			0x0b
337cb6dcffSAndrew F. Davis #define INA3221_WARN3			0x0c
342057bdfbSNicolin Chen #define INA3221_SHUNT_SUM		0x0d
352057bdfbSNicolin Chen #define INA3221_CRIT_SUM		0x0e
367cb6dcffSAndrew F. Davis #define INA3221_MASK_ENABLE		0x0f
377cb6dcffSAndrew F. Davis 
3859d608e1SNicolin Chen #define INA3221_CONFIG_MODE_MASK	GENMASK(2, 0)
3959d608e1SNicolin Chen #define INA3221_CONFIG_MODE_POWERDOWN	0
40791ebc9dSNicolin Chen #define INA3221_CONFIG_MODE_SHUNT	BIT(0)
41791ebc9dSNicolin Chen #define INA3221_CONFIG_MODE_BUS		BIT(1)
42791ebc9dSNicolin Chen #define INA3221_CONFIG_MODE_CONTINUOUS	BIT(2)
434c0415a3SNicolin Chen #define INA3221_CONFIG_VSH_CT_SHIFT	3
444c0415a3SNicolin Chen #define INA3221_CONFIG_VSH_CT_MASK	GENMASK(5, 3)
454c0415a3SNicolin Chen #define INA3221_CONFIG_VSH_CT(x)	(((x) & GENMASK(5, 3)) >> 3)
464c0415a3SNicolin Chen #define INA3221_CONFIG_VBUS_CT_SHIFT	6
474c0415a3SNicolin Chen #define INA3221_CONFIG_VBUS_CT_MASK	GENMASK(8, 6)
484c0415a3SNicolin Chen #define INA3221_CONFIG_VBUS_CT(x)	(((x) & GENMASK(8, 6)) >> 6)
495c090abfSNicolin Chen #define INA3221_CONFIG_AVG_SHIFT	9
505c090abfSNicolin Chen #define INA3221_CONFIG_AVG_MASK		GENMASK(11, 9)
515c090abfSNicolin Chen #define INA3221_CONFIG_AVG(x)		(((x) & GENMASK(11, 9)) >> 9)
524c0415a3SNicolin Chen #define INA3221_CONFIG_CHs_EN_MASK	GENMASK(14, 12)
53a9e9dd9cSNicolin Chen #define INA3221_CONFIG_CHx_EN(x)	BIT(14 - (x))
547cb6dcffSAndrew F. Davis 
552057bdfbSNicolin Chen #define INA3221_MASK_ENABLE_SCC_MASK	GENMASK(14, 12)
562057bdfbSNicolin Chen 
57323aeb0eSNicolin Chen #define INA3221_CONFIG_DEFAULT		0x7127
587cb6dcffSAndrew F. Davis #define INA3221_RSHUNT_DEFAULT		10000
597cb6dcffSAndrew F. Davis 
607cb6dcffSAndrew F. Davis enum ina3221_fields {
617cb6dcffSAndrew F. Davis 	/* Configuration */
627cb6dcffSAndrew F. Davis 	F_RST,
637cb6dcffSAndrew F. Davis 
644c0415a3SNicolin Chen 	/* Status Flags */
654c0415a3SNicolin Chen 	F_CVRF,
664c0415a3SNicolin Chen 
672057bdfbSNicolin Chen 	/* Warning Flags */
687cb6dcffSAndrew F. Davis 	F_WF3, F_WF2, F_WF1,
692057bdfbSNicolin Chen 
702057bdfbSNicolin Chen 	/* Alert Flags: SF is the summation-alert flag */
712057bdfbSNicolin Chen 	F_SF, F_CF3, F_CF2, F_CF1,
727cb6dcffSAndrew F. Davis 
737cb6dcffSAndrew F. Davis 	/* sentinel */
747cb6dcffSAndrew F. Davis 	F_MAX_FIELDS
757cb6dcffSAndrew F. Davis };
767cb6dcffSAndrew F. Davis 
777cb6dcffSAndrew F. Davis static const struct reg_field ina3221_reg_fields[] = {
787cb6dcffSAndrew F. Davis 	[F_RST] = REG_FIELD(INA3221_CONFIG, 15, 15),
797cb6dcffSAndrew F. Davis 
804c0415a3SNicolin Chen 	[F_CVRF] = REG_FIELD(INA3221_MASK_ENABLE, 0, 0),
817cb6dcffSAndrew F. Davis 	[F_WF3] = REG_FIELD(INA3221_MASK_ENABLE, 3, 3),
827cb6dcffSAndrew F. Davis 	[F_WF2] = REG_FIELD(INA3221_MASK_ENABLE, 4, 4),
837cb6dcffSAndrew F. Davis 	[F_WF1] = REG_FIELD(INA3221_MASK_ENABLE, 5, 5),
842057bdfbSNicolin Chen 	[F_SF] = REG_FIELD(INA3221_MASK_ENABLE, 6, 6),
857cb6dcffSAndrew F. Davis 	[F_CF3] = REG_FIELD(INA3221_MASK_ENABLE, 7, 7),
867cb6dcffSAndrew F. Davis 	[F_CF2] = REG_FIELD(INA3221_MASK_ENABLE, 8, 8),
877cb6dcffSAndrew F. Davis 	[F_CF1] = REG_FIELD(INA3221_MASK_ENABLE, 9, 9),
887cb6dcffSAndrew F. Davis };
897cb6dcffSAndrew F. Davis 
907cb6dcffSAndrew F. Davis enum ina3221_channels {
917cb6dcffSAndrew F. Davis 	INA3221_CHANNEL1,
927cb6dcffSAndrew F. Davis 	INA3221_CHANNEL2,
937cb6dcffSAndrew F. Davis 	INA3221_CHANNEL3,
947cb6dcffSAndrew F. Davis 	INA3221_NUM_CHANNELS
957cb6dcffSAndrew F. Davis };
967cb6dcffSAndrew F. Davis 
977cb6dcffSAndrew F. Davis /**
98a9e9dd9cSNicolin Chen  * struct ina3221_input - channel input source specific information
99a9e9dd9cSNicolin Chen  * @label: label of channel input source
100a9e9dd9cSNicolin Chen  * @shunt_resistor: shunt resistor value of channel input source
101a9e9dd9cSNicolin Chen  * @disconnected: connection status of channel input source
102a9e9dd9cSNicolin Chen  */
103a9e9dd9cSNicolin Chen struct ina3221_input {
104a9e9dd9cSNicolin Chen 	const char *label;
105a9e9dd9cSNicolin Chen 	int shunt_resistor;
106a9e9dd9cSNicolin Chen 	bool disconnected;
107a9e9dd9cSNicolin Chen };
108a9e9dd9cSNicolin Chen 
109a9e9dd9cSNicolin Chen /**
1107cb6dcffSAndrew F. Davis  * struct ina3221_data - device specific information
111323aeb0eSNicolin Chen  * @pm_dev: Device pointer for pm runtime
1127cb6dcffSAndrew F. Davis  * @regmap: Register map of the device
1137cb6dcffSAndrew F. Davis  * @fields: Register fields of the device
114a9e9dd9cSNicolin Chen  * @inputs: Array of channel input source specific structures
11587625b24SNicolin Chen  * @lock: mutex lock to serialize sysfs attribute accesses
11659d608e1SNicolin Chen  * @reg_config: Register value of INA3221_CONFIG
1172057bdfbSNicolin Chen  * @summation_shunt_resistor: equivalent shunt resistor value for summation
11843dece16SNicolin Chen  * @single_shot: running in single-shot operating mode
1197cb6dcffSAndrew F. Davis  */
1207cb6dcffSAndrew F. Davis struct ina3221_data {
121323aeb0eSNicolin Chen 	struct device *pm_dev;
1227cb6dcffSAndrew F. Davis 	struct regmap *regmap;
1237cb6dcffSAndrew F. Davis 	struct regmap_field *fields[F_MAX_FIELDS];
124a9e9dd9cSNicolin Chen 	struct ina3221_input inputs[INA3221_NUM_CHANNELS];
12587625b24SNicolin Chen 	struct mutex lock;
12659d608e1SNicolin Chen 	u32 reg_config;
1272057bdfbSNicolin Chen 	int summation_shunt_resistor;
12843dece16SNicolin Chen 
12943dece16SNicolin Chen 	bool single_shot;
1307cb6dcffSAndrew F. Davis };
1317cb6dcffSAndrew F. Davis 
ina3221_is_enabled(struct ina3221_data * ina,int channel)132a9e9dd9cSNicolin Chen static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel)
133a9e9dd9cSNicolin Chen {
1342057bdfbSNicolin Chen 	/* Summation channel checks shunt resistor values */
1352057bdfbSNicolin Chen 	if (channel > INA3221_CHANNEL3)
1362057bdfbSNicolin Chen 		return ina->summation_shunt_resistor != 0;
1372057bdfbSNicolin Chen 
138323aeb0eSNicolin Chen 	return pm_runtime_active(ina->pm_dev) &&
139323aeb0eSNicolin Chen 	       (ina->reg_config & INA3221_CONFIG_CHx_EN(channel));
140a9e9dd9cSNicolin Chen }
141a9e9dd9cSNicolin Chen 
142f9279cdaSLee Jones /*
1432057bdfbSNicolin Chen  * Helper function to return the resistor value for current summation.
1442057bdfbSNicolin Chen  *
1452057bdfbSNicolin Chen  * There is a condition to calculate current summation -- all the shunt
1462057bdfbSNicolin Chen  * resistor values should be the same, so as to simply fit the formula:
1472057bdfbSNicolin Chen  *     current summation = shunt voltage summation / shunt resistor
1482057bdfbSNicolin Chen  *
1492057bdfbSNicolin Chen  * Returns the equivalent shunt resistor value on success or 0 on failure
1502057bdfbSNicolin Chen  */
ina3221_summation_shunt_resistor(struct ina3221_data * ina)1512057bdfbSNicolin Chen static inline int ina3221_summation_shunt_resistor(struct ina3221_data *ina)
1522057bdfbSNicolin Chen {
1532057bdfbSNicolin Chen 	struct ina3221_input *input = ina->inputs;
1542057bdfbSNicolin Chen 	int i, shunt_resistor = 0;
1552057bdfbSNicolin Chen 
1562057bdfbSNicolin Chen 	for (i = 0; i < INA3221_NUM_CHANNELS; i++) {
1572057bdfbSNicolin Chen 		if (input[i].disconnected || !input[i].shunt_resistor)
1582057bdfbSNicolin Chen 			continue;
1592057bdfbSNicolin Chen 		if (!shunt_resistor) {
1602057bdfbSNicolin Chen 			/* Found the reference shunt resistor value */
1612057bdfbSNicolin Chen 			shunt_resistor = input[i].shunt_resistor;
1622057bdfbSNicolin Chen 		} else {
1632057bdfbSNicolin Chen 			/* No summation if resistor values are different */
1642057bdfbSNicolin Chen 			if (shunt_resistor != input[i].shunt_resistor)
1652057bdfbSNicolin Chen 				return 0;
1662057bdfbSNicolin Chen 		}
1672057bdfbSNicolin Chen 	}
1682057bdfbSNicolin Chen 
1692057bdfbSNicolin Chen 	return shunt_resistor;
1702057bdfbSNicolin Chen }
1712057bdfbSNicolin Chen 
1724c0415a3SNicolin Chen /* Lookup table for Bus and Shunt conversion times in usec */
1734c0415a3SNicolin Chen static const u16 ina3221_conv_time[] = {
1744c0415a3SNicolin Chen 	140, 204, 332, 588, 1100, 2116, 4156, 8244,
1754c0415a3SNicolin Chen };
1764c0415a3SNicolin Chen 
1775c090abfSNicolin Chen /* Lookup table for number of samples using in averaging mode */
1785c090abfSNicolin Chen static const int ina3221_avg_samples[] = {
1795c090abfSNicolin Chen 	1, 4, 16, 64, 128, 256, 512, 1024,
1805c090abfSNicolin Chen };
1815c090abfSNicolin Chen 
182023912dbSNicolin Chen /* Converting update_interval in msec to conversion time in usec */
ina3221_interval_ms_to_conv_time(u16 config,int interval)183023912dbSNicolin Chen static inline u32 ina3221_interval_ms_to_conv_time(u16 config, int interval)
1844c0415a3SNicolin Chen {
185023912dbSNicolin Chen 	u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK);
186023912dbSNicolin Chen 	u32 samples_idx = INA3221_CONFIG_AVG(config);
187023912dbSNicolin Chen 	u32 samples = ina3221_avg_samples[samples_idx];
188023912dbSNicolin Chen 
189023912dbSNicolin Chen 	/* Bisect the result to Bus and Shunt conversion times */
190023912dbSNicolin Chen 	return DIV_ROUND_CLOSEST(interval * 1000 / 2, channels * samples);
191023912dbSNicolin Chen }
192023912dbSNicolin Chen 
193023912dbSNicolin Chen /* Converting CONFIG register value to update_interval in usec */
ina3221_reg_to_interval_us(u16 config)194023912dbSNicolin Chen static inline u32 ina3221_reg_to_interval_us(u16 config)
195023912dbSNicolin Chen {
196023912dbSNicolin Chen 	u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK);
197023912dbSNicolin Chen 	u32 vbus_ct_idx = INA3221_CONFIG_VBUS_CT(config);
198023912dbSNicolin Chen 	u32 vsh_ct_idx = INA3221_CONFIG_VSH_CT(config);
1994c0415a3SNicolin Chen 	u32 vbus_ct = ina3221_conv_time[vbus_ct_idx];
2004c0415a3SNicolin Chen 	u32 vsh_ct = ina3221_conv_time[vsh_ct_idx];
2014c0415a3SNicolin Chen 
2024c0415a3SNicolin Chen 	/* Calculate total conversion time */
2036b6af854SNinad Malwade 	return channels * (vbus_ct + vsh_ct);
204023912dbSNicolin Chen }
205023912dbSNicolin Chen 
ina3221_wait_for_data(struct ina3221_data * ina)206023912dbSNicolin Chen static inline int ina3221_wait_for_data(struct ina3221_data *ina)
207023912dbSNicolin Chen {
208023912dbSNicolin Chen 	u32 wait, cvrf;
209023912dbSNicolin Chen 
210023912dbSNicolin Chen 	wait = ina3221_reg_to_interval_us(ina->reg_config);
2114c0415a3SNicolin Chen 
2124c0415a3SNicolin Chen 	/* Polling the CVRF bit to make sure read data is ready */
2134c0415a3SNicolin Chen 	return regmap_field_read_poll_timeout(ina->fields[F_CVRF],
2142ccb4f16SNicolin Chen 					      cvrf, cvrf, wait, wait * 2);
2154c0415a3SNicolin Chen }
2164c0415a3SNicolin Chen 
ina3221_read_value(struct ina3221_data * ina,unsigned int reg,int * val)2177cb6dcffSAndrew F. Davis static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg,
2187cb6dcffSAndrew F. Davis 			      int *val)
2197cb6dcffSAndrew F. Davis {
2207cb6dcffSAndrew F. Davis 	unsigned int regval;
2217cb6dcffSAndrew F. Davis 	int ret;
2227cb6dcffSAndrew F. Davis 
2237cb6dcffSAndrew F. Davis 	ret = regmap_read(ina->regmap, reg, &regval);
2247cb6dcffSAndrew F. Davis 	if (ret)
2257cb6dcffSAndrew F. Davis 		return ret;
2267cb6dcffSAndrew F. Davis 
2272057bdfbSNicolin Chen 	/*
2282057bdfbSNicolin Chen 	 * Shunt Voltage Sum register has 14-bit value with 1-bit shift
2292057bdfbSNicolin Chen 	 * Other Shunt Voltage registers have 12 bits with 3-bit shift
2302057bdfbSNicolin Chen 	 */
231b8d27d2cSNinad Malwade 	if (reg == INA3221_SHUNT_SUM || reg == INA3221_CRIT_SUM)
2322057bdfbSNicolin Chen 		*val = sign_extend32(regval >> 1, 14);
2332057bdfbSNicolin Chen 	else
2347cb6dcffSAndrew F. Davis 		*val = sign_extend32(regval >> 3, 12);
2357cb6dcffSAndrew F. Davis 
2367cb6dcffSAndrew F. Davis 	return 0;
2377cb6dcffSAndrew F. Davis }
2387cb6dcffSAndrew F. Davis 
239d4b0166dSNicolin Chen static const u8 ina3221_in_reg[] = {
240d4b0166dSNicolin Chen 	INA3221_BUS1,
241d4b0166dSNicolin Chen 	INA3221_BUS2,
242d4b0166dSNicolin Chen 	INA3221_BUS3,
243d4b0166dSNicolin Chen 	INA3221_SHUNT1,
244d4b0166dSNicolin Chen 	INA3221_SHUNT2,
245d4b0166dSNicolin Chen 	INA3221_SHUNT3,
2462057bdfbSNicolin Chen 	INA3221_SHUNT_SUM,
247d4b0166dSNicolin Chen };
2487cb6dcffSAndrew F. Davis 
ina3221_read_chip(struct device * dev,u32 attr,long * val)2495c090abfSNicolin Chen static int ina3221_read_chip(struct device *dev, u32 attr, long *val)
2505c090abfSNicolin Chen {
2515c090abfSNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
2525c090abfSNicolin Chen 	int regval;
2535c090abfSNicolin Chen 
2545c090abfSNicolin Chen 	switch (attr) {
2555c090abfSNicolin Chen 	case hwmon_chip_samples:
2565c090abfSNicolin Chen 		regval = INA3221_CONFIG_AVG(ina->reg_config);
2575c090abfSNicolin Chen 		*val = ina3221_avg_samples[regval];
2585c090abfSNicolin Chen 		return 0;
259023912dbSNicolin Chen 	case hwmon_chip_update_interval:
260023912dbSNicolin Chen 		/* Return in msec */
261023912dbSNicolin Chen 		*val = ina3221_reg_to_interval_us(ina->reg_config);
262023912dbSNicolin Chen 		*val = DIV_ROUND_CLOSEST(*val, 1000);
263023912dbSNicolin Chen 		return 0;
2645c090abfSNicolin Chen 	default:
2655c090abfSNicolin Chen 		return -EOPNOTSUPP;
2665c090abfSNicolin Chen 	}
2675c090abfSNicolin Chen }
2685c090abfSNicolin Chen 
ina3221_read_in(struct device * dev,u32 attr,int channel,long * val)269d4b0166dSNicolin Chen static int ina3221_read_in(struct device *dev, u32 attr, int channel, long *val)
270d4b0166dSNicolin Chen {
271d4b0166dSNicolin Chen 	const bool is_shunt = channel > INA3221_CHANNEL3;
272d4b0166dSNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
273d4b0166dSNicolin Chen 	u8 reg = ina3221_in_reg[channel];
274d4b0166dSNicolin Chen 	int regval, ret;
275d4b0166dSNicolin Chen 
2762057bdfbSNicolin Chen 	/*
2772057bdfbSNicolin Chen 	 * Translate shunt channel index to sensor channel index except
2782057bdfbSNicolin Chen 	 * the 7th channel (6 since being 0-aligned) is for summation.
2792057bdfbSNicolin Chen 	 */
2802057bdfbSNicolin Chen 	if (channel != 6)
281d4b0166dSNicolin Chen 		channel %= INA3221_NUM_CHANNELS;
282d4b0166dSNicolin Chen 
283d4b0166dSNicolin Chen 	switch (attr) {
284d4b0166dSNicolin Chen 	case hwmon_in_input:
285d4b0166dSNicolin Chen 		if (!ina3221_is_enabled(ina, channel))
286a9e9dd9cSNicolin Chen 			return -ENODATA;
287a9e9dd9cSNicolin Chen 
28843dece16SNicolin Chen 		/* Write CONFIG register to trigger a single-shot measurement */
2896b6af854SNinad Malwade 		if (ina->single_shot) {
29043dece16SNicolin Chen 			regmap_write(ina->regmap, INA3221_CONFIG,
29143dece16SNicolin Chen 				     ina->reg_config);
29243dece16SNicolin Chen 
2934c0415a3SNicolin Chen 			ret = ina3221_wait_for_data(ina);
2944c0415a3SNicolin Chen 			if (ret)
2954c0415a3SNicolin Chen 				return ret;
2966b6af854SNinad Malwade 		}
2974c0415a3SNicolin Chen 
298d4b0166dSNicolin Chen 		ret = ina3221_read_value(ina, reg, &regval);
2997cb6dcffSAndrew F. Davis 		if (ret)
3007cb6dcffSAndrew F. Davis 			return ret;
3017cb6dcffSAndrew F. Davis 
302d4b0166dSNicolin Chen 		/*
303d4b0166dSNicolin Chen 		 * Scale of shunt voltage (uV): LSB is 40uV
304d4b0166dSNicolin Chen 		 * Scale of bus voltage (mV): LSB is 8mV
305d4b0166dSNicolin Chen 		 */
306d4b0166dSNicolin Chen 		*val = regval * (is_shunt ? 40 : 8);
307d4b0166dSNicolin Chen 		return 0;
308d4b0166dSNicolin Chen 	case hwmon_in_enable:
309d4b0166dSNicolin Chen 		*val = ina3221_is_enabled(ina, channel);
310d4b0166dSNicolin Chen 		return 0;
311d4b0166dSNicolin Chen 	default:
312d4b0166dSNicolin Chen 		return -EOPNOTSUPP;
313d4b0166dSNicolin Chen 	}
3147cb6dcffSAndrew F. Davis }
3157cb6dcffSAndrew F. Davis 
3162057bdfbSNicolin Chen static const u8 ina3221_curr_reg[][INA3221_NUM_CHANNELS + 1] = {
3172057bdfbSNicolin Chen 	[hwmon_curr_input] = { INA3221_SHUNT1, INA3221_SHUNT2,
3182057bdfbSNicolin Chen 			       INA3221_SHUNT3, INA3221_SHUNT_SUM },
3192057bdfbSNicolin Chen 	[hwmon_curr_max] = { INA3221_WARN1, INA3221_WARN2, INA3221_WARN3, 0 },
3202057bdfbSNicolin Chen 	[hwmon_curr_crit] = { INA3221_CRIT1, INA3221_CRIT2,
3212057bdfbSNicolin Chen 			      INA3221_CRIT3, INA3221_CRIT_SUM },
3222057bdfbSNicolin Chen 	[hwmon_curr_max_alarm] = { F_WF1, F_WF2, F_WF3, 0 },
3232057bdfbSNicolin Chen 	[hwmon_curr_crit_alarm] = { F_CF1, F_CF2, F_CF3, F_SF },
324d4b0166dSNicolin Chen };
325d4b0166dSNicolin Chen 
ina3221_read_curr(struct device * dev,u32 attr,int channel,long * val)326d4b0166dSNicolin Chen static int ina3221_read_curr(struct device *dev, u32 attr,
327d4b0166dSNicolin Chen 			     int channel, long *val)
3287cb6dcffSAndrew F. Davis {
3297cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
3302057bdfbSNicolin Chen 	struct ina3221_input *input = ina->inputs;
331d4b0166dSNicolin Chen 	u8 reg = ina3221_curr_reg[attr][channel];
3322057bdfbSNicolin Chen 	int resistance_uo, voltage_nv;
3332057bdfbSNicolin Chen 	int regval, ret;
3342057bdfbSNicolin Chen 
3352057bdfbSNicolin Chen 	if (channel > INA3221_CHANNEL3)
3362057bdfbSNicolin Chen 		resistance_uo = ina->summation_shunt_resistor;
3372057bdfbSNicolin Chen 	else
3382057bdfbSNicolin Chen 		resistance_uo = input[channel].shunt_resistor;
3397cb6dcffSAndrew F. Davis 
340d4b0166dSNicolin Chen 	switch (attr) {
341d4b0166dSNicolin Chen 	case hwmon_curr_input:
342d4b0166dSNicolin Chen 		if (!ina3221_is_enabled(ina, channel))
343a9e9dd9cSNicolin Chen 			return -ENODATA;
3444c0415a3SNicolin Chen 
34543dece16SNicolin Chen 		/* Write CONFIG register to trigger a single-shot measurement */
3466b6af854SNinad Malwade 		if (ina->single_shot) {
34743dece16SNicolin Chen 			regmap_write(ina->regmap, INA3221_CONFIG,
34843dece16SNicolin Chen 				     ina->reg_config);
34943dece16SNicolin Chen 
3504c0415a3SNicolin Chen 			ret = ina3221_wait_for_data(ina);
3514c0415a3SNicolin Chen 			if (ret)
3524c0415a3SNicolin Chen 				return ret;
3536b6af854SNinad Malwade 		}
3544c0415a3SNicolin Chen 
355df561f66SGustavo A. R. Silva 		fallthrough;
356d4b0166dSNicolin Chen 	case hwmon_curr_crit:
357d4b0166dSNicolin Chen 	case hwmon_curr_max:
3582057bdfbSNicolin Chen 		if (!resistance_uo)
3592057bdfbSNicolin Chen 			return -ENODATA;
3602057bdfbSNicolin Chen 
361d4b0166dSNicolin Chen 		ret = ina3221_read_value(ina, reg, &regval);
3627cb6dcffSAndrew F. Davis 		if (ret)
3637cb6dcffSAndrew F. Davis 			return ret;
3647cb6dcffSAndrew F. Davis 
365d4b0166dSNicolin Chen 		/* Scale of shunt voltage: LSB is 40uV (40000nV) */
366d4b0166dSNicolin Chen 		voltage_nv = regval * 40000;
367d4b0166dSNicolin Chen 		/* Return current in mA */
368d4b0166dSNicolin Chen 		*val = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo);
369d4b0166dSNicolin Chen 		return 0;
370d4b0166dSNicolin Chen 	case hwmon_curr_crit_alarm:
371d4b0166dSNicolin Chen 	case hwmon_curr_max_alarm:
372efb0489eSNicolin Chen 		/* No actual register read if channel is disabled */
373efb0489eSNicolin Chen 		if (!ina3221_is_enabled(ina, channel)) {
374efb0489eSNicolin Chen 			/* Return 0 for alert flags */
375efb0489eSNicolin Chen 			*val = 0;
376efb0489eSNicolin Chen 			return 0;
377efb0489eSNicolin Chen 		}
378d4b0166dSNicolin Chen 		ret = regmap_field_read(ina->fields[reg], &regval);
379d4b0166dSNicolin Chen 		if (ret)
380d4b0166dSNicolin Chen 			return ret;
381d4b0166dSNicolin Chen 		*val = regval;
382d4b0166dSNicolin Chen 		return 0;
383d4b0166dSNicolin Chen 	default:
384d4b0166dSNicolin Chen 		return -EOPNOTSUPP;
385d4b0166dSNicolin Chen 	}
3867cb6dcffSAndrew F. Davis }
3877cb6dcffSAndrew F. Davis 
ina3221_write_chip(struct device * dev,u32 attr,long val)3885c090abfSNicolin Chen static int ina3221_write_chip(struct device *dev, u32 attr, long val)
3895c090abfSNicolin Chen {
3905c090abfSNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
3915c090abfSNicolin Chen 	int ret, idx;
392521c0b61SNicolin Chen 	u32 tmp;
3935c090abfSNicolin Chen 
3945c090abfSNicolin Chen 	switch (attr) {
3955c090abfSNicolin Chen 	case hwmon_chip_samples:
3965c090abfSNicolin Chen 		idx = find_closest(val, ina3221_avg_samples,
3975c090abfSNicolin Chen 				   ARRAY_SIZE(ina3221_avg_samples));
3985c090abfSNicolin Chen 
399521c0b61SNicolin Chen 		tmp = (ina->reg_config & ~INA3221_CONFIG_AVG_MASK) |
400521c0b61SNicolin Chen 		      (idx << INA3221_CONFIG_AVG_SHIFT);
401521c0b61SNicolin Chen 		ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp);
4025c090abfSNicolin Chen 		if (ret)
4035c090abfSNicolin Chen 			return ret;
4045c090abfSNicolin Chen 
4055c090abfSNicolin Chen 		/* Update reg_config accordingly */
406521c0b61SNicolin Chen 		ina->reg_config = tmp;
407521c0b61SNicolin Chen 		return 0;
408023912dbSNicolin Chen 	case hwmon_chip_update_interval:
409023912dbSNicolin Chen 		tmp = ina3221_interval_ms_to_conv_time(ina->reg_config, val);
410023912dbSNicolin Chen 		idx = find_closest(tmp, ina3221_conv_time,
411023912dbSNicolin Chen 				   ARRAY_SIZE(ina3221_conv_time));
412023912dbSNicolin Chen 
413023912dbSNicolin Chen 		/* Update Bus and Shunt voltage conversion times */
414023912dbSNicolin Chen 		tmp = INA3221_CONFIG_VBUS_CT_MASK | INA3221_CONFIG_VSH_CT_MASK;
415023912dbSNicolin Chen 		tmp = (ina->reg_config & ~tmp) |
416023912dbSNicolin Chen 		      (idx << INA3221_CONFIG_VBUS_CT_SHIFT) |
417023912dbSNicolin Chen 		      (idx << INA3221_CONFIG_VSH_CT_SHIFT);
418023912dbSNicolin Chen 		ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp);
419023912dbSNicolin Chen 		if (ret)
420023912dbSNicolin Chen 			return ret;
421023912dbSNicolin Chen 
422023912dbSNicolin Chen 		/* Update reg_config accordingly */
423023912dbSNicolin Chen 		ina->reg_config = tmp;
424023912dbSNicolin Chen 		return 0;
4255c090abfSNicolin Chen 	default:
4265c090abfSNicolin Chen 		return -EOPNOTSUPP;
4275c090abfSNicolin Chen 	}
4285c090abfSNicolin Chen }
4295c090abfSNicolin Chen 
ina3221_write_curr(struct device * dev,u32 attr,int channel,long val)430d4b0166dSNicolin Chen static int ina3221_write_curr(struct device *dev, u32 attr,
431d4b0166dSNicolin Chen 			      int channel, long val)
4327cb6dcffSAndrew F. Davis {
4337cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
4342057bdfbSNicolin Chen 	struct ina3221_input *input = ina->inputs;
435d4b0166dSNicolin Chen 	u8 reg = ina3221_curr_reg[attr][channel];
4362057bdfbSNicolin Chen 	int resistance_uo, current_ma, voltage_uv;
4372057bdfbSNicolin Chen 	int regval;
4382057bdfbSNicolin Chen 
4392057bdfbSNicolin Chen 	if (channel > INA3221_CHANNEL3)
4402057bdfbSNicolin Chen 		resistance_uo = ina->summation_shunt_resistor;
4412057bdfbSNicolin Chen 	else
4422057bdfbSNicolin Chen 		resistance_uo = input[channel].shunt_resistor;
4432057bdfbSNicolin Chen 
4442057bdfbSNicolin Chen 	if (!resistance_uo)
4452057bdfbSNicolin Chen 		return -EOPNOTSUPP;
4467cb6dcffSAndrew F. Davis 
4477cb6dcffSAndrew F. Davis 	/* clamp current */
448d4b0166dSNicolin Chen 	current_ma = clamp_val(val,
4497cb6dcffSAndrew F. Davis 			       INT_MIN / resistance_uo,
4507cb6dcffSAndrew F. Davis 			       INT_MAX / resistance_uo);
4517cb6dcffSAndrew F. Davis 
4527cb6dcffSAndrew F. Davis 	voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000);
4537cb6dcffSAndrew F. Davis 
4547cb6dcffSAndrew F. Davis 	/* clamp voltage */
4557cb6dcffSAndrew F. Davis 	voltage_uv = clamp_val(voltage_uv, -163800, 163800);
4567cb6dcffSAndrew F. Davis 
4572057bdfbSNicolin Chen 	/*
4582057bdfbSNicolin Chen 	 * Formula to convert voltage_uv to register value:
4592057bdfbSNicolin Chen 	 *     regval = (voltage_uv / scale) << shift
4602057bdfbSNicolin Chen 	 * Note:
4612057bdfbSNicolin Chen 	 *     The scale is 40uV for all shunt voltage registers
4622057bdfbSNicolin Chen 	 *     Shunt Voltage Sum register left-shifts 1 bit
4632057bdfbSNicolin Chen 	 *     All other Shunt Voltage registers shift 3 bits
4642057bdfbSNicolin Chen 	 * Results:
4652057bdfbSNicolin Chen 	 *     SHUNT_SUM: (1 / 40uV) << 1 = 1 / 20uV
4662057bdfbSNicolin Chen 	 *     SHUNT[1-3]: (1 / 40uV) << 3 = 1 / 5uV
4672057bdfbSNicolin Chen 	 */
468b8d27d2cSNinad Malwade 	if (reg == INA3221_SHUNT_SUM || reg == INA3221_CRIT_SUM)
4692057bdfbSNicolin Chen 		regval = DIV_ROUND_CLOSEST(voltage_uv, 20) & 0xfffe;
4702057bdfbSNicolin Chen 	else
471d4b0166dSNicolin Chen 		regval = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8;
4727cb6dcffSAndrew F. Davis 
473d4b0166dSNicolin Chen 	return regmap_write(ina->regmap, reg, regval);
474d4b0166dSNicolin Chen }
475d4b0166dSNicolin Chen 
ina3221_write_enable(struct device * dev,int channel,bool enable)476d4b0166dSNicolin Chen static int ina3221_write_enable(struct device *dev, int channel, bool enable)
477d4b0166dSNicolin Chen {
478d4b0166dSNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
479d4b0166dSNicolin Chen 	u16 config, mask = INA3221_CONFIG_CHx_EN(channel);
480323aeb0eSNicolin Chen 	u16 config_old = ina->reg_config & mask;
481521c0b61SNicolin Chen 	u32 tmp;
482d4b0166dSNicolin Chen 	int ret;
483d4b0166dSNicolin Chen 
484d4b0166dSNicolin Chen 	config = enable ? mask : 0;
485d4b0166dSNicolin Chen 
486323aeb0eSNicolin Chen 	/* Bypass if enable status is not being changed */
487323aeb0eSNicolin Chen 	if (config_old == config)
488323aeb0eSNicolin Chen 		return 0;
489323aeb0eSNicolin Chen 
490323aeb0eSNicolin Chen 	/* For enabling routine, increase refcount and resume() at first */
491323aeb0eSNicolin Chen 	if (enable) {
492bce776f1SZhang Qilong 		ret = pm_runtime_resume_and_get(ina->pm_dev);
493323aeb0eSNicolin Chen 		if (ret < 0) {
494323aeb0eSNicolin Chen 			dev_err(dev, "Failed to get PM runtime\n");
495323aeb0eSNicolin Chen 			return ret;
496323aeb0eSNicolin Chen 		}
497323aeb0eSNicolin Chen 	}
498323aeb0eSNicolin Chen 
499d4b0166dSNicolin Chen 	/* Enable or disable the channel */
500521c0b61SNicolin Chen 	tmp = (ina->reg_config & ~mask) | (config & mask);
501521c0b61SNicolin Chen 	ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp);
5027cb6dcffSAndrew F. Davis 	if (ret)
503323aeb0eSNicolin Chen 		goto fail;
5047cb6dcffSAndrew F. Davis 
505d4b0166dSNicolin Chen 	/* Cache the latest config register value */
506521c0b61SNicolin Chen 	ina->reg_config = tmp;
507323aeb0eSNicolin Chen 
508323aeb0eSNicolin Chen 	/* For disabling routine, decrease refcount or suspend() at last */
509323aeb0eSNicolin Chen 	if (!enable)
510323aeb0eSNicolin Chen 		pm_runtime_put_sync(ina->pm_dev);
511d4b0166dSNicolin Chen 
512d4b0166dSNicolin Chen 	return 0;
513323aeb0eSNicolin Chen 
514323aeb0eSNicolin Chen fail:
515323aeb0eSNicolin Chen 	if (enable) {
516323aeb0eSNicolin Chen 		dev_err(dev, "Failed to enable channel %d: error %d\n",
517323aeb0eSNicolin Chen 			channel, ret);
518323aeb0eSNicolin Chen 		pm_runtime_put_sync(ina->pm_dev);
519323aeb0eSNicolin Chen 	}
520323aeb0eSNicolin Chen 
521323aeb0eSNicolin Chen 	return ret;
5227cb6dcffSAndrew F. Davis }
5237cb6dcffSAndrew F. Davis 
ina3221_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)524d4b0166dSNicolin Chen static int ina3221_read(struct device *dev, enum hwmon_sensor_types type,
525d4b0166dSNicolin Chen 			u32 attr, int channel, long *val)
526d4b0166dSNicolin Chen {
52787625b24SNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
52887625b24SNicolin Chen 	int ret;
52987625b24SNicolin Chen 
53087625b24SNicolin Chen 	mutex_lock(&ina->lock);
53187625b24SNicolin Chen 
532d4b0166dSNicolin Chen 	switch (type) {
5335c090abfSNicolin Chen 	case hwmon_chip:
5345c090abfSNicolin Chen 		ret = ina3221_read_chip(dev, attr, val);
5355c090abfSNicolin Chen 		break;
536d4b0166dSNicolin Chen 	case hwmon_in:
537d4b0166dSNicolin Chen 		/* 0-align channel ID */
53887625b24SNicolin Chen 		ret = ina3221_read_in(dev, attr, channel - 1, val);
53987625b24SNicolin Chen 		break;
540d4b0166dSNicolin Chen 	case hwmon_curr:
54187625b24SNicolin Chen 		ret = ina3221_read_curr(dev, attr, channel, val);
54287625b24SNicolin Chen 		break;
543d4b0166dSNicolin Chen 	default:
54487625b24SNicolin Chen 		ret = -EOPNOTSUPP;
54587625b24SNicolin Chen 		break;
546d4b0166dSNicolin Chen 	}
54787625b24SNicolin Chen 
54887625b24SNicolin Chen 	mutex_unlock(&ina->lock);
54987625b24SNicolin Chen 
55087625b24SNicolin Chen 	return ret;
551d4b0166dSNicolin Chen }
552d4b0166dSNicolin Chen 
ina3221_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)553d4b0166dSNicolin Chen static int ina3221_write(struct device *dev, enum hwmon_sensor_types type,
554d4b0166dSNicolin Chen 			 u32 attr, int channel, long val)
555d4b0166dSNicolin Chen {
55687625b24SNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
55787625b24SNicolin Chen 	int ret;
55887625b24SNicolin Chen 
55987625b24SNicolin Chen 	mutex_lock(&ina->lock);
56087625b24SNicolin Chen 
561d4b0166dSNicolin Chen 	switch (type) {
5625c090abfSNicolin Chen 	case hwmon_chip:
5635c090abfSNicolin Chen 		ret = ina3221_write_chip(dev, attr, val);
5645c090abfSNicolin Chen 		break;
565d4b0166dSNicolin Chen 	case hwmon_in:
566d4b0166dSNicolin Chen 		/* 0-align channel ID */
56787625b24SNicolin Chen 		ret = ina3221_write_enable(dev, channel - 1, val);
56887625b24SNicolin Chen 		break;
569d4b0166dSNicolin Chen 	case hwmon_curr:
57087625b24SNicolin Chen 		ret = ina3221_write_curr(dev, attr, channel, val);
57187625b24SNicolin Chen 		break;
572d4b0166dSNicolin Chen 	default:
57387625b24SNicolin Chen 		ret = -EOPNOTSUPP;
57487625b24SNicolin Chen 		break;
575d4b0166dSNicolin Chen 	}
57687625b24SNicolin Chen 
57787625b24SNicolin Chen 	mutex_unlock(&ina->lock);
57887625b24SNicolin Chen 
57987625b24SNicolin Chen 	return ret;
580d4b0166dSNicolin Chen }
581d4b0166dSNicolin Chen 
ina3221_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)582d4b0166dSNicolin Chen static int ina3221_read_string(struct device *dev, enum hwmon_sensor_types type,
583d4b0166dSNicolin Chen 			       u32 attr, int channel, const char **str)
584d4b0166dSNicolin Chen {
585d4b0166dSNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
586d4b0166dSNicolin Chen 	int index = channel - 1;
587d4b0166dSNicolin Chen 
5882057bdfbSNicolin Chen 	if (channel == 7)
5892057bdfbSNicolin Chen 		*str = "sum of shunt voltages";
5902057bdfbSNicolin Chen 	else
591d4b0166dSNicolin Chen 		*str = ina->inputs[index].label;
592d4b0166dSNicolin Chen 
593d4b0166dSNicolin Chen 	return 0;
594d4b0166dSNicolin Chen }
595d4b0166dSNicolin Chen 
ina3221_is_visible(const void * drvdata,enum hwmon_sensor_types type,u32 attr,int channel)596d4b0166dSNicolin Chen static umode_t ina3221_is_visible(const void *drvdata,
597d4b0166dSNicolin Chen 				  enum hwmon_sensor_types type,
598d4b0166dSNicolin Chen 				  u32 attr, int channel)
599d4b0166dSNicolin Chen {
600d4b0166dSNicolin Chen 	const struct ina3221_data *ina = drvdata;
601d4b0166dSNicolin Chen 	const struct ina3221_input *input = NULL;
602d4b0166dSNicolin Chen 
603d4b0166dSNicolin Chen 	switch (type) {
6045c090abfSNicolin Chen 	case hwmon_chip:
6055c090abfSNicolin Chen 		switch (attr) {
6065c090abfSNicolin Chen 		case hwmon_chip_samples:
607023912dbSNicolin Chen 		case hwmon_chip_update_interval:
6085c090abfSNicolin Chen 			return 0644;
6095c090abfSNicolin Chen 		default:
6105c090abfSNicolin Chen 			return 0;
6115c090abfSNicolin Chen 		}
612d4b0166dSNicolin Chen 	case hwmon_in:
613d4b0166dSNicolin Chen 		/* Ignore in0_ */
614d4b0166dSNicolin Chen 		if (channel == 0)
615d4b0166dSNicolin Chen 			return 0;
616d4b0166dSNicolin Chen 
617d4b0166dSNicolin Chen 		switch (attr) {
618d4b0166dSNicolin Chen 		case hwmon_in_label:
619d4b0166dSNicolin Chen 			if (channel - 1 <= INA3221_CHANNEL3)
620d4b0166dSNicolin Chen 				input = &ina->inputs[channel - 1];
6212057bdfbSNicolin Chen 			else if (channel == 7)
6222057bdfbSNicolin Chen 				return 0444;
623d4b0166dSNicolin Chen 			/* Hide label node if label is not provided */
624d4b0166dSNicolin Chen 			return (input && input->label) ? 0444 : 0;
625d4b0166dSNicolin Chen 		case hwmon_in_input:
626d4b0166dSNicolin Chen 			return 0444;
627d4b0166dSNicolin Chen 		case hwmon_in_enable:
628d4b0166dSNicolin Chen 			return 0644;
629d4b0166dSNicolin Chen 		default:
630d4b0166dSNicolin Chen 			return 0;
631d4b0166dSNicolin Chen 		}
632d4b0166dSNicolin Chen 	case hwmon_curr:
633d4b0166dSNicolin Chen 		switch (attr) {
634d4b0166dSNicolin Chen 		case hwmon_curr_input:
635d4b0166dSNicolin Chen 		case hwmon_curr_crit_alarm:
636d4b0166dSNicolin Chen 		case hwmon_curr_max_alarm:
637d4b0166dSNicolin Chen 			return 0444;
638d4b0166dSNicolin Chen 		case hwmon_curr_crit:
639d4b0166dSNicolin Chen 		case hwmon_curr_max:
640d4b0166dSNicolin Chen 			return 0644;
641d4b0166dSNicolin Chen 		default:
642d4b0166dSNicolin Chen 			return 0;
643d4b0166dSNicolin Chen 		}
644d4b0166dSNicolin Chen 	default:
645d4b0166dSNicolin Chen 		return 0;
646d4b0166dSNicolin Chen 	}
647d4b0166dSNicolin Chen }
648d4b0166dSNicolin Chen 
6496f307b7cSGuenter Roeck #define INA3221_HWMON_CURR_CONFIG (HWMON_C_INPUT | \
6506f307b7cSGuenter Roeck 				   HWMON_C_CRIT | HWMON_C_CRIT_ALARM | \
6516f307b7cSGuenter Roeck 				   HWMON_C_MAX | HWMON_C_MAX_ALARM)
6526f307b7cSGuenter Roeck 
65332439975SKrzysztof Kozlowski static const struct hwmon_channel_info * const ina3221_info[] = {
6545c090abfSNicolin Chen 	HWMON_CHANNEL_INFO(chip,
655023912dbSNicolin Chen 			   HWMON_C_SAMPLES,
656023912dbSNicolin Chen 			   HWMON_C_UPDATE_INTERVAL),
6576f307b7cSGuenter Roeck 	HWMON_CHANNEL_INFO(in,
658d4b0166dSNicolin Chen 			   /* 0: dummy, skipped in is_visible */
659d4b0166dSNicolin Chen 			   HWMON_I_INPUT,
660d4b0166dSNicolin Chen 			   /* 1-3: input voltage Channels */
661d4b0166dSNicolin Chen 			   HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL,
662d4b0166dSNicolin Chen 			   HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL,
663d4b0166dSNicolin Chen 			   HWMON_I_INPUT | HWMON_I_ENABLE | HWMON_I_LABEL,
664d4b0166dSNicolin Chen 			   /* 4-6: shunt voltage Channels */
665d4b0166dSNicolin Chen 			   HWMON_I_INPUT,
666d4b0166dSNicolin Chen 			   HWMON_I_INPUT,
6672057bdfbSNicolin Chen 			   HWMON_I_INPUT,
6682057bdfbSNicolin Chen 			   /* 7: summation of shunt voltage channels */
6692057bdfbSNicolin Chen 			   HWMON_I_INPUT | HWMON_I_LABEL),
6706f307b7cSGuenter Roeck 	HWMON_CHANNEL_INFO(curr,
6712057bdfbSNicolin Chen 			   /* 1-3: current channels*/
672d4b0166dSNicolin Chen 			   INA3221_HWMON_CURR_CONFIG,
673d4b0166dSNicolin Chen 			   INA3221_HWMON_CURR_CONFIG,
6742057bdfbSNicolin Chen 			   INA3221_HWMON_CURR_CONFIG,
6752057bdfbSNicolin Chen 			   /* 4: summation of current channels */
6762057bdfbSNicolin Chen 			   HWMON_C_INPUT | HWMON_C_CRIT | HWMON_C_CRIT_ALARM),
677d4b0166dSNicolin Chen 	NULL
678d4b0166dSNicolin Chen };
679d4b0166dSNicolin Chen 
680d4b0166dSNicolin Chen static const struct hwmon_ops ina3221_hwmon_ops = {
681d4b0166dSNicolin Chen 	.is_visible = ina3221_is_visible,
682d4b0166dSNicolin Chen 	.read_string = ina3221_read_string,
683d4b0166dSNicolin Chen 	.read = ina3221_read,
684d4b0166dSNicolin Chen 	.write = ina3221_write,
685d4b0166dSNicolin Chen };
686d4b0166dSNicolin Chen 
687d4b0166dSNicolin Chen static const struct hwmon_chip_info ina3221_chip_info = {
688d4b0166dSNicolin Chen 	.ops = &ina3221_hwmon_ops,
689d4b0166dSNicolin Chen 	.info = ina3221_info,
690d4b0166dSNicolin Chen };
691d4b0166dSNicolin Chen 
692d4b0166dSNicolin Chen /* Extra attribute groups */
ina3221_shunt_show(struct device * dev,struct device_attribute * attr,char * buf)693a4ec92edSGuenter Roeck static ssize_t ina3221_shunt_show(struct device *dev,
6947cb6dcffSAndrew F. Davis 				  struct device_attribute *attr, char *buf)
6957cb6dcffSAndrew F. Davis {
6967cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
6977cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
6987cb6dcffSAndrew F. Davis 	unsigned int channel = sd_attr->index;
699a9e9dd9cSNicolin Chen 	struct ina3221_input *input = &ina->inputs[channel];
7007cb6dcffSAndrew F. Davis 
7011f4d4af4SGuenter Roeck 	return sysfs_emit(buf, "%d\n", input->shunt_resistor);
7027cb6dcffSAndrew F. Davis }
7037cb6dcffSAndrew F. Davis 
ina3221_shunt_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)704a4ec92edSGuenter Roeck static ssize_t ina3221_shunt_store(struct device *dev,
7057cb6dcffSAndrew F. Davis 				   struct device_attribute *attr,
7067cb6dcffSAndrew F. Davis 				   const char *buf, size_t count)
7077cb6dcffSAndrew F. Davis {
7087cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
7097cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
7107cb6dcffSAndrew F. Davis 	unsigned int channel = sd_attr->index;
711a9e9dd9cSNicolin Chen 	struct ina3221_input *input = &ina->inputs[channel];
7129ad0df1aSGuenter Roeck 	int val;
7137cb6dcffSAndrew F. Davis 	int ret;
7147cb6dcffSAndrew F. Davis 
7159ad0df1aSGuenter Roeck 	ret = kstrtoint(buf, 0, &val);
7167cb6dcffSAndrew F. Davis 	if (ret)
7177cb6dcffSAndrew F. Davis 		return ret;
7187cb6dcffSAndrew F. Davis 
7199ad0df1aSGuenter Roeck 	val = clamp_val(val, 1, INT_MAX);
7207cb6dcffSAndrew F. Davis 
721a9e9dd9cSNicolin Chen 	input->shunt_resistor = val;
7227cb6dcffSAndrew F. Davis 
7232057bdfbSNicolin Chen 	/* Update summation_shunt_resistor for summation channel */
7242057bdfbSNicolin Chen 	ina->summation_shunt_resistor = ina3221_summation_shunt_resistor(ina);
7252057bdfbSNicolin Chen 
7267cb6dcffSAndrew F. Davis 	return count;
7277cb6dcffSAndrew F. Davis }
7287cb6dcffSAndrew F. Davis 
7297cb6dcffSAndrew F. Davis /* shunt resistance */
730a4ec92edSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(shunt1_resistor, ina3221_shunt, INA3221_CHANNEL1);
731a4ec92edSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(shunt2_resistor, ina3221_shunt, INA3221_CHANNEL2);
732a4ec92edSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(shunt3_resistor, ina3221_shunt, INA3221_CHANNEL3);
7337cb6dcffSAndrew F. Davis 
7347cb6dcffSAndrew F. Davis static struct attribute *ina3221_attrs[] = {
7357cb6dcffSAndrew F. Davis 	&sensor_dev_attr_shunt1_resistor.dev_attr.attr,
7367cb6dcffSAndrew F. Davis 	&sensor_dev_attr_shunt2_resistor.dev_attr.attr,
7377cb6dcffSAndrew F. Davis 	&sensor_dev_attr_shunt3_resistor.dev_attr.attr,
7387cb6dcffSAndrew F. Davis 	NULL,
7397cb6dcffSAndrew F. Davis };
740d4b0166dSNicolin Chen ATTRIBUTE_GROUPS(ina3221);
7417cb6dcffSAndrew F. Davis 
7427cb6dcffSAndrew F. Davis static const struct regmap_range ina3221_yes_ranges[] = {
743c20217b3SNicolin Chen 	regmap_reg_range(INA3221_CONFIG, INA3221_BUS3),
7442057bdfbSNicolin Chen 	regmap_reg_range(INA3221_SHUNT_SUM, INA3221_SHUNT_SUM),
7457cb6dcffSAndrew F. Davis 	regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE),
7467cb6dcffSAndrew F. Davis };
7477cb6dcffSAndrew F. Davis 
7487cb6dcffSAndrew F. Davis static const struct regmap_access_table ina3221_volatile_table = {
7497cb6dcffSAndrew F. Davis 	.yes_ranges = ina3221_yes_ranges,
7507cb6dcffSAndrew F. Davis 	.n_yes_ranges = ARRAY_SIZE(ina3221_yes_ranges),
7517cb6dcffSAndrew F. Davis };
7527cb6dcffSAndrew F. Davis 
7537cb6dcffSAndrew F. Davis static const struct regmap_config ina3221_regmap_config = {
7547cb6dcffSAndrew F. Davis 	.reg_bits = 8,
7557cb6dcffSAndrew F. Davis 	.val_bits = 16,
7567cb6dcffSAndrew F. Davis 
7577cb6dcffSAndrew F. Davis 	.cache_type = REGCACHE_RBTREE,
7587cb6dcffSAndrew F. Davis 	.volatile_table = &ina3221_volatile_table,
7597cb6dcffSAndrew F. Davis };
7607cb6dcffSAndrew F. Davis 
ina3221_probe_child_from_dt(struct device * dev,struct device_node * child,struct ina3221_data * ina)761a9e9dd9cSNicolin Chen static int ina3221_probe_child_from_dt(struct device *dev,
762a9e9dd9cSNicolin Chen 				       struct device_node *child,
763a9e9dd9cSNicolin Chen 				       struct ina3221_data *ina)
764a9e9dd9cSNicolin Chen {
765a9e9dd9cSNicolin Chen 	struct ina3221_input *input;
766a9e9dd9cSNicolin Chen 	u32 val;
767a9e9dd9cSNicolin Chen 	int ret;
768a9e9dd9cSNicolin Chen 
769a9e9dd9cSNicolin Chen 	ret = of_property_read_u32(child, "reg", &val);
770a9e9dd9cSNicolin Chen 	if (ret) {
7711b1f4efaSRob Herring 		dev_err(dev, "missing reg property of %pOFn\n", child);
772a9e9dd9cSNicolin Chen 		return ret;
773a9e9dd9cSNicolin Chen 	} else if (val > INA3221_CHANNEL3) {
7741b1f4efaSRob Herring 		dev_err(dev, "invalid reg %d of %pOFn\n", val, child);
775c93f5e2aSMarcus Folkesson 		return -EINVAL;
776a9e9dd9cSNicolin Chen 	}
777a9e9dd9cSNicolin Chen 
778a9e9dd9cSNicolin Chen 	input = &ina->inputs[val];
779a9e9dd9cSNicolin Chen 
780a9e9dd9cSNicolin Chen 	/* Log the disconnected channel input */
781a9e9dd9cSNicolin Chen 	if (!of_device_is_available(child)) {
782a9e9dd9cSNicolin Chen 		input->disconnected = true;
783a9e9dd9cSNicolin Chen 		return 0;
784a9e9dd9cSNicolin Chen 	}
785a9e9dd9cSNicolin Chen 
786a9e9dd9cSNicolin Chen 	/* Save the connected input label if available */
787a9e9dd9cSNicolin Chen 	of_property_read_string(child, "label", &input->label);
788a9e9dd9cSNicolin Chen 
789a9e9dd9cSNicolin Chen 	/* Overwrite default shunt resistor value optionally */
790a6e43263SNicolin Chen 	if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) {
791a6e43263SNicolin Chen 		if (val < 1 || val > INT_MAX) {
7921b1f4efaSRob Herring 			dev_err(dev, "invalid shunt resistor value %u of %pOFn\n",
7931b1f4efaSRob Herring 				val, child);
794a6e43263SNicolin Chen 			return -EINVAL;
795a6e43263SNicolin Chen 		}
796a9e9dd9cSNicolin Chen 		input->shunt_resistor = val;
797a6e43263SNicolin Chen 	}
798a9e9dd9cSNicolin Chen 
799a9e9dd9cSNicolin Chen 	return 0;
800a9e9dd9cSNicolin Chen }
801a9e9dd9cSNicolin Chen 
ina3221_probe_from_dt(struct device * dev,struct ina3221_data * ina)802a9e9dd9cSNicolin Chen static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina)
803a9e9dd9cSNicolin Chen {
804a9e9dd9cSNicolin Chen 	const struct device_node *np = dev->of_node;
805a9e9dd9cSNicolin Chen 	struct device_node *child;
806a9e9dd9cSNicolin Chen 	int ret;
807a9e9dd9cSNicolin Chen 
808a9e9dd9cSNicolin Chen 	/* Compatible with non-DT platforms */
809a9e9dd9cSNicolin Chen 	if (!np)
810a9e9dd9cSNicolin Chen 		return 0;
811a9e9dd9cSNicolin Chen 
81243dece16SNicolin Chen 	ina->single_shot = of_property_read_bool(np, "ti,single-shot");
81343dece16SNicolin Chen 
814a9e9dd9cSNicolin Chen 	for_each_child_of_node(np, child) {
815a9e9dd9cSNicolin Chen 		ret = ina3221_probe_child_from_dt(dev, child, ina);
8169f754657SNishka Dasgupta 		if (ret) {
8179f754657SNishka Dasgupta 			of_node_put(child);
818a9e9dd9cSNicolin Chen 			return ret;
819a9e9dd9cSNicolin Chen 		}
8209f754657SNishka Dasgupta 	}
821a9e9dd9cSNicolin Chen 
822a9e9dd9cSNicolin Chen 	return 0;
823a9e9dd9cSNicolin Chen }
824a9e9dd9cSNicolin Chen 
ina3221_probe(struct i2c_client * client)82567487038SStephen Kitt static int ina3221_probe(struct i2c_client *client)
8267cb6dcffSAndrew F. Davis {
8277cb6dcffSAndrew F. Davis 	struct device *dev = &client->dev;
8287cb6dcffSAndrew F. Davis 	struct ina3221_data *ina;
8297cb6dcffSAndrew F. Davis 	struct device *hwmon_dev;
8307cb6dcffSAndrew F. Davis 	int i, ret;
8317cb6dcffSAndrew F. Davis 
8327cb6dcffSAndrew F. Davis 	ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL);
8337cb6dcffSAndrew F. Davis 	if (!ina)
8347cb6dcffSAndrew F. Davis 		return -ENOMEM;
8357cb6dcffSAndrew F. Davis 
8367cb6dcffSAndrew F. Davis 	ina->regmap = devm_regmap_init_i2c(client, &ina3221_regmap_config);
8377cb6dcffSAndrew F. Davis 	if (IS_ERR(ina->regmap)) {
8387cb6dcffSAndrew F. Davis 		dev_err(dev, "Unable to allocate register map\n");
8397cb6dcffSAndrew F. Davis 		return PTR_ERR(ina->regmap);
8407cb6dcffSAndrew F. Davis 	}
8417cb6dcffSAndrew F. Davis 
8427cb6dcffSAndrew F. Davis 	for (i = 0; i < F_MAX_FIELDS; i++) {
8437cb6dcffSAndrew F. Davis 		ina->fields[i] = devm_regmap_field_alloc(dev,
8447cb6dcffSAndrew F. Davis 							 ina->regmap,
8457cb6dcffSAndrew F. Davis 							 ina3221_reg_fields[i]);
8467cb6dcffSAndrew F. Davis 		if (IS_ERR(ina->fields[i])) {
8477cb6dcffSAndrew F. Davis 			dev_err(dev, "Unable to allocate regmap fields\n");
8487cb6dcffSAndrew F. Davis 			return PTR_ERR(ina->fields[i]);
8497cb6dcffSAndrew F. Davis 		}
8507cb6dcffSAndrew F. Davis 	}
8517cb6dcffSAndrew F. Davis 
8527cb6dcffSAndrew F. Davis 	for (i = 0; i < INA3221_NUM_CHANNELS; i++)
853a9e9dd9cSNicolin Chen 		ina->inputs[i].shunt_resistor = INA3221_RSHUNT_DEFAULT;
854a9e9dd9cSNicolin Chen 
855a9e9dd9cSNicolin Chen 	ret = ina3221_probe_from_dt(dev, ina);
856a9e9dd9cSNicolin Chen 	if (ret) {
857a9e9dd9cSNicolin Chen 		dev_err(dev, "Unable to probe from device tree\n");
858a9e9dd9cSNicolin Chen 		return ret;
859a9e9dd9cSNicolin Chen 	}
8607cb6dcffSAndrew F. Davis 
861323aeb0eSNicolin Chen 	/* The driver will be reset, so use reset value */
862323aeb0eSNicolin Chen 	ina->reg_config = INA3221_CONFIG_DEFAULT;
863a9e9dd9cSNicolin Chen 
86443dece16SNicolin Chen 	/* Clear continuous bit to use single-shot mode */
86543dece16SNicolin Chen 	if (ina->single_shot)
86643dece16SNicolin Chen 		ina->reg_config &= ~INA3221_CONFIG_MODE_CONTINUOUS;
86743dece16SNicolin Chen 
868a9e9dd9cSNicolin Chen 	/* Disable channels if their inputs are disconnected */
869a9e9dd9cSNicolin Chen 	for (i = 0; i < INA3221_NUM_CHANNELS; i++) {
870a9e9dd9cSNicolin Chen 		if (ina->inputs[i].disconnected)
871a9e9dd9cSNicolin Chen 			ina->reg_config &= ~INA3221_CONFIG_CHx_EN(i);
872a9e9dd9cSNicolin Chen 	}
873a9e9dd9cSNicolin Chen 
8742057bdfbSNicolin Chen 	/* Initialize summation_shunt_resistor for summation channel control */
8752057bdfbSNicolin Chen 	ina->summation_shunt_resistor = ina3221_summation_shunt_resistor(ina);
8762057bdfbSNicolin Chen 
877323aeb0eSNicolin Chen 	ina->pm_dev = dev;
87887625b24SNicolin Chen 	mutex_init(&ina->lock);
87959d608e1SNicolin Chen 	dev_set_drvdata(dev, ina);
88059d608e1SNicolin Chen 
881323aeb0eSNicolin Chen 	/* Enable PM runtime -- status is suspended by default */
882323aeb0eSNicolin Chen 	pm_runtime_enable(ina->pm_dev);
883323aeb0eSNicolin Chen 
884323aeb0eSNicolin Chen 	/* Initialize (resume) the device */
885323aeb0eSNicolin Chen 	for (i = 0; i < INA3221_NUM_CHANNELS; i++) {
886323aeb0eSNicolin Chen 		if (ina->inputs[i].disconnected)
887323aeb0eSNicolin Chen 			continue;
888323aeb0eSNicolin Chen 		/* Match the refcount with number of enabled channels */
889323aeb0eSNicolin Chen 		ret = pm_runtime_get_sync(ina->pm_dev);
890323aeb0eSNicolin Chen 		if (ret < 0)
891323aeb0eSNicolin Chen 			goto fail;
892323aeb0eSNicolin Chen 	}
893323aeb0eSNicolin Chen 
894d4b0166dSNicolin Chen 	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ina,
895d4b0166dSNicolin Chen 							 &ina3221_chip_info,
896d4b0166dSNicolin Chen 							 ina3221_groups);
8977cb6dcffSAndrew F. Davis 	if (IS_ERR(hwmon_dev)) {
8987cb6dcffSAndrew F. Davis 		dev_err(dev, "Unable to register hwmon device\n");
899323aeb0eSNicolin Chen 		ret = PTR_ERR(hwmon_dev);
900323aeb0eSNicolin Chen 		goto fail;
9017cb6dcffSAndrew F. Davis 	}
9027cb6dcffSAndrew F. Davis 
9037cb6dcffSAndrew F. Davis 	return 0;
904323aeb0eSNicolin Chen 
905323aeb0eSNicolin Chen fail:
906323aeb0eSNicolin Chen 	pm_runtime_disable(ina->pm_dev);
907323aeb0eSNicolin Chen 	pm_runtime_set_suspended(ina->pm_dev);
908323aeb0eSNicolin Chen 	/* pm_runtime_put_noidle() will decrease the PM refcount until 0 */
909323aeb0eSNicolin Chen 	for (i = 0; i < INA3221_NUM_CHANNELS; i++)
910323aeb0eSNicolin Chen 		pm_runtime_put_noidle(ina->pm_dev);
911323aeb0eSNicolin Chen 	mutex_destroy(&ina->lock);
912323aeb0eSNicolin Chen 
913323aeb0eSNicolin Chen 	return ret;
9147cb6dcffSAndrew F. Davis }
9157cb6dcffSAndrew F. Davis 
ina3221_remove(struct i2c_client * client)916ed5c2f5fSUwe Kleine-König static void ina3221_remove(struct i2c_client *client)
91787625b24SNicolin Chen {
91887625b24SNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(&client->dev);
919323aeb0eSNicolin Chen 	int i;
920323aeb0eSNicolin Chen 
921323aeb0eSNicolin Chen 	pm_runtime_disable(ina->pm_dev);
922323aeb0eSNicolin Chen 	pm_runtime_set_suspended(ina->pm_dev);
923323aeb0eSNicolin Chen 
924323aeb0eSNicolin Chen 	/* pm_runtime_put_noidle() will decrease the PM refcount until 0 */
925323aeb0eSNicolin Chen 	for (i = 0; i < INA3221_NUM_CHANNELS; i++)
926323aeb0eSNicolin Chen 		pm_runtime_put_noidle(ina->pm_dev);
92787625b24SNicolin Chen 
92887625b24SNicolin Chen 	mutex_destroy(&ina->lock);
92987625b24SNicolin Chen }
93087625b24SNicolin Chen 
ina3221_suspend(struct device * dev)9312d5604c8SJonathan Cameron static int ina3221_suspend(struct device *dev)
93259d608e1SNicolin Chen {
93359d608e1SNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
93459d608e1SNicolin Chen 	int ret;
93559d608e1SNicolin Chen 
93659d608e1SNicolin Chen 	/* Save config register value and enable cache-only */
93759d608e1SNicolin Chen 	ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config);
93859d608e1SNicolin Chen 	if (ret)
93959d608e1SNicolin Chen 		return ret;
94059d608e1SNicolin Chen 
94159d608e1SNicolin Chen 	/* Set to power-down mode for power saving */
94259d608e1SNicolin Chen 	ret = regmap_update_bits(ina->regmap, INA3221_CONFIG,
94359d608e1SNicolin Chen 				 INA3221_CONFIG_MODE_MASK,
94459d608e1SNicolin Chen 				 INA3221_CONFIG_MODE_POWERDOWN);
94559d608e1SNicolin Chen 	if (ret)
94659d608e1SNicolin Chen 		return ret;
94759d608e1SNicolin Chen 
94859d608e1SNicolin Chen 	regcache_cache_only(ina->regmap, true);
94959d608e1SNicolin Chen 	regcache_mark_dirty(ina->regmap);
95059d608e1SNicolin Chen 
95159d608e1SNicolin Chen 	return 0;
95259d608e1SNicolin Chen }
95359d608e1SNicolin Chen 
ina3221_resume(struct device * dev)9542d5604c8SJonathan Cameron static int ina3221_resume(struct device *dev)
95559d608e1SNicolin Chen {
95659d608e1SNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
95759d608e1SNicolin Chen 	int ret;
95859d608e1SNicolin Chen 
95959d608e1SNicolin Chen 	regcache_cache_only(ina->regmap, false);
96059d608e1SNicolin Chen 
96159d608e1SNicolin Chen 	/* Software reset the chip */
96259d608e1SNicolin Chen 	ret = regmap_field_write(ina->fields[F_RST], true);
96359d608e1SNicolin Chen 	if (ret) {
96459d608e1SNicolin Chen 		dev_err(dev, "Unable to reset device\n");
96559d608e1SNicolin Chen 		return ret;
96659d608e1SNicolin Chen 	}
96759d608e1SNicolin Chen 
96859d608e1SNicolin Chen 	/* Restore cached register values to hardware */
96959d608e1SNicolin Chen 	ret = regcache_sync(ina->regmap);
97059d608e1SNicolin Chen 	if (ret)
97159d608e1SNicolin Chen 		return ret;
97259d608e1SNicolin Chen 
97359d608e1SNicolin Chen 	/* Restore config register value to hardware */
97459d608e1SNicolin Chen 	ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config);
97559d608e1SNicolin Chen 	if (ret)
97659d608e1SNicolin Chen 		return ret;
97759d608e1SNicolin Chen 
9782057bdfbSNicolin Chen 	/* Initialize summation channel control */
9792057bdfbSNicolin Chen 	if (ina->summation_shunt_resistor) {
9802057bdfbSNicolin Chen 		/*
9812057bdfbSNicolin Chen 		 * Take all three channels into summation by default
9822057bdfbSNicolin Chen 		 * Shunt measurements of disconnected channels should
9832057bdfbSNicolin Chen 		 * be 0, so it does not matter for summation.
9842057bdfbSNicolin Chen 		 */
9852057bdfbSNicolin Chen 		ret = regmap_update_bits(ina->regmap, INA3221_MASK_ENABLE,
9862057bdfbSNicolin Chen 					 INA3221_MASK_ENABLE_SCC_MASK,
9872057bdfbSNicolin Chen 					 INA3221_MASK_ENABLE_SCC_MASK);
9882057bdfbSNicolin Chen 		if (ret) {
9892057bdfbSNicolin Chen 			dev_err(dev, "Unable to control summation channel\n");
9902057bdfbSNicolin Chen 			return ret;
9912057bdfbSNicolin Chen 		}
9922057bdfbSNicolin Chen 	}
9932057bdfbSNicolin Chen 
99459d608e1SNicolin Chen 	return 0;
99559d608e1SNicolin Chen }
99659d608e1SNicolin Chen 
9972d5604c8SJonathan Cameron static DEFINE_RUNTIME_DEV_PM_OPS(ina3221_pm, ina3221_suspend, ina3221_resume,
9982d5604c8SJonathan Cameron 				 NULL);
99959d608e1SNicolin Chen 
10007cb6dcffSAndrew F. Davis static const struct of_device_id ina3221_of_match_table[] = {
10017cb6dcffSAndrew F. Davis 	{ .compatible = "ti,ina3221", },
10027cb6dcffSAndrew F. Davis 	{ /* sentinel */ }
10037cb6dcffSAndrew F. Davis };
10047cb6dcffSAndrew F. Davis MODULE_DEVICE_TABLE(of, ina3221_of_match_table);
10057cb6dcffSAndrew F. Davis 
10067cb6dcffSAndrew F. Davis static const struct i2c_device_id ina3221_ids[] = {
10077cb6dcffSAndrew F. Davis 	{ "ina3221", 0 },
10087cb6dcffSAndrew F. Davis 	{ /* sentinel */ }
10097cb6dcffSAndrew F. Davis };
10107cb6dcffSAndrew F. Davis MODULE_DEVICE_TABLE(i2c, ina3221_ids);
10117cb6dcffSAndrew F. Davis 
10127cb6dcffSAndrew F. Davis static struct i2c_driver ina3221_i2c_driver = {
1013*1975d167SUwe Kleine-König 	.probe = ina3221_probe,
101487625b24SNicolin Chen 	.remove = ina3221_remove,
10157cb6dcffSAndrew F. Davis 	.driver = {
10167cb6dcffSAndrew F. Davis 		.name = INA3221_DRIVER_NAME,
10177cb6dcffSAndrew F. Davis 		.of_match_table = ina3221_of_match_table,
10182d5604c8SJonathan Cameron 		.pm = pm_ptr(&ina3221_pm),
10197cb6dcffSAndrew F. Davis 	},
10207cb6dcffSAndrew F. Davis 	.id_table = ina3221_ids,
10217cb6dcffSAndrew F. Davis };
10227cb6dcffSAndrew F. Davis module_i2c_driver(ina3221_i2c_driver);
10237cb6dcffSAndrew F. Davis 
10247cb6dcffSAndrew F. Davis MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
10257cb6dcffSAndrew F. Davis MODULE_DESCRIPTION("Texas Instruments INA3221 HWMon Driver");
10267cb6dcffSAndrew F. Davis MODULE_LICENSE("GPL v2");
1027