summaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/pmbus
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2015-06-08 13:29:45 -0400
committerGuenter Roeck <linux@roeck-us.net>2015-08-12 15:29:22 -0400
commitbf89386f166b18c21b2b7a2c5b6e496726c4f25f (patch)
tree2b85e7be65eb6815ecf03ca24bd3723f17368863 /drivers/hwmon/pmbus
parent836954dadcb351d65cf96584f22c9e437169bd49 (diff)
hwmon: (ltc2978) Add support for LTC3882
LTC3882 is mostly compatible with LTC3880. Major differences are that it does not measure the input current, and it no longer supports LTC's legacy mechanism to identify the chip. Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon/pmbus')
-rw-r--r--drivers/hwmon/pmbus/ltc2978.c50
1 files changed, 44 insertions, 6 deletions
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
index 7e10fbf8e133..28e1e735b5c2 100644
--- a/drivers/hwmon/pmbus/ltc2978.c
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -25,13 +25,13 @@
25#include <linux/regulator/driver.h> 25#include <linux/regulator/driver.h>
26#include "pmbus.h" 26#include "pmbus.h"
27 27
28enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 }; 28enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltm4676 };
29 29
30/* Common for all chips */ 30/* Common for all chips */
31#define LTC2978_MFR_VOUT_PEAK 0xdd 31#define LTC2978_MFR_VOUT_PEAK 0xdd
32#define LTC2978_MFR_VIN_PEAK 0xde 32#define LTC2978_MFR_VIN_PEAK 0xde
33#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf 33#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf
34#define LTC2978_MFR_SPECIAL_ID 0xe7 34#define LTC2978_MFR_SPECIAL_ID 0xe7 /* Not on LTC3882 */
35 35
36/* LTC2974, LCT2977, and LTC2978 */ 36/* LTC2974, LCT2977, and LTC2978 */
37#define LTC2978_MFR_VOUT_MIN 0xfb 37#define LTC2978_MFR_VOUT_MIN 0xfb
@@ -42,7 +42,7 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 };
42#define LTC2974_MFR_IOUT_PEAK 0xd7 42#define LTC2974_MFR_IOUT_PEAK 0xd7
43#define LTC2974_MFR_IOUT_MIN 0xd8 43#define LTC2974_MFR_IOUT_MIN 0xd8
44 44
45/* LTC3880, LTC3883, and LTM4676 */ 45/* LTC3880, LTC3882, LTC3883, and LTM4676 */
46#define LTC3880_MFR_IOUT_PEAK 0xd7 46#define LTC3880_MFR_IOUT_PEAK 0xd7
47#define LTC3880_MFR_CLEAR_PEAKS 0xe3 47#define LTC3880_MFR_CLEAR_PEAKS 0xe3
48#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 48#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4
@@ -313,7 +313,7 @@ static int ltc2978_clear_peaks(struct i2c_client *client, int page,
313{ 313{
314 int ret; 314 int ret;
315 315
316 if (id == ltc3880 || id == ltc3883 || id == ltm4676) 316 if (id == ltc3880 || id == ltc3882 || id == ltc3883 || id == ltm4676)
317 ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); 317 ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
318 else 318 else
319 ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); 319 ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
@@ -369,6 +369,7 @@ static const struct i2c_device_id ltc2978_id[] = {
369 {"ltc2977", ltc2977}, 369 {"ltc2977", ltc2977},
370 {"ltc2978", ltc2978}, 370 {"ltc2978", ltc2978},
371 {"ltc3880", ltc3880}, 371 {"ltc3880", ltc3880},
372 {"ltc3882", ltc3882},
372 {"ltc3883", ltc3883}, 373 {"ltc3883", ltc3883},
373 {"ltm4676", ltm4676}, 374 {"ltm4676", ltm4676},
374 {} 375 {}
@@ -393,8 +394,30 @@ static int ltc2978_get_id(struct i2c_client *client)
393 int chip_id; 394 int chip_id;
394 395
395 chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID); 396 chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID);
396 if (chip_id < 0) 397 if (chip_id < 0) {
397 return chip_id; 398 const struct i2c_device_id *id;
399 u8 buf[I2C_SMBUS_BLOCK_MAX];
400 int ret;
401
402 if (!i2c_check_functionality(client->adapter,
403 I2C_FUNC_SMBUS_READ_BLOCK_DATA))
404 return -ENODEV;
405
406 ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
407 if (ret < 0)
408 return ret;
409 if (ret < 3 || strncmp(buf, "LTC", 3))
410 return -ENODEV;
411
412 ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
413 if (ret < 0)
414 return ret;
415 for (id = &ltc2978_id[0]; strlen(id->name); id++) {
416 if (!strncasecmp(id->name, buf, strlen(id->name)))
417 return (int)id->driver_data;
418 }
419 return -ENODEV;
420 }
398 421
399 if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) 422 if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2)
400 return ltc2974; 423 return ltc2974;
@@ -498,6 +521,20 @@ static int ltc2978_probe(struct i2c_client *client,
498 | PMBUS_HAVE_POUT 521 | PMBUS_HAVE_POUT
499 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; 522 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
500 break; 523 break;
524 case ltc3882:
525 info->read_word_data = ltc3880_read_word_data;
526 info->pages = LTC3880_NUM_PAGES;
527 info->func[0] = PMBUS_HAVE_VIN
528 | PMBUS_HAVE_STATUS_INPUT
529 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
530 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
531 | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
532 | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
533 info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
534 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
535 | PMBUS_HAVE_POUT
536 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
537 break;
501 case ltc3883: 538 case ltc3883:
502 info->read_word_data = ltc3883_read_word_data; 539 info->read_word_data = ltc3883_read_word_data;
503 info->pages = LTC3883_NUM_PAGES; 540 info->pages = LTC3883_NUM_PAGES;
@@ -530,6 +567,7 @@ static const struct of_device_id ltc2978_of_match[] = {
530 { .compatible = "lltc,ltc2977" }, 567 { .compatible = "lltc,ltc2977" },
531 { .compatible = "lltc,ltc2978" }, 568 { .compatible = "lltc,ltc2978" },
532 { .compatible = "lltc,ltc3880" }, 569 { .compatible = "lltc,ltc3880" },
570 { .compatible = "lltc,ltc3882" },
533 { .compatible = "lltc,ltc3883" }, 571 { .compatible = "lltc,ltc3883" },
534 { .compatible = "lltc,ltm4676" }, 572 { .compatible = "lltc,ltm4676" },
535 { } 573 { }