aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2009-08-20 17:49:25 -0400
committerGuenter Roeck <linux@roeck-us.net>2013-02-06 12:57:59 -0500
commitceeadc5c5187b78ffbea737c7a82ecc1e31e80df (patch)
tree6f506721e61dbc2fd8ed76fb5a69443949869395
parent2bf9233a108cea32edbb5a65afa8e609fa146577 (diff)
hwmon: Driver for Texas Instruments INA209
Add support for the TI / Burr-Brown INA209 voltage / current / power monitor. Cc: Paul Hays <haysp@magma.net> Cc: Ira W. Snyder <iws@ovro.caltech.edu> Tested-by: Ira W. Snyder <iws@ovro.caltech.edu> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r--Documentation/devicetree/bindings/i2c/ina209.txt18
-rw-r--r--Documentation/hwmon/ina20993
-rw-r--r--drivers/hwmon/Kconfig10
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/ina209.c636
5 files changed, 758 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/i2c/ina209.txt b/Documentation/devicetree/bindings/i2c/ina209.txt
new file mode 100644
index 000000000000..9dd2bee80840
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/ina209.txt
@@ -0,0 +1,18 @@
1ina209 properties
2
3Required properties:
4- compatible: Must be "ti,ina209"
5- reg: I2C address
6
7Optional properties:
8
9- shunt-resistor
10 Shunt resistor value in micro-Ohm
11
12Example:
13
14temp-sensor@4c {
15 compatible = "ti,ina209";
16 reg = <0x4c>;
17 shunt-resistor = <5000>;
18};
diff --git a/Documentation/hwmon/ina209 b/Documentation/hwmon/ina209
new file mode 100644
index 000000000000..672501de4509
--- /dev/null
+++ b/Documentation/hwmon/ina209
@@ -0,0 +1,93 @@
1Kernel driver ina209
2=====================
3
4Supported chips:
5 * Burr-Brown / Texas Instruments INA209
6 Prefix: 'ina209'
7 Addresses scanned: -
8 Datasheet:
9 http://www.ti.com/lit/gpn/ina209
10
11Author: Paul Hays <Paul.Hays@cattail.ca>
12Author: Ira W. Snyder <iws@ovro.caltech.edu>
13Author: Guenter Roeck <linux@roeck-us.net>
14
15
16Description
17-----------
18
19The TI / Burr-Brown INA209 monitors voltage, current, and power on the high side
20of a D.C. power supply. It can perform measurements and calculations in the
21background to supply readings at any time. It includes a programmable
22calibration multiplier to scale the displayed current and power values.
23
24
25Sysfs entries
26-------------
27
28The INA209 chip is highly configurable both via hardwiring and via
29the I2C bus. See the datasheet for details.
30
31This tries to expose most monitoring features of the hardware via
32sysfs. It does not support every feature of this chip.
33
34
35in0_input shunt voltage (mV)
36in0_input_highest shunt voltage historical maximum reading (mV)
37in0_input_lowest shunt voltage historical minimum reading (mV)
38in0_reset_history reset shunt voltage history
39in0_max shunt voltage max alarm limit (mV)
40in0_min shunt voltage min alarm limit (mV)
41in0_crit_max shunt voltage crit max alarm limit (mV)
42in0_crit_min shunt voltage crit min alarm limit (mV)
43in0_max_alarm shunt voltage max alarm limit exceeded
44in0_min_alarm shunt voltage min alarm limit exceeded
45in0_crit_max_alarm shunt voltage crit max alarm limit exceeded
46in0_crit_min_alarm shunt voltage crit min alarm limit exceeded
47
48in1_input bus voltage (mV)
49in1_input_highest bus voltage historical maximum reading (mV)
50in1_input_lowest bus voltage historical minimum reading (mV)
51in1_reset_history reset bus voltage history
52in1_max bus voltage max alarm limit (mV)
53in1_min bus voltage min alarm limit (mV)
54in1_crit_max bus voltage crit max alarm limit (mV)
55in1_crit_min bus voltage crit min alarm limit (mV)
56in1_max_alarm bus voltage max alarm limit exceeded
57in1_min_alarm bus voltage min alarm limit exceeded
58in1_crit_max_alarm bus voltage crit max alarm limit exceeded
59in1_crit_min_alarm bus voltage crit min alarm limit exceeded
60
61power1_input power measurement (uW)
62power1_input_highest power historical maximum reading (uW)
63power1_reset_history reset power history
64power1_max power max alarm limit (uW)
65power1_crit power crit alarm limit (uW)
66power1_max_alarm power max alarm limit exceeded
67power1_crit_alarm power crit alarm limit exceeded
68
69curr1_input current measurement (mA)
70
71update_interval data conversion time; affects number of samples used
72 to average results for shunt and bus voltages.
73
74General Remarks
75---------------
76
77The power and current registers in this chip require that the calibration
78register is programmed correctly before they are used. Normally this is expected
79to be done in the BIOS. In the absence of BIOS programming, the shunt resistor
80voltage can be provided using platform data. The driver uses platform data from
81the ina2xx driver for this purpose. If calibration register data is not provided
82via platform data, the driver checks if the calibration register has been
83programmed (ie has a value not equal to zero). If so, this value is retained.
84Otherwise, a default value reflecting a shunt resistor value of 10 mOhm is
85programmed into the calibration register.
86
87
88Output Pins
89-----------
90
91Output pin programming is a board feature which depends on the BIOS. It is
92outside the scope of a hardware monitoring driver to enable or disable output
93pins.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 3588b2a0915c..5e77cef09ca6 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1157,6 +1157,16 @@ config SENSORS_AMC6821
1157 This driver can also be build as a module. If so, the module 1157 This driver can also be build as a module. If so, the module
1158 will be called amc6821. 1158 will be called amc6821.
1159 1159
1160config SENSORS_INA209
1161 tristate "TI / Burr Brown INA209"
1162 depends on I2C
1163 help
1164 If you say yes here you get support for the TI / Burr Brown INA209
1165 voltage / current / power monitor I2C interface.
1166
1167 This driver can also be built as a module. If so, the module will
1168 be called ina209.
1169
1160config SENSORS_INA2XX 1170config SENSORS_INA2XX
1161 tristate "Texas Instruments INA219 and compatibles" 1171 tristate "Texas Instruments INA219 and compatibles"
1162 depends on I2C 1172 depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index a37a82c64da2..8d6d97ea7c1e 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
65obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o 65obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
66obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o 66obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
67obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o 67obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
68obj-$(CONFIG_SENSORS_INA209) += ina209.o
68obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o 69obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o
69obj-$(CONFIG_SENSORS_IT87) += it87.o 70obj-$(CONFIG_SENSORS_IT87) += it87.o
70obj-$(CONFIG_SENSORS_JC42) += jc42.o 71obj-$(CONFIG_SENSORS_JC42) += jc42.o
diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c
new file mode 100644
index 000000000000..c6fdd5bd395e
--- /dev/null
+++ b/drivers/hwmon/ina209.c
@@ -0,0 +1,636 @@
1/*
2 * Driver for the Texas Instruments / Burr Brown INA209
3 * Bidirectional Current/Power Monitor
4 *
5 * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
6 *
7 * Derived from Ira W. Snyder's original driver submission
8 * Copyright (C) 2008 Paul Hays <Paul.Hays@cattail.ca>
9 * Copyright (C) 2008-2009 Ira W. Snyder <iws@ovro.caltech.edu>
10 *
11 * Aligned with ina2xx driver
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 * Datasheet:
20 * http://www.ti.com/lit/gpn/ina209
21 */
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/init.h>
26#include <linux/err.h>
27#include <linux/slab.h>
28#include <linux/bug.h>
29#include <linux/i2c.h>
30#include <linux/hwmon.h>
31#include <linux/hwmon-sysfs.h>
32
33#include <linux/platform_data/ina2xx.h>
34
35/* register definitions */
36#define INA209_CONFIGURATION 0x00
37#define INA209_STATUS 0x01
38#define INA209_STATUS_MASK 0x02
39#define INA209_SHUNT_VOLTAGE 0x03
40#define INA209_BUS_VOLTAGE 0x04
41#define INA209_POWER 0x05
42#define INA209_CURRENT 0x06
43#define INA209_SHUNT_VOLTAGE_POS_PEAK 0x07
44#define INA209_SHUNT_VOLTAGE_NEG_PEAK 0x08
45#define INA209_BUS_VOLTAGE_MAX_PEAK 0x09
46#define INA209_BUS_VOLTAGE_MIN_PEAK 0x0a
47#define INA209_POWER_PEAK 0x0b
48#define INA209_SHUNT_VOLTAGE_POS_WARN 0x0c
49#define INA209_SHUNT_VOLTAGE_NEG_WARN 0x0d
50#define INA209_POWER_WARN 0x0e
51#define INA209_BUS_VOLTAGE_OVER_WARN 0x0f
52#define INA209_BUS_VOLTAGE_UNDER_WARN 0x10
53#define INA209_POWER_OVER_LIMIT 0x11
54#define INA209_BUS_VOLTAGE_OVER_LIMIT 0x12
55#define INA209_BUS_VOLTAGE_UNDER_LIMIT 0x13
56#define INA209_CRITICAL_DAC_POS 0x14
57#define INA209_CRITICAL_DAC_NEG 0x15
58#define INA209_CALIBRATION 0x16
59
60#define INA209_REGISTERS 0x17
61
62#define INA209_CONFIG_DEFAULT 0x3c47 /* PGA=8, full range */
63#define INA209_SHUNT_DEFAULT 10000 /* uOhm */
64
65struct ina209_data {
66 struct device *hwmon_dev;
67
68 struct mutex update_lock;
69 bool valid;
70 unsigned long last_updated; /* in jiffies */
71
72 u16 regs[INA209_REGISTERS]; /* All chip registers */
73
74 u16 config_orig; /* Original configuration */
75 u16 calibration_orig; /* Original calibration */
76 u16 update_interval;
77};
78
79static struct ina209_data *ina209_update_device(struct device *dev)
80{
81 struct i2c_client *client = to_i2c_client(dev);
82 struct ina209_data *data = i2c_get_clientdata(client);
83 struct ina209_data *ret = data;
84 s32 val;
85 int i;
86
87 mutex_lock(&data->update_lock);
88
89 if (!data->valid ||
90 time_after(jiffies, data->last_updated + data->update_interval)) {
91 for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
92 val = i2c_smbus_read_word_swapped(client, i);
93 if (val < 0) {
94 ret = ERR_PTR(val);
95 goto abort;
96 }
97 data->regs[i] = val;
98 }
99 data->last_updated = jiffies;
100 data->valid = true;
101 }
102abort:
103 mutex_unlock(&data->update_lock);
104 return ret;
105}
106
107/*
108 * Read a value from a device register and convert it to the
109 * appropriate sysfs units
110 */
111static long ina209_from_reg(const u8 reg, const u16 val)
112{
113 switch (reg) {
114 case INA209_SHUNT_VOLTAGE:
115 case INA209_SHUNT_VOLTAGE_POS_PEAK:
116 case INA209_SHUNT_VOLTAGE_NEG_PEAK:
117 case INA209_SHUNT_VOLTAGE_POS_WARN:
118 case INA209_SHUNT_VOLTAGE_NEG_WARN:
119 /* LSB=10 uV. Convert to mV. */
120 return DIV_ROUND_CLOSEST(val, 100);
121
122 case INA209_BUS_VOLTAGE:
123 case INA209_BUS_VOLTAGE_MAX_PEAK:
124 case INA209_BUS_VOLTAGE_MIN_PEAK:
125 case INA209_BUS_VOLTAGE_OVER_WARN:
126 case INA209_BUS_VOLTAGE_UNDER_WARN:
127 case INA209_BUS_VOLTAGE_OVER_LIMIT:
128 case INA209_BUS_VOLTAGE_UNDER_LIMIT:
129 /* LSB=4 mV, last 3 bits unused */
130 return (val >> 3) * 4;
131
132 case INA209_CRITICAL_DAC_POS:
133 /* LSB=1 mV, in the upper 8 bits */
134 return val >> 8;
135
136 case INA209_CRITICAL_DAC_NEG:
137 /* LSB=1 mV, in the upper 8 bits */
138 return -1 * (val >> 8);
139
140 case INA209_POWER:
141 case INA209_POWER_PEAK:
142 case INA209_POWER_WARN:
143 case INA209_POWER_OVER_LIMIT:
144 /* LSB=20 mW. Convert to uW */
145 return val * 20 * 1000L;
146
147 case INA209_CURRENT:
148 /* LSB=1 mA (selected). Is in mA */
149 return val;
150 }
151
152 /* programmer goofed */
153 WARN_ON_ONCE(1);
154 return 0;
155}
156
157/*
158 * Take a value and convert it to register format, clamping the value
159 * to the appropriate range.
160 */
161static int ina209_to_reg(u8 reg, u16 old, long val)
162{
163 switch (reg) {
164 case INA209_SHUNT_VOLTAGE_POS_WARN:
165 case INA209_SHUNT_VOLTAGE_NEG_WARN:
166 /* Limit to +- 320 mV, 10 uV LSB */
167 return clamp_val(val, -320, 320) * 100;
168
169 case INA209_BUS_VOLTAGE_OVER_WARN:
170 case INA209_BUS_VOLTAGE_UNDER_WARN:
171 case INA209_BUS_VOLTAGE_OVER_LIMIT:
172 case INA209_BUS_VOLTAGE_UNDER_LIMIT:
173 /*
174 * Limit to 0-32000 mV, 4 mV LSB
175 *
176 * The last three bits aren't part of the value, but we'll
177 * preserve them in their original state.
178 */
179 return (DIV_ROUND_CLOSEST(clamp_val(val, 0, 32000), 4) << 3)
180 | (old & 0x7);
181
182 case INA209_CRITICAL_DAC_NEG:
183 /*
184 * Limit to -255-0 mV, 1 mV LSB
185 * Convert the value to a positive value for the register
186 *
187 * The value lives in the top 8 bits only, be careful
188 * and keep original value of other bits.
189 */
190 return (clamp_val(-val, 0, 255) << 8) | (old & 0xff);
191
192 case INA209_CRITICAL_DAC_POS:
193 /*
194 * Limit to 0-255 mV, 1 mV LSB
195 *
196 * The value lives in the top 8 bits only, be careful
197 * and keep original value of other bits.
198 */
199 return (clamp_val(val, 0, 255) << 8) | (old & 0xff);
200
201 case INA209_POWER_WARN:
202 case INA209_POWER_OVER_LIMIT:
203 /* 20 mW LSB */
204 return DIV_ROUND_CLOSEST(val, 20 * 1000);
205 }
206
207 /* Other registers are read-only, return access error */
208 return -EACCES;
209}
210
211static int ina209_interval_from_reg(u16 reg)
212{
213 return 68 >> (15 - ((reg >> 3) & 0x0f));
214}
215
216static u16 ina209_reg_from_interval(u16 config, long interval)
217{
218 int i, adc;
219
220 if (interval <= 0) {
221 adc = 8;
222 } else {
223 adc = 15;
224 for (i = 34 + 34 / 2; i; i >>= 1) {
225 if (i < interval)
226 break;
227 adc--;
228 }
229 }
230 return (config & 0xf807) | (adc << 3) | (adc << 7);
231}
232
233static ssize_t ina209_set_interval(struct device *dev,
234 struct device_attribute *da,
235 const char *buf, size_t count)
236{
237 struct i2c_client *client = to_i2c_client(dev);
238 struct ina209_data *data = ina209_update_device(dev);
239 long val;
240 u16 regval;
241 int ret;
242
243 if (IS_ERR(data))
244 return PTR_ERR(data);
245
246 ret = kstrtol(buf, 10, &val);
247 if (ret < 0)
248 return ret;
249
250 mutex_lock(&data->update_lock);
251 regval = ina209_reg_from_interval(data->regs[INA209_CONFIGURATION],
252 val);
253 i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION, regval);
254 data->regs[INA209_CONFIGURATION] = regval;
255 data->update_interval = ina209_interval_from_reg(regval);
256 mutex_unlock(&data->update_lock);
257 return count;
258}
259
260static ssize_t ina209_show_interval(struct device *dev,
261 struct device_attribute *da, char *buf)
262{
263 struct i2c_client *client = to_i2c_client(dev);
264 struct ina209_data *data = i2c_get_clientdata(client);
265
266 return snprintf(buf, PAGE_SIZE, "%d\n", data->update_interval);
267}
268
269/*
270 * History is reset by writing 1 into bit 0 of the respective peak register.
271 * Since more than one peak register may be affected by the scope of a
272 * reset_history attribute write, use a bit mask in attr->index to identify
273 * which registers are affected.
274 */
275static u16 ina209_reset_history_regs[] = {
276 INA209_SHUNT_VOLTAGE_POS_PEAK,
277 INA209_SHUNT_VOLTAGE_NEG_PEAK,
278 INA209_BUS_VOLTAGE_MAX_PEAK,
279 INA209_BUS_VOLTAGE_MIN_PEAK,
280 INA209_POWER_PEAK
281};
282
283static ssize_t ina209_reset_history(struct device *dev,
284 struct device_attribute *da,
285 const char *buf,
286 size_t count)
287{
288 struct i2c_client *client = to_i2c_client(dev);
289 struct ina209_data *data = i2c_get_clientdata(client);
290 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
291 u32 mask = attr->index;
292 long val;
293 int i, ret;
294
295 ret = kstrtol(buf, 10, &val);
296 if (ret < 0)
297 return ret;
298
299 mutex_lock(&data->update_lock);
300 for (i = 0; i < ARRAY_SIZE(ina209_reset_history_regs); i++) {
301 if (mask & (1 << i))
302 i2c_smbus_write_word_swapped(client,
303 ina209_reset_history_regs[i], 1);
304 }
305 data->valid = false;
306 mutex_unlock(&data->update_lock);
307 return count;
308}
309
310static ssize_t ina209_set_value(struct device *dev,
311 struct device_attribute *da,
312 const char *buf,
313 size_t count)
314{
315 struct i2c_client *client = to_i2c_client(dev);
316 struct ina209_data *data = ina209_update_device(dev);
317 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
318 int reg = attr->index;
319 long val;
320 int ret;
321
322 if (IS_ERR(data))
323 return PTR_ERR(data);
324
325 ret = kstrtol(buf, 10, &val);
326 if (ret < 0)
327 return ret;
328
329 mutex_lock(&data->update_lock);
330 ret = ina209_to_reg(reg, data->regs[reg], val);
331 if (ret < 0) {
332 count = ret;
333 goto abort;
334 }
335 i2c_smbus_write_word_swapped(client, reg, ret);
336 data->regs[reg] = ret;
337abort:
338 mutex_unlock(&data->update_lock);
339 return count;
340}
341
342static ssize_t ina209_show_value(struct device *dev,
343 struct device_attribute *da,
344 char *buf)
345{
346 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
347 struct ina209_data *data = ina209_update_device(dev);
348 long val;
349
350 if (IS_ERR(data))
351 return PTR_ERR(data);
352
353 val = ina209_from_reg(attr->index, data->regs[attr->index]);
354 return snprintf(buf, PAGE_SIZE, "%ld\n", val);
355}
356
357static ssize_t ina209_show_alarm(struct device *dev,
358 struct device_attribute *da,
359 char *buf)
360{
361 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
362 struct ina209_data *data = ina209_update_device(dev);
363 const unsigned int mask = attr->index;
364 u16 status;
365
366 if (IS_ERR(data))
367 return PTR_ERR(data);
368
369 status = data->regs[INA209_STATUS];
370
371 /*
372 * All alarms are in the INA209_STATUS register. To avoid a long
373 * switch statement, the mask is passed in attr->index
374 */
375 return snprintf(buf, PAGE_SIZE, "%u\n", !!(status & mask));
376}
377
378/* Shunt voltage, history, limits, alarms */
379static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina209_show_value, NULL,
380 INA209_SHUNT_VOLTAGE);
381static SENSOR_DEVICE_ATTR(in0_input_highest, S_IRUGO, ina209_show_value, NULL,
382 INA209_SHUNT_VOLTAGE_POS_PEAK);
383static SENSOR_DEVICE_ATTR(in0_input_lowest, S_IRUGO, ina209_show_value, NULL,
384 INA209_SHUNT_VOLTAGE_NEG_PEAK);
385static SENSOR_DEVICE_ATTR(in0_reset_history, S_IWUSR, NULL,
386 ina209_reset_history, (1 << 0) | (1 << 1));
387static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, ina209_show_value,
388 ina209_set_value, INA209_SHUNT_VOLTAGE_POS_WARN);
389static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, ina209_show_value,
390 ina209_set_value, INA209_SHUNT_VOLTAGE_NEG_WARN);
391static SENSOR_DEVICE_ATTR(in0_crit_max, S_IRUGO | S_IWUSR, ina209_show_value,
392 ina209_set_value, INA209_CRITICAL_DAC_POS);
393static SENSOR_DEVICE_ATTR(in0_crit_min, S_IRUGO | S_IWUSR, ina209_show_value,
394 ina209_set_value, INA209_CRITICAL_DAC_NEG);
395
396static SENSOR_DEVICE_ATTR(in0_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
397 1 << 11);
398static SENSOR_DEVICE_ATTR(in0_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
399 1 << 12);
400static SENSOR_DEVICE_ATTR(in0_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
401 1 << 6);
402static SENSOR_DEVICE_ATTR(in0_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
403 1 << 7);
404
405/* Bus voltage, history, limits, alarms */
406static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina209_show_value, NULL,
407 INA209_BUS_VOLTAGE);
408static SENSOR_DEVICE_ATTR(in1_input_highest, S_IRUGO, ina209_show_value, NULL,
409 INA209_BUS_VOLTAGE_MAX_PEAK);
410static SENSOR_DEVICE_ATTR(in1_input_lowest, S_IRUGO, ina209_show_value, NULL,
411 INA209_BUS_VOLTAGE_MIN_PEAK);
412static SENSOR_DEVICE_ATTR(in1_reset_history, S_IWUSR, NULL,
413 ina209_reset_history, (1 << 2) | (1 << 3));
414static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, ina209_show_value,
415 ina209_set_value, INA209_BUS_VOLTAGE_OVER_WARN);
416static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, ina209_show_value,
417 ina209_set_value, INA209_BUS_VOLTAGE_UNDER_WARN);
418static SENSOR_DEVICE_ATTR(in1_crit_max, S_IRUGO | S_IWUSR, ina209_show_value,
419 ina209_set_value, INA209_BUS_VOLTAGE_OVER_LIMIT);
420static SENSOR_DEVICE_ATTR(in1_crit_min, S_IRUGO | S_IWUSR, ina209_show_value,
421 ina209_set_value, INA209_BUS_VOLTAGE_UNDER_LIMIT);
422
423static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
424 1 << 14);
425static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
426 1 << 15);
427static SENSOR_DEVICE_ATTR(in1_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL,
428 1 << 9);
429static SENSOR_DEVICE_ATTR(in1_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
430 1 << 10);
431
432/* Power */
433static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina209_show_value, NULL,
434 INA209_POWER);
435static SENSOR_DEVICE_ATTR(power1_input_highest, S_IRUGO, ina209_show_value,
436 NULL, INA209_POWER_PEAK);
437static SENSOR_DEVICE_ATTR(power1_reset_history, S_IWUSR, NULL,
438 ina209_reset_history, 1 << 4);
439static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO | S_IWUSR, ina209_show_value,
440 ina209_set_value, INA209_POWER_WARN);
441static SENSOR_DEVICE_ATTR(power1_crit, S_IRUGO | S_IWUSR, ina209_show_value,
442 ina209_set_value, INA209_POWER_OVER_LIMIT);
443
444static SENSOR_DEVICE_ATTR(power1_max_alarm, S_IRUGO, ina209_show_alarm, NULL,
445 1 << 13);
446static SENSOR_DEVICE_ATTR(power1_crit_alarm, S_IRUGO, ina209_show_alarm, NULL,
447 1 << 8);
448
449/* Current */
450static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina209_show_value, NULL,
451 INA209_CURRENT);
452
453static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR,
454 ina209_show_interval, ina209_set_interval, 0);
455
456/*
457 * Finally, construct an array of pointers to members of the above objects,
458 * as required for sysfs_create_group()
459 */
460static struct attribute *ina209_attributes[] = {
461 &sensor_dev_attr_in0_input.dev_attr.attr,
462 &sensor_dev_attr_in0_input_highest.dev_attr.attr,
463 &sensor_dev_attr_in0_input_lowest.dev_attr.attr,
464 &sensor_dev_attr_in0_reset_history.dev_attr.attr,
465 &sensor_dev_attr_in0_max.dev_attr.attr,
466 &sensor_dev_attr_in0_min.dev_attr.attr,
467 &sensor_dev_attr_in0_crit_max.dev_attr.attr,
468 &sensor_dev_attr_in0_crit_min.dev_attr.attr,
469 &sensor_dev_attr_in0_max_alarm.dev_attr.attr,
470 &sensor_dev_attr_in0_min_alarm.dev_attr.attr,
471 &sensor_dev_attr_in0_crit_max_alarm.dev_attr.attr,
472 &sensor_dev_attr_in0_crit_min_alarm.dev_attr.attr,
473
474 &sensor_dev_attr_in1_input.dev_attr.attr,
475 &sensor_dev_attr_in1_input_highest.dev_attr.attr,
476 &sensor_dev_attr_in1_input_lowest.dev_attr.attr,
477 &sensor_dev_attr_in1_reset_history.dev_attr.attr,
478 &sensor_dev_attr_in1_max.dev_attr.attr,
479 &sensor_dev_attr_in1_min.dev_attr.attr,
480 &sensor_dev_attr_in1_crit_max.dev_attr.attr,
481 &sensor_dev_attr_in1_crit_min.dev_attr.attr,
482 &sensor_dev_attr_in1_max_alarm.dev_attr.attr,
483 &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
484 &sensor_dev_attr_in1_crit_max_alarm.dev_attr.attr,
485 &sensor_dev_attr_in1_crit_min_alarm.dev_attr.attr,
486
487 &sensor_dev_attr_power1_input.dev_attr.attr,
488 &sensor_dev_attr_power1_input_highest.dev_attr.attr,
489 &sensor_dev_attr_power1_reset_history.dev_attr.attr,
490 &sensor_dev_attr_power1_max.dev_attr.attr,
491 &sensor_dev_attr_power1_crit.dev_attr.attr,
492 &sensor_dev_attr_power1_max_alarm.dev_attr.attr,
493 &sensor_dev_attr_power1_crit_alarm.dev_attr.attr,
494
495 &sensor_dev_attr_curr1_input.dev_attr.attr,
496
497 &sensor_dev_attr_update_interval.dev_attr.attr,
498
499 NULL,
500};
501
502static const struct attribute_group ina209_group = {
503 .attrs = ina209_attributes,
504};
505
506static void ina209_restore_conf(struct i2c_client *client,
507 struct ina209_data *data)
508{
509 /* Restore initial configuration */
510 i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION,
511 data->config_orig);
512 i2c_smbus_write_word_swapped(client, INA209_CALIBRATION,
513 data->calibration_orig);
514}
515
516static int ina209_init_client(struct i2c_client *client,
517 struct ina209_data *data)
518{
519 struct ina2xx_platform_data *pdata = dev_get_platdata(&client->dev);
520 u32 shunt;
521 int reg;
522
523 reg = i2c_smbus_read_word_swapped(client, INA209_CALIBRATION);
524 if (reg < 0)
525 return reg;
526 data->calibration_orig = reg;
527
528 reg = i2c_smbus_read_word_swapped(client, INA209_CONFIGURATION);
529 if (reg < 0)
530 return reg;
531 data->config_orig = reg;
532
533 if (pdata) {
534 if (pdata->shunt_uohms <= 0)
535 return -EINVAL;
536 shunt = pdata->shunt_uohms;
537 } else if (!of_property_read_u32(client->dev.of_node, "shunt-resistor",
538 &shunt)) {
539 if (shunt == 0)
540 return -EINVAL;
541 } else {
542 shunt = data->calibration_orig ?
543 40960000 / data->calibration_orig : INA209_SHUNT_DEFAULT;
544 }
545
546 i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION,
547 INA209_CONFIG_DEFAULT);
548 data->update_interval = ina209_interval_from_reg(INA209_CONFIG_DEFAULT);
549
550 /*
551 * Calibrate current LSB to 1mA. Shunt is in uOhms.
552 * See equation 13 in datasheet.
553 */
554 i2c_smbus_write_word_swapped(client, INA209_CALIBRATION,
555 clamp_val(40960000 / shunt, 1, 65535));
556
557 /* Clear status register */
558 i2c_smbus_read_word_swapped(client, INA209_STATUS);
559
560 return 0;
561}
562
563static int ina209_probe(struct i2c_client *client,
564 const struct i2c_device_id *id)
565{
566 struct i2c_adapter *adapter = client->adapter;
567 struct ina209_data *data;
568 int ret;
569
570 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
571 return -ENODEV;
572
573 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
574 if (!data)
575 return -ENOMEM;
576
577 i2c_set_clientdata(client, data);
578 mutex_init(&data->update_lock);
579
580 ret = ina209_init_client(client, data);
581 if (ret)
582 return ret;
583
584 /* Register sysfs hooks */
585 ret = sysfs_create_group(&client->dev.kobj, &ina209_group);
586 if (ret)
587 goto out_restore_conf;
588
589 data->hwmon_dev = hwmon_device_register(&client->dev);
590 if (IS_ERR(data->hwmon_dev)) {
591 ret = PTR_ERR(data->hwmon_dev);
592 goto out_hwmon_device_register;
593 }
594
595 return 0;
596
597out_hwmon_device_register:
598 sysfs_remove_group(&client->dev.kobj, &ina209_group);
599out_restore_conf:
600 ina209_restore_conf(client, data);
601 return ret;
602}
603
604static int ina209_remove(struct i2c_client *client)
605{
606 struct ina209_data *data = i2c_get_clientdata(client);
607
608 hwmon_device_unregister(data->hwmon_dev);
609 sysfs_remove_group(&client->dev.kobj, &ina209_group);
610 ina209_restore_conf(client, data);
611
612 return 0;
613}
614
615static const struct i2c_device_id ina209_id[] = {
616 { "ina209", 0 },
617 { }
618};
619MODULE_DEVICE_TABLE(i2c, ina209_id);
620
621/* This is the driver that will be inserted */
622static struct i2c_driver ina209_driver = {
623 .class = I2C_CLASS_HWMON,
624 .driver = {
625 .name = "ina209",
626 },
627 .probe = ina209_probe,
628 .remove = ina209_remove,
629 .id_table = ina209_id,
630};
631
632module_i2c_driver(ina209_driver);
633
634MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>, Paul Hays <Paul.Hays@cattail.ca>, Guenter Roeck <linux@roeck-us.net>");
635MODULE_DESCRIPTION("INA209 driver");
636MODULE_LICENSE("GPL");