aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorGuenter Roeck <guenter.roeck@ericsson.com>2011-09-02 12:58:37 -0400
committerGuenter Roeck <guenter.roeck@ericsson.com>2011-10-24 14:09:42 -0400
commitc3ff9a674c2313d4f28e38d384b18b561b313eb7 (patch)
tree6c8dea7a9c7f43e471abac7ad56e882b74cc3b8d /drivers/hwmon
parent3d790287c4e6caa8790421737b1cf8f0a6531559 (diff)
hwmon: (pmbus/ltc2978) Explicit driver for LTC2978
Provide explicit driver for LTC2978 to enable support for minimum and peak attributes. Remove ltc2978 chip id from generic pmbus driver. Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com> Reviewed-by: Robert Coulson <robert.coulson@ericsson.com>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/pmbus/Kconfig12
-rw-r--r--drivers/hwmon/pmbus/Makefile1
-rw-r--r--drivers/hwmon/pmbus/ltc2978.c295
-rw-r--r--drivers/hwmon/pmbus/pmbus.c1
4 files changed, 307 insertions, 2 deletions
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index efaf340651a0..c4dcdca25555 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -20,7 +20,7 @@ config SENSORS_PMBUS
20 help 20 help
21 If you say yes here you get hardware monitoring support for generic 21 If you say yes here you get hardware monitoring support for generic
22 PMBus devices, including but not limited to ADP4000, BMR450, BMR451, 22 PMBus devices, including but not limited to ADP4000, BMR450, BMR451,
23 BMR453, BMR454, LTC2978, NCP4200, and NCP4208. 23 BMR453, BMR454, NCP4200, and NCP4208.
24 24
25 This driver can also be built as a module. If so, the module will 25 This driver can also be built as a module. If so, the module will
26 be called pmbus. 26 be called pmbus.
@@ -46,6 +46,16 @@ config SENSORS_LM25066
46 This driver can also be built as a module. If so, the module will 46 This driver can also be built as a module. If so, the module will
47 be called lm25066. 47 be called lm25066.
48 48
49config SENSORS_LTC2978
50 tristate "Linear Technologies LTC2978"
51 default n
52 help
53 If you say yes here you get hardware monitoring support for Linear
54 Technology LTC2978.
55
56 This driver can also be built as a module. If so, the module will
57 be called ltc2978.
58
49config SENSORS_MAX16064 59config SENSORS_MAX16064
50 tristate "Maxim MAX16064" 60 tristate "Maxim MAX16064"
51 default n 61 default n
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
index b9e4fb421f6c..789376c85dbb 100644
--- a/drivers/hwmon/pmbus/Makefile
+++ b/drivers/hwmon/pmbus/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_PMBUS) += pmbus_core.o
6obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o 6obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
7obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o 7obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
8obj-$(CONFIG_SENSORS_LM25066) += lm25066.o 8obj-$(CONFIG_SENSORS_LM25066) += lm25066.o
9obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
9obj-$(CONFIG_SENSORS_MAX16064) += max16064.o 10obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
10obj-$(CONFIG_SENSORS_MAX34440) += max34440.o 11obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
11obj-$(CONFIG_SENSORS_MAX8688) += max8688.o 12obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
new file mode 100644
index 000000000000..02b2e49adb31
--- /dev/null
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -0,0 +1,295 @@
1/*
2 * Hardware monitoring driver for LTC2978
3 *
4 * Copyright (c) 2011 Ericsson AB.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/err.h>
25#include <linux/slab.h>
26#include <linux/i2c.h>
27#include "pmbus.h"
28
29enum chips { ltc2978 };
30
31#define LTC2978_MFR_VOUT_PEAK 0xdd
32#define LTC2978_MFR_VIN_PEAK 0xde
33#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf
34#define LTC2978_MFR_SPECIAL_ID 0xe7
35
36#define LTC2978_MFR_VOUT_MIN 0xfb
37#define LTC2978_MFR_VIN_MIN 0xfc
38#define LTC2978_MFR_TEMPERATURE_MIN 0xfd
39
40#define LTC2978_ID_REV1 0x0121
41#define LTC2978_ID_REV2 0x0122
42
43/*
44 * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
45 * happens pretty much each time chip data is updated. Raw peak data therefore
46 * does not provide much value. To be able to provide useful peak data, keep an
47 * internal cache of measured peak data, which is only cleared if an explicit
48 * "clear peak" command is executed for the sensor in question.
49 */
50struct ltc2978_data {
51 enum chips id;
52 int vin_min, vin_max;
53 int temp_min, temp_max;
54 int vout_min[8], vout_max[8];
55 struct pmbus_driver_info info;
56};
57
58#define to_ltc2978_data(x) container_of(x, struct ltc2978_data, info)
59
60static inline int lin11_to_val(int data)
61{
62 s16 e = ((s16)data) >> 11;
63 s32 m = (((s16)(data << 5)) >> 5);
64
65 /*
66 * mantissa is 10 bit + sign, exponent adds up to 15 bit.
67 * Add 6 bit to exponent for maximum accuracy (10 + 15 + 6 = 31).
68 */
69 e += 6;
70 return (e < 0 ? m >> -e : m << e);
71}
72
73static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
74{
75 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
76 struct ltc2978_data *data = to_ltc2978_data(info);
77 int ret;
78
79 switch (reg) {
80 case PMBUS_VIRT_READ_VIN_MAX:
81 ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_PEAK);
82 if (ret >= 0) {
83 if (lin11_to_val(ret) > lin11_to_val(data->vin_max))
84 data->vin_max = ret;
85 ret = data->vin_max;
86 }
87 break;
88 case PMBUS_VIRT_READ_VOUT_MAX:
89 ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK);
90 if (ret >= 0) {
91 /*
92 * VOUT is 16 bit unsigned with fixed exponent,
93 * so we can compare it directly
94 */
95 if (ret > data->vout_max[page])
96 data->vout_max[page] = ret;
97 ret = data->vout_max[page];
98 }
99 break;
100 case PMBUS_VIRT_READ_TEMP_MAX:
101 ret = pmbus_read_word_data(client, page,
102 LTC2978_MFR_TEMPERATURE_PEAK);
103 if (ret >= 0) {
104 if (lin11_to_val(ret) > lin11_to_val(data->temp_max))
105 data->temp_max = ret;
106 ret = data->temp_max;
107 }
108 break;
109 case PMBUS_VIRT_READ_VIN_MIN:
110 ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_MIN);
111 if (ret >= 0) {
112 if (lin11_to_val(ret) < lin11_to_val(data->vin_min))
113 data->vin_min = ret;
114 ret = data->vin_min;
115 }
116 break;
117 case PMBUS_VIRT_READ_VOUT_MIN:
118 ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_MIN);
119 if (ret >= 0) {
120 /*
121 * VOUT_MIN is known to not be supported on some lots
122 * of LTC2978 revision 1, and will return the maximum
123 * possible voltage if read. If VOUT_MAX is valid and
124 * lower than the reading of VOUT_MIN, use it instead.
125 */
126 if (data->vout_max[page] && ret > data->vout_max[page])
127 ret = data->vout_max[page];
128 if (ret < data->vout_min[page])
129 data->vout_min[page] = ret;
130 ret = data->vout_min[page];
131 }
132 break;
133 case PMBUS_VIRT_READ_TEMP_MIN:
134 ret = pmbus_read_word_data(client, page,
135 LTC2978_MFR_TEMPERATURE_MIN);
136 if (ret >= 0) {
137 if (lin11_to_val(ret)
138 < lin11_to_val(data->temp_min))
139 data->temp_min = ret;
140 ret = data->temp_min;
141 }
142 break;
143 case PMBUS_VIRT_RESET_VOUT_HISTORY:
144 case PMBUS_VIRT_RESET_VIN_HISTORY:
145 case PMBUS_VIRT_RESET_TEMP_HISTORY:
146 ret = 0;
147 break;
148 default:
149 ret = -ENODATA;
150 break;
151 }
152 return ret;
153}
154
155static int ltc2978_write_word_data(struct i2c_client *client, int page,
156 int reg, u16 word)
157{
158 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
159 struct ltc2978_data *data = to_ltc2978_data(info);
160 int ret;
161
162 switch (reg) {
163 case PMBUS_VIRT_RESET_VOUT_HISTORY:
164 data->vout_min[page] = 0xffff;
165 data->vout_max[page] = 0;
166 ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
167 break;
168 case PMBUS_VIRT_RESET_VIN_HISTORY:
169 data->vin_min = 0x7bff;
170 data->vin_max = 0;
171 ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
172 break;
173 case PMBUS_VIRT_RESET_TEMP_HISTORY:
174 data->temp_min = 0x7bff;
175 data->temp_max = 0x7fff;
176 ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
177 break;
178 default:
179 ret = -ENODATA;
180 break;
181 }
182 return ret;
183}
184
185static const struct i2c_device_id ltc2978_id[] = {
186 {"ltc2978", ltc2978},
187 {}
188};
189MODULE_DEVICE_TABLE(i2c, ltc2978_id);
190
191static int ltc2978_probe(struct i2c_client *client,
192 const struct i2c_device_id *id)
193{
194 int chip_id, ret, i;
195 struct ltc2978_data *data;
196 struct pmbus_driver_info *info;
197
198 if (!i2c_check_functionality(client->adapter,
199 I2C_FUNC_SMBUS_READ_WORD_DATA))
200 return -ENODEV;
201
202 data = kzalloc(sizeof(struct ltc2978_data), GFP_KERNEL);
203 if (!data)
204 return -ENOMEM;
205
206 chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID);
207 if (chip_id < 0) {
208 ret = chip_id;
209 goto err_mem;
210 }
211
212 if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
213 data->id = ltc2978;
214 } else {
215 dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
216 ret = -ENODEV;
217 goto err_mem;
218 }
219 if (data->id != id->driver_data)
220 dev_warn(&client->dev,
221 "Device mismatch: Configured %s, detected %s\n",
222 id->name,
223 ltc2978_id[data->id].name);
224
225 info = &data->info;
226 info->read_word_data = ltc2978_read_word_data;
227 info->write_word_data = ltc2978_write_word_data;
228
229 data->vout_min[0] = 0xffff;
230 data->vin_min = 0x7bff;
231 data->temp_min = 0x7bff;
232 data->temp_max = 0x7fff;
233
234 switch (id->driver_data) {
235 case ltc2978:
236 info->pages = 8;
237 info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
238 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
239 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
240 for (i = 1; i < 8; i++) {
241 info->func[i] = PMBUS_HAVE_VOUT
242 | PMBUS_HAVE_STATUS_VOUT;
243 data->vout_min[i] = 0xffff;
244 }
245 break;
246 default:
247 ret = -ENODEV;
248 goto err_mem;
249 }
250
251 ret = pmbus_do_probe(client, id, info);
252 if (ret)
253 goto err_mem;
254 return 0;
255
256err_mem:
257 kfree(data);
258 return ret;
259}
260
261static int ltc2978_remove(struct i2c_client *client)
262{
263 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
264 const struct ltc2978_data *data = to_ltc2978_data(info);
265
266 pmbus_do_remove(client);
267 kfree(data);
268 return 0;
269}
270
271/* This is the driver that will be inserted */
272static struct i2c_driver ltc2978_driver = {
273 .driver = {
274 .name = "ltc2978",
275 },
276 .probe = ltc2978_probe,
277 .remove = ltc2978_remove,
278 .id_table = ltc2978_id,
279};
280
281static int __init ltc2978_init(void)
282{
283 return i2c_add_driver(&ltc2978_driver);
284}
285
286static void __exit ltc2978_exit(void)
287{
288 i2c_del_driver(&ltc2978_driver);
289}
290
291MODULE_AUTHOR("Guenter Roeck");
292MODULE_DESCRIPTION("PMBus driver for LTC2978");
293MODULE_LICENSE("GPL");
294module_init(ltc2978_init);
295module_exit(ltc2978_exit);
diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c
index 1dfba4477498..ef5cc1eda0f6 100644
--- a/drivers/hwmon/pmbus/pmbus.c
+++ b/drivers/hwmon/pmbus/pmbus.c
@@ -204,7 +204,6 @@ static const struct i2c_device_id pmbus_id[] = {
204 {"bmr451", 1}, 204 {"bmr451", 1},
205 {"bmr453", 1}, 205 {"bmr453", 1},
206 {"bmr454", 1}, 206 {"bmr454", 1},
207 {"ltc2978", 8},
208 {"ncp4200", 1}, 207 {"ncp4200", 1},
209 {"ncp4208", 1}, 208 {"ncp4208", 1},
210 {"pmbus", 0}, 209 {"pmbus", 0},