hwmon: tegra: tsensor: lp0 save/restore configuration
[linux-2.6.git] / drivers / hwmon / ina219.c
1 /*
2  * ina219.c - driver for TI INA219 current / power monitor sensor
3  *
4  * Copyright (c) 2011, NVIDIA Corporation.
5  *
6  * The INA219 is a sensor chip made by Texas Instruments. It measures
7  * power, voltage and current on a power rail.
8  * Complete datasheet can be obtained from website:
9  *   http://focus.ti.com/lit/ds/symlink/ina219.pdf
10  *
11  * This program is free software. you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18  * more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23  */
24
25 #include <linux/module.h>
26 #include <linux/kernel.h>
27 #include <linux/spinlock.h>
28 #include <linux/sysfs.h>
29 #include <linux/kobject.h>
30 #include <linux/hrtimer.h>
31 #include <linux/slab.h>
32 #include <linux/interrupt.h>
33 #include <linux/mutex.h>
34 #include <linux/i2c.h>
35 #include <linux/slab.h>
36 #include <linux/err.h>
37 #include <linux/gpio.h>
38 #include <linux/device.h>
39 #include <linux/sysdev.h>
40 #include "linux/ina219.h"
41 #include <linux/init.h>
42 #include <linux/hwmon-sysfs.h>
43 #include <linux/hwmon.h>
44
45 #define DRIVER_NAME "ina219"
46
47 /* INA219 register offsets */
48 #define INA219_CONFIG   0
49 #define INA219_SHUNT    1
50 #define INA219_VOLTAGE  2
51 #define INA219_POWER    3
52 #define INA219_CURRENT  4
53 #define INA219_CAL      5
54
55 /*
56         INA219 Sensor defines
57         Config info for ina219s
58         D15   D14  D13  D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
59         rst  BRNG  PG1 PG0  BADC4 .-.BADC1 SADC4 - SADC1 MODE3 - MODE1
60         reset D15
61         bus_range=0 (d13)
62         pga_gain=0  (D12:D11)
63         bus_adc_setting=0x3     (d10:D7) 12-bit w/o oversampling (532uS)
64         shunt_adc_setting=0xb    (D6:D3) 8x oversampling (4.26ms)
65         mode=0x7                 (D2:D0) continuous shunt & bus
66 */
67 #define INA219_CONFIG_DATA 0x1df
68 #define INA219_RESET 0x8000
69
70 struct power_mon_data {
71         s32 voltage;
72         s32 currentInMillis;
73         s32 power;
74 };
75
76 struct ina219_data {
77         struct device *hwmon_dev;
78         struct i2c_client *client;
79         struct ina219_platform_data *pInfo;
80         struct power_mon_data pm_data;
81         struct mutex mutex;
82 };
83
84 /* Set non-zero to enable debug prints */
85 #define INA219_DEBUG_PRINTS 0
86
87 #if INA219_DEBUG_PRINTS
88 #define DEBUG_INA219(x) printk x
89 #else
90 #define DEBUG_INA219(x)
91 #endif
92
93 static s16 reorder_bytes(s16 a)
94 {
95         s16 ret = ((a >> 8) & 0xff) | ((a & 0xff) << 8);
96         return ret;
97 }
98
99 /* set ina219 to power down mode */
100 static s32 power_down_INA219(struct i2c_client *client)
101 {
102         s32 retval;
103         retval = i2c_smbus_write_word_data(client, INA219_CONFIG, 0);
104         if (retval < 0)
105                 dev_err(&client->dev, "power down failure sts: 0x%x\n", retval);
106         return retval;
107 }
108
109
110 static s32 show_voltage(struct device *dev,
111                         struct device_attribute *attr,
112                         char *buf)
113 {
114         struct i2c_client *client = to_i2c_client(dev);
115         struct ina219_data *data = i2c_get_clientdata(client);
116         s32 retval;
117         s32 voltage_mV;
118
119         /* fill config data */
120         retval = i2c_smbus_write_word_data(client, INA219_CONFIG,
121                 reorder_bytes(INA219_CONFIG_DATA));
122         if (retval < 0) {
123                 dev_err(dev, "config data write failed sts: 0x%x\n", retval);
124                 goto error;
125         }
126
127         /* fill calibration data */
128         retval = i2c_smbus_write_word_data(client, INA219_CAL,
129                 reorder_bytes(data->pInfo->calibration_data));
130         if (retval < 0) {
131                 dev_err(dev, "calib data write failed sts: 0x%x\n", retval);
132                 goto error;
133         }
134
135         /* getting voltage readings in milli volts*/
136         voltage_mV =
137                 reorder_bytes(i2c_smbus_read_word_data(client,
138                         INA219_VOLTAGE));
139         DEBUG_INA219(("Ina219 voltage reg Value: 0x%x\n", voltage_mV));
140         if (voltage_mV < 0)
141                 goto error;
142         voltage_mV = voltage_mV >> 1;
143         DEBUG_INA219(("Ina219 voltage in mv: %d\n", voltage_mV));
144
145         /* set ina219 to power down mode */
146         retval = power_down_INA219(client);
147         if (retval < 0)
148                 goto error;
149
150         DEBUG_INA219(("%s volt = %d\n", __func__, voltage_mV));
151         return sprintf(buf, "%d mV\n", voltage_mV);
152 error:
153         dev_err(dev, "%s: failed\n", __func__);
154         return retval;
155 }
156
157
158 static s32 show_power(struct device *dev,
159                         struct device_attribute *attr,
160                         char *buf)
161 {
162         struct i2c_client *client = to_i2c_client(dev);
163         struct ina219_data *data = i2c_get_clientdata(client);
164         s32 retval;
165         s32 power_mW;
166         s32 voltage_mV;
167         s32 overflow, conversion;
168
169         /* fill config data */
170         retval = i2c_smbus_write_word_data(client, INA219_CONFIG,
171                 reorder_bytes(INA219_CONFIG_DATA));
172         if (retval < 0) {
173                 dev_err(dev, "config data write failed sts: 0x%x\n", retval);
174                 goto error;
175         }
176
177         /* fill calib data */
178         retval = i2c_smbus_write_word_data(client, INA219_CAL,
179                 reorder_bytes(data->pInfo->calibration_data));
180         if (retval < 0) {
181                 dev_err(dev, "calibration data write failed sts: 0x%x\n",
182                         retval);
183                 goto error;
184         }
185
186         /* check if the readings are valid */
187         do {
188                 /* read power register to clear conversion bit */
189                 retval = reorder_bytes(i2c_smbus_read_word_data(client,
190                         INA219_POWER));
191                 if (retval < 0) {
192                         dev_err(dev, "CNVR bit clearing failure sts: 0x%x\n",
193                                 retval);
194                         goto error;
195                 }
196
197                 voltage_mV =
198                         reorder_bytes(i2c_smbus_read_word_data(client,
199                                 INA219_VOLTAGE));
200                 DEBUG_INA219(("Ina219 voltage reg Value: 0x%x\n", voltage_mV));
201                 overflow = voltage_mV & 1;
202                 if (overflow) {
203                         dev_err(dev, "overflow error\n");
204                         return 0;
205                 }
206                 conversion = (voltage_mV >> 1) & 1;
207                 DEBUG_INA219(("\n ina219 CNVR value:%d", conversion));
208         } while (!conversion);
209
210         /* getting power readings in milli watts*/
211         power_mW = reorder_bytes(i2c_smbus_read_word_data(client,
212                 INA219_POWER));
213         DEBUG_INA219(("Ina219 power Reg: 0x%x\n", power_mW));
214         power_mW *= data->pInfo->power_lsb;
215         DEBUG_INA219(("Ina219 power Val: %d\n", power_mW));
216         if (power_mW < 0)
217                 goto error;
218
219         /* set ina219 to power down mode */
220         retval = power_down_INA219(client);
221         if (retval < 0)
222                 goto error;
223
224         DEBUG_INA219(("%s pow = %d\n", __func__, power_mW));
225         return sprintf(buf, "%d mW\n", power_mW);
226 error:
227         dev_err(dev, "%s: failed\n", __func__);
228         return retval;
229 }
230
231 static s32 show_current(struct device *dev,
232                         struct device_attribute *attr,
233                         char *buf)
234 {
235         struct i2c_client *client = to_i2c_client(dev);
236         struct ina219_data *data = i2c_get_clientdata(client);
237         s32 retval;
238         s32 current_mA;
239         s32 voltage_mV;
240         s32 overflow, conversion;
241
242         /* fill config data */
243         retval = i2c_smbus_write_word_data(client, INA219_CONFIG,
244                 reorder_bytes(INA219_CONFIG_DATA));
245         if (retval < 0) {
246                 dev_err(dev, "config data write failed sts: 0x%x\n", retval);
247                 goto error;
248         }
249
250         /* fill calib data */
251         retval = i2c_smbus_write_word_data(client, INA219_CAL,
252                 reorder_bytes(data->pInfo->calibration_data));
253         if (retval < 0) {
254                 dev_err(dev, "calibration data write failed sts: 0x%x\n",
255                         retval);
256                 goto error;
257         }
258
259         /* check if the readings are valid */
260         do {
261                 /* read power register to clear conversion bit */
262                 retval = reorder_bytes(i2c_smbus_read_word_data(client,
263                         INA219_POWER));
264                 if (retval < 0) {
265                         dev_err(dev, "CNVR bit clearing failure sts: 0x%x\n",
266                                 retval);
267                         goto error;
268                 }
269
270                 voltage_mV =
271                         reorder_bytes(i2c_smbus_read_word_data(client,
272                                 INA219_VOLTAGE));
273                 DEBUG_INA219(("Ina219 voltage reg Value: 0x%x\n", voltage_mV));
274                 overflow = voltage_mV & 1;
275                 if (overflow) {
276                         dev_err(dev, "overflow error\n");
277                         return 0;
278                 }
279                 conversion = (voltage_mV >> 1) & 1;
280                 DEBUG_INA219(("\n ina219 CNVR value:%d", conversion));
281         } while (!conversion);
282
283         /* getting current readings in milli amps*/
284         current_mA = reorder_bytes(i2c_smbus_read_word_data(client,
285                 INA219_CURRENT));
286         DEBUG_INA219(("Ina219 current Reg: 0x%x\n", current_mA));
287         if (current_mA < 0)
288                 goto error;
289         current_mA =
290                 (current_mA * data->pInfo->power_lsb) / data->pInfo->divisor;
291         DEBUG_INA219(("Ina219 current Value: %d\n", current_mA));
292
293         /* set ina219 to power down mode */
294         retval = power_down_INA219(client);
295         if (retval < 0)
296                 goto error;
297
298
299         DEBUG_INA219(("%s current = %d\n", __func__, current_mA));
300         return sprintf(buf, "%d mA\n", current_mA);
301 error:
302         dev_err(dev, "%s: failed\n", __func__);
303         return retval;
304 }
305
306 static struct sensor_device_attribute ina219[] = {
307         SENSOR_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 0),
308         SENSOR_ATTR(curr1_input, S_IRUGO, show_current, NULL, 0),
309         SENSOR_ATTR(power1_input, S_IRUGO, show_power, NULL, 0),
310 };
311
312 static int __devinit ina219_probe(struct i2c_client *client,
313                                 const struct i2c_device_id *id)
314 {
315         struct ina219_data *data;
316         int err;
317         u8 i;
318         data = kzalloc(sizeof(struct ina219_data), GFP_KERNEL);
319         if (!data) {
320                 err = -ENOMEM;
321                 goto exit;
322         }
323
324         i2c_set_clientdata(client, data);
325         data->pInfo = client->dev.platform_data;
326         mutex_init(&data->mutex);
327         /* reset ina219 */
328         err = i2c_smbus_write_word_data(client, INA219_CONFIG,
329                 reorder_bytes(INA219_RESET));
330         if (err < 0) {
331                 dev_err(&client->dev, "ina219 reset failure status: 0x%x\n",
332                         err);
333                 goto exit_free;
334         }
335
336         for (i = 0; i < ARRAY_SIZE(ina219); i++) {
337                 err = device_create_file(&client->dev, &ina219[i].dev_attr);
338                 if (err) {
339                         dev_err(&client->dev, "device_create_file failed.\n");
340                         goto exit_free;
341                 }
342         }
343
344         data->hwmon_dev = hwmon_device_register(&client->dev);
345         if (IS_ERR(data->hwmon_dev)) {
346                 err = PTR_ERR(data->hwmon_dev);
347                 goto exit_remove;
348         }
349
350         /* set ina219 to power down mode */
351         err = power_down_INA219(client);
352         if (err < 0)
353                 goto exit_remove;
354
355         return 0;
356
357 exit_remove:
358         for (i = 0; i < ARRAY_SIZE(ina219); i++)
359                 device_remove_file(&client->dev, &ina219[i].dev_attr);
360 exit_free:
361         kfree(data);
362 exit:
363         return err;
364 }
365
366 static int __devexit ina219_remove(struct i2c_client *client)
367 {
368         u8 i;
369         struct ina219_data *data = i2c_get_clientdata(client);
370         hwmon_device_unregister(data->hwmon_dev);
371         for (i = 0; i < ARRAY_SIZE(ina219); i++)
372                 device_remove_file(&client->dev, &ina219[i].dev_attr);
373         kfree(data);
374         return 0;
375 }
376
377 static const struct i2c_device_id ina219_id[] = {
378         {DRIVER_NAME, 0 },
379         {}
380 };
381 MODULE_DEVICE_TABLE(i2c, ina219_id);
382
383 static struct i2c_driver ina219_driver = {
384         .class          = I2C_CLASS_HWMON,
385         .driver = {
386                 .name   = DRIVER_NAME,
387         },
388         .probe          = ina219_probe,
389         .remove         = __devexit_p(ina219_remove),
390         .id_table       = ina219_id,
391 };
392
393 static int __init ina219_init(void)
394 {
395         return i2c_add_driver(&ina219_driver);
396 }
397
398 static void __exit ina219_exit(void)
399 {
400         i2c_del_driver(&ina219_driver);
401 }
402
403 module_init(ina219_init);
404 module_exit(ina219_exit);
405 MODULE_LICENSE("GPL");