aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorper.dalen@appeartv.com <per.dalen@appeartv.com>2011-03-03 14:13:21 -0500
committerGuenter Roeck <guenter.roeck@ericsson.com>2011-03-15 01:39:11 -0400
commitde7790155f745d30d58ed131ed112b8735413ab7 (patch)
tree884ecf5816d1d9279ad2e0e0864f18a693c8a3a6
parent9f6ad1ce6484a92ef864e00611a8ef3daf9c986d (diff)
hwmon: Add support for LTC4151
LTC4151 is High Voltage I2C Current and Voltage Monitor from Linear Technology. Signed-off-by: Per Dalen <per.dalen@appeartv.com> Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
-rw-r--r--Documentation/hwmon/ltc415147
-rw-r--r--drivers/hwmon/Kconfig11
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/ltc4151.c256
4 files changed, 315 insertions, 0 deletions
diff --git a/Documentation/hwmon/ltc4151 b/Documentation/hwmon/ltc4151
new file mode 100644
index 000000000000..43c667e6677a
--- /dev/null
+++ b/Documentation/hwmon/ltc4151
@@ -0,0 +1,47 @@
1Kernel driver ltc4151
2=====================
3
4Supported chips:
5 * Linear Technology LTC4151
6 Prefix: 'ltc4151'
7 Addresses scanned: -
8 Datasheet:
9 http://www.linear.com/docs/Datasheet/4151fc.pdf
10
11Author: Per Dalen <per.dalen@appeartv.com>
12
13
14Description
15-----------
16
17The LTC4151 is a High Voltage I2C Current and Voltage Monitor.
18
19
20Usage Notes
21-----------
22
23This driver does not probe for LTC4151 devices, since there is no register
24which can be safely used to identify the chip. You will have to instantiate
25the devices explicitly.
26
27Example: the following will load the driver for an LTC4151 at address 0x6f
28on I2C bus #0:
29# modprobe ltc4151
30# echo ltc4151 0x6f > /sys/bus/i2c/devices/i2c-0/new_device
31
32
33Sysfs entries
34-------------
35
36Voltage readings provided by this driver are reported as obtained from the ADIN
37and VIN registers.
38
39Current reading provided by this driver is reported as obtained from the Current
40Sense register. The reported value assumes that a 1 mOhm sense resistor is
41installed.
42
43in1_input VDIN voltage (mV)
44
45in2_input ADIN voltage (mV)
46
47curr1_input SENSE current (mA)
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 19b0af40c7aa..7bda62264250 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -636,6 +636,17 @@ config SENSORS_LM93
636 This driver can also be built as a module. If so, the module 636 This driver can also be built as a module. If so, the module
637 will be called lm93. 637 will be called lm93.
638 638
639config SENSORS_LTC4151
640 tristate "Linear Technology LTC4151"
641 depends on I2C
642 default n
643 help
644 If you say yes here you get support for Linear Technology LTC4151
645 High Voltage I2C Current and Voltage Monitor interface.
646
647 This driver can also be built as a module. If so, the module will
648 be called ltc4151.
649
639config SENSORS_LTC4215 650config SENSORS_LTC4215
640 tristate "Linear Technology LTC4215" 651 tristate "Linear Technology LTC4215"
641 depends on I2C && EXPERIMENTAL 652 depends on I2C && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index feacc7c243ce..bd0410e4b44f 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_SENSORS_LM90) += lm90.o
80obj-$(CONFIG_SENSORS_LM92) += lm92.o 80obj-$(CONFIG_SENSORS_LM92) += lm92.o
81obj-$(CONFIG_SENSORS_LM93) += lm93.o 81obj-$(CONFIG_SENSORS_LM93) += lm93.o
82obj-$(CONFIG_SENSORS_LM95241) += lm95241.o 82obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
83obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
83obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o 84obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
84obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o 85obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o
85obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o 86obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o
diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c
new file mode 100644
index 000000000000..4ac06b75aa60
--- /dev/null
+++ b/drivers/hwmon/ltc4151.c
@@ -0,0 +1,256 @@
1/*
2 * Driver for Linear Technology LTC4151 High Voltage I2C Current
3 * and Voltage Monitor
4 *
5 * Copyright (C) 2011 AppearTV AS
6 *
7 * Derived from:
8 *
9 * Driver for Linear Technology LTC4261 I2C Negative Voltage Hot
10 * Swap Controller
11 * Copyright (C) 2010 Ericsson AB.
12 *
13 * Datasheet: http://www.linear.com/docs/Datasheet/4151fc.pdf
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; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 *
29 */
30
31#include <linux/kernel.h>
32#include <linux/module.h>
33#include <linux/init.h>
34#include <linux/err.h>
35#include <linux/slab.h>
36#include <linux/i2c.h>
37#include <linux/hwmon.h>
38#include <linux/hwmon-sysfs.h>
39
40/* chip registers */
41#define LTC4151_SENSE_H 0x00
42#define LTC4151_SENSE_L 0x01
43#define LTC4151_VIN_H 0x02
44#define LTC4151_VIN_L 0x03
45#define LTC4151_ADIN_H 0x04
46#define LTC4151_ADIN_L 0x05
47
48struct ltc4151_data {
49 struct device *hwmon_dev;
50
51 struct mutex update_lock;
52 bool valid;
53 unsigned long last_updated; /* in jiffies */
54
55 /* Registers */
56 u8 regs[6];
57};
58
59static struct ltc4151_data *ltc4151_update_device(struct device *dev)
60{
61 struct i2c_client *client = to_i2c_client(dev);
62 struct ltc4151_data *data = i2c_get_clientdata(client);
63 struct ltc4151_data *ret = data;
64
65 mutex_lock(&data->update_lock);
66
67 /*
68 * The chip's A/D updates 6 times per second
69 * (Conversion Rate 6 - 9 Hz)
70 */
71 if (time_after(jiffies, data->last_updated + HZ / 6) || !data->valid) {
72 int i;
73
74 dev_dbg(&client->dev, "Starting ltc4151 update\n");
75
76 /* Read all registers */
77 for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
78 int val;
79
80 val = i2c_smbus_read_byte_data(client, i);
81 if (unlikely(val < 0)) {
82 dev_dbg(dev,
83 "Failed to read ADC value: error %d\n",
84 val);
85 ret = ERR_PTR(val);
86 goto abort;
87 }
88 data->regs[i] = val;
89 }
90 data->last_updated = jiffies;
91 data->valid = 1;
92 }
93abort:
94 mutex_unlock(&data->update_lock);
95 return ret;
96}
97
98/* Return the voltage from the given register in mV */
99static int ltc4151_get_value(struct ltc4151_data *data, u8 reg)
100{
101 u32 val;
102
103 val = (data->regs[reg] << 4) + (data->regs[reg + 1] >> 4);
104
105 switch (reg) {
106 case LTC4151_ADIN_H:
107 /* 500uV resolution. Convert to mV. */
108 val = val * 500 / 1000;
109 break;
110 case LTC4151_SENSE_H:
111 /*
112 * 20uV resolution. Convert to current as measured with
113 * an 1 mOhm sense resistor, in mA.
114 */
115 val = val * 20;
116 break;
117 case LTC4151_VIN_H:
118 /* 25 mV per increment */
119 val = val * 25;
120 break;
121 default:
122 /* If we get here, the developer messed up */
123 WARN_ON_ONCE(1);
124 val = 0;
125 break;
126 }
127
128 return val;
129}
130
131static ssize_t ltc4151_show_value(struct device *dev,
132 struct device_attribute *da, char *buf)
133{
134 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
135 struct ltc4151_data *data = ltc4151_update_device(dev);
136 int value;
137
138 if (IS_ERR(data))
139 return PTR_ERR(data);
140
141 value = ltc4151_get_value(data, attr->index);
142 return snprintf(buf, PAGE_SIZE, "%d\n", value);
143}
144
145/*
146 * Input voltages.
147 */
148static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
149 ltc4151_show_value, NULL, LTC4151_VIN_H);
150static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, \
151 ltc4151_show_value, NULL, LTC4151_ADIN_H);
152
153/* Currents (via sense resistor) */
154static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
155 ltc4151_show_value, NULL, LTC4151_SENSE_H);
156
157/* Finally, construct an array of pointers to members of the above objects,
158 * as required for sysfs_create_group()
159 */
160static struct attribute *ltc4151_attributes[] = {
161 &sensor_dev_attr_in1_input.dev_attr.attr,
162 &sensor_dev_attr_in2_input.dev_attr.attr,
163
164 &sensor_dev_attr_curr1_input.dev_attr.attr,
165
166 NULL,
167};
168
169static const struct attribute_group ltc4151_group = {
170 .attrs = ltc4151_attributes,
171};
172
173static int ltc4151_probe(struct i2c_client *client,
174 const struct i2c_device_id *id)
175{
176 struct i2c_adapter *adapter = client->adapter;
177 struct ltc4151_data *data;
178 int ret;
179
180 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
181 return -ENODEV;
182
183 data = kzalloc(sizeof(*data), GFP_KERNEL);
184 if (!data) {
185 ret = -ENOMEM;
186 goto out_kzalloc;
187 }
188
189 i2c_set_clientdata(client, data);
190 mutex_init(&data->update_lock);
191
192 /* Register sysfs hooks */
193 ret = sysfs_create_group(&client->dev.kobj, &ltc4151_group);
194 if (ret)
195 goto out_sysfs_create_group;
196
197 data->hwmon_dev = hwmon_device_register(&client->dev);
198 if (IS_ERR(data->hwmon_dev)) {
199 ret = PTR_ERR(data->hwmon_dev);
200 goto out_hwmon_device_register;
201 }
202
203 return 0;
204
205out_hwmon_device_register:
206 sysfs_remove_group(&client->dev.kobj, &ltc4151_group);
207out_sysfs_create_group:
208 kfree(data);
209out_kzalloc:
210 return ret;
211}
212
213static int ltc4151_remove(struct i2c_client *client)
214{
215 struct ltc4151_data *data = i2c_get_clientdata(client);
216
217 hwmon_device_unregister(data->hwmon_dev);
218 sysfs_remove_group(&client->dev.kobj, &ltc4151_group);
219
220 kfree(data);
221
222 return 0;
223}
224
225static const struct i2c_device_id ltc4151_id[] = {
226 { "ltc4151", 0 },
227 { }
228};
229MODULE_DEVICE_TABLE(i2c, ltc4151_id);
230
231/* This is the driver that will be inserted */
232static struct i2c_driver ltc4151_driver = {
233 .driver = {
234 .name = "ltc4151",
235 },
236 .probe = ltc4151_probe,
237 .remove = ltc4151_remove,
238 .id_table = ltc4151_id,
239};
240
241static int __init ltc4151_init(void)
242{
243 return i2c_add_driver(&ltc4151_driver);
244}
245
246static void __exit ltc4151_exit(void)
247{
248 i2c_del_driver(&ltc4151_driver);
249}
250
251MODULE_AUTHOR("Per Dalen <per.dalen@appeartv.com>");
252MODULE_DESCRIPTION("LTC4151 driver");
253MODULE_LICENSE("GPL");
254
255module_init(ltc4151_init);
256module_exit(ltc4151_exit);