xref: /linux/drivers/hwmon/ina2xx.c (revision bd0ddd4d0883a95e6a3d49e7174e546b2f1845cf)
1f7c2fe38SFelten, Lothar /*
2f7c2fe38SFelten, Lothar  * Driver for Texas Instruments INA219, INA226 power monitor chips
3f7c2fe38SFelten, Lothar  *
4f7c2fe38SFelten, Lothar  * INA219:
5f7c2fe38SFelten, Lothar  * Zero Drift Bi-Directional Current/Power Monitor with I2C Interface
6f7c2fe38SFelten, Lothar  * Datasheet: http://www.ti.com/product/ina219
7f7c2fe38SFelten, Lothar  *
8dc92cd0cSGuenter Roeck  * INA220:
9dc92cd0cSGuenter Roeck  * Bi-Directional Current/Power Monitor with I2C Interface
10dc92cd0cSGuenter Roeck  * Datasheet: http://www.ti.com/product/ina220
11dc92cd0cSGuenter Roeck  *
12f7c2fe38SFelten, Lothar  * INA226:
13f7c2fe38SFelten, Lothar  * Bi-Directional Current/Power Monitor with I2C Interface
14f7c2fe38SFelten, Lothar  * Datasheet: http://www.ti.com/product/ina226
15f7c2fe38SFelten, Lothar  *
16dc92cd0cSGuenter Roeck  * INA230:
17dc92cd0cSGuenter Roeck  * Bi-directional Current/Power Monitor with I2C Interface
18dc92cd0cSGuenter Roeck  * Datasheet: http://www.ti.com/product/ina230
19dc92cd0cSGuenter Roeck  *
20f7c2fe38SFelten, Lothar  * Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
21f7c2fe38SFelten, Lothar  * Thanks to Jan Volkering
22f7c2fe38SFelten, Lothar  *
23f7c2fe38SFelten, Lothar  * This program is free software; you can redistribute it and/or modify
24f7c2fe38SFelten, Lothar  * it under the terms of the GNU General Public License as published by
25f7c2fe38SFelten, Lothar  * the Free Software Foundation; version 2 of the License.
26f7c2fe38SFelten, Lothar  */
27f7c2fe38SFelten, Lothar 
28f7c2fe38SFelten, Lothar #include <linux/kernel.h>
29f7c2fe38SFelten, Lothar #include <linux/module.h>
30f7c2fe38SFelten, Lothar #include <linux/init.h>
31f7c2fe38SFelten, Lothar #include <linux/err.h>
32f7c2fe38SFelten, Lothar #include <linux/slab.h>
33f7c2fe38SFelten, Lothar #include <linux/i2c.h>
34f7c2fe38SFelten, Lothar #include <linux/hwmon.h>
35f7c2fe38SFelten, Lothar #include <linux/hwmon-sysfs.h>
36dcd8f392SJean Delvare #include <linux/jiffies.h>
37*bd0ddd4dSJavier Martinez Canillas #include <linux/of_device.h>
3831e7ad74STang Yuantian #include <linux/of.h>
39509416a8SBartosz Golaszewski #include <linux/delay.h>
40d38df34eSBartosz Golaszewski #include <linux/util_macros.h>
41a0de56c8SMarc Titinger #include <linux/regmap.h>
42f7c2fe38SFelten, Lothar 
43f7c2fe38SFelten, Lothar #include <linux/platform_data/ina2xx.h>
44f7c2fe38SFelten, Lothar 
45f7c2fe38SFelten, Lothar /* common register definitions */
46f7c2fe38SFelten, Lothar #define INA2XX_CONFIG			0x00
47f7c2fe38SFelten, Lothar #define INA2XX_SHUNT_VOLTAGE		0x01 /* readonly */
48f7c2fe38SFelten, Lothar #define INA2XX_BUS_VOLTAGE		0x02 /* readonly */
49f7c2fe38SFelten, Lothar #define INA2XX_POWER			0x03 /* readonly */
50f7c2fe38SFelten, Lothar #define INA2XX_CURRENT			0x04 /* readonly */
51f7c2fe38SFelten, Lothar #define INA2XX_CALIBRATION		0x05
52f7c2fe38SFelten, Lothar 
53f7c2fe38SFelten, Lothar /* INA226 register definitions */
54f7c2fe38SFelten, Lothar #define INA226_MASK_ENABLE		0x06
55f7c2fe38SFelten, Lothar #define INA226_ALERT_LIMIT		0x07
56f7c2fe38SFelten, Lothar #define INA226_DIE_ID			0xFF
57f7c2fe38SFelten, Lothar 
58f7c2fe38SFelten, Lothar /* register count */
59f7c2fe38SFelten, Lothar #define INA219_REGISTERS		6
60f7c2fe38SFelten, Lothar #define INA226_REGISTERS		8
61f7c2fe38SFelten, Lothar 
62f7c2fe38SFelten, Lothar #define INA2XX_MAX_REGISTERS		8
63f7c2fe38SFelten, Lothar 
64f7c2fe38SFelten, Lothar /* settings - depend on use case */
65f7c2fe38SFelten, Lothar #define INA219_CONFIG_DEFAULT		0x399F	/* PGA=8 */
66f7c2fe38SFelten, Lothar #define INA226_CONFIG_DEFAULT		0x4527	/* averages=16 */
67f7c2fe38SFelten, Lothar 
68f7c2fe38SFelten, Lothar /* worst case is 68.10 ms (~14.6Hz, ina219) */
69f7c2fe38SFelten, Lothar #define INA2XX_CONVERSION_RATE		15
70509416a8SBartosz Golaszewski #define INA2XX_MAX_DELAY		69 /* worst case delay in ms */
71509416a8SBartosz Golaszewski 
72509416a8SBartosz Golaszewski #define INA2XX_RSHUNT_DEFAULT		10000
73f7c2fe38SFelten, Lothar 
7472a87a47SBartosz Golaszewski /* bit mask for reading the averaging setting in the configuration register */
7572a87a47SBartosz Golaszewski #define INA226_AVG_RD_MASK		0x0E00
7672a87a47SBartosz Golaszewski 
7772a87a47SBartosz Golaszewski #define INA226_READ_AVG(reg)		(((reg) & INA226_AVG_RD_MASK) >> 9)
7872a87a47SBartosz Golaszewski #define INA226_SHIFT_AVG(val)		((val) << 9)
7972a87a47SBartosz Golaszewski 
8072a87a47SBartosz Golaszewski /* common attrs, ina226 attrs and NULL */
8172a87a47SBartosz Golaszewski #define INA2XX_MAX_ATTRIBUTE_GROUPS	3
8272a87a47SBartosz Golaszewski 
8372a87a47SBartosz Golaszewski /*
8472a87a47SBartosz Golaszewski  * Both bus voltage and shunt voltage conversion times for ina226 are set
8572a87a47SBartosz Golaszewski  * to 0b0100 on POR, which translates to 2200 microseconds in total.
8672a87a47SBartosz Golaszewski  */
8772a87a47SBartosz Golaszewski #define INA226_TOTAL_CONV_TIME_DEFAULT	2200
8872a87a47SBartosz Golaszewski 
89a0de56c8SMarc Titinger static struct regmap_config ina2xx_regmap_config = {
90a0de56c8SMarc Titinger 	.reg_bits = 8,
91a0de56c8SMarc Titinger 	.val_bits = 16,
92a0de56c8SMarc Titinger };
93a0de56c8SMarc Titinger 
94f7c2fe38SFelten, Lothar enum ina2xx_ids { ina219, ina226 };
95f7c2fe38SFelten, Lothar 
966106db25SGuenter Roeck struct ina2xx_config {
976106db25SGuenter Roeck 	u16 config_default;
986106db25SGuenter Roeck 	int calibration_factor;
996106db25SGuenter Roeck 	int registers;
1006106db25SGuenter Roeck 	int shunt_div;
1016106db25SGuenter Roeck 	int bus_voltage_shift;
1026106db25SGuenter Roeck 	int bus_voltage_lsb;	/* uV */
1036106db25SGuenter Roeck 	int power_lsb;		/* uW */
1046106db25SGuenter Roeck };
1056106db25SGuenter Roeck 
106f7c2fe38SFelten, Lothar struct ina2xx_data {
1076106db25SGuenter Roeck 	const struct ina2xx_config *config;
108f7c2fe38SFelten, Lothar 
109509416a8SBartosz Golaszewski 	long rshunt;
110a0de56c8SMarc Titinger 	struct mutex config_lock;
111a0de56c8SMarc Titinger 	struct regmap *regmap;
112f7c2fe38SFelten, Lothar 
11372a87a47SBartosz Golaszewski 	const struct attribute_group *groups[INA2XX_MAX_ATTRIBUTE_GROUPS];
114f7c2fe38SFelten, Lothar };
115f7c2fe38SFelten, Lothar 
1166106db25SGuenter Roeck static const struct ina2xx_config ina2xx_config[] = {
1176106db25SGuenter Roeck 	[ina219] = {
1186106db25SGuenter Roeck 		.config_default = INA219_CONFIG_DEFAULT,
1196106db25SGuenter Roeck 		.calibration_factor = 40960000,
1206106db25SGuenter Roeck 		.registers = INA219_REGISTERS,
1216106db25SGuenter Roeck 		.shunt_div = 100,
1226106db25SGuenter Roeck 		.bus_voltage_shift = 3,
1236106db25SGuenter Roeck 		.bus_voltage_lsb = 4000,
1246106db25SGuenter Roeck 		.power_lsb = 20000,
1256106db25SGuenter Roeck 	},
1266106db25SGuenter Roeck 	[ina226] = {
1276106db25SGuenter Roeck 		.config_default = INA226_CONFIG_DEFAULT,
1286106db25SGuenter Roeck 		.calibration_factor = 5120000,
1296106db25SGuenter Roeck 		.registers = INA226_REGISTERS,
1306106db25SGuenter Roeck 		.shunt_div = 400,
1316106db25SGuenter Roeck 		.bus_voltage_shift = 0,
1326106db25SGuenter Roeck 		.bus_voltage_lsb = 1250,
1336106db25SGuenter Roeck 		.power_lsb = 25000,
1346106db25SGuenter Roeck 	},
1356106db25SGuenter Roeck };
1366106db25SGuenter Roeck 
13772a87a47SBartosz Golaszewski /*
13872a87a47SBartosz Golaszewski  * Available averaging rates for ina226. The indices correspond with
13972a87a47SBartosz Golaszewski  * the bit values expected by the chip (according to the ina226 datasheet,
14072a87a47SBartosz Golaszewski  * table 3 AVG bit settings, found at
14172a87a47SBartosz Golaszewski  * http://www.ti.com/lit/ds/symlink/ina226.pdf.
14272a87a47SBartosz Golaszewski  */
14372a87a47SBartosz Golaszewski static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 };
14472a87a47SBartosz Golaszewski 
14572a87a47SBartosz Golaszewski static int ina226_reg_to_interval(u16 config)
14672a87a47SBartosz Golaszewski {
14772a87a47SBartosz Golaszewski 	int avg = ina226_avg_tab[INA226_READ_AVG(config)];
14872a87a47SBartosz Golaszewski 
14972a87a47SBartosz Golaszewski 	/*
15072a87a47SBartosz Golaszewski 	 * Multiply the total conversion time by the number of averages.
15172a87a47SBartosz Golaszewski 	 * Return the result in milliseconds.
15272a87a47SBartosz Golaszewski 	 */
15372a87a47SBartosz Golaszewski 	return DIV_ROUND_CLOSEST(avg * INA226_TOTAL_CONV_TIME_DEFAULT, 1000);
15472a87a47SBartosz Golaszewski }
15572a87a47SBartosz Golaszewski 
156a0de56c8SMarc Titinger /*
157a0de56c8SMarc Titinger  * Return the new, shifted AVG field value of CONFIG register,
158a0de56c8SMarc Titinger  * to use with regmap_update_bits
159a0de56c8SMarc Titinger  */
160a0de56c8SMarc Titinger static u16 ina226_interval_to_reg(int interval)
16172a87a47SBartosz Golaszewski {
16272a87a47SBartosz Golaszewski 	int avg, avg_bits;
16372a87a47SBartosz Golaszewski 
16472a87a47SBartosz Golaszewski 	avg = DIV_ROUND_CLOSEST(interval * 1000,
16572a87a47SBartosz Golaszewski 				INA226_TOTAL_CONV_TIME_DEFAULT);
166d38df34eSBartosz Golaszewski 	avg_bits = find_closest(avg, ina226_avg_tab,
167d38df34eSBartosz Golaszewski 				ARRAY_SIZE(ina226_avg_tab));
16872a87a47SBartosz Golaszewski 
169a0de56c8SMarc Titinger 	return INA226_SHIFT_AVG(avg_bits);
17072a87a47SBartosz Golaszewski }
17172a87a47SBartosz Golaszewski 
1728a5fc795SBartosz Golaszewski static int ina2xx_calibrate(struct ina2xx_data *data)
1738a5fc795SBartosz Golaszewski {
174b721fe2aSBartosz Golaszewski 	u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
175b721fe2aSBartosz Golaszewski 				    data->rshunt);
176b721fe2aSBartosz Golaszewski 
177a0de56c8SMarc Titinger 	return regmap_write(data->regmap, INA2XX_CALIBRATION, val);
1788a5fc795SBartosz Golaszewski }
1798a5fc795SBartosz Golaszewski 
180509416a8SBartosz Golaszewski /*
181509416a8SBartosz Golaszewski  * Initialize the configuration and calibration registers.
182509416a8SBartosz Golaszewski  */
183509416a8SBartosz Golaszewski static int ina2xx_init(struct ina2xx_data *data)
184509416a8SBartosz Golaszewski {
185a0de56c8SMarc Titinger 	int ret = regmap_write(data->regmap, INA2XX_CONFIG,
186a0de56c8SMarc Titinger 			       data->config->config_default);
187509416a8SBartosz Golaszewski 	if (ret < 0)
188509416a8SBartosz Golaszewski 		return ret;
189509416a8SBartosz Golaszewski 
190509416a8SBartosz Golaszewski 	/*
191509416a8SBartosz Golaszewski 	 * Set current LSB to 1mA, shunt is in uOhms
192509416a8SBartosz Golaszewski 	 * (equation 13 in datasheet).
193509416a8SBartosz Golaszewski 	 */
1948a5fc795SBartosz Golaszewski 	return ina2xx_calibrate(data);
195509416a8SBartosz Golaszewski }
196509416a8SBartosz Golaszewski 
197a0de56c8SMarc Titinger static int ina2xx_read_reg(struct device *dev, int reg, unsigned int *regval)
198f7c2fe38SFelten, Lothar {
199468bf0e3SGuenter Roeck 	struct ina2xx_data *data = dev_get_drvdata(dev);
200a0de56c8SMarc Titinger 	int ret, retry;
201509416a8SBartosz Golaszewski 
202a0de56c8SMarc Titinger 	dev_dbg(dev, "Starting register %d read\n", reg);
203509416a8SBartosz Golaszewski 
204509416a8SBartosz Golaszewski 	for (retry = 5; retry; retry--) {
205a0de56c8SMarc Titinger 
206a0de56c8SMarc Titinger 		ret = regmap_read(data->regmap, reg, regval);
207a0de56c8SMarc Titinger 		if (ret < 0)
208a0de56c8SMarc Titinger 			return ret;
209a0de56c8SMarc Titinger 
210a0de56c8SMarc Titinger 		dev_dbg(dev, "read %d, val = 0x%04x\n", reg, *regval);
211509416a8SBartosz Golaszewski 
212509416a8SBartosz Golaszewski 		/*
213509416a8SBartosz Golaszewski 		 * If the current value in the calibration register is 0, the
214509416a8SBartosz Golaszewski 		 * power and current registers will also remain at 0. In case
215509416a8SBartosz Golaszewski 		 * the chip has been reset let's check the calibration
216509416a8SBartosz Golaszewski 		 * register and reinitialize if needed.
217a0de56c8SMarc Titinger 		 * We do that extra read of the calibration register if there
218a0de56c8SMarc Titinger 		 * is some hint of a chip reset.
219509416a8SBartosz Golaszewski 		 */
220a0de56c8SMarc Titinger 		if (*regval == 0) {
221a0de56c8SMarc Titinger 			unsigned int cal;
222a0de56c8SMarc Titinger 
223a0de56c8SMarc Titinger 			ret = regmap_read(data->regmap, INA2XX_CALIBRATION,
224a0de56c8SMarc Titinger 					  &cal);
225a0de56c8SMarc Titinger 			if (ret < 0)
226a0de56c8SMarc Titinger 				return ret;
227a0de56c8SMarc Titinger 
228a0de56c8SMarc Titinger 			if (cal == 0) {
229509416a8SBartosz Golaszewski 				dev_warn(dev, "chip not calibrated, reinitializing\n");
230509416a8SBartosz Golaszewski 
231a0de56c8SMarc Titinger 				ret = ina2xx_init(data);
232a0de56c8SMarc Titinger 				if (ret < 0)
233a0de56c8SMarc Titinger 					return ret;
234509416a8SBartosz Golaszewski 				/*
235a0de56c8SMarc Titinger 				 * Let's make sure the power and current
236a0de56c8SMarc Titinger 				 * registers have been updated before trying
237a0de56c8SMarc Titinger 				 * again.
238509416a8SBartosz Golaszewski 				 */
239509416a8SBartosz Golaszewski 				msleep(INA2XX_MAX_DELAY);
240509416a8SBartosz Golaszewski 				continue;
241509416a8SBartosz Golaszewski 			}
242a0de56c8SMarc Titinger 		}
243509416a8SBartosz Golaszewski 		return 0;
244509416a8SBartosz Golaszewski 	}
245509416a8SBartosz Golaszewski 
246509416a8SBartosz Golaszewski 	/*
247509416a8SBartosz Golaszewski 	 * If we're here then although all write operations succeeded, the
248509416a8SBartosz Golaszewski 	 * chip still returns 0 in the calibration register. Nothing more we
249509416a8SBartosz Golaszewski 	 * can do here.
250509416a8SBartosz Golaszewski 	 */
251509416a8SBartosz Golaszewski 	dev_err(dev, "unable to reinitialize the chip\n");
252509416a8SBartosz Golaszewski 	return -ENODEV;
253509416a8SBartosz Golaszewski }
254509416a8SBartosz Golaszewski 
255a0de56c8SMarc Titinger static int ina2xx_get_value(struct ina2xx_data *data, u8 reg,
256a0de56c8SMarc Titinger 			    unsigned int regval)
257f7c2fe38SFelten, Lothar {
2586106db25SGuenter Roeck 	int val;
259f7c2fe38SFelten, Lothar 
260f7c2fe38SFelten, Lothar 	switch (reg) {
261f7c2fe38SFelten, Lothar 	case INA2XX_SHUNT_VOLTAGE:
262c0214f98SFabio Baltieri 		/* signed register */
263a0de56c8SMarc Titinger 		val = DIV_ROUND_CLOSEST((s16)regval, data->config->shunt_div);
264f7c2fe38SFelten, Lothar 		break;
265f7c2fe38SFelten, Lothar 	case INA2XX_BUS_VOLTAGE:
266a0de56c8SMarc Titinger 		val = (regval >> data->config->bus_voltage_shift)
2676106db25SGuenter Roeck 		  * data->config->bus_voltage_lsb;
2686106db25SGuenter Roeck 		val = DIV_ROUND_CLOSEST(val, 1000);
269f7c2fe38SFelten, Lothar 		break;
270f7c2fe38SFelten, Lothar 	case INA2XX_POWER:
271a0de56c8SMarc Titinger 		val = regval * data->config->power_lsb;
272f7c2fe38SFelten, Lothar 		break;
273f7c2fe38SFelten, Lothar 	case INA2XX_CURRENT:
274c0214f98SFabio Baltieri 		/* signed register, LSB=1mA (selected), in mA */
275a0de56c8SMarc Titinger 		val = (s16)regval;
276f7c2fe38SFelten, Lothar 		break;
2778a5fc795SBartosz Golaszewski 	case INA2XX_CALIBRATION:
278b721fe2aSBartosz Golaszewski 		val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
279a0de56c8SMarc Titinger 					regval);
2808a5fc795SBartosz Golaszewski 		break;
281f7c2fe38SFelten, Lothar 	default:
282f7c2fe38SFelten, Lothar 		/* programmer goofed */
283f7c2fe38SFelten, Lothar 		WARN_ON_ONCE(1);
284f7c2fe38SFelten, Lothar 		val = 0;
285f7c2fe38SFelten, Lothar 		break;
286f7c2fe38SFelten, Lothar 	}
287f7c2fe38SFelten, Lothar 
288f7c2fe38SFelten, Lothar 	return val;
289f7c2fe38SFelten, Lothar }
290f7c2fe38SFelten, Lothar 
291f7c2fe38SFelten, Lothar static ssize_t ina2xx_show_value(struct device *dev,
292f7c2fe38SFelten, Lothar 				 struct device_attribute *da, char *buf)
293f7c2fe38SFelten, Lothar {
294f7c2fe38SFelten, Lothar 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
295a0de56c8SMarc Titinger 	struct ina2xx_data *data = dev_get_drvdata(dev);
296a0de56c8SMarc Titinger 	unsigned int regval;
297f7c2fe38SFelten, Lothar 
298a0de56c8SMarc Titinger 	int err = ina2xx_read_reg(dev, attr->index, &regval);
299a0de56c8SMarc Titinger 
300a0de56c8SMarc Titinger 	if (err < 0)
301a0de56c8SMarc Titinger 		return err;
302f7c2fe38SFelten, Lothar 
3036106db25SGuenter Roeck 	return snprintf(buf, PAGE_SIZE, "%d\n",
304a0de56c8SMarc Titinger 			ina2xx_get_value(data, attr->index, regval));
305f7c2fe38SFelten, Lothar }
306f7c2fe38SFelten, Lothar 
3078a5fc795SBartosz Golaszewski static ssize_t ina2xx_set_shunt(struct device *dev,
3088a5fc795SBartosz Golaszewski 				struct device_attribute *da,
3098a5fc795SBartosz Golaszewski 				const char *buf, size_t count)
3108a5fc795SBartosz Golaszewski {
3118a5fc795SBartosz Golaszewski 	unsigned long val;
3128a5fc795SBartosz Golaszewski 	int status;
313a0de56c8SMarc Titinger 	struct ina2xx_data *data = dev_get_drvdata(dev);
3148a5fc795SBartosz Golaszewski 
3158a5fc795SBartosz Golaszewski 	status = kstrtoul(buf, 10, &val);
3168a5fc795SBartosz Golaszewski 	if (status < 0)
3178a5fc795SBartosz Golaszewski 		return status;
3188a5fc795SBartosz Golaszewski 
3198a5fc795SBartosz Golaszewski 	if (val == 0 ||
3208a5fc795SBartosz Golaszewski 	    /* Values greater than the calibration factor make no sense. */
3218a5fc795SBartosz Golaszewski 	    val > data->config->calibration_factor)
3228a5fc795SBartosz Golaszewski 		return -EINVAL;
3238a5fc795SBartosz Golaszewski 
324a0de56c8SMarc Titinger 	mutex_lock(&data->config_lock);
3258a5fc795SBartosz Golaszewski 	data->rshunt = val;
3268a5fc795SBartosz Golaszewski 	status = ina2xx_calibrate(data);
327a0de56c8SMarc Titinger 	mutex_unlock(&data->config_lock);
3288a5fc795SBartosz Golaszewski 	if (status < 0)
3298a5fc795SBartosz Golaszewski 		return status;
3308a5fc795SBartosz Golaszewski 
3318a5fc795SBartosz Golaszewski 	return count;
3328a5fc795SBartosz Golaszewski }
3338a5fc795SBartosz Golaszewski 
33472a87a47SBartosz Golaszewski static ssize_t ina226_set_interval(struct device *dev,
33572a87a47SBartosz Golaszewski 				   struct device_attribute *da,
33672a87a47SBartosz Golaszewski 				   const char *buf, size_t count)
33772a87a47SBartosz Golaszewski {
33872a87a47SBartosz Golaszewski 	struct ina2xx_data *data = dev_get_drvdata(dev);
33972a87a47SBartosz Golaszewski 	unsigned long val;
34072a87a47SBartosz Golaszewski 	int status;
34172a87a47SBartosz Golaszewski 
34272a87a47SBartosz Golaszewski 	status = kstrtoul(buf, 10, &val);
34372a87a47SBartosz Golaszewski 	if (status < 0)
34472a87a47SBartosz Golaszewski 		return status;
34572a87a47SBartosz Golaszewski 
34672a87a47SBartosz Golaszewski 	if (val > INT_MAX || val == 0)
34772a87a47SBartosz Golaszewski 		return -EINVAL;
34872a87a47SBartosz Golaszewski 
349a0de56c8SMarc Titinger 	status = regmap_update_bits(data->regmap, INA2XX_CONFIG,
350a0de56c8SMarc Titinger 				    INA226_AVG_RD_MASK,
351a0de56c8SMarc Titinger 				    ina226_interval_to_reg(val));
35272a87a47SBartosz Golaszewski 	if (status < 0)
35372a87a47SBartosz Golaszewski 		return status;
35472a87a47SBartosz Golaszewski 
35572a87a47SBartosz Golaszewski 	return count;
35672a87a47SBartosz Golaszewski }
35772a87a47SBartosz Golaszewski 
35872a87a47SBartosz Golaszewski static ssize_t ina226_show_interval(struct device *dev,
35972a87a47SBartosz Golaszewski 				    struct device_attribute *da, char *buf)
36072a87a47SBartosz Golaszewski {
361a0de56c8SMarc Titinger 	struct ina2xx_data *data = dev_get_drvdata(dev);
362a0de56c8SMarc Titinger 	int status;
363a0de56c8SMarc Titinger 	unsigned int regval;
36472a87a47SBartosz Golaszewski 
365a0de56c8SMarc Titinger 	status = regmap_read(data->regmap, INA2XX_CONFIG, &regval);
366a0de56c8SMarc Titinger 	if (status)
367a0de56c8SMarc Titinger 		return status;
36872a87a47SBartosz Golaszewski 
369a0de56c8SMarc Titinger 	return snprintf(buf, PAGE_SIZE, "%d\n", ina226_reg_to_interval(regval));
37072a87a47SBartosz Golaszewski }
37172a87a47SBartosz Golaszewski 
372f7c2fe38SFelten, Lothar /* shunt voltage */
373f0df0fd9SGuenter Roeck static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
374f0df0fd9SGuenter Roeck 			  INA2XX_SHUNT_VOLTAGE);
375f7c2fe38SFelten, Lothar 
376f7c2fe38SFelten, Lothar /* bus voltage */
377f0df0fd9SGuenter Roeck static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina2xx_show_value, NULL,
378f0df0fd9SGuenter Roeck 			  INA2XX_BUS_VOLTAGE);
379f7c2fe38SFelten, Lothar 
380f7c2fe38SFelten, Lothar /* calculated current */
381f0df0fd9SGuenter Roeck static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina2xx_show_value, NULL,
382f0df0fd9SGuenter Roeck 			  INA2XX_CURRENT);
383f7c2fe38SFelten, Lothar 
384f7c2fe38SFelten, Lothar /* calculated power */
385f0df0fd9SGuenter Roeck static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL,
386f0df0fd9SGuenter Roeck 			  INA2XX_POWER);
387f7c2fe38SFelten, Lothar 
3888a5fc795SBartosz Golaszewski /* shunt resistance */
3898a5fc795SBartosz Golaszewski static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR,
3908a5fc795SBartosz Golaszewski 			  ina2xx_show_value, ina2xx_set_shunt,
3918a5fc795SBartosz Golaszewski 			  INA2XX_CALIBRATION);
3928a5fc795SBartosz Golaszewski 
39372a87a47SBartosz Golaszewski /* update interval (ina226 only) */
39472a87a47SBartosz Golaszewski static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR,
39572a87a47SBartosz Golaszewski 			  ina226_show_interval, ina226_set_interval, 0);
39672a87a47SBartosz Golaszewski 
397f7c2fe38SFelten, Lothar /* pointers to created device attributes */
398468bf0e3SGuenter Roeck static struct attribute *ina2xx_attrs[] = {
399f7c2fe38SFelten, Lothar 	&sensor_dev_attr_in0_input.dev_attr.attr,
400f7c2fe38SFelten, Lothar 	&sensor_dev_attr_in1_input.dev_attr.attr,
401f7c2fe38SFelten, Lothar 	&sensor_dev_attr_curr1_input.dev_attr.attr,
402f7c2fe38SFelten, Lothar 	&sensor_dev_attr_power1_input.dev_attr.attr,
4038a5fc795SBartosz Golaszewski 	&sensor_dev_attr_shunt_resistor.dev_attr.attr,
404f7c2fe38SFelten, Lothar 	NULL,
405f7c2fe38SFelten, Lothar };
40672a87a47SBartosz Golaszewski 
40772a87a47SBartosz Golaszewski static const struct attribute_group ina2xx_group = {
40872a87a47SBartosz Golaszewski 	.attrs = ina2xx_attrs,
40972a87a47SBartosz Golaszewski };
41072a87a47SBartosz Golaszewski 
41172a87a47SBartosz Golaszewski static struct attribute *ina226_attrs[] = {
41272a87a47SBartosz Golaszewski 	&sensor_dev_attr_update_interval.dev_attr.attr,
41372a87a47SBartosz Golaszewski 	NULL,
41472a87a47SBartosz Golaszewski };
41572a87a47SBartosz Golaszewski 
41672a87a47SBartosz Golaszewski static const struct attribute_group ina226_group = {
41772a87a47SBartosz Golaszewski 	.attrs = ina226_attrs,
41872a87a47SBartosz Golaszewski };
419f7c2fe38SFelten, Lothar 
420f7c2fe38SFelten, Lothar static int ina2xx_probe(struct i2c_client *client,
421f7c2fe38SFelten, Lothar 			const struct i2c_device_id *id)
422f7c2fe38SFelten, Lothar {
423468bf0e3SGuenter Roeck 	struct device *dev = &client->dev;
424468bf0e3SGuenter Roeck 	struct ina2xx_data *data;
425468bf0e3SGuenter Roeck 	struct device *hwmon_dev;
426468bf0e3SGuenter Roeck 	u32 val;
42772a87a47SBartosz Golaszewski 	int ret, group = 0;
428*bd0ddd4dSJavier Martinez Canillas 	enum ina2xx_ids chip;
429*bd0ddd4dSJavier Martinez Canillas 
430*bd0ddd4dSJavier Martinez Canillas 	if (client->dev.of_node)
431*bd0ddd4dSJavier Martinez Canillas 		chip = (enum ina2xx_ids)of_device_get_match_data(&client->dev);
432*bd0ddd4dSJavier Martinez Canillas 	else
433*bd0ddd4dSJavier Martinez Canillas 		chip = id->driver_data;
434f7c2fe38SFelten, Lothar 
435468bf0e3SGuenter Roeck 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
436f7c2fe38SFelten, Lothar 	if (!data)
437f7c2fe38SFelten, Lothar 		return -ENOMEM;
438f7c2fe38SFelten, Lothar 
439f7c2fe38SFelten, Lothar 	/* set the device type */
440*bd0ddd4dSJavier Martinez Canillas 	data->config = &ina2xx_config[chip];
44172a87a47SBartosz Golaszewski 
442001e2e73SMarc Titinger 	if (of_property_read_u32(dev->of_node, "shunt-resistor", &val) < 0) {
443001e2e73SMarc Titinger 		struct ina2xx_platform_data *pdata = dev_get_platdata(dev);
444001e2e73SMarc Titinger 
445001e2e73SMarc Titinger 		if (pdata)
446001e2e73SMarc Titinger 			val = pdata->shunt_uohms;
447001e2e73SMarc Titinger 		else
448001e2e73SMarc Titinger 			val = INA2XX_RSHUNT_DEFAULT;
449001e2e73SMarc Titinger 	}
450001e2e73SMarc Titinger 
451001e2e73SMarc Titinger 	if (val <= 0 || val > data->config->calibration_factor)
452509416a8SBartosz Golaszewski 		return -ENODEV;
453509416a8SBartosz Golaszewski 
454001e2e73SMarc Titinger 	data->rshunt = val;
455001e2e73SMarc Titinger 
456a0de56c8SMarc Titinger 	ina2xx_regmap_config.max_register = data->config->registers;
457a0de56c8SMarc Titinger 
458a0de56c8SMarc Titinger 	data->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config);
459a0de56c8SMarc Titinger 	if (IS_ERR(data->regmap)) {
460a0de56c8SMarc Titinger 		dev_err(dev, "failed to allocate register map\n");
461a0de56c8SMarc Titinger 		return PTR_ERR(data->regmap);
462a0de56c8SMarc Titinger 	}
463a0de56c8SMarc Titinger 
464509416a8SBartosz Golaszewski 	ret = ina2xx_init(data);
465509416a8SBartosz Golaszewski 	if (ret < 0) {
466509416a8SBartosz Golaszewski 		dev_err(dev, "error configuring the device: %d\n", ret);
467509416a8SBartosz Golaszewski 		return -ENODEV;
468509416a8SBartosz Golaszewski 	}
469509416a8SBartosz Golaszewski 
470a0de56c8SMarc Titinger 	mutex_init(&data->config_lock);
471f7c2fe38SFelten, Lothar 
47272a87a47SBartosz Golaszewski 	data->groups[group++] = &ina2xx_group;
4735aa4e83dSMarc Titinger 	if (id->driver_data == ina226)
47472a87a47SBartosz Golaszewski 		data->groups[group++] = &ina226_group;
47572a87a47SBartosz Golaszewski 
476468bf0e3SGuenter Roeck 	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
47772a87a47SBartosz Golaszewski 							   data, data->groups);
478468bf0e3SGuenter Roeck 	if (IS_ERR(hwmon_dev))
479468bf0e3SGuenter Roeck 		return PTR_ERR(hwmon_dev);
480f7c2fe38SFelten, Lothar 
481468bf0e3SGuenter Roeck 	dev_info(dev, "power monitor %s (Rshunt = %li uOhm)\n",
482509416a8SBartosz Golaszewski 		 id->name, data->rshunt);
4836106db25SGuenter Roeck 
484f7c2fe38SFelten, Lothar 	return 0;
485f7c2fe38SFelten, Lothar }
486f7c2fe38SFelten, Lothar 
487f7c2fe38SFelten, Lothar static const struct i2c_device_id ina2xx_id[] = {
488f7c2fe38SFelten, Lothar 	{ "ina219", ina219 },
489dc92cd0cSGuenter Roeck 	{ "ina220", ina219 },
490f7c2fe38SFelten, Lothar 	{ "ina226", ina226 },
491dc92cd0cSGuenter Roeck 	{ "ina230", ina226 },
492add513beSKevin Hilman 	{ "ina231", ina226 },
493f7c2fe38SFelten, Lothar 	{ }
494f7c2fe38SFelten, Lothar };
495f7c2fe38SFelten, Lothar MODULE_DEVICE_TABLE(i2c, ina2xx_id);
496f7c2fe38SFelten, Lothar 
497*bd0ddd4dSJavier Martinez Canillas static const struct of_device_id ina2xx_of_match[] = {
498*bd0ddd4dSJavier Martinez Canillas 	{
499*bd0ddd4dSJavier Martinez Canillas 		.compatible = "ti,ina219",
500*bd0ddd4dSJavier Martinez Canillas 		.data = (void *)ina219
501*bd0ddd4dSJavier Martinez Canillas 	},
502*bd0ddd4dSJavier Martinez Canillas 	{
503*bd0ddd4dSJavier Martinez Canillas 		.compatible = "ti,ina220",
504*bd0ddd4dSJavier Martinez Canillas 		.data = (void *)ina219
505*bd0ddd4dSJavier Martinez Canillas 	},
506*bd0ddd4dSJavier Martinez Canillas 	{
507*bd0ddd4dSJavier Martinez Canillas 		.compatible = "ti,ina226",
508*bd0ddd4dSJavier Martinez Canillas 		.data = (void *)ina226
509*bd0ddd4dSJavier Martinez Canillas 	},
510*bd0ddd4dSJavier Martinez Canillas 	{
511*bd0ddd4dSJavier Martinez Canillas 		.compatible = "ti,ina230",
512*bd0ddd4dSJavier Martinez Canillas 		.data = (void *)ina226
513*bd0ddd4dSJavier Martinez Canillas 	},
514*bd0ddd4dSJavier Martinez Canillas 	{
515*bd0ddd4dSJavier Martinez Canillas 		.compatible = "ti,ina231",
516*bd0ddd4dSJavier Martinez Canillas 		.data = (void *)ina226
517*bd0ddd4dSJavier Martinez Canillas 	},
518*bd0ddd4dSJavier Martinez Canillas 	{ },
519*bd0ddd4dSJavier Martinez Canillas };
520*bd0ddd4dSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, ina2xx_of_match);
521*bd0ddd4dSJavier Martinez Canillas 
522f7c2fe38SFelten, Lothar static struct i2c_driver ina2xx_driver = {
523f7c2fe38SFelten, Lothar 	.driver = {
524f7c2fe38SFelten, Lothar 		.name	= "ina2xx",
525*bd0ddd4dSJavier Martinez Canillas 		.of_match_table = of_match_ptr(ina2xx_of_match),
526f7c2fe38SFelten, Lothar 	},
527f7c2fe38SFelten, Lothar 	.probe		= ina2xx_probe,
528f7c2fe38SFelten, Lothar 	.id_table	= ina2xx_id,
529f7c2fe38SFelten, Lothar };
530f7c2fe38SFelten, Lothar 
531d835ca0fSWei Yongjun module_i2c_driver(ina2xx_driver);
532f7c2fe38SFelten, Lothar 
533f7c2fe38SFelten, Lothar MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>");
534f7c2fe38SFelten, Lothar MODULE_DESCRIPTION("ina2xx driver");
535f7c2fe38SFelten, Lothar MODULE_LICENSE("GPL");
536