aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/pmbus/ltc2978.c
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2013-01-27 12:24:28 -0500
committerGuenter Roeck <linux@roeck-us.net>2013-04-08 00:16:41 -0400
commitfd9175d2f603509e7ddf14e7b60633f6e88fb0e7 (patch)
treeb95554cbce8703c52411323196e62ec755b867b5 /drivers/hwmon/pmbus/ltc2978.c
parent8c770f3a472fa74ad86871f42f6e991951ddeed2 (diff)
hwmon: (pmbus/ltc2978) Add support for LTC2974 and LTC3883
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon/pmbus/ltc2978.c')
-rw-r--r--drivers/hwmon/pmbus/ltc2978.c149
1 files changed, 130 insertions, 19 deletions
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
index 945f7eced409..586a89ef9e0f 100644
--- a/drivers/hwmon/pmbus/ltc2978.c
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -1,7 +1,8 @@
1/* 1/*
2 * Hardware monitoring driver for LTC2978 and LTC3880 2 * Hardware monitoring driver for LTC2974, LTC2978, LTC3880, and LTC3883
3 * 3 *
4 * Copyright (c) 2011 Ericsson AB. 4 * Copyright (c) 2011 Ericsson AB.
5 * Copyright (c) 2013 Guenter Roeck
5 * 6 *
6 * This program is free software; you can redistribute it and/or modify 7 * 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 * it under the terms of the GNU General Public License as published by
@@ -26,31 +27,43 @@
26#include <linux/i2c.h> 27#include <linux/i2c.h>
27#include "pmbus.h" 28#include "pmbus.h"
28 29
29enum chips { ltc2978, ltc3880 }; 30enum chips { ltc2974, ltc2978, ltc3880, ltc3883 };
30 31
31/* LTC2978 and LTC3880 */ 32/* Common for all chips */
32#define LTC2978_MFR_VOUT_PEAK 0xdd 33#define LTC2978_MFR_VOUT_PEAK 0xdd
33#define LTC2978_MFR_VIN_PEAK 0xde 34#define LTC2978_MFR_VIN_PEAK 0xde
34#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf 35#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf
35#define LTC2978_MFR_SPECIAL_ID 0xe7 36#define LTC2978_MFR_SPECIAL_ID 0xe7
36 37
37/* LTC2978 only */ 38/* LTC2974 and LTC2978 */
38#define LTC2978_MFR_VOUT_MIN 0xfb 39#define LTC2978_MFR_VOUT_MIN 0xfb
39#define LTC2978_MFR_VIN_MIN 0xfc 40#define LTC2978_MFR_VIN_MIN 0xfc
40#define LTC2978_MFR_TEMPERATURE_MIN 0xfd 41#define LTC2978_MFR_TEMPERATURE_MIN 0xfd
41 42
42/* LTC3880 only */ 43/* LTC2974 only */
44#define LTC2974_MFR_IOUT_PEAK 0xd7
45#define LTC2974_MFR_IOUT_MIN 0xd8
46
47/* LTC3880 and LTC3883 */
43#define LTC3880_MFR_IOUT_PEAK 0xd7 48#define LTC3880_MFR_IOUT_PEAK 0xd7
44#define LTC3880_MFR_CLEAR_PEAKS 0xe3 49#define LTC3880_MFR_CLEAR_PEAKS 0xe3
45#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 50#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4
46 51
52/* LTC3883 only */
53#define LTC3883_MFR_IIN_PEAK 0xe1
54
55#define LTC2974_ID 0x0212
47#define LTC2978_ID_REV1 0x0121 56#define LTC2978_ID_REV1 0x0121
48#define LTC2978_ID_REV2 0x0122 57#define LTC2978_ID_REV2 0x0122
49#define LTC3880_ID 0x4000 58#define LTC3880_ID 0x4000
50#define LTC3880_ID_MASK 0xff00 59#define LTC3880_ID_MASK 0xff00
60#define LTC3883_ID 0x4300
61#define LTC3883_ID_MASK 0xff00
51 62
63#define LTC2974_NUM_PAGES 4
52#define LTC2978_NUM_PAGES 8 64#define LTC2978_NUM_PAGES 8
53#define LTC3880_NUM_PAGES 2 65#define LTC3880_NUM_PAGES 2
66#define LTC3883_NUM_PAGES 1
54 67
55/* 68/*
56 * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which 69 * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
@@ -63,9 +76,10 @@ enum chips { ltc2978, ltc3880 };
63struct ltc2978_data { 76struct ltc2978_data {
64 enum chips id; 77 enum chips id;
65 u16 vin_min, vin_max; 78 u16 vin_min, vin_max;
66 u16 temp_min, temp_max[LTC3880_NUM_PAGES]; 79 u16 temp_min[LTC2974_NUM_PAGES], temp_max[LTC2974_NUM_PAGES];
67 u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES]; 80 u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES];
68 u16 iout_max[LTC3880_NUM_PAGES]; 81 u16 iout_min[LTC2974_NUM_PAGES], iout_max[LTC2974_NUM_PAGES];
82 u16 iin_max;
69 u16 temp2_max; 83 u16 temp2_max;
70 struct pmbus_driver_info info; 84 struct pmbus_driver_info info;
71}; 85};
@@ -171,9 +185,9 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
171 LTC2978_MFR_TEMPERATURE_MIN); 185 LTC2978_MFR_TEMPERATURE_MIN);
172 if (ret >= 0) { 186 if (ret >= 0) {
173 if (lin11_to_val(ret) 187 if (lin11_to_val(ret)
174 < lin11_to_val(data->temp_min)) 188 < lin11_to_val(data->temp_min[page]))
175 data->temp_min = ret; 189 data->temp_min[page] = ret;
176 ret = data->temp_min; 190 ret = data->temp_min[page];
177 } 191 }
178 break; 192 break;
179 case PMBUS_VIRT_READ_IOUT_MAX: 193 case PMBUS_VIRT_READ_IOUT_MAX:
@@ -189,6 +203,41 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
189 return ret; 203 return ret;
190} 204}
191 205
206static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg)
207{
208 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
209 struct ltc2978_data *data = to_ltc2978_data(info);
210 int ret;
211
212 switch (reg) {
213 case PMBUS_VIRT_READ_IOUT_MAX:
214 ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_PEAK);
215 if (ret >= 0) {
216 if (lin11_to_val(ret)
217 > lin11_to_val(data->iout_max[page]))
218 data->iout_max[page] = ret;
219 ret = data->iout_max[page];
220 }
221 break;
222 case PMBUS_VIRT_READ_IOUT_MIN:
223 ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_MIN);
224 if (ret >= 0) {
225 if (lin11_to_val(ret)
226 < lin11_to_val(data->iout_min[page]))
227 data->iout_min[page] = ret;
228 ret = data->iout_min[page];
229 }
230 break;
231 case PMBUS_VIRT_RESET_IOUT_HISTORY:
232 ret = 0;
233 break;
234 default:
235 ret = ltc2978_read_word_data(client, page, reg);
236 break;
237 }
238 return ret;
239}
240
192static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg) 241static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
193{ 242{
194 const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 243 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
@@ -230,15 +279,41 @@ static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
230 return ret; 279 return ret;
231} 280}
232 281
282static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg)
283{
284 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
285 struct ltc2978_data *data = to_ltc2978_data(info);
286 int ret;
287
288 switch (reg) {
289 case PMBUS_VIRT_READ_IIN_MAX:
290 ret = pmbus_read_word_data(client, page, LTC3883_MFR_IIN_PEAK);
291 if (ret >= 0) {
292 if (lin11_to_val(ret)
293 > lin11_to_val(data->iin_max))
294 data->iin_max = ret;
295 ret = data->iin_max;
296 }
297 break;
298 case PMBUS_VIRT_RESET_IIN_HISTORY:
299 ret = 0;
300 break;
301 default:
302 ret = ltc3880_read_word_data(client, page, reg);
303 break;
304 }
305 return ret;
306}
307
233static int ltc2978_clear_peaks(struct i2c_client *client, int page, 308static int ltc2978_clear_peaks(struct i2c_client *client, int page,
234 enum chips id) 309 enum chips id)
235{ 310{
236 int ret; 311 int ret;
237 312
238 if (id == ltc2978) 313 if (id == ltc3880 || id == ltc3883)
239 ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
240 else
241 ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); 314 ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
315 else
316 ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
242 317
243 return ret; 318 return ret;
244} 319}
@@ -251,8 +326,13 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
251 int ret; 326 int ret;
252 327
253 switch (reg) { 328 switch (reg) {
329 case PMBUS_VIRT_RESET_IIN_HISTORY:
330 data->iin_max = 0x7c00;
331 ret = ltc2978_clear_peaks(client, page, data->id);
332 break;
254 case PMBUS_VIRT_RESET_IOUT_HISTORY: 333 case PMBUS_VIRT_RESET_IOUT_HISTORY:
255 data->iout_max[page] = 0x7c00; 334 data->iout_max[page] = 0x7c00;
335 data->iout_min[page] = 0xfbff;
256 ret = ltc2978_clear_peaks(client, page, data->id); 336 ret = ltc2978_clear_peaks(client, page, data->id);
257 break; 337 break;
258 case PMBUS_VIRT_RESET_TEMP2_HISTORY: 338 case PMBUS_VIRT_RESET_TEMP2_HISTORY:
@@ -270,7 +350,7 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
270 ret = ltc2978_clear_peaks(client, page, data->id); 350 ret = ltc2978_clear_peaks(client, page, data->id);
271 break; 351 break;
272 case PMBUS_VIRT_RESET_TEMP_HISTORY: 352 case PMBUS_VIRT_RESET_TEMP_HISTORY:
273 data->temp_min = 0x7bff; 353 data->temp_min[page] = 0x7bff;
274 data->temp_max[page] = 0x7c00; 354 data->temp_max[page] = 0x7c00;
275 ret = ltc2978_clear_peaks(client, page, data->id); 355 ret = ltc2978_clear_peaks(client, page, data->id);
276 break; 356 break;
@@ -282,8 +362,10 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
282} 362}
283 363
284static const struct i2c_device_id ltc2978_id[] = { 364static const struct i2c_device_id ltc2978_id[] = {
365 {"ltc2974", ltc2974},
285 {"ltc2978", ltc2978}, 366 {"ltc2978", ltc2978},
286 {"ltc3880", ltc3880}, 367 {"ltc3880", ltc3880},
368 {"ltc3883", ltc3883},
287 {} 369 {}
288}; 370};
289MODULE_DEVICE_TABLE(i2c, ltc2978_id); 371MODULE_DEVICE_TABLE(i2c, ltc2978_id);
@@ -308,10 +390,14 @@ static int ltc2978_probe(struct i2c_client *client,
308 if (chip_id < 0) 390 if (chip_id < 0)
309 return chip_id; 391 return chip_id;
310 392
311 if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) { 393 if (chip_id == LTC2974_ID) {
394 data->id = ltc2974;
395 } else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
312 data->id = ltc2978; 396 data->id = ltc2978;
313 } else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) { 397 } else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) {
314 data->id = ltc3880; 398 data->id = ltc3880;
399 } else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) {
400 data->id = ltc3883;
315 } else { 401 } else {
316 dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); 402 dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
317 return -ENODEV; 403 return -ENODEV;
@@ -329,12 +415,29 @@ static int ltc2978_probe(struct i2c_client *client,
329 data->vin_max = 0x7c00; 415 data->vin_max = 0x7c00;
330 for (i = 0; i < ARRAY_SIZE(data->vout_min); i++) 416 for (i = 0; i < ARRAY_SIZE(data->vout_min); i++)
331 data->vout_min[i] = 0xffff; 417 data->vout_min[i] = 0xffff;
332 data->temp_min = 0x7bff; 418 for (i = 0; i < ARRAY_SIZE(data->iout_min); i++)
419 data->iout_min[i] = 0xfbff;
420 for (i = 0; i < ARRAY_SIZE(data->iout_max); i++)
421 data->iout_max[i] = 0x7c00;
422 for (i = 0; i < ARRAY_SIZE(data->temp_min); i++)
423 data->temp_min[i] = 0x7bff;
333 for (i = 0; i < ARRAY_SIZE(data->temp_max); i++) 424 for (i = 0; i < ARRAY_SIZE(data->temp_max); i++)
334 data->temp_max[i] = 0x7c00; 425 data->temp_max[i] = 0x7c00;
335 data->temp2_max = 0x7c00; 426 data->temp2_max = 0x7c00;
336 427
337 switch (data->id) { 428 switch (data->id) {
429 case ltc2974:
430 info->read_word_data = ltc2974_read_word_data;
431 info->pages = LTC2974_NUM_PAGES;
432 info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
433 | PMBUS_HAVE_TEMP2;
434 for (i = 0; i < info->pages; i++) {
435 info->func[i] |= PMBUS_HAVE_VOUT
436 | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
437 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
438 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
439 }
440 break;
338 case ltc2978: 441 case ltc2978:
339 info->read_word_data = ltc2978_read_word_data; 442 info->read_word_data = ltc2978_read_word_data;
340 info->pages = LTC2978_NUM_PAGES; 443 info->pages = LTC2978_NUM_PAGES;
@@ -359,8 +462,16 @@ static int ltc2978_probe(struct i2c_client *client,
359 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT 462 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
360 | PMBUS_HAVE_POUT 463 | PMBUS_HAVE_POUT
361 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; 464 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
362 data->iout_max[0] = 0x7c00; 465 break;
363 data->iout_max[1] = 0x7c00; 466 case ltc3883:
467 info->read_word_data = ltc3883_read_word_data;
468 info->pages = LTC3883_NUM_PAGES;
469 info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
470 | PMBUS_HAVE_STATUS_INPUT
471 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
472 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
473 | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
474 | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
364 break; 475 break;
365 default: 476 default:
366 return -ENODEV; 477 return -ENODEV;
@@ -381,5 +492,5 @@ static struct i2c_driver ltc2978_driver = {
381module_i2c_driver(ltc2978_driver); 492module_i2c_driver(ltc2978_driver);
382 493
383MODULE_AUTHOR("Guenter Roeck"); 494MODULE_AUTHOR("Guenter Roeck");
384MODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880"); 495MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, and LTC3883");
385MODULE_LICENSE("GPL"); 496MODULE_LICENSE("GPL");