Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Driver for Texas Instruments INA219, INA226 power monitor chips
  3 *
  4 * INA219:
  5 * Zero Drift Bi-Directional Current/Power Monitor with I2C Interface
  6 * Datasheet: http://www.ti.com/product/ina219
  7 *
  8 * INA226:
  9 * Bi-Directional Current/Power Monitor with I2C Interface
 10 * Datasheet: http://www.ti.com/product/ina226
 11 *
 12 * Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
 13 * Thanks to Jan Volkering
 14 *
 15 * This program is free software; you can redistribute it and/or modify
 16 * it under the terms of the GNU General Public License as published by
 17 * the Free Software Foundation; version 2 of the License.
 18 */
 19
 20#include <linux/kernel.h>
 21#include <linux/module.h>
 22#include <linux/init.h>
 23#include <linux/err.h>
 24#include <linux/slab.h>
 25#include <linux/i2c.h>
 26#include <linux/hwmon.h>
 27#include <linux/hwmon-sysfs.h>
 28
 29#include <linux/platform_data/ina2xx.h>
 30
 31/* common register definitions */
 32#define INA2XX_CONFIG			0x00
 33#define INA2XX_SHUNT_VOLTAGE		0x01 /* readonly */
 34#define INA2XX_BUS_VOLTAGE		0x02 /* readonly */
 35#define INA2XX_POWER			0x03 /* readonly */
 36#define INA2XX_CURRENT			0x04 /* readonly */
 37#define INA2XX_CALIBRATION		0x05
 38
 39/* INA226 register definitions */
 40#define INA226_MASK_ENABLE		0x06
 41#define INA226_ALERT_LIMIT		0x07
 42#define INA226_DIE_ID			0xFF
 43
 44
 45/* register count */
 46#define INA219_REGISTERS		6
 47#define INA226_REGISTERS		8
 48
 49#define INA2XX_MAX_REGISTERS		8
 50
 51/* settings - depend on use case */
 52#define INA219_CONFIG_DEFAULT		0x399F	/* PGA=8 */
 53#define INA226_CONFIG_DEFAULT		0x4527	/* averages=16 */
 54
 55/* worst case is 68.10 ms (~14.6Hz, ina219) */
 56#define INA2XX_CONVERSION_RATE		15
 57
 58enum ina2xx_ids { ina219, ina226 };
 59
 60struct ina2xx_data {
 61	struct device *hwmon_dev;
 62
 63	struct mutex update_lock;
 64	bool valid;
 65	unsigned long last_updated;
 66
 67	int kind;
 68	int registers;
 69	u16 regs[INA2XX_MAX_REGISTERS];
 70};
 71
 72static struct ina2xx_data *ina2xx_update_device(struct device *dev)
 73{
 74	struct i2c_client *client = to_i2c_client(dev);
 75	struct ina2xx_data *data = i2c_get_clientdata(client);
 76	struct ina2xx_data *ret = data;
 77
 78	mutex_lock(&data->update_lock);
 79
 80	if (time_after(jiffies, data->last_updated +
 81		       HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
 82
 83		int i;
 84
 85		dev_dbg(&client->dev, "Starting ina2xx update\n");
 86
 87		/* Read all registers */
 88		for (i = 0; i < data->registers; i++) {
 89			int rv = i2c_smbus_read_word_swapped(client, i);
 90			if (rv < 0) {
 91				ret = ERR_PTR(rv);
 92				goto abort;
 93			}
 94			data->regs[i] = rv;
 95		}
 96		data->last_updated = jiffies;
 97		data->valid = 1;
 98	}
 99abort:
100	mutex_unlock(&data->update_lock);
101	return ret;
102}
103
104static int ina219_get_value(struct ina2xx_data *data, u8 reg)
105{
106	/*
107	 * calculate exact value for the given register
108	 * we assume default power-on reset settings:
109	 * bus voltage range 32V
110	 * gain = /8
111	 * adc 1 & 2 -> conversion time 532uS
112	 * mode is continuous shunt and bus
113	 * calibration value is INA219_CALIBRATION_VALUE
114	 */
115	int val = data->regs[reg];
116
117	switch (reg) {
118	case INA2XX_SHUNT_VOLTAGE:
119		/* LSB=10uV. Convert to mV. */
120		val = DIV_ROUND_CLOSEST(val, 100);
121		break;
122	case INA2XX_BUS_VOLTAGE:
123		/* LSB=4mV. Register is not right aligned, convert to mV. */
124		val = (val >> 3) * 4;
125		break;
126	case INA2XX_POWER:
127		/* LSB=20mW. Convert to uW */
128		val = val * 20 * 1000;
129		break;
130	case INA2XX_CURRENT:
131		/* LSB=1mA (selected). Is in mA */
132		break;
133	default:
134		/* programmer goofed */
135		WARN_ON_ONCE(1);
136		val = 0;
137		break;
138	}
139
140	return val;
141}
142
143static int ina226_get_value(struct ina2xx_data *data, u8 reg)
144{
145	/*
146	 * calculate exact value for the given register
147	 * we assume default power-on reset settings:
148	 * bus voltage range 32V
149	 * gain = /8
150	 * adc 1 & 2 -> conversion time 532uS
151	 * mode is continuous shunt and bus
152	 * calibration value is INA226_CALIBRATION_VALUE
153	 */
154	int val = data->regs[reg];
155
156	switch (reg) {
157	case INA2XX_SHUNT_VOLTAGE:
158		/* LSB=2.5uV. Convert to mV. */
159		val = DIV_ROUND_CLOSEST(val, 400);
160		break;
161	case INA2XX_BUS_VOLTAGE:
162		/* LSB=1.25mV. Convert to mV. */
163		val = val + DIV_ROUND_CLOSEST(val, 4);
164		break;
165	case INA2XX_POWER:
166		/* LSB=25mW. Convert to uW */
167		val = val * 25 * 1000;
168		break;
169	case INA2XX_CURRENT:
170		/* LSB=1mA (selected). Is in mA */
171		break;
172	default:
173		/* programmer goofed */
174		WARN_ON_ONCE(1);
175		val = 0;
176		break;
177	}
178
179	return val;
180}
181
182static ssize_t ina2xx_show_value(struct device *dev,
183				 struct device_attribute *da, char *buf)
184{
185	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
186	struct ina2xx_data *data = ina2xx_update_device(dev);
187	int value = 0;
188
189	if (IS_ERR(data))
190		return PTR_ERR(data);
191
192	switch (data->kind) {
193	case ina219:
194		value = ina219_get_value(data, attr->index);
195		break;
196	case ina226:
197		value = ina226_get_value(data, attr->index);
198		break;
199	default:
200		WARN_ON_ONCE(1);
201		break;
202	}
203	return snprintf(buf, PAGE_SIZE, "%d\n", value);
204}
205
206/* shunt voltage */
207static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \
208	ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE);
209
210/* bus voltage */
211static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
212	ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE);
213
214/* calculated current */
215static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
216	ina2xx_show_value, NULL, INA2XX_CURRENT);
217
218/* calculated power */
219static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \
220	ina2xx_show_value, NULL, INA2XX_POWER);
221
222/* pointers to created device attributes */
223static struct attribute *ina2xx_attributes[] = {
224	&sensor_dev_attr_in0_input.dev_attr.attr,
225	&sensor_dev_attr_in1_input.dev_attr.attr,
226	&sensor_dev_attr_curr1_input.dev_attr.attr,
227	&sensor_dev_attr_power1_input.dev_attr.attr,
228	NULL,
229};
230
231static const struct attribute_group ina2xx_group = {
232	.attrs = ina2xx_attributes,
233};
234
235static int ina2xx_probe(struct i2c_client *client,
236			const struct i2c_device_id *id)
237{
238	struct i2c_adapter *adapter = client->adapter;
239	struct ina2xx_data *data;
240	struct ina2xx_platform_data *pdata;
241	int ret = 0;
242	long shunt = 10000; /* default shunt value 10mOhms */
243
244	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
245		return -ENODEV;
246
247	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
248	if (!data)
249		return -ENOMEM;
250
251	if (client->dev.platform_data) {
252		pdata =
253		  (struct ina2xx_platform_data *)client->dev.platform_data;
254		shunt = pdata->shunt_uohms;
255	}
256
257	if (shunt <= 0)
258		return -ENODEV;
259
260	/* set the device type */
261	data->kind = id->driver_data;
262
263	switch (data->kind) {
264	case ina219:
265		/* device configuration */
266		i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
267					     INA219_CONFIG_DEFAULT);
268
269		/* set current LSB to 1mA, shunt is in uOhms */
270		/* (equation 13 in datasheet) */
271		i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
272					     40960000 / shunt);
273		dev_info(&client->dev,
274			 "power monitor INA219 (Rshunt = %li uOhm)\n", shunt);
275		data->registers = INA219_REGISTERS;
276		break;
277	case ina226:
278		/* device configuration */
279		i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
280					     INA226_CONFIG_DEFAULT);
281
282		/* set current LSB to 1mA, shunt is in uOhms */
283		/* (equation 1 in datasheet)*/
284		i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
285					     5120000 / shunt);
286		dev_info(&client->dev,
287			 "power monitor INA226 (Rshunt = %li uOhm)\n", shunt);
288		data->registers = INA226_REGISTERS;
289		break;
290	default:
291		/* unknown device id */
292		return -ENODEV;
293	}
294
295	i2c_set_clientdata(client, data);
296	mutex_init(&data->update_lock);
297
298	ret = sysfs_create_group(&client->dev.kobj, &ina2xx_group);
299	if (ret)
300		return ret;
301
302	data->hwmon_dev = hwmon_device_register(&client->dev);
303	if (IS_ERR(data->hwmon_dev)) {
304		ret = PTR_ERR(data->hwmon_dev);
305		goto out_err_hwmon;
306	}
307
308	return 0;
309
310out_err_hwmon:
311	sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
312	return ret;
313}
314
315static int ina2xx_remove(struct i2c_client *client)
316{
317	struct ina2xx_data *data = i2c_get_clientdata(client);
318
319	hwmon_device_unregister(data->hwmon_dev);
320	sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
321
322	return 0;
323}
324
325static const struct i2c_device_id ina2xx_id[] = {
326	{ "ina219", ina219 },
327	{ "ina226", ina226 },
328	{ }
329};
330MODULE_DEVICE_TABLE(i2c, ina2xx_id);
331
332static struct i2c_driver ina2xx_driver = {
333	.driver = {
334		.name	= "ina2xx",
335	},
336	.probe		= ina2xx_probe,
337	.remove		= ina2xx_remove,
338	.id_table	= ina2xx_id,
339};
340
341static int __init ina2xx_init(void)
342{
343	return i2c_add_driver(&ina2xx_driver);
344}
345
346static void __exit ina2xx_exit(void)
347{
348	i2c_del_driver(&ina2xx_driver);
349}
350
351MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>");
352MODULE_DESCRIPTION("ina2xx driver");
353MODULE_LICENSE("GPL");
354
355module_init(ina2xx_init);
356module_exit(ina2xx_exit);