aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorFelten, Lothar <l-felten@ti.com>2012-05-12 04:36:38 -0400
committerGuenter Roeck <guenter.roeck@ericsson.com>2012-05-22 09:48:02 -0400
commitf7c2fe386ae92b471a0edd4fa4bed7033224b9bf (patch)
tree8cb48fef02388eb5e64314aeb10143e5c20833cc /drivers/hwmon
parent9172b5d124c2f54374d8cc5ed6098ecd8fb988cd (diff)
hwmon: INA219 and INA226 support
Add support for the Texas Instruments INA219 and INA226 power monitors. Signed-off-by: Lothar Felten <l-felten@ti.com> [guenter.roeck@ericsson.com: formatting cleanup; check for smbus word data; select PGA=8 for INA219] Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig13
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/ina2xx.c368
3 files changed, 382 insertions, 0 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 8deedc1b9840..1c7bbd458902 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1102,6 +1102,19 @@ config SENSORS_AMC6821
1102 This driver can also be build as a module. If so, the module 1102 This driver can also be build as a module. If so, the module
1103 will be called amc6821. 1103 will be called amc6821.
1104 1104
1105config SENSORS_INA2XX
1106 tristate "Texas Instruments INA219, INA226"
1107 depends on I2C && EXPERIMENTAL
1108 help
1109 If you say yes here you get support for INA219 and INA226 power
1110 monitor chips.
1111
1112 The INA2xx driver is configured for the default configuration of
1113 the part as described in the datasheet.
1114 Default value for Rshunt is 10 mOhms.
1115 This driver can also be built as a module. If so, the module
1116 will be called ina2xx.
1117
1105config SENSORS_THMC50 1118config SENSORS_THMC50
1106 tristate "Texas Instruments THMC50 / Analog Devices ADM1022" 1119 tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
1107 depends on I2C 1120 depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 6d3f11f71815..e1eeac13b851 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
62obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o 62obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
63obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o 63obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
64obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o 64obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
65obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o
65obj-$(CONFIG_SENSORS_IT87) += it87.o 66obj-$(CONFIG_SENSORS_IT87) += it87.o
66obj-$(CONFIG_SENSORS_JC42) += jc42.o 67obj-$(CONFIG_SENSORS_JC42) += jc42.o
67obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o 68obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
new file mode 100644
index 000000000000..7f3f4a385729
--- /dev/null
+++ b/drivers/hwmon/ina2xx.c
@@ -0,0 +1,368 @@
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
72int ina2xx_read_word(struct i2c_client *client, int reg)
73{
74 int val = i2c_smbus_read_word_data(client, reg);
75 if (unlikely(val < 0)) {
76 dev_dbg(&client->dev,
77 "Failed to read register: %d\n", reg);
78 return val;
79 }
80 return be16_to_cpu(val);
81}
82
83void ina2xx_write_word(struct i2c_client *client, int reg, int data)
84{
85 i2c_smbus_write_word_data(client, reg, cpu_to_be16(data));
86}
87
88static struct ina2xx_data *ina2xx_update_device(struct device *dev)
89{
90 struct i2c_client *client = to_i2c_client(dev);
91 struct ina2xx_data *data = i2c_get_clientdata(client);
92 struct ina2xx_data *ret = data;
93
94 mutex_lock(&data->update_lock);
95
96 if (time_after(jiffies, data->last_updated +
97 HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
98
99 int i;
100
101 dev_dbg(&client->dev, "Starting ina2xx update\n");
102
103 /* Read all registers */
104 for (i = 0; i < data->registers; i++) {
105 int rv = ina2xx_read_word(client, i);
106 if (rv < 0) {
107 ret = ERR_PTR(rv);
108 goto abort;
109 }
110 data->regs[i] = rv;
111 }
112 data->last_updated = jiffies;
113 data->valid = 1;
114 }
115abort:
116 mutex_unlock(&data->update_lock);
117 return ret;
118}
119
120static int ina219_get_value(struct ina2xx_data *data, u8 reg)
121{
122 /*
123 * calculate exact value for the given register
124 * we assume default power-on reset settings:
125 * bus voltage range 32V
126 * gain = /8
127 * adc 1 & 2 -> conversion time 532uS
128 * mode is continuous shunt and bus
129 * calibration value is INA219_CALIBRATION_VALUE
130 */
131 int val = data->regs[reg];
132
133 switch (reg) {
134 case INA2XX_SHUNT_VOLTAGE:
135 /* LSB=10uV. Convert to mV. */
136 val = DIV_ROUND_CLOSEST(val, 100);
137 break;
138 case INA2XX_BUS_VOLTAGE:
139 /* LSB=4mV. Register is not right aligned, convert to mV. */
140 val = (val >> 3) * 4;
141 break;
142 case INA2XX_POWER:
143 /* LSB=20mW. Convert to uW */
144 val = val * 20 * 1000;
145 break;
146 case INA2XX_CURRENT:
147 /* LSB=1mA (selected). Is in mA */
148 break;
149 default:
150 /* programmer goofed */
151 WARN_ON_ONCE(1);
152 val = 0;
153 break;
154 }
155
156 return val;
157}
158
159static int ina226_get_value(struct ina2xx_data *data, u8 reg)
160{
161 /*
162 * calculate exact value for the given register
163 * we assume default power-on reset settings:
164 * bus voltage range 32V
165 * gain = /8
166 * adc 1 & 2 -> conversion time 532uS
167 * mode is continuous shunt and bus
168 * calibration value is INA226_CALIBRATION_VALUE
169 */
170 int val = data->regs[reg];
171
172 switch (reg) {
173 case INA2XX_SHUNT_VOLTAGE:
174 /* LSB=2.5uV. Convert to mV. */
175 val = DIV_ROUND_CLOSEST(val, 400);
176 break;
177 case INA2XX_BUS_VOLTAGE:
178 /* LSB=1.25mV. Convert to mV. */
179 val = val + DIV_ROUND_CLOSEST(val, 4);
180 break;
181 case INA2XX_POWER:
182 /* LSB=25mW. Convert to uW */
183 val = val * 25 * 1000;
184 break;
185 case INA2XX_CURRENT:
186 /* LSB=1mA (selected). Is in mA */
187 break;
188 default:
189 /* programmer goofed */
190 WARN_ON_ONCE(1);
191 val = 0;
192 break;
193 }
194
195 return val;
196}
197
198static ssize_t ina2xx_show_value(struct device *dev,
199 struct device_attribute *da, char *buf)
200{
201 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
202 struct ina2xx_data *data = ina2xx_update_device(dev);
203 int value = 0;
204
205 if (IS_ERR(data))
206 return PTR_ERR(data);
207
208 switch (data->kind) {
209 case ina219:
210 value = ina219_get_value(data, attr->index);
211 break;
212 case ina226:
213 value = ina226_get_value(data, attr->index);
214 break;
215 default:
216 WARN_ON_ONCE(1);
217 break;
218 }
219 return snprintf(buf, PAGE_SIZE, "%d\n", value);
220}
221
222/* shunt voltage */
223static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \
224 ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE);
225
226/* bus voltage */
227static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
228 ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE);
229
230/* calculated current */
231static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
232 ina2xx_show_value, NULL, INA2XX_CURRENT);
233
234/* calculated power */
235static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \
236 ina2xx_show_value, NULL, INA2XX_POWER);
237
238/* pointers to created device attributes */
239static struct attribute *ina2xx_attributes[] = {
240 &sensor_dev_attr_in0_input.dev_attr.attr,
241 &sensor_dev_attr_in1_input.dev_attr.attr,
242 &sensor_dev_attr_curr1_input.dev_attr.attr,
243 &sensor_dev_attr_power1_input.dev_attr.attr,
244 NULL,
245};
246
247static const struct attribute_group ina2xx_group = {
248 .attrs = ina2xx_attributes,
249};
250
251static int ina2xx_probe(struct i2c_client *client,
252 const struct i2c_device_id *id)
253{
254 struct i2c_adapter *adapter = client->adapter;
255 struct ina2xx_data *data;
256 struct ina2xx_platform_data *pdata;
257 int ret = 0;
258 long shunt = 10000; /* default shunt value 10mOhms */
259
260 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
261 return -ENODEV;
262
263 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
264 if (!data)
265 return -ENOMEM;
266
267 if (client->dev.platform_data) {
268 pdata =
269 (struct ina2xx_platform_data *)client->dev.platform_data;
270 shunt = pdata->shunt_uohms;
271 }
272
273 if (shunt <= 0)
274 return -ENODEV;
275
276 /* set the device type */
277 data->kind = id->driver_data;
278
279 switch (data->kind) {
280 case ina219:
281 /* device configuration */
282 ina2xx_write_word(client, INA2XX_CONFIG, INA219_CONFIG_DEFAULT);
283
284 /* set current LSB to 1mA, shunt is in uOhms */
285 /* (equation 13 in datasheet) */
286 ina2xx_write_word(client, INA2XX_CALIBRATION, 40960000 / shunt);
287 dev_info(&client->dev,
288 "power monitor INA219 (Rshunt = %li uOhm)\n", shunt);
289 data->registers = INA219_REGISTERS;
290 break;
291 case ina226:
292 /* device configuration */
293 ina2xx_write_word(client, INA2XX_CONFIG, INA226_CONFIG_DEFAULT);
294
295 /* set current LSB to 1mA, shunt is in uOhms */
296 /* (equation 1 in datasheet)*/
297 ina2xx_write_word(client, INA2XX_CALIBRATION, 5120000 / shunt);
298 dev_info(&client->dev,
299 "power monitor INA226 (Rshunt = %li uOhm)\n", shunt);
300 data->registers = INA226_REGISTERS;
301 break;
302 default:
303 /* unknown device id */
304 return -ENODEV;
305 }
306
307 i2c_set_clientdata(client, data);
308 mutex_init(&data->update_lock);
309
310 ret = sysfs_create_group(&client->dev.kobj, &ina2xx_group);
311 if (ret)
312 return ret;
313
314 data->hwmon_dev = hwmon_device_register(&client->dev);
315 if (IS_ERR(data->hwmon_dev)) {
316 ret = PTR_ERR(data->hwmon_dev);
317 goto out_err_hwmon;
318 }
319
320 return 0;
321
322out_err_hwmon:
323 sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
324 return ret;
325}
326
327static int ina2xx_remove(struct i2c_client *client)
328{
329 struct ina2xx_data *data = i2c_get_clientdata(client);
330
331 hwmon_device_unregister(data->hwmon_dev);
332 sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
333
334 return 0;
335}
336
337static const struct i2c_device_id ina2xx_id[] = {
338 { "ina219", ina219 },
339 { "ina226", ina226 },
340 { }
341};
342MODULE_DEVICE_TABLE(i2c, ina2xx_id);
343
344static struct i2c_driver ina2xx_driver = {
345 .driver = {
346 .name = "ina2xx",
347 },
348 .probe = ina2xx_probe,
349 .remove = ina2xx_remove,
350 .id_table = ina2xx_id,
351};
352
353static int __init ina2xx_init(void)
354{
355 return i2c_add_driver(&ina2xx_driver);
356}
357
358static void __exit ina2xx_exit(void)
359{
360 i2c_del_driver(&ina2xx_driver);
361}
362
363MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>");
364MODULE_DESCRIPTION("ina2xx driver");
365MODULE_LICENSE("GPL");
366
367module_init(ina2xx_init);
368module_exit(ina2xx_exit);