xref: /openbmc/linux/drivers/hwmon/ina3221.c (revision 59d608e1)
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)
467cb6dcffSAndrew F. Davis 
477cb6dcffSAndrew F. Davis #define INA3221_RSHUNT_DEFAULT		10000
487cb6dcffSAndrew F. Davis 
497cb6dcffSAndrew F. Davis enum ina3221_fields {
507cb6dcffSAndrew F. Davis 	/* Configuration */
517cb6dcffSAndrew F. Davis 	F_RST,
527cb6dcffSAndrew F. Davis 
537cb6dcffSAndrew F. Davis 	/* Alert Flags */
547cb6dcffSAndrew F. Davis 	F_WF3, F_WF2, F_WF1,
557cb6dcffSAndrew F. Davis 	F_CF3, F_CF2, F_CF1,
567cb6dcffSAndrew F. Davis 
577cb6dcffSAndrew F. Davis 	/* sentinel */
587cb6dcffSAndrew F. Davis 	F_MAX_FIELDS
597cb6dcffSAndrew F. Davis };
607cb6dcffSAndrew F. Davis 
617cb6dcffSAndrew F. Davis static const struct reg_field ina3221_reg_fields[] = {
627cb6dcffSAndrew F. Davis 	[F_RST] = REG_FIELD(INA3221_CONFIG, 15, 15),
637cb6dcffSAndrew F. Davis 
647cb6dcffSAndrew F. Davis 	[F_WF3] = REG_FIELD(INA3221_MASK_ENABLE, 3, 3),
657cb6dcffSAndrew F. Davis 	[F_WF2] = REG_FIELD(INA3221_MASK_ENABLE, 4, 4),
667cb6dcffSAndrew F. Davis 	[F_WF1] = REG_FIELD(INA3221_MASK_ENABLE, 5, 5),
677cb6dcffSAndrew F. Davis 	[F_CF3] = REG_FIELD(INA3221_MASK_ENABLE, 7, 7),
687cb6dcffSAndrew F. Davis 	[F_CF2] = REG_FIELD(INA3221_MASK_ENABLE, 8, 8),
697cb6dcffSAndrew F. Davis 	[F_CF1] = REG_FIELD(INA3221_MASK_ENABLE, 9, 9),
707cb6dcffSAndrew F. Davis };
717cb6dcffSAndrew F. Davis 
727cb6dcffSAndrew F. Davis enum ina3221_channels {
737cb6dcffSAndrew F. Davis 	INA3221_CHANNEL1,
747cb6dcffSAndrew F. Davis 	INA3221_CHANNEL2,
757cb6dcffSAndrew F. Davis 	INA3221_CHANNEL3,
767cb6dcffSAndrew F. Davis 	INA3221_NUM_CHANNELS
777cb6dcffSAndrew F. Davis };
787cb6dcffSAndrew F. Davis 
797cb6dcffSAndrew F. Davis static const unsigned int register_channel[] = {
807cb6dcffSAndrew F. Davis 	[INA3221_SHUNT1] = INA3221_CHANNEL1,
817cb6dcffSAndrew F. Davis 	[INA3221_SHUNT2] = INA3221_CHANNEL2,
827cb6dcffSAndrew F. Davis 	[INA3221_SHUNT3] = INA3221_CHANNEL3,
837cb6dcffSAndrew F. Davis 	[INA3221_CRIT1] = INA3221_CHANNEL1,
847cb6dcffSAndrew F. Davis 	[INA3221_CRIT2] = INA3221_CHANNEL2,
857cb6dcffSAndrew F. Davis 	[INA3221_CRIT3] = INA3221_CHANNEL3,
867cb6dcffSAndrew F. Davis 	[INA3221_WARN1] = INA3221_CHANNEL1,
877cb6dcffSAndrew F. Davis 	[INA3221_WARN2] = INA3221_CHANNEL2,
887cb6dcffSAndrew F. Davis 	[INA3221_WARN3] = INA3221_CHANNEL3,
897cb6dcffSAndrew F. Davis };
907cb6dcffSAndrew F. Davis 
917cb6dcffSAndrew F. Davis /**
927cb6dcffSAndrew F. Davis  * struct ina3221_data - device specific information
937cb6dcffSAndrew F. Davis  * @regmap: Register map of the device
947cb6dcffSAndrew F. Davis  * @fields: Register fields of the device
957cb6dcffSAndrew F. Davis  * @shunt_resistors: Array of resistor values per channel
9659d608e1SNicolin Chen  * @reg_config: Register value of INA3221_CONFIG
977cb6dcffSAndrew F. Davis  */
987cb6dcffSAndrew F. Davis struct ina3221_data {
997cb6dcffSAndrew F. Davis 	struct regmap *regmap;
1007cb6dcffSAndrew F. Davis 	struct regmap_field *fields[F_MAX_FIELDS];
1019ad0df1aSGuenter Roeck 	int shunt_resistors[INA3221_NUM_CHANNELS];
10259d608e1SNicolin Chen 	u32 reg_config;
1037cb6dcffSAndrew F. Davis };
1047cb6dcffSAndrew F. Davis 
1057cb6dcffSAndrew F. Davis static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg,
1067cb6dcffSAndrew F. Davis 			      int *val)
1077cb6dcffSAndrew F. Davis {
1087cb6dcffSAndrew F. Davis 	unsigned int regval;
1097cb6dcffSAndrew F. Davis 	int ret;
1107cb6dcffSAndrew F. Davis 
1117cb6dcffSAndrew F. Davis 	ret = regmap_read(ina->regmap, reg, &regval);
1127cb6dcffSAndrew F. Davis 	if (ret)
1137cb6dcffSAndrew F. Davis 		return ret;
1147cb6dcffSAndrew F. Davis 
1157cb6dcffSAndrew F. Davis 	*val = sign_extend32(regval >> 3, 12);
1167cb6dcffSAndrew F. Davis 
1177cb6dcffSAndrew F. Davis 	return 0;
1187cb6dcffSAndrew F. Davis }
1197cb6dcffSAndrew F. Davis 
1207cb6dcffSAndrew F. Davis static ssize_t ina3221_show_bus_voltage(struct device *dev,
1217cb6dcffSAndrew F. Davis 					struct device_attribute *attr,
1227cb6dcffSAndrew F. Davis 					char *buf)
1237cb6dcffSAndrew F. Davis {
1247cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
1257cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
1267cb6dcffSAndrew F. Davis 	unsigned int reg = sd_attr->index;
1277cb6dcffSAndrew F. Davis 	int val, voltage_mv, ret;
1287cb6dcffSAndrew F. Davis 
1297cb6dcffSAndrew F. Davis 	ret = ina3221_read_value(ina, reg, &val);
1307cb6dcffSAndrew F. Davis 	if (ret)
1317cb6dcffSAndrew F. Davis 		return ret;
1327cb6dcffSAndrew F. Davis 
1337cb6dcffSAndrew F. Davis 	voltage_mv = val * 8;
1347cb6dcffSAndrew F. Davis 
1357cb6dcffSAndrew F. Davis 	return snprintf(buf, PAGE_SIZE, "%d\n", voltage_mv);
1367cb6dcffSAndrew F. Davis }
1377cb6dcffSAndrew F. Davis 
1387cb6dcffSAndrew F. Davis static ssize_t ina3221_show_shunt_voltage(struct device *dev,
1397cb6dcffSAndrew F. Davis 					  struct device_attribute *attr,
1407cb6dcffSAndrew F. Davis 					  char *buf)
1417cb6dcffSAndrew F. Davis {
1427cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
1437cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
1447cb6dcffSAndrew F. Davis 	unsigned int reg = sd_attr->index;
1457cb6dcffSAndrew F. Davis 	int val, voltage_uv, ret;
1467cb6dcffSAndrew F. Davis 
1477cb6dcffSAndrew F. Davis 	ret = ina3221_read_value(ina, reg, &val);
1487cb6dcffSAndrew F. Davis 	if (ret)
1497cb6dcffSAndrew F. Davis 		return ret;
1507cb6dcffSAndrew F. Davis 	voltage_uv = val * 40;
1517cb6dcffSAndrew F. Davis 
1527cb6dcffSAndrew F. Davis 	return snprintf(buf, PAGE_SIZE, "%d\n", voltage_uv);
1537cb6dcffSAndrew F. Davis }
1547cb6dcffSAndrew F. Davis 
1557cb6dcffSAndrew F. Davis static ssize_t ina3221_show_current(struct device *dev,
1567cb6dcffSAndrew F. Davis 				    struct device_attribute *attr, char *buf)
1577cb6dcffSAndrew F. Davis {
1587cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
1597cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
1607cb6dcffSAndrew F. Davis 	unsigned int reg = sd_attr->index;
1617cb6dcffSAndrew F. Davis 	unsigned int channel = register_channel[reg];
1629ad0df1aSGuenter Roeck 	int resistance_uo = ina->shunt_resistors[channel];
1637cb6dcffSAndrew F. Davis 	int val, current_ma, voltage_nv, ret;
1647cb6dcffSAndrew F. Davis 
1657cb6dcffSAndrew F. Davis 	ret = ina3221_read_value(ina, reg, &val);
1667cb6dcffSAndrew F. Davis 	if (ret)
1677cb6dcffSAndrew F. Davis 		return ret;
1687cb6dcffSAndrew F. Davis 	voltage_nv = val * 40000;
1697cb6dcffSAndrew F. Davis 
1707cb6dcffSAndrew F. Davis 	current_ma = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo);
1717cb6dcffSAndrew F. Davis 
1727cb6dcffSAndrew F. Davis 	return snprintf(buf, PAGE_SIZE, "%d\n", current_ma);
1737cb6dcffSAndrew F. Davis }
1747cb6dcffSAndrew F. Davis 
1757cb6dcffSAndrew F. Davis static ssize_t ina3221_set_current(struct device *dev,
1767cb6dcffSAndrew F. Davis 				   struct device_attribute *attr,
1777cb6dcffSAndrew F. Davis 				   const char *buf, size_t count)
1787cb6dcffSAndrew F. Davis {
1797cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
1807cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
1817cb6dcffSAndrew F. Davis 	unsigned int reg = sd_attr->index;
1827cb6dcffSAndrew F. Davis 	unsigned int channel = register_channel[reg];
1839ad0df1aSGuenter Roeck 	int resistance_uo = ina->shunt_resistors[channel];
1847cb6dcffSAndrew F. Davis 	int val, current_ma, voltage_uv, ret;
1857cb6dcffSAndrew F. Davis 
1867cb6dcffSAndrew F. Davis 	ret = kstrtoint(buf, 0, &current_ma);
1877cb6dcffSAndrew F. Davis 	if (ret)
1887cb6dcffSAndrew F. Davis 		return ret;
1897cb6dcffSAndrew F. Davis 
1907cb6dcffSAndrew F. Davis 	/* clamp current */
1917cb6dcffSAndrew F. Davis 	current_ma = clamp_val(current_ma,
1927cb6dcffSAndrew F. Davis 			       INT_MIN / resistance_uo,
1937cb6dcffSAndrew F. Davis 			       INT_MAX / resistance_uo);
1947cb6dcffSAndrew F. Davis 
1957cb6dcffSAndrew F. Davis 	voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000);
1967cb6dcffSAndrew F. Davis 
1977cb6dcffSAndrew F. Davis 	/* clamp voltage */
1987cb6dcffSAndrew F. Davis 	voltage_uv = clamp_val(voltage_uv, -163800, 163800);
1997cb6dcffSAndrew F. Davis 
2007cb6dcffSAndrew F. Davis 	/* 1 / 40uV(scale) << 3(register shift) = 5 */
2017cb6dcffSAndrew F. Davis 	val = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8;
2027cb6dcffSAndrew F. Davis 
2037cb6dcffSAndrew F. Davis 	ret = regmap_write(ina->regmap, reg, val);
2047cb6dcffSAndrew F. Davis 	if (ret)
2057cb6dcffSAndrew F. Davis 		return ret;
2067cb6dcffSAndrew F. Davis 
2077cb6dcffSAndrew F. Davis 	return count;
2087cb6dcffSAndrew F. Davis }
2097cb6dcffSAndrew F. Davis 
2107cb6dcffSAndrew F. Davis static ssize_t ina3221_show_shunt(struct device *dev,
2117cb6dcffSAndrew F. Davis 				  struct device_attribute *attr, char *buf)
2127cb6dcffSAndrew F. Davis {
2137cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
2147cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
2157cb6dcffSAndrew F. Davis 	unsigned int channel = sd_attr->index;
2167cb6dcffSAndrew F. Davis 	unsigned int resistance_uo;
2177cb6dcffSAndrew F. Davis 
2187cb6dcffSAndrew F. Davis 	resistance_uo = ina->shunt_resistors[channel];
2197cb6dcffSAndrew F. Davis 
2207cb6dcffSAndrew F. Davis 	return snprintf(buf, PAGE_SIZE, "%d\n", resistance_uo);
2217cb6dcffSAndrew F. Davis }
2227cb6dcffSAndrew F. Davis 
2237cb6dcffSAndrew F. Davis static ssize_t ina3221_set_shunt(struct device *dev,
2247cb6dcffSAndrew F. Davis 				 struct device_attribute *attr,
2257cb6dcffSAndrew F. Davis 				 const char *buf, size_t count)
2267cb6dcffSAndrew F. Davis {
2277cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
2287cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
2297cb6dcffSAndrew F. Davis 	unsigned int channel = sd_attr->index;
2309ad0df1aSGuenter Roeck 	int val;
2317cb6dcffSAndrew F. Davis 	int ret;
2327cb6dcffSAndrew F. Davis 
2339ad0df1aSGuenter Roeck 	ret = kstrtoint(buf, 0, &val);
2347cb6dcffSAndrew F. Davis 	if (ret)
2357cb6dcffSAndrew F. Davis 		return ret;
2367cb6dcffSAndrew F. Davis 
2379ad0df1aSGuenter Roeck 	val = clamp_val(val, 1, INT_MAX);
2387cb6dcffSAndrew F. Davis 
2397cb6dcffSAndrew F. Davis 	ina->shunt_resistors[channel] = val;
2407cb6dcffSAndrew F. Davis 
2417cb6dcffSAndrew F. Davis 	return count;
2427cb6dcffSAndrew F. Davis }
2437cb6dcffSAndrew F. Davis 
2447cb6dcffSAndrew F. Davis static ssize_t ina3221_show_alert(struct device *dev,
2457cb6dcffSAndrew F. Davis 				  struct device_attribute *attr, char *buf)
2467cb6dcffSAndrew F. Davis {
2477cb6dcffSAndrew F. Davis 	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
2487cb6dcffSAndrew F. Davis 	struct ina3221_data *ina = dev_get_drvdata(dev);
2497cb6dcffSAndrew F. Davis 	unsigned int field = sd_attr->index;
2507cb6dcffSAndrew F. Davis 	unsigned int regval;
2517cb6dcffSAndrew F. Davis 	int ret;
2527cb6dcffSAndrew F. Davis 
2537cb6dcffSAndrew F. Davis 	ret = regmap_field_read(ina->fields[field], &regval);
2547cb6dcffSAndrew F. Davis 	if (ret)
2557cb6dcffSAndrew F. Davis 		return ret;
2567cb6dcffSAndrew F. Davis 
2577cb6dcffSAndrew F. Davis 	return snprintf(buf, PAGE_SIZE, "%d\n", regval);
2587cb6dcffSAndrew F. Davis }
2597cb6dcffSAndrew F. Davis 
2607cb6dcffSAndrew F. Davis /* bus voltage */
2617cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO,
2627cb6dcffSAndrew F. Davis 		ina3221_show_bus_voltage, NULL, INA3221_BUS1);
2637cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO,
2647cb6dcffSAndrew F. Davis 		ina3221_show_bus_voltage, NULL, INA3221_BUS2);
2657cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO,
2667cb6dcffSAndrew F. Davis 		ina3221_show_bus_voltage, NULL, INA3221_BUS3);
2677cb6dcffSAndrew F. Davis 
2687cb6dcffSAndrew F. Davis /* calculated current */
2697cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO,
2707cb6dcffSAndrew F. Davis 		ina3221_show_current, NULL, INA3221_SHUNT1);
2717cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO,
2727cb6dcffSAndrew F. Davis 		ina3221_show_current, NULL, INA3221_SHUNT2);
2737cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO,
2747cb6dcffSAndrew F. Davis 		ina3221_show_current, NULL, INA3221_SHUNT3);
2757cb6dcffSAndrew F. Davis 
2767cb6dcffSAndrew F. Davis /* shunt resistance */
2777cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(shunt1_resistor, S_IRUGO | S_IWUSR,
2787cb6dcffSAndrew F. Davis 		ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL1);
2797cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(shunt2_resistor, S_IRUGO | S_IWUSR,
2807cb6dcffSAndrew F. Davis 		ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL2);
2817cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(shunt3_resistor, S_IRUGO | S_IWUSR,
2827cb6dcffSAndrew F. Davis 		ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL3);
2837cb6dcffSAndrew F. Davis 
2847cb6dcffSAndrew F. Davis /* critical current */
2857cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr1_crit, S_IRUGO | S_IWUSR,
2867cb6dcffSAndrew F. Davis 		ina3221_show_current, ina3221_set_current, INA3221_CRIT1);
2877cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr2_crit, S_IRUGO | S_IWUSR,
2887cb6dcffSAndrew F. Davis 		ina3221_show_current, ina3221_set_current, INA3221_CRIT2);
2897cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr3_crit, S_IRUGO | S_IWUSR,
2907cb6dcffSAndrew F. Davis 		ina3221_show_current, ina3221_set_current, INA3221_CRIT3);
2917cb6dcffSAndrew F. Davis 
2927cb6dcffSAndrew F. Davis /* critical current alert */
2937cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr1_crit_alarm, S_IRUGO,
2947cb6dcffSAndrew F. Davis 		ina3221_show_alert, NULL, F_CF1);
2957cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr2_crit_alarm, S_IRUGO,
2967cb6dcffSAndrew F. Davis 		ina3221_show_alert, NULL, F_CF2);
2977cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr3_crit_alarm, S_IRUGO,
2987cb6dcffSAndrew F. Davis 		ina3221_show_alert, NULL, F_CF3);
2997cb6dcffSAndrew F. Davis 
3007cb6dcffSAndrew F. Davis /* warning current */
3017cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR,
3027cb6dcffSAndrew F. Davis 		ina3221_show_current, ina3221_set_current, INA3221_WARN1);
3037cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr2_max, S_IRUGO | S_IWUSR,
3047cb6dcffSAndrew F. Davis 		ina3221_show_current, ina3221_set_current, INA3221_WARN2);
3057cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr3_max, S_IRUGO | S_IWUSR,
3067cb6dcffSAndrew F. Davis 		ina3221_show_current, ina3221_set_current, INA3221_WARN3);
3077cb6dcffSAndrew F. Davis 
3087cb6dcffSAndrew F. Davis /* warning current alert */
3097cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO,
3107cb6dcffSAndrew F. Davis 		ina3221_show_alert, NULL, F_WF1);
3117cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr2_max_alarm, S_IRUGO,
3127cb6dcffSAndrew F. Davis 		ina3221_show_alert, NULL, F_WF2);
3137cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(curr3_max_alarm, S_IRUGO,
3147cb6dcffSAndrew F. Davis 		ina3221_show_alert, NULL, F_WF3);
3157cb6dcffSAndrew F. Davis 
3167cb6dcffSAndrew F. Davis /* shunt voltage */
3177cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO,
3187cb6dcffSAndrew F. Davis 		ina3221_show_shunt_voltage, NULL, INA3221_SHUNT1);
3197cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO,
3207cb6dcffSAndrew F. Davis 		ina3221_show_shunt_voltage, NULL, INA3221_SHUNT2);
3217cb6dcffSAndrew F. Davis static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO,
3227cb6dcffSAndrew F. Davis 		ina3221_show_shunt_voltage, NULL, INA3221_SHUNT3);
3237cb6dcffSAndrew F. Davis 
3247cb6dcffSAndrew F. Davis static struct attribute *ina3221_attrs[] = {
3257cb6dcffSAndrew F. Davis 	/* channel 1 */
3267cb6dcffSAndrew F. Davis 	&sensor_dev_attr_in1_input.dev_attr.attr,
3277cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr1_input.dev_attr.attr,
3287cb6dcffSAndrew F. Davis 	&sensor_dev_attr_shunt1_resistor.dev_attr.attr,
3297cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr1_crit.dev_attr.attr,
3307cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr1_crit_alarm.dev_attr.attr,
3317cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr1_max.dev_attr.attr,
3327cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
3337cb6dcffSAndrew F. Davis 	&sensor_dev_attr_in4_input.dev_attr.attr,
3347cb6dcffSAndrew F. Davis 
3357cb6dcffSAndrew F. Davis 	/* channel 2 */
3367cb6dcffSAndrew F. Davis 	&sensor_dev_attr_in2_input.dev_attr.attr,
3377cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr2_input.dev_attr.attr,
3387cb6dcffSAndrew F. Davis 	&sensor_dev_attr_shunt2_resistor.dev_attr.attr,
3397cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr2_crit.dev_attr.attr,
3407cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr2_crit_alarm.dev_attr.attr,
3417cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr2_max.dev_attr.attr,
3427cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
3437cb6dcffSAndrew F. Davis 	&sensor_dev_attr_in5_input.dev_attr.attr,
3447cb6dcffSAndrew F. Davis 
3457cb6dcffSAndrew F. Davis 	/* channel 3 */
3467cb6dcffSAndrew F. Davis 	&sensor_dev_attr_in3_input.dev_attr.attr,
3477cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr3_input.dev_attr.attr,
3487cb6dcffSAndrew F. Davis 	&sensor_dev_attr_shunt3_resistor.dev_attr.attr,
3497cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr3_crit.dev_attr.attr,
3507cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr3_crit_alarm.dev_attr.attr,
3517cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr3_max.dev_attr.attr,
3527cb6dcffSAndrew F. Davis 	&sensor_dev_attr_curr3_max_alarm.dev_attr.attr,
3537cb6dcffSAndrew F. Davis 	&sensor_dev_attr_in6_input.dev_attr.attr,
3547cb6dcffSAndrew F. Davis 
3557cb6dcffSAndrew F. Davis 	NULL,
3567cb6dcffSAndrew F. Davis };
3577cb6dcffSAndrew F. Davis ATTRIBUTE_GROUPS(ina3221);
3587cb6dcffSAndrew F. Davis 
3597cb6dcffSAndrew F. Davis static const struct regmap_range ina3221_yes_ranges[] = {
360c20217b3SNicolin Chen 	regmap_reg_range(INA3221_CONFIG, INA3221_BUS3),
3617cb6dcffSAndrew F. Davis 	regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE),
3627cb6dcffSAndrew F. Davis };
3637cb6dcffSAndrew F. Davis 
3647cb6dcffSAndrew F. Davis static const struct regmap_access_table ina3221_volatile_table = {
3657cb6dcffSAndrew F. Davis 	.yes_ranges = ina3221_yes_ranges,
3667cb6dcffSAndrew F. Davis 	.n_yes_ranges = ARRAY_SIZE(ina3221_yes_ranges),
3677cb6dcffSAndrew F. Davis };
3687cb6dcffSAndrew F. Davis 
3697cb6dcffSAndrew F. Davis static const struct regmap_config ina3221_regmap_config = {
3707cb6dcffSAndrew F. Davis 	.reg_bits = 8,
3717cb6dcffSAndrew F. Davis 	.val_bits = 16,
3727cb6dcffSAndrew F. Davis 
3737cb6dcffSAndrew F. Davis 	.cache_type = REGCACHE_RBTREE,
3747cb6dcffSAndrew F. Davis 	.volatile_table = &ina3221_volatile_table,
3757cb6dcffSAndrew F. Davis };
3767cb6dcffSAndrew F. Davis 
3777cb6dcffSAndrew F. Davis static int ina3221_probe(struct i2c_client *client,
3787cb6dcffSAndrew F. Davis 			 const struct i2c_device_id *id)
3797cb6dcffSAndrew F. Davis {
3807cb6dcffSAndrew F. Davis 	struct device *dev = &client->dev;
3817cb6dcffSAndrew F. Davis 	struct ina3221_data *ina;
3827cb6dcffSAndrew F. Davis 	struct device *hwmon_dev;
3837cb6dcffSAndrew F. Davis 	int i, ret;
3847cb6dcffSAndrew F. Davis 
3857cb6dcffSAndrew F. Davis 	ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL);
3867cb6dcffSAndrew F. Davis 	if (!ina)
3877cb6dcffSAndrew F. Davis 		return -ENOMEM;
3887cb6dcffSAndrew F. Davis 
3897cb6dcffSAndrew F. Davis 	ina->regmap = devm_regmap_init_i2c(client, &ina3221_regmap_config);
3907cb6dcffSAndrew F. Davis 	if (IS_ERR(ina->regmap)) {
3917cb6dcffSAndrew F. Davis 		dev_err(dev, "Unable to allocate register map\n");
3927cb6dcffSAndrew F. Davis 		return PTR_ERR(ina->regmap);
3937cb6dcffSAndrew F. Davis 	}
3947cb6dcffSAndrew F. Davis 
3957cb6dcffSAndrew F. Davis 	for (i = 0; i < F_MAX_FIELDS; i++) {
3967cb6dcffSAndrew F. Davis 		ina->fields[i] = devm_regmap_field_alloc(dev,
3977cb6dcffSAndrew F. Davis 							 ina->regmap,
3987cb6dcffSAndrew F. Davis 							 ina3221_reg_fields[i]);
3997cb6dcffSAndrew F. Davis 		if (IS_ERR(ina->fields[i])) {
4007cb6dcffSAndrew F. Davis 			dev_err(dev, "Unable to allocate regmap fields\n");
4017cb6dcffSAndrew F. Davis 			return PTR_ERR(ina->fields[i]);
4027cb6dcffSAndrew F. Davis 		}
4037cb6dcffSAndrew F. Davis 	}
4047cb6dcffSAndrew F. Davis 
4057cb6dcffSAndrew F. Davis 	for (i = 0; i < INA3221_NUM_CHANNELS; i++)
4067cb6dcffSAndrew F. Davis 		ina->shunt_resistors[i] = INA3221_RSHUNT_DEFAULT;
4077cb6dcffSAndrew F. Davis 
4087cb6dcffSAndrew F. Davis 	ret = regmap_field_write(ina->fields[F_RST], true);
4097cb6dcffSAndrew F. Davis 	if (ret) {
4107cb6dcffSAndrew F. Davis 		dev_err(dev, "Unable to reset device\n");
4117cb6dcffSAndrew F. Davis 		return ret;
4127cb6dcffSAndrew F. Davis 	}
4137cb6dcffSAndrew F. Davis 
41459d608e1SNicolin Chen 	dev_set_drvdata(dev, ina);
41559d608e1SNicolin Chen 
4167cb6dcffSAndrew F. Davis 	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
4177cb6dcffSAndrew F. Davis 							   client->name,
4187cb6dcffSAndrew F. Davis 							   ina, ina3221_groups);
4197cb6dcffSAndrew F. Davis 	if (IS_ERR(hwmon_dev)) {
4207cb6dcffSAndrew F. Davis 		dev_err(dev, "Unable to register hwmon device\n");
4217cb6dcffSAndrew F. Davis 		return PTR_ERR(hwmon_dev);
4227cb6dcffSAndrew F. Davis 	}
4237cb6dcffSAndrew F. Davis 
4247cb6dcffSAndrew F. Davis 	return 0;
4257cb6dcffSAndrew F. Davis }
4267cb6dcffSAndrew F. Davis 
42759d608e1SNicolin Chen #ifdef CONFIG_PM
42859d608e1SNicolin Chen static int ina3221_suspend(struct device *dev)
42959d608e1SNicolin Chen {
43059d608e1SNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
43159d608e1SNicolin Chen 	int ret;
43259d608e1SNicolin Chen 
43359d608e1SNicolin Chen 	/* Save config register value and enable cache-only */
43459d608e1SNicolin Chen 	ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config);
43559d608e1SNicolin Chen 	if (ret)
43659d608e1SNicolin Chen 		return ret;
43759d608e1SNicolin Chen 
43859d608e1SNicolin Chen 	/* Set to power-down mode for power saving */
43959d608e1SNicolin Chen 	ret = regmap_update_bits(ina->regmap, INA3221_CONFIG,
44059d608e1SNicolin Chen 				 INA3221_CONFIG_MODE_MASK,
44159d608e1SNicolin Chen 				 INA3221_CONFIG_MODE_POWERDOWN);
44259d608e1SNicolin Chen 	if (ret)
44359d608e1SNicolin Chen 		return ret;
44459d608e1SNicolin Chen 
44559d608e1SNicolin Chen 	regcache_cache_only(ina->regmap, true);
44659d608e1SNicolin Chen 	regcache_mark_dirty(ina->regmap);
44759d608e1SNicolin Chen 
44859d608e1SNicolin Chen 	return 0;
44959d608e1SNicolin Chen }
45059d608e1SNicolin Chen 
45159d608e1SNicolin Chen static int ina3221_resume(struct device *dev)
45259d608e1SNicolin Chen {
45359d608e1SNicolin Chen 	struct ina3221_data *ina = dev_get_drvdata(dev);
45459d608e1SNicolin Chen 	int ret;
45559d608e1SNicolin Chen 
45659d608e1SNicolin Chen 	regcache_cache_only(ina->regmap, false);
45759d608e1SNicolin Chen 
45859d608e1SNicolin Chen 	/* Software reset the chip */
45959d608e1SNicolin Chen 	ret = regmap_field_write(ina->fields[F_RST], true);
46059d608e1SNicolin Chen 	if (ret) {
46159d608e1SNicolin Chen 		dev_err(dev, "Unable to reset device\n");
46259d608e1SNicolin Chen 		return ret;
46359d608e1SNicolin Chen 	}
46459d608e1SNicolin Chen 
46559d608e1SNicolin Chen 	/* Restore cached register values to hardware */
46659d608e1SNicolin Chen 	ret = regcache_sync(ina->regmap);
46759d608e1SNicolin Chen 	if (ret)
46859d608e1SNicolin Chen 		return ret;
46959d608e1SNicolin Chen 
47059d608e1SNicolin Chen 	/* Restore config register value to hardware */
47159d608e1SNicolin Chen 	ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config);
47259d608e1SNicolin Chen 	if (ret)
47359d608e1SNicolin Chen 		return ret;
47459d608e1SNicolin Chen 
47559d608e1SNicolin Chen 	return 0;
47659d608e1SNicolin Chen }
47759d608e1SNicolin Chen #endif
47859d608e1SNicolin Chen 
47959d608e1SNicolin Chen static const struct dev_pm_ops ina3221_pm = {
48059d608e1SNicolin Chen 	SET_SYSTEM_SLEEP_PM_OPS(ina3221_suspend, ina3221_resume)
48159d608e1SNicolin Chen };
48259d608e1SNicolin Chen 
4837cb6dcffSAndrew F. Davis static const struct of_device_id ina3221_of_match_table[] = {
4847cb6dcffSAndrew F. Davis 	{ .compatible = "ti,ina3221", },
4857cb6dcffSAndrew F. Davis 	{ /* sentinel */ }
4867cb6dcffSAndrew F. Davis };
4877cb6dcffSAndrew F. Davis MODULE_DEVICE_TABLE(of, ina3221_of_match_table);
4887cb6dcffSAndrew F. Davis 
4897cb6dcffSAndrew F. Davis static const struct i2c_device_id ina3221_ids[] = {
4907cb6dcffSAndrew F. Davis 	{ "ina3221", 0 },
4917cb6dcffSAndrew F. Davis 	{ /* sentinel */ }
4927cb6dcffSAndrew F. Davis };
4937cb6dcffSAndrew F. Davis MODULE_DEVICE_TABLE(i2c, ina3221_ids);
4947cb6dcffSAndrew F. Davis 
4957cb6dcffSAndrew F. Davis static struct i2c_driver ina3221_i2c_driver = {
4967cb6dcffSAndrew F. Davis 	.probe = ina3221_probe,
4977cb6dcffSAndrew F. Davis 	.driver = {
4987cb6dcffSAndrew F. Davis 		.name = INA3221_DRIVER_NAME,
4997cb6dcffSAndrew F. Davis 		.of_match_table = ina3221_of_match_table,
50059d608e1SNicolin Chen 		.pm = &ina3221_pm,
5017cb6dcffSAndrew F. Davis 	},
5027cb6dcffSAndrew F. Davis 	.id_table = ina3221_ids,
5037cb6dcffSAndrew F. Davis };
5047cb6dcffSAndrew F. Davis module_i2c_driver(ina3221_i2c_driver);
5057cb6dcffSAndrew F. Davis 
5067cb6dcffSAndrew F. Davis MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
5077cb6dcffSAndrew F. Davis MODULE_DESCRIPTION("Texas Instruments INA3221 HWMon Driver");
5087cb6dcffSAndrew F. Davis MODULE_LICENSE("GPL v2");
509