blob: de8f2c6c6b66a52b059d48b85ef56aaf5072d6e7 [file] [log] [blame]
Felten, Lotharf7c2fe32012-05-12 04:36:38 -04001/*
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
Guenter Roeck6106db22012-05-12 11:21:01 -070060struct ina2xx_config {
61 u16 config_default;
62 int calibration_factor;
63 int registers;
64 int shunt_div;
65 int bus_voltage_shift;
66 int bus_voltage_lsb; /* uV */
67 int power_lsb; /* uW */
68};
69
Felten, Lotharf7c2fe32012-05-12 04:36:38 -040070struct ina2xx_data {
71 struct device *hwmon_dev;
Guenter Roeck6106db22012-05-12 11:21:01 -070072 const struct ina2xx_config *config;
Felten, Lotharf7c2fe32012-05-12 04:36:38 -040073
74 struct mutex update_lock;
75 bool valid;
76 unsigned long last_updated;
77
78 int kind;
Felten, Lotharf7c2fe32012-05-12 04:36:38 -040079 u16 regs[INA2XX_MAX_REGISTERS];
80};
81
Guenter Roeck6106db22012-05-12 11:21:01 -070082static const struct ina2xx_config ina2xx_config[] = {
83 [ina219] = {
84 .config_default = INA219_CONFIG_DEFAULT,
85 .calibration_factor = 40960000,
86 .registers = INA219_REGISTERS,
87 .shunt_div = 100,
88 .bus_voltage_shift = 3,
89 .bus_voltage_lsb = 4000,
90 .power_lsb = 20000,
91 },
92 [ina226] = {
93 .config_default = INA226_CONFIG_DEFAULT,
94 .calibration_factor = 5120000,
95 .registers = INA226_REGISTERS,
96 .shunt_div = 400,
97 .bus_voltage_shift = 0,
98 .bus_voltage_lsb = 1250,
99 .power_lsb = 25000,
100 },
101};
102
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400103static struct ina2xx_data *ina2xx_update_device(struct device *dev)
104{
105 struct i2c_client *client = to_i2c_client(dev);
106 struct ina2xx_data *data = i2c_get_clientdata(client);
107 struct ina2xx_data *ret = data;
108
109 mutex_lock(&data->update_lock);
110
111 if (time_after(jiffies, data->last_updated +
112 HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
113
114 int i;
115
116 dev_dbg(&client->dev, "Starting ina2xx update\n");
117
118 /* Read all registers */
Guenter Roeck6106db22012-05-12 11:21:01 -0700119 for (i = 0; i < data->config->registers; i++) {
Guenter Roeck080b98e2012-09-11 08:22:14 -0700120 int rv = i2c_smbus_read_word_swapped(client, i);
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400121 if (rv < 0) {
122 ret = ERR_PTR(rv);
123 goto abort;
124 }
125 data->regs[i] = rv;
126 }
127 data->last_updated = jiffies;
128 data->valid = 1;
129 }
130abort:
131 mutex_unlock(&data->update_lock);
132 return ret;
133}
134
Guenter Roeck6106db22012-05-12 11:21:01 -0700135static int ina2xx_get_value(struct ina2xx_data *data, u8 reg)
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400136{
Guenter Roeck6106db22012-05-12 11:21:01 -0700137 int val;
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400138
139 switch (reg) {
140 case INA2XX_SHUNT_VOLTAGE:
Guenter Roeck6106db22012-05-12 11:21:01 -0700141 val = DIV_ROUND_CLOSEST(data->regs[reg],
142 data->config->shunt_div);
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400143 break;
144 case INA2XX_BUS_VOLTAGE:
Guenter Roeck6106db22012-05-12 11:21:01 -0700145 val = (data->regs[reg] >> data->config->bus_voltage_shift)
146 * data->config->bus_voltage_lsb;
147 val = DIV_ROUND_CLOSEST(val, 1000);
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400148 break;
149 case INA2XX_POWER:
Guenter Roeck6106db22012-05-12 11:21:01 -0700150 val = data->regs[reg] * data->config->power_lsb;
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400151 break;
152 case INA2XX_CURRENT:
153 /* LSB=1mA (selected). Is in mA */
Guenter Roeck6106db22012-05-12 11:21:01 -0700154 val = data->regs[reg];
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400155 break;
156 default:
157 /* programmer goofed */
158 WARN_ON_ONCE(1);
159 val = 0;
160 break;
161 }
162
163 return val;
164}
165
166static ssize_t ina2xx_show_value(struct device *dev,
167 struct device_attribute *da, char *buf)
168{
169 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
170 struct ina2xx_data *data = ina2xx_update_device(dev);
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400171
172 if (IS_ERR(data))
173 return PTR_ERR(data);
174
Guenter Roeck6106db22012-05-12 11:21:01 -0700175 return snprintf(buf, PAGE_SIZE, "%d\n",
176 ina2xx_get_value(data, attr->index));
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400177}
178
179/* shunt voltage */
180static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \
181 ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE);
182
183/* bus voltage */
184static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
185 ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE);
186
187/* calculated current */
188static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
189 ina2xx_show_value, NULL, INA2XX_CURRENT);
190
191/* calculated power */
192static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \
193 ina2xx_show_value, NULL, INA2XX_POWER);
194
195/* pointers to created device attributes */
196static struct attribute *ina2xx_attributes[] = {
197 &sensor_dev_attr_in0_input.dev_attr.attr,
198 &sensor_dev_attr_in1_input.dev_attr.attr,
199 &sensor_dev_attr_curr1_input.dev_attr.attr,
200 &sensor_dev_attr_power1_input.dev_attr.attr,
201 NULL,
202};
203
204static const struct attribute_group ina2xx_group = {
205 .attrs = ina2xx_attributes,
206};
207
208static int ina2xx_probe(struct i2c_client *client,
209 const struct i2c_device_id *id)
210{
211 struct i2c_adapter *adapter = client->adapter;
212 struct ina2xx_data *data;
213 struct ina2xx_platform_data *pdata;
Guenter Roeck6106db22012-05-12 11:21:01 -0700214 int ret;
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400215 long shunt = 10000; /* default shunt value 10mOhms */
216
217 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
218 return -ENODEV;
219
220 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
221 if (!data)
222 return -ENOMEM;
223
224 if (client->dev.platform_data) {
225 pdata =
226 (struct ina2xx_platform_data *)client->dev.platform_data;
227 shunt = pdata->shunt_uohms;
228 }
229
230 if (shunt <= 0)
231 return -ENODEV;
232
233 /* set the device type */
234 data->kind = id->driver_data;
Guenter Roeck6106db22012-05-12 11:21:01 -0700235 data->config = &ina2xx_config[data->kind];
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400236
Guenter Roeck6106db22012-05-12 11:21:01 -0700237 /* device configuration */
238 i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
239 data->config->config_default);
240 /* set current LSB to 1mA, shunt is in uOhms */
241 /* (equation 13 in datasheet) */
242 i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
243 data->config->calibration_factor / shunt);
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400244
245 i2c_set_clientdata(client, data);
246 mutex_init(&data->update_lock);
247
248 ret = sysfs_create_group(&client->dev.kobj, &ina2xx_group);
249 if (ret)
250 return ret;
251
252 data->hwmon_dev = hwmon_device_register(&client->dev);
253 if (IS_ERR(data->hwmon_dev)) {
254 ret = PTR_ERR(data->hwmon_dev);
255 goto out_err_hwmon;
256 }
257
Guenter Roeck6106db22012-05-12 11:21:01 -0700258 dev_info(&client->dev, "power monitor %s (Rshunt = %li uOhm)\n",
259 id->name, shunt);
260
Felten, Lotharf7c2fe32012-05-12 04:36:38 -0400261 return 0;
262
263out_err_hwmon:
264 sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
265 return ret;
266}
267
268static int ina2xx_remove(struct i2c_client *client)
269{
270 struct ina2xx_data *data = i2c_get_clientdata(client);
271
272 hwmon_device_unregister(data->hwmon_dev);
273 sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
274
275 return 0;
276}
277
278static const struct i2c_device_id ina2xx_id[] = {
279 { "ina219", ina219 },
280 { "ina226", ina226 },
281 { }
282};
283MODULE_DEVICE_TABLE(i2c, ina2xx_id);
284
285static struct i2c_driver ina2xx_driver = {
286 .driver = {
287 .name = "ina2xx",
288 },
289 .probe = ina2xx_probe,
290 .remove = ina2xx_remove,
291 .id_table = ina2xx_id,
292};
293
294static int __init ina2xx_init(void)
295{
296 return i2c_add_driver(&ina2xx_driver);
297}
298
299static void __exit ina2xx_exit(void)
300{
301 i2c_del_driver(&ina2xx_driver);
302}
303
304MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>");
305MODULE_DESCRIPTION("ina2xx driver");
306MODULE_LICENSE("GPL");
307
308module_init(ina2xx_init);
309module_exit(ina2xx_exit);