From fcdc5739dce03d8050ebfa7153412c2efcdee94f Mon Sep 17 00:00:00 2001 From: Constantine Shulyupin Date: Wed, 1 Jul 2015 09:52:23 +0300 Subject: hwmon: (nct7802) add temperature sensor type attribute Sensor type: 3 diode (current mode), MD=1 4 thermistor, MD=2 Reference: Nuvoton Hardware Monitoring IC NCT7802Y 7.2.32 Mode Selection Register Location : Index 22h Signed-off-by: Constantine Shulyupin Signed-off-by: Guenter Roeck --- drivers/hwmon/nct7802.c | 72 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index fbfc02b..344cbec 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -49,7 +49,7 @@ static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = { #define REG_VOLTAGE_LOW 0x0f #define REG_FANCOUNT_LOW 0x13 #define REG_START 0x21 -#define REG_MODE 0x22 +#define REG_MODE 0x22 /* 7.2.32 Mode Selection Register */ #define REG_PECI_ENABLE 0x23 #define REG_FAN_ENABLE 0x24 #define REG_VMON_ENABLE 0x25 @@ -66,6 +66,43 @@ struct nct7802_data { struct mutex access_lock; /* for multi-byte read and write operations */ }; +static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct nct7802_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + unsigned int mode; + int ret; + + ret = regmap_read(data->regmap, REG_MODE, &mode); + if (ret < 0) + return ret; + + return sprintf(buf, "%u\n", (mode >> (2 * sattr->index) & 3) + 2); +} + +static ssize_t store_temp_type(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nct7802_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + unsigned int type; + int err; + + err = kstrtouint(buf, 0, &type); + if (err < 0) + return err; + if (sattr->index == 2 && type != 4) /* RD3 */ + return -EINVAL; + if (type < 3 || type > 4) + return -EINVAL; + err = regmap_update_bits(data->regmap, REG_MODE, + 3 << 2 * sattr->index, (type - 2) << 2 * sattr->index); + return err ? : count; +} + + static int nct7802_read_temp(struct nct7802_data *data, u8 reg_temp, u8 reg_temp_low, int *temp) { @@ -377,6 +414,8 @@ store_beep(struct device *dev, struct device_attribute *attr, const char *buf, return err ? : count; } +static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR, + show_temp_type, store_temp_type, 0); static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0x01, REG_TEMP_LSB); static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, @@ -386,6 +425,8 @@ static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x3a, 0); +static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, + show_temp_type, store_temp_type, 1); static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0x02, REG_TEMP_LSB); static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, @@ -395,6 +436,8 @@ static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x3b, 0); +static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, + show_temp_type, store_temp_type, 2); static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0x03, REG_TEMP_LSB); static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, @@ -475,6 +518,7 @@ static SENSOR_DEVICE_ATTR_2(temp6_beep, S_IRUGO | S_IWUSR, show_beep, store_beep, 0x5c, 5); static struct attribute *nct7802_temp_attrs[] = { + &sensor_dev_attr_temp1_type.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_min.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, @@ -485,7 +529,8 @@ static struct attribute *nct7802_temp_attrs[] = { &sensor_dev_attr_temp1_fault.dev_attr.attr, &sensor_dev_attr_temp1_beep.dev_attr.attr, - &sensor_dev_attr_temp2_input.dev_attr.attr, /* 9 */ + &sensor_dev_attr_temp2_type.dev_attr.attr, /* 10 */ + &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr, @@ -495,7 +540,8 @@ static struct attribute *nct7802_temp_attrs[] = { &sensor_dev_attr_temp2_fault.dev_attr.attr, &sensor_dev_attr_temp2_beep.dev_attr.attr, - &sensor_dev_attr_temp3_input.dev_attr.attr, /* 18 */ + &sensor_dev_attr_temp3_type.dev_attr.attr, /* 20 */ + &sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_temp3_min.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp3_crit.dev_attr.attr, @@ -505,7 +551,7 @@ static struct attribute *nct7802_temp_attrs[] = { &sensor_dev_attr_temp3_fault.dev_attr.attr, &sensor_dev_attr_temp3_beep.dev_attr.attr, - &sensor_dev_attr_temp4_input.dev_attr.attr, /* 27 */ + &sensor_dev_attr_temp4_input.dev_attr.attr, /* 30 */ &sensor_dev_attr_temp4_min.dev_attr.attr, &sensor_dev_attr_temp4_max.dev_attr.attr, &sensor_dev_attr_temp4_crit.dev_attr.attr, @@ -514,7 +560,7 @@ static struct attribute *nct7802_temp_attrs[] = { &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp4_beep.dev_attr.attr, - &sensor_dev_attr_temp5_input.dev_attr.attr, /* 35 */ + &sensor_dev_attr_temp5_input.dev_attr.attr, /* 38 */ &sensor_dev_attr_temp5_min.dev_attr.attr, &sensor_dev_attr_temp5_max.dev_attr.attr, &sensor_dev_attr_temp5_crit.dev_attr.attr, @@ -523,7 +569,7 @@ static struct attribute *nct7802_temp_attrs[] = { &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp5_beep.dev_attr.attr, - &sensor_dev_attr_temp6_input.dev_attr.attr, /* 43 */ + &sensor_dev_attr_temp6_input.dev_attr.attr, /* 46 */ &sensor_dev_attr_temp6_beep.dev_attr.attr, NULL @@ -541,25 +587,27 @@ static umode_t nct7802_temp_is_visible(struct kobject *kobj, if (err < 0) return 0; - if (index < 9 && + if (index < 10 && (reg & 03) != 0x01 && (reg & 0x03) != 0x02) /* RD1 */ return 0; - if (index >= 9 && index < 18 && + + if (index >= 10 && index < 20 && (reg & 0x0c) != 0x04 && (reg & 0x0c) != 0x08) /* RD2 */ return 0; - if (index >= 18 && index < 27 && (reg & 0x30) != 0x20) /* RD3 */ + if (index >= 20 && index < 30 && (reg & 0x30) != 0x20) /* RD3 */ return 0; - if (index >= 27 && index < 35) /* local */ + + if (index >= 30 && index < 38) /* local */ return attr->mode; err = regmap_read(data->regmap, REG_PECI_ENABLE, ®); if (err < 0) return 0; - if (index >= 35 && index < 43 && !(reg & 0x01)) /* PECI 0 */ + if (index >= 38 && index < 46 && !(reg & 0x01)) /* PECI 0 */ return 0; - if (index >= 0x43 && (!(reg & 0x02))) /* PECI 1 */ + if (index >= 0x46 && (!(reg & 0x02))) /* PECI 1 */ return 0; return attr->mode; -- cgit v1.1 From ea33597c6f9862d7b926bdb9c3ac25012f307dd5 Mon Sep 17 00:00:00 2001 From: Constantine Shulyupin Date: Sat, 4 Jul 2015 21:49:51 +0300 Subject: hwmon: (nct7802) Add pwm control Added fan output control registers. Modes of operation are PWM (default) and DC. Introduced show_pwm, store_pwm, nct7802_pwm_attrs, nct7802_pwm_group. Signed-off-by: Guenter Roeck --- drivers/hwmon/nct7802.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index 344cbec..457b0f2 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -102,6 +102,36 @@ static ssize_t store_temp_type(struct device *dev, return err ? : count; } +static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct nct7802_data *data = dev_get_drvdata(dev); + unsigned int val; + int ret; + + ret = regmap_read(data->regmap, attr->index, &val); + if (ret < 0) + return ret; + + return sprintf(buf, "%d\n", val); +} + +static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct nct7802_data *data = dev_get_drvdata(dev); + int err; + u8 val; + + err = kstrtou8(buf, 0, &val); + if (err < 0) + return err; + + err = regmap_write(data->regmap, attr->index, val); + return err ? : count; +} static int nct7802_read_temp(struct nct7802_data *data, u8 reg_temp, u8 reg_temp_low, int *temp) @@ -735,6 +765,11 @@ static SENSOR_DEVICE_ATTR_2(fan3_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 2); static SENSOR_DEVICE_ATTR_2(fan3_beep, S_IRUGO | S_IWUSR, show_beep, store_beep, 0x5b, 2); +/* 7.2.91... Fan Control Output Value */ +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x60); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x61); +static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x62); + static struct attribute *nct7802_fan_attrs[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, @@ -773,10 +808,22 @@ static struct attribute_group nct7802_fan_group = { .is_visible = nct7802_fan_is_visible, }; +static struct attribute *nct7802_pwm_attrs[] = { + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3.dev_attr.attr, + NULL +}; + +static struct attribute_group nct7802_pwm_group = { + .attrs = nct7802_pwm_attrs, +}; + static const struct attribute_group *nct7802_groups[] = { &nct7802_temp_group, &nct7802_in_group, &nct7802_fan_group, + &nct7802_pwm_group, NULL }; -- cgit v1.1 From 876420e05a0fda4801c0a0de67e9bbe9831dffee Mon Sep 17 00:00:00 2001 From: Constantine Shulyupin Date: Sun, 5 Jul 2015 01:41:31 +0300 Subject: hwmon: (nct7802) Add pwm mode attributes Introduced: show_pwm_mode, pwm1_mode, pwm2_mode, pwm2_mode Signed-off-by: Guenter Roeck --- drivers/hwmon/nct7802.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index 457b0f2..1c80aa4 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -102,6 +102,24 @@ static ssize_t store_temp_type(struct device *dev, return err ? : count; } +static ssize_t show_pwm_mode(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct7802_data *data = dev_get_drvdata(dev); + unsigned int regval; + int ret; + + if (sattr->index > 1) + return sprintf(buf, "1\n"); + + ret = regmap_read(data->regmap, 0x5E, ®val); + if (ret < 0) + return ret; + + return sprintf(buf, "%u\n", !(regval & (1 << sattr->index))); +} + static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -765,6 +783,11 @@ static SENSOR_DEVICE_ATTR_2(fan3_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 2); static SENSOR_DEVICE_ATTR_2(fan3_beep, S_IRUGO | S_IWUSR, show_beep, store_beep, 0x5b, 2); +/* 7.2.89 Fan Control Output Type */ +static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0); +static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO, show_pwm_mode, NULL, 1); +static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2); + /* 7.2.91... Fan Control Output Value */ static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x60); static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x61); @@ -809,8 +832,11 @@ static struct attribute_group nct7802_fan_group = { }; static struct attribute *nct7802_pwm_attrs[] = { + &sensor_dev_attr_pwm1_mode.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2_mode.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3_mode.dev_attr.attr, &sensor_dev_attr_pwm3.dev_attr.attr, NULL }; -- cgit v1.1 From 2725fe2b74e264a649af72beaaf6cc2c2e1f3495 Mon Sep 17 00:00:00 2001 From: Peter Hung Date: Tue, 7 Jul 2015 16:22:36 +0800 Subject: hwmon: (f71882fg) Add support for F81866 and F71868 Add New Fintek SuperIO F81866(0x1010) & F71868(0x1106) with H/W Monitor functions. We increased F71882FG_MAX_INS from 9 to 10 to read F71868 10 voltage sets. Signed-off-by: Peter Hung Signed-off-by: Guenter Roeck --- drivers/hwmon/f71882fg.c | 53 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 2e5c6f4..3a7185a 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -51,6 +51,7 @@ #define SIO_F71808A_ID 0x1001 /* Chipset ID */ #define SIO_F71858_ID 0x0507 /* Chipset ID */ #define SIO_F71862_ID 0x0601 /* Chipset ID */ +#define SIO_F71868_ID 0x1106 /* Chipset ID */ #define SIO_F71869_ID 0x0814 /* Chipset ID */ #define SIO_F71869A_ID 0x1007 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */ @@ -59,6 +60,7 @@ #define SIO_F71889A_ID 0x1005 /* Chipset ID */ #define SIO_F8000_ID 0x0581 /* Chipset ID */ #define SIO_F81865_ID 0x0704 /* Chipset ID */ +#define SIO_F81866_ID 0x1010 /* Chipset ID */ #define REGION_LENGTH 8 #define ADDR_REG_OFFSET 5 @@ -101,7 +103,7 @@ #define F71882FG_REG_START 0x01 -#define F71882FG_MAX_INS 9 +#define F71882FG_MAX_INS 10 #define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */ @@ -109,14 +111,15 @@ static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); -enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71869a, f71882fg, - f71889fg, f71889ed, f71889a, f8000, f81865f }; +enum chips { f71808e, f71808a, f71858fg, f71862fg, f71868a, f71869, f71869a, + f71882fg, f71889fg, f71889ed, f71889a, f8000, f81865f, f81866a}; static const char *const f71882fg_names[] = { "f71808e", "f71808a", "f71858fg", "f71862fg", + "f71868a", "f71869", /* Both f71869f and f71869e, reg. compatible and same id */ "f71869a", "f71882fg", @@ -125,21 +128,24 @@ static const char *const f71882fg_names[] = { "f71889a", "f8000", "f81865f", + "f81866a", }; static const char f71882fg_has_in[][F71882FG_MAX_INS] = { - [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1 }, - [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1 }, - [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, - [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71869a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, - [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1, 0 }, + [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1, 0 }, + [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, + [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71868a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71869a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, + [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, + [f81866a] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, }; static const char f71882fg_has_in1_alarm[] = { @@ -147,6 +153,7 @@ static const char f71882fg_has_in1_alarm[] = { [f71808a] = 0, [f71858fg] = 0, [f71862fg] = 0, + [f71868a] = 0, [f71869] = 0, [f71869a] = 0, [f71882fg] = 1, @@ -155,6 +162,7 @@ static const char f71882fg_has_in1_alarm[] = { [f71889a] = 1, [f8000] = 0, [f81865f] = 1, + [f81866a] = 1, }; static const char f71882fg_fan_has_beep[] = { @@ -162,6 +170,7 @@ static const char f71882fg_fan_has_beep[] = { [f71808a] = 0, [f71858fg] = 0, [f71862fg] = 1, + [f71868a] = 1, [f71869] = 1, [f71869a] = 1, [f71882fg] = 1, @@ -170,6 +179,7 @@ static const char f71882fg_fan_has_beep[] = { [f71889a] = 1, [f8000] = 0, [f81865f] = 1, + [f81866a] = 1, }; static const char f71882fg_nr_fans[] = { @@ -177,6 +187,7 @@ static const char f71882fg_nr_fans[] = { [f71808a] = 2, /* +1 fan which is monitor + simple pwm only */ [f71858fg] = 3, [f71862fg] = 3, + [f71868a] = 3, [f71869] = 3, [f71869a] = 3, [f71882fg] = 4, @@ -185,6 +196,7 @@ static const char f71882fg_nr_fans[] = { [f71889a] = 3, [f8000] = 3, /* +1 fan which is monitor only */ [f81865f] = 2, + [f81866a] = 3, }; static const char f71882fg_temp_has_beep[] = { @@ -192,6 +204,7 @@ static const char f71882fg_temp_has_beep[] = { [f71808a] = 1, [f71858fg] = 0, [f71862fg] = 1, + [f71868a] = 1, [f71869] = 1, [f71869a] = 1, [f71882fg] = 1, @@ -200,6 +213,7 @@ static const char f71882fg_temp_has_beep[] = { [f71889a] = 1, [f8000] = 0, [f81865f] = 1, + [f81866a] = 1, }; static const char f71882fg_nr_temps[] = { @@ -207,6 +221,7 @@ static const char f71882fg_nr_temps[] = { [f71808a] = 2, [f71858fg] = 3, [f71862fg] = 3, + [f71868a] = 3, [f71869] = 3, [f71869a] = 3, [f71882fg] = 3, @@ -215,6 +230,7 @@ static const char f71882fg_nr_temps[] = { [f71889a] = 3, [f8000] = 3, [f81865f] = 2, + [f81866a] = 3, }; static struct platform_device *f71882fg_pdev; @@ -531,6 +547,7 @@ static struct sensor_device_attribute_2 fxxxx_in_attr[] = { SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6), SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7), SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8), + SENSOR_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 0, 9), }; /* For models with in1 alarm capability */ @@ -2551,6 +2568,9 @@ static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data) case SIO_F71862_ID: sio_data->type = f71862fg; break; + case SIO_F71868_ID: + sio_data->type = f71868a; + break; case SIO_F71869_ID: sio_data->type = f71869; break; @@ -2575,6 +2595,9 @@ static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data) case SIO_F81865_ID: sio_data->type = f81865f; break; + case SIO_F81866_ID: + sio_data->type = f81866a; + break; default: pr_info("Unsupported Fintek device: %04x\n", (unsigned int)devid); -- cgit v1.1 From dcd956fc0b01135e6a00922165e653178d2b177b Mon Sep 17 00:00:00 2001 From: Peter Hung Date: Tue, 7 Jul 2015 16:22:37 +0800 Subject: hwmon: (f71882fg) Fix f81866a temp/beep setting The temperature value of Fintek F81866 is the same with f71882fg. It located with 0x6c + 2*(nr), others located with 0x6c + 2*(nr+1). We change the rule in f71882fg_probe(), If type = f71858fg/f8000/f81866a. the temp_start will set to 0, others are 1. The F81866 over-temperature beep setting is not the same with f71882fg too. They are using the same address 63H, but F81866 is using bit 0/1/2 & 4/5/6, others are using bit 1/2/3 & 5/6/7, So we copy from fxxxx_temp_beep_attr[] to f81866_temp_beep_attr and change bit setting. Signed-off-by: Peter Hung Signed-off-by: Guenter Roeck --- drivers/hwmon/f71882fg.c | 60 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 3a7185a..79f1f50 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -506,6 +506,23 @@ static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { { store_temp_beep, 0, 7), } }; +static struct sensor_device_attribute_2 f81866_temp_beep_attr[3][2] = { { + SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 0), + SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 4), +}, { + SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 1), + SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 5), +}, { + SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 2), + SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 6), +} }; + /* * Temp attr for the f8000 * Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max) @@ -2287,6 +2304,7 @@ static int f71882fg_probe(struct platform_device *pdev) int nr_fans = f71882fg_nr_fans[sio_data->type]; int nr_temps = f71882fg_nr_temps[sio_data->type]; int err, i; + int size; u8 start_reg, reg; data = devm_kzalloc(&pdev->dev, sizeof(struct f71882fg_data), @@ -2297,7 +2315,8 @@ static int f71882fg_probe(struct platform_device *pdev) data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; data->type = sio_data->type; data->temp_start = - (data->type == f71858fg || data->type == f8000) ? 0 : 1; + (data->type == f71858fg || data->type == f8000 || + data->type == f81866a) ? 0 : 1; mutex_init(&data->update_lock); platform_set_drvdata(pdev, data); @@ -2339,6 +2358,11 @@ static int f71882fg_probe(struct platform_device *pdev) f8000_temp_attr, ARRAY_SIZE(f8000_temp_attr)); break; + case f81866a: + err = f71882fg_create_sysfs_files(pdev, + f71858fg_temp_attr, + ARRAY_SIZE(f71858fg_temp_attr)); + break; default: err = f71882fg_create_sysfs_files(pdev, &fxxxx_temp_attr[0][0], @@ -2348,10 +2372,18 @@ static int f71882fg_probe(struct platform_device *pdev) goto exit_unregister_sysfs; if (f71882fg_temp_has_beep[data->type]) { - err = f71882fg_create_sysfs_files(pdev, - &fxxxx_temp_beep_attr[0][0], - ARRAY_SIZE(fxxxx_temp_beep_attr[0]) - * nr_temps); + if (data->type == f81866a) { + size = ARRAY_SIZE(f81866_temp_beep_attr[0]); + err = f71882fg_create_sysfs_files(pdev, + &f81866_temp_beep_attr[0][0], + size * nr_temps); + + } else { + size = ARRAY_SIZE(fxxxx_temp_beep_attr[0]); + err = f71882fg_create_sysfs_files(pdev, + &fxxxx_temp_beep_attr[0][0], + size * nr_temps); + } if (err) goto exit_unregister_sysfs; } @@ -2468,15 +2500,27 @@ static int f71882fg_remove(struct platform_device *pdev) f8000_temp_attr, ARRAY_SIZE(f8000_temp_attr)); break; + case f81866a: + f71882fg_remove_sysfs_files(pdev, + f71858fg_temp_attr, + ARRAY_SIZE(f71858fg_temp_attr)); + break; default: f71882fg_remove_sysfs_files(pdev, &fxxxx_temp_attr[0][0], ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps); } if (f71882fg_temp_has_beep[data->type]) { - f71882fg_remove_sysfs_files(pdev, - &fxxxx_temp_beep_attr[0][0], - ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps); + if (data->type == f81866a) + f71882fg_remove_sysfs_files(pdev, + &f81866_temp_beep_attr[0][0], + ARRAY_SIZE(f81866_temp_beep_attr[0]) + * nr_temps); + else + f71882fg_remove_sysfs_files(pdev, + &fxxxx_temp_beep_attr[0][0], + ARRAY_SIZE(fxxxx_temp_beep_attr[0]) + * nr_temps); } for (i = 0; i < F71882FG_MAX_INS; i++) { -- cgit v1.1 From 3e40b8602aa5309e0b117701c36971367af40682 Mon Sep 17 00:00:00 2001 From: Peter Hung Date: Tue, 7 Jul 2015 16:22:38 +0800 Subject: hwmon:(f71882fg) Fix f81866a voltage protection The f81866a voltage-1 protector(VIN1) address is differ from f71882. f71882 status:12H, beep:13H, v-high:32H f81866a status:16H, beep:17H, v-high:3aH Signed-off-by: Peter Hung Signed-off-by: Guenter Roeck --- drivers/hwmon/f71882fg.c | 50 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 79f1f50..e4ff21f 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -71,6 +71,10 @@ #define F71882FG_REG_IN(nr) (0x20 + (nr)) #define F71882FG_REG_IN1_HIGH 0x32 /* f7188x only */ +#define F81866_REG_IN_STATUS 0x16 /* F81866 only */ +#define F81866_REG_IN_BEEP 0x17 /* F81866 only */ +#define F81866_REG_IN1_HIGH 0x3a /* F81866 only */ + #define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr))) #define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr))) #define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr))) @@ -1204,10 +1208,21 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) if (time_after(jiffies, data->last_limits + 60 * HZ) || !data->valid) { if (f71882fg_has_in1_alarm[data->type]) { - data->in1_max = - f71882fg_read8(data, F71882FG_REG_IN1_HIGH); - data->in_beep = - f71882fg_read8(data, F71882FG_REG_IN_BEEP); + if (data->type == f81866a) { + data->in1_max = + f71882fg_read8(data, + F81866_REG_IN1_HIGH); + data->in_beep = + f71882fg_read8(data, + F81866_REG_IN_BEEP); + } else { + data->in1_max = + f71882fg_read8(data, + F71882FG_REG_IN1_HIGH); + data->in_beep = + f71882fg_read8(data, + F71882FG_REG_IN_BEEP); + } } /* Get High & boundary temps*/ @@ -1331,9 +1346,16 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) data->fan[3] = f71882fg_read16(data, F71882FG_REG_FAN(3)); - if (f71882fg_has_in1_alarm[data->type]) - data->in_status = f71882fg_read8(data, + if (f71882fg_has_in1_alarm[data->type]) { + if (data->type == f81866a) + data->in_status = f71882fg_read8(data, + F81866_REG_IN_STATUS); + + else + data->in_status = f71882fg_read8(data, F71882FG_REG_IN_STATUS); + } + for (nr = 0; nr < F71882FG_MAX_INS; nr++) if (f71882fg_has_in[data->type][nr]) data->in[nr] = f71882fg_read8(data, @@ -1474,7 +1496,10 @@ static ssize_t store_in_max(struct device *dev, struct device_attribute val = clamp_val(val, 0, 255); mutex_lock(&data->update_lock); - f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val); + if (data->type == f81866a) + f71882fg_write8(data, F81866_REG_IN1_HIGH, val); + else + f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val); data->in1_max = val; mutex_unlock(&data->update_lock); @@ -1505,13 +1530,20 @@ static ssize_t store_in_beep(struct device *dev, struct device_attribute return err; mutex_lock(&data->update_lock); - data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP); + if (data->type == f81866a) + data->in_beep = f71882fg_read8(data, F81866_REG_IN_BEEP); + else + data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP); + if (val) data->in_beep |= 1 << nr; else data->in_beep &= ~(1 << nr); - f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep); + if (data->type == f81866a) + f71882fg_write8(data, F81866_REG_IN_BEEP, data->in_beep); + else + f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep); mutex_unlock(&data->update_lock); return count; -- cgit v1.1 From 5102f022688ccd59b1fe4efc8a46ec3aca02dfc5 Mon Sep 17 00:00:00 2001 From: Constantine Shulyupin Date: Wed, 8 Jul 2015 00:40:10 +0300 Subject: hwmon: (nct7802) Add pwmX_enable attribute Introduced REG_SMARTFAN_EN, SMARTFAN_EN_SHIFT, pwmX_enable, show_pwm_enable, store_pwm_enable. Signed-off-by: Constantine Shulyupin Signed-off-by: Guenter Roeck --- drivers/hwmon/nct7802.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index 1c80aa4..f4908bb 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -53,6 +53,8 @@ static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = { #define REG_PECI_ENABLE 0x23 #define REG_FAN_ENABLE 0x24 #define REG_VMON_ENABLE 0x25 +#define REG_SMARTFAN_EN(x) (0x64 + (x) / 2) +#define SMARTFAN_EN_SHIFT(x) ((x) % 2 * 4) #define REG_VENDOR_ID 0xfd #define REG_CHIP_ID 0xfe #define REG_VERSION_ID 0xff @@ -151,6 +153,41 @@ static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, return err ? : count; } +static ssize_t show_pwm_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nct7802_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + unsigned int reg, enabled; + int ret; + + ret = regmap_read(data->regmap, REG_SMARTFAN_EN(sattr->index), ®); + if (ret < 0) + return ret; + enabled = reg >> SMARTFAN_EN_SHIFT(sattr->index) & 1; + return sprintf(buf, "%u\n", enabled + 1); +} + +static ssize_t store_pwm_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nct7802_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + u8 val; + int ret; + + ret = kstrtou8(buf, 0, &val); + if (ret < 0) + return ret; + if (val < 1 || val > 2) + return -EINVAL; + ret = regmap_update_bits(data->regmap, REG_SMARTFAN_EN(sattr->index), + 1 << SMARTFAN_EN_SHIFT(sattr->index), + (val - 1) << SMARTFAN_EN_SHIFT(sattr->index)); + return ret ? : count; +} + static int nct7802_read_temp(struct nct7802_data *data, u8 reg_temp, u8 reg_temp_low, int *temp) { @@ -793,6 +830,14 @@ static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x60); static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x61); static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x62); +/* 7.2.95... Temperature to Fan mapping Relationships Register */ +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, + store_pwm_enable, 0); +static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable, + store_pwm_enable, 1); +static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable, + store_pwm_enable, 2); + static struct attribute *nct7802_fan_attrs[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, @@ -832,10 +877,13 @@ static struct attribute_group nct7802_fan_group = { }; static struct attribute *nct7802_pwm_attrs[] = { + &sensor_dev_attr_pwm1_enable.dev_attr.attr, &sensor_dev_attr_pwm1_mode.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2_enable.dev_attr.attr, &sensor_dev_attr_pwm2_mode.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3_enable.dev_attr.attr, &sensor_dev_attr_pwm3_mode.dev_attr.attr, &sensor_dev_attr_pwm3.dev_attr.attr, NULL -- cgit v1.1 From d8363bb5ad4ff3986c03c6895cc74e2a30041aee Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 7 Jul 2015 19:16:53 -0600 Subject: hwmon: (f71882fg) Add support for f81768d Add f81768d (id 0x1210) currently found on Jetway motherboards. It has 11 voltages but otherwise needed no special handling in this driver. Signed-off-by: George Joseph Signed-off-by: Guenter Roeck --- drivers/hwmon/f71882fg.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index e4ff21f..cb28e4b 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -59,6 +59,7 @@ #define SIO_F71889E_ID 0x0909 /* Chipset ID */ #define SIO_F71889A_ID 0x1005 /* Chipset ID */ #define SIO_F8000_ID 0x0581 /* Chipset ID */ +#define SIO_F81768D_ID 0x1210 /* Chipset ID */ #define SIO_F81865_ID 0x0704 /* Chipset ID */ #define SIO_F81866_ID 0x1010 /* Chipset ID */ @@ -107,7 +108,7 @@ #define F71882FG_REG_START 0x01 -#define F71882FG_MAX_INS 10 +#define F71882FG_MAX_INS 11 #define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */ @@ -116,7 +117,8 @@ module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); enum chips { f71808e, f71808a, f71858fg, f71862fg, f71868a, f71869, f71869a, - f71882fg, f71889fg, f71889ed, f71889a, f8000, f81865f, f81866a}; + f71882fg, f71889fg, f71889ed, f71889a, f8000, f81768d, f81865f, + f81866a}; static const char *const f71882fg_names[] = { "f71808e", @@ -131,25 +133,27 @@ static const char *const f71882fg_names[] = { "f71889ed", "f71889a", "f8000", + "f81768d", "f81865f", "f81866a", }; static const char f71882fg_has_in[][F71882FG_MAX_INS] = { - [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1, 0 }, - [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1, 0 }, - [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, - [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f71868a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f71869a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, - [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, - [f81866a] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0 }, + [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0 }, + [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71868a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71869a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + [f81768d] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, + [f81866a] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, }; static const char f71882fg_has_in1_alarm[] = { @@ -165,6 +169,7 @@ static const char f71882fg_has_in1_alarm[] = { [f71889ed] = 1, [f71889a] = 1, [f8000] = 0, + [f81768d] = 1, [f81865f] = 1, [f81866a] = 1, }; @@ -182,6 +187,7 @@ static const char f71882fg_fan_has_beep[] = { [f71889ed] = 1, [f71889a] = 1, [f8000] = 0, + [f81768d] = 1, [f81865f] = 1, [f81866a] = 1, }; @@ -199,6 +205,7 @@ static const char f71882fg_nr_fans[] = { [f71889ed] = 3, [f71889a] = 3, [f8000] = 3, /* +1 fan which is monitor only */ + [f81768d] = 3, [f81865f] = 2, [f81866a] = 3, }; @@ -216,6 +223,7 @@ static const char f71882fg_temp_has_beep[] = { [f71889ed] = 1, [f71889a] = 1, [f8000] = 0, + [f81768d] = 1, [f81865f] = 1, [f81866a] = 1, }; @@ -233,6 +241,7 @@ static const char f71882fg_nr_temps[] = { [f71889ed] = 3, [f71889a] = 3, [f8000] = 3, + [f81768d] = 3, [f81865f] = 2, [f81866a] = 3, }; @@ -569,6 +578,7 @@ static struct sensor_device_attribute_2 fxxxx_in_attr[] = { SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7), SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8), SENSOR_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 0, 9), + SENSOR_ATTR_2(in10_input, S_IRUGO, show_in, NULL, 0, 10), }; /* For models with in1 alarm capability */ @@ -2668,6 +2678,9 @@ static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data) case SIO_F8000_ID: sio_data->type = f8000; break; + case SIO_F81768D_ID: + sio_data->type = f81768d; + break; case SIO_F81865_ID: sio_data->type = f81865f; break; -- cgit v1.1 From d4068a59277d0ad5374f71163d45599d589bd617 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:51:32 +0900 Subject: hwmon: (g762) Drop owner assignment from struct i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Guenter Roeck --- drivers/hwmon/g762.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index 85d106f..b96a2a9 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c @@ -1113,7 +1113,6 @@ static int g762_remove(struct i2c_client *client) static struct i2c_driver g762_driver = { .driver = { .name = DRVNAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(g762_dt_match), }, .probe = g762_probe, -- cgit v1.1 From 7b7a8b4237a0d7808df5aa12f49f7979f879cf12 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 10 Jul 2015 12:59:13 +0800 Subject: hwmon: (pmbus) Explicitly set regulator type for pmbus_regulator_ops The pmbus_regulator_ops is for voltage regulators, so explicitly set regulator type for better readability. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 89a23ff..21f8b2f 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -390,6 +390,7 @@ extern struct regulator_ops pmbus_regulator_ops; .of_match = of_match_ptr(_name # _id), \ .regulators_node = of_match_ptr("regulators"), \ .ops = &pmbus_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ } -- cgit v1.1 From a07d73113febf0e17299338b9a6401955fe63b14 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 10 Jul 2015 13:00:08 +0800 Subject: hwmon: (pmbus_core) Constify pmbus_regulator_ops pmbus_regulator_ops is not modified after initialized, so make it const. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus.h | 2 +- drivers/hwmon/pmbus/pmbus_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 21f8b2f..58262b5 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -380,7 +380,7 @@ struct pmbus_driver_info { /* Regulator ops */ -extern struct regulator_ops pmbus_regulator_ops; +extern const struct regulator_ops pmbus_regulator_ops; /* Macro for filling in array of struct regulator_desc */ #define PMBUS_REGULATOR(_name, _id) \ diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index f2e47c7..12d85b1 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -1796,7 +1796,7 @@ static int pmbus_regulator_disable(struct regulator_dev *rdev) return _pmbus_regulator_on_off(rdev, 0); } -struct regulator_ops pmbus_regulator_ops = { +const struct regulator_ops pmbus_regulator_ops = { .enable = pmbus_regulator_enable, .disable = pmbus_regulator_disable, .is_enabled = pmbus_regulator_is_enabled, -- cgit v1.1 From 99b416085ce99b03b8be63d6ba8872902e9809ae Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 4 Jul 2015 09:19:48 -0700 Subject: hwmon: (adm1275) Use BIT macro Use BIT macro to simplify adding new bit masks. Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/adm1275.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 60aad95..d34ba4f 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "pmbus.h" enum chips { adm1075, adm1275, adm1276 }; @@ -30,28 +31,28 @@ enum chips { adm1075, adm1275, adm1276 }; #define ADM1275_PEAK_VOUT 0xd2 #define ADM1275_PMON_CONFIG 0xd4 -#define ADM1275_VIN_VOUT_SELECT (1 << 6) -#define ADM1275_VRANGE (1 << 5) -#define ADM1075_IRANGE_50 (1 << 4) -#define ADM1075_IRANGE_25 (1 << 3) -#define ADM1075_IRANGE_MASK ((1 << 3) | (1 << 4)) +#define ADM1275_VIN_VOUT_SELECT BIT(6) +#define ADM1275_VRANGE BIT(5) +#define ADM1075_IRANGE_50 BIT(4) +#define ADM1075_IRANGE_25 BIT(3) +#define ADM1075_IRANGE_MASK (BIT(3) | BIT(4)) #define ADM1275_IOUT_WARN2_LIMIT 0xd7 #define ADM1275_DEVICE_CONFIG 0xd8 -#define ADM1275_IOUT_WARN2_SELECT (1 << 4) +#define ADM1275_IOUT_WARN2_SELECT BIT(4) #define ADM1276_PEAK_PIN 0xda -#define ADM1275_MFR_STATUS_IOUT_WARN2 (1 << 0) +#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) #define ADM1075_READ_VAUX 0xdd #define ADM1075_VAUX_OV_WARN_LIMIT 0xde #define ADM1075_VAUX_UV_WARN_LIMIT 0xdf #define ADM1075_VAUX_STATUS 0xf6 -#define ADM1075_VAUX_OV_WARN (1<<7) -#define ADM1075_VAUX_UV_WARN (1<<6) +#define ADM1075_VAUX_OV_WARN BIT(7) +#define ADM1075_VAUX_UV_WARN BIT(6) struct adm1275_data { int id; -- cgit v1.1 From 904b296f308dc70d5560a2b4311bbe255de12fd7 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 4 Jul 2015 08:39:18 -0700 Subject: hwmon: (adm1275) Introduce configuration data structure for coeffcients Each new chip supported by the driver has a new set of coefficients, making hard-coding coefficients more and more cumbersome. Introduce a datastructure and table to simplify configuration. Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/adm1275.c | 113 +++++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 45 deletions(-) diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index d34ba4f..3a8d69b 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -62,6 +62,34 @@ struct adm1275_data { #define to_adm1275_data(x) container_of(x, struct adm1275_data, info) +struct coefficients { + s16 m; + s16 b; + s16 R; +}; + +static const struct coefficients adm1075_coefficients[] = { + [0] = { 27169, 0, -1 }, /* voltage */ + [1] = { 806, 20475, -1 }, /* current, irange25 */ + [2] = { 404, 20475, -1 }, /* current, irange50 */ + [3] = { 0, -1, 8549 }, /* power, irange25 */ + [4] = { 0, -1, 4279 }, /* power, irange50 */ +}; + +static const struct coefficients adm1275_coefficients[] = { + [0] = { 19199, 0, -2 }, /* voltage, vrange set */ + [1] = { 6720, 0, -1 }, /* voltage, vrange not set */ + [2] = { 807, 20475, -1 }, /* current */ +}; + +static const struct coefficients adm1276_coefficients[] = { + [0] = { 19199, 0, -2 }, /* voltage, vrange set */ + [1] = { 6720, 0, -1 }, /* voltage, vrange not set */ + [2] = { 807, 20475, -1 }, /* current */ + [3] = { 6043, 0, -2 }, /* power, vrange set */ + [4] = { 2115, 0, -1 }, /* power, vrange not set */ +}; + static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); @@ -235,6 +263,8 @@ static int adm1275_probe(struct i2c_client *client, struct pmbus_driver_info *info; struct adm1275_data *data; const struct i2c_device_id *mid; + const struct coefficients *coefficients; + int vindex = -1, cindex = -1, pindex = -1; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA @@ -291,61 +321,34 @@ static int adm1275_probe(struct i2c_client *client, info->format[PSC_VOLTAGE_IN] = direct; info->format[PSC_VOLTAGE_OUT] = direct; info->format[PSC_CURRENT_OUT] = direct; - info->m[PSC_CURRENT_OUT] = 807; - info->b[PSC_CURRENT_OUT] = 20475; - info->R[PSC_CURRENT_OUT] = -1; + info->format[PSC_POWER] = direct; info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; info->read_word_data = adm1275_read_word_data; info->read_byte_data = adm1275_read_byte_data; info->write_word_data = adm1275_write_word_data; - if (data->id == adm1075) { - info->m[PSC_VOLTAGE_IN] = 27169; - info->b[PSC_VOLTAGE_IN] = 0; - info->R[PSC_VOLTAGE_IN] = -1; - info->m[PSC_VOLTAGE_OUT] = 27169; - info->b[PSC_VOLTAGE_OUT] = 0; - info->R[PSC_VOLTAGE_OUT] = -1; - } else if (config & ADM1275_VRANGE) { - info->m[PSC_VOLTAGE_IN] = 19199; - info->b[PSC_VOLTAGE_IN] = 0; - info->R[PSC_VOLTAGE_IN] = -2; - info->m[PSC_VOLTAGE_OUT] = 19199; - info->b[PSC_VOLTAGE_OUT] = 0; - info->R[PSC_VOLTAGE_OUT] = -2; - } else { - info->m[PSC_VOLTAGE_IN] = 6720; - info->b[PSC_VOLTAGE_IN] = 0; - info->R[PSC_VOLTAGE_IN] = -1; - info->m[PSC_VOLTAGE_OUT] = 6720; - info->b[PSC_VOLTAGE_OUT] = 0; - info->R[PSC_VOLTAGE_OUT] = -1; - } - if (device_config & ADM1275_IOUT_WARN2_SELECT) data->have_oc_fault = true; switch (data->id) { case adm1075: - info->format[PSC_POWER] = direct; - info->b[PSC_POWER] = 0; - info->R[PSC_POWER] = -1; + coefficients = adm1075_coefficients; + vindex = 0; switch (config & ADM1075_IRANGE_MASK) { case ADM1075_IRANGE_25: - info->m[PSC_POWER] = 8549; - info->m[PSC_CURRENT_OUT] = 806; + cindex = 1; + pindex = 3; break; case ADM1075_IRANGE_50: - info->m[PSC_POWER] = 4279; - info->m[PSC_CURRENT_OUT] = 404; + cindex = 2; + pindex = 4; break; default: dev_err(&client->dev, "Invalid input current range"); - info->m[PSC_POWER] = 0; - info->m[PSC_CURRENT_OUT] = 0; break; } + info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT; if (config & ADM1275_VIN_VOUT_SELECT) @@ -353,6 +356,10 @@ static int adm1275_probe(struct i2c_client *client, PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; break; case adm1275: + coefficients = adm1275_coefficients; + vindex = (config & ADM1275_VRANGE) ? 0 : 1; + cindex = 2; + if (config & ADM1275_VIN_VOUT_SELECT) info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; @@ -361,22 +368,38 @@ static int adm1275_probe(struct i2c_client *client, PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; break; case adm1276: - info->format[PSC_POWER] = direct; + coefficients = adm1276_coefficients; + vindex = (config & ADM1275_VRANGE) ? 0 : 1; + cindex = 2; + pindex = (config & ADM1275_VRANGE) ? 3 : 4; + info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT; if (config & ADM1275_VIN_VOUT_SELECT) info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; - if (config & ADM1275_VRANGE) { - info->m[PSC_POWER] = 6043; - info->b[PSC_POWER] = 0; - info->R[PSC_POWER] = -2; - } else { - info->m[PSC_POWER] = 2115; - info->b[PSC_POWER] = 0; - info->R[PSC_POWER] = -1; - } break; + default: + dev_err(&client->dev, "Unsupported device\n"); + return -ENODEV; + } + if (vindex >= 0) { + info->m[PSC_VOLTAGE_IN] = coefficients[vindex].m; + info->b[PSC_VOLTAGE_IN] = coefficients[vindex].b; + info->R[PSC_VOLTAGE_IN] = coefficients[vindex].R; + info->m[PSC_VOLTAGE_OUT] = coefficients[vindex].m; + info->b[PSC_VOLTAGE_OUT] = coefficients[vindex].b; + info->R[PSC_VOLTAGE_OUT] = coefficients[vindex].R; + } + if (cindex >= 0) { + info->m[PSC_CURRENT_OUT] = coefficients[cindex].m; + info->b[PSC_CURRENT_OUT] = coefficients[cindex].b; + info->R[PSC_CURRENT_OUT] = coefficients[cindex].R; + } + if (pindex >= 0) { + info->m[PSC_POWER] = coefficients[pindex].m; + info->b[PSC_POWER] = coefficients[pindex].b; + info->R[PSC_POWER] = coefficients[pindex].R; } return pmbus_do_probe(client, id, info); -- cgit v1.1 From 9048539b7cd6ca99e03e6d9745779473349426f7 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 4 Jul 2015 10:09:54 -0700 Subject: hwmon: (adm1275) Introduce new feature flags Introduce have_vout, have_vaux_status, have_pin_max, and have_uc_fault to simplify adding support for new chips. Also simplify error returns where appropriate to return immediately on error. Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/adm1275.c | 97 ++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 3a8d69b..1c19a2e 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -57,6 +57,10 @@ enum chips { adm1075, adm1275, adm1276 }; struct adm1275_data { int id; bool have_oc_fault; + bool have_uc_fault; + bool have_vout; + bool have_vaux_status; + bool have_pin_max; struct pmbus_driver_info info; }; @@ -101,40 +105,30 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) switch (reg) { case PMBUS_IOUT_UC_FAULT_LIMIT: - if (data->have_oc_fault) { - ret = -ENXIO; - break; - } + if (!data->have_uc_fault) + return -ENXIO; ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); break; case PMBUS_IOUT_OC_FAULT_LIMIT: - if (!data->have_oc_fault) { - ret = -ENXIO; - break; - } + if (!data->have_oc_fault) + return -ENXIO; ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); break; case PMBUS_VOUT_OV_WARN_LIMIT: - if (data->id != adm1075) { - ret = -ENODATA; - break; - } + if (data->have_vout) + return -ENODATA; ret = pmbus_read_word_data(client, 0, ADM1075_VAUX_OV_WARN_LIMIT); break; case PMBUS_VOUT_UV_WARN_LIMIT: - if (data->id != adm1075) { - ret = -ENODATA; - break; - } + if (data->have_vout) + return -ENODATA; ret = pmbus_read_word_data(client, 0, ADM1075_VAUX_UV_WARN_LIMIT); break; case PMBUS_READ_VOUT: - if (data->id != adm1075) { - ret = -ENODATA; - break; - } + if (data->have_vout) + return -ENODATA; ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX); break; case PMBUS_VIRT_READ_IOUT_MAX: @@ -147,10 +141,8 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN); break; case PMBUS_VIRT_READ_PIN_MAX: - if (data->id == adm1275) { - ret = -ENXIO; - break; - } + if (!data->have_pin_max) + return -ENXIO; ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN); break; case PMBUS_VIRT_RESET_IOUT_HISTORY: @@ -158,8 +150,8 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) case PMBUS_VIRT_RESET_VIN_HISTORY: break; case PMBUS_VIRT_RESET_PIN_HISTORY: - if (data->id == adm1275) - ret = -ENXIO; + if (!data->have_pin_max) + return -ENXIO; break; default: ret = -ENODATA; @@ -215,29 +207,31 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT); if (ret < 0) break; + if (!data->have_oc_fault && !data->have_uc_fault) + break; mfr_status = pmbus_read_byte_data(client, page, PMBUS_STATUS_MFR_SPECIFIC); - if (mfr_status < 0) { - ret = mfr_status; - break; - } + if (mfr_status < 0) + return mfr_status; if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) { ret |= data->have_oc_fault ? PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT; } break; case PMBUS_STATUS_VOUT: - if (data->id != adm1075) { - ret = -ENODATA; - break; - } + if (data->have_vout) + return -ENODATA; ret = 0; - mfr_status = pmbus_read_byte_data(client, 0, - ADM1075_VAUX_STATUS); - if (mfr_status & ADM1075_VAUX_OV_WARN) - ret |= PB_VOLTAGE_OV_WARNING; - if (mfr_status & ADM1075_VAUX_UV_WARN) - ret |= PB_VOLTAGE_UV_WARNING; + if (data->have_vaux_status) { + mfr_status = pmbus_read_byte_data(client, 0, + ADM1075_VAUX_STATUS); + if (mfr_status < 0) + return mfr_status; + if (mfr_status & ADM1075_VAUX_OV_WARN) + ret |= PB_VOLTAGE_OV_WARNING; + if (mfr_status & ADM1075_VAUX_UV_WARN) + ret |= PB_VOLTAGE_UV_WARNING; + } break; default: ret = -ENODATA; @@ -328,11 +322,15 @@ static int adm1275_probe(struct i2c_client *client, info->read_byte_data = adm1275_read_byte_data; info->write_word_data = adm1275_write_word_data; - if (device_config & ADM1275_IOUT_WARN2_SELECT) - data->have_oc_fault = true; - switch (data->id) { case adm1075: + if (device_config & ADM1275_IOUT_WARN2_SELECT) + data->have_oc_fault = true; + else + data->have_uc_fault = true; + data->have_pin_max = true; + data->have_vaux_status = true; + coefficients = adm1075_coefficients; vindex = 0; switch (config & ADM1075_IRANGE_MASK) { @@ -356,6 +354,12 @@ static int adm1275_probe(struct i2c_client *client, PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; break; case adm1275: + if (device_config & ADM1275_IOUT_WARN2_SELECT) + data->have_oc_fault = true; + else + data->have_uc_fault = true; + data->have_vout = true; + coefficients = adm1275_coefficients; vindex = (config & ADM1275_VRANGE) ? 0 : 1; cindex = 2; @@ -368,6 +372,13 @@ static int adm1275_probe(struct i2c_client *client, PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; break; case adm1276: + if (device_config & ADM1275_IOUT_WARN2_SELECT) + data->have_oc_fault = true; + else + data->have_uc_fault = true; + data->have_vout = true; + data->have_pin_max = true; + coefficients = adm1276_coefficients; vindex = (config & ADM1275_VRANGE) ? 0 : 1; cindex = 2; -- cgit v1.1 From 48065a138acb8435c60739ffa62622d69f61b712 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 5 Jul 2015 13:45:43 -0700 Subject: hwmon: (pmbus) Add support for lowest power value attributes Add support for powerX_input_lowest for both input and output power. Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus.h | 50 +++++++++++++++++++++------------------- drivers/hwmon/pmbus/pmbus_core.c | 8 +++++++ 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 58262b5..2427f6e 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -162,30 +162,32 @@ #define PMBUS_VIRT_READ_IIN_MAX (PMBUS_VIRT_BASE + 10) #define PMBUS_VIRT_RESET_IIN_HISTORY (PMBUS_VIRT_BASE + 11) #define PMBUS_VIRT_READ_PIN_AVG (PMBUS_VIRT_BASE + 12) -#define PMBUS_VIRT_READ_PIN_MAX (PMBUS_VIRT_BASE + 13) -#define PMBUS_VIRT_RESET_PIN_HISTORY (PMBUS_VIRT_BASE + 14) -#define PMBUS_VIRT_READ_POUT_AVG (PMBUS_VIRT_BASE + 15) -#define PMBUS_VIRT_READ_POUT_MAX (PMBUS_VIRT_BASE + 16) -#define PMBUS_VIRT_RESET_POUT_HISTORY (PMBUS_VIRT_BASE + 17) -#define PMBUS_VIRT_READ_VOUT_AVG (PMBUS_VIRT_BASE + 18) -#define PMBUS_VIRT_READ_VOUT_MIN (PMBUS_VIRT_BASE + 19) -#define PMBUS_VIRT_READ_VOUT_MAX (PMBUS_VIRT_BASE + 20) -#define PMBUS_VIRT_RESET_VOUT_HISTORY (PMBUS_VIRT_BASE + 21) -#define PMBUS_VIRT_READ_IOUT_AVG (PMBUS_VIRT_BASE + 22) -#define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 23) -#define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 24) -#define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 25) -#define PMBUS_VIRT_READ_TEMP2_AVG (PMBUS_VIRT_BASE + 26) -#define PMBUS_VIRT_READ_TEMP2_MIN (PMBUS_VIRT_BASE + 27) -#define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 28) -#define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 29) - -#define PMBUS_VIRT_READ_VMON (PMBUS_VIRT_BASE + 30) -#define PMBUS_VIRT_VMON_UV_WARN_LIMIT (PMBUS_VIRT_BASE + 31) -#define PMBUS_VIRT_VMON_OV_WARN_LIMIT (PMBUS_VIRT_BASE + 32) -#define PMBUS_VIRT_VMON_UV_FAULT_LIMIT (PMBUS_VIRT_BASE + 33) -#define PMBUS_VIRT_VMON_OV_FAULT_LIMIT (PMBUS_VIRT_BASE + 34) -#define PMBUS_VIRT_STATUS_VMON (PMBUS_VIRT_BASE + 35) +#define PMBUS_VIRT_READ_PIN_MIN (PMBUS_VIRT_BASE + 13) +#define PMBUS_VIRT_READ_PIN_MAX (PMBUS_VIRT_BASE + 14) +#define PMBUS_VIRT_RESET_PIN_HISTORY (PMBUS_VIRT_BASE + 15) +#define PMBUS_VIRT_READ_POUT_AVG (PMBUS_VIRT_BASE + 16) +#define PMBUS_VIRT_READ_POUT_MIN (PMBUS_VIRT_BASE + 17) +#define PMBUS_VIRT_READ_POUT_MAX (PMBUS_VIRT_BASE + 18) +#define PMBUS_VIRT_RESET_POUT_HISTORY (PMBUS_VIRT_BASE + 19) +#define PMBUS_VIRT_READ_VOUT_AVG (PMBUS_VIRT_BASE + 20) +#define PMBUS_VIRT_READ_VOUT_MIN (PMBUS_VIRT_BASE + 21) +#define PMBUS_VIRT_READ_VOUT_MAX (PMBUS_VIRT_BASE + 22) +#define PMBUS_VIRT_RESET_VOUT_HISTORY (PMBUS_VIRT_BASE + 23) +#define PMBUS_VIRT_READ_IOUT_AVG (PMBUS_VIRT_BASE + 24) +#define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 25) +#define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 26) +#define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 27) +#define PMBUS_VIRT_READ_TEMP2_AVG (PMBUS_VIRT_BASE + 28) +#define PMBUS_VIRT_READ_TEMP2_MIN (PMBUS_VIRT_BASE + 29) +#define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 30) +#define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 31) + +#define PMBUS_VIRT_READ_VMON (PMBUS_VIRT_BASE + 32) +#define PMBUS_VIRT_VMON_UV_WARN_LIMIT (PMBUS_VIRT_BASE + 33) +#define PMBUS_VIRT_VMON_OV_WARN_LIMIT (PMBUS_VIRT_BASE + 34) +#define PMBUS_VIRT_VMON_UV_FAULT_LIMIT (PMBUS_VIRT_BASE + 35) +#define PMBUS_VIRT_VMON_OV_FAULT_LIMIT (PMBUS_VIRT_BASE + 36) +#define PMBUS_VIRT_STATUS_VMON (PMBUS_VIRT_BASE + 37) /* * OPERATION diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 12d85b1..306a1b1 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -1329,6 +1329,10 @@ static const struct pmbus_limit_attr pin_limit_attrs[] = { .update = true, .attr = "average", }, { + .reg = PMBUS_VIRT_READ_PIN_MIN, + .update = true, + .attr = "input_lowest", + }, { .reg = PMBUS_VIRT_READ_PIN_MAX, .update = true, .attr = "input_highest", @@ -1359,6 +1363,10 @@ static const struct pmbus_limit_attr pout_limit_attrs[] = { .update = true, .attr = "average", }, { + .reg = PMBUS_VIRT_READ_POUT_MIN, + .update = true, + .attr = "input_lowest", + }, { .reg = PMBUS_VIRT_READ_POUT_MAX, .update = true, .attr = "input_highest", -- cgit v1.1 From 68a403823600fc9d8277f930981d3a013353b2fe Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 17 Mar 2015 13:19:51 -0700 Subject: hwmon: (adm1275) Add support for ADM1293 and ADM1294 ADM1293 and ADM1294 are mostly compatible with other chips of the same series, but have more configuration options. There are also some differences in register details. Signed-off-by: Guenter Roeck --- Documentation/hwmon/adm1275 | 40 +++++++----- drivers/hwmon/pmbus/Kconfig | 4 +- drivers/hwmon/pmbus/adm1275.c | 141 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 158 insertions(+), 27 deletions(-) diff --git a/Documentation/hwmon/adm1275 b/Documentation/hwmon/adm1275 index 15b4a20..d697229 100644 --- a/Documentation/hwmon/adm1275 +++ b/Documentation/hwmon/adm1275 @@ -14,6 +14,10 @@ Supported chips: Prefix: 'adm1276' Addresses scanned: - Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1276.pdf + * Analog Devices ADM1293/ADM1294 + Prefix: 'adm1293', 'adm1294' + Addresses scanned: - + Datasheet: http://www.analog.com/media/en/technical-documentation/data-sheets/ADM1293_1294.pdf Author: Guenter Roeck @@ -22,12 +26,12 @@ Description ----------- This driver supports hardware montoring for Analog Devices ADM1075, ADM1275, -and ADM1276 Hot-Swap Controller and Digital Power Monitor. +ADM1276, ADM1293, and ADM1294 Hot-Swap Controller and Digital Power Monitors. -ADM1075, ADM1275, and ADM1276 are hot-swap controllers that allow a circuit -board to be removed from or inserted into a live backplane. They also feature -current and voltage readback via an integrated 12-bit analog-to-digital -converter (ADC), accessed using a PMBus interface. +ADM1075, ADM1275, ADM1276, ADM1293, and ADM1294 are hot-swap controllers that +allow a circuit board to be removed from or inserted into a live backplane. +They also feature current and voltage readback via an integrated 12 +bit analog-to-digital converter (ADC), accessed using a PMBus interface. The driver is a client driver to the core PMBus driver. Please see Documentation/hwmon/pmbus for details on PMBus client drivers. @@ -58,16 +62,16 @@ Sysfs entries The following attributes are supported. Limits are read-write, history reset attributes are write-only, all other attributes are read-only. -in1_label "vin1" or "vout1" depending on chip variant and - configuration. On ADM1075, vout1 reports the voltage on - the VAUX pin. -in1_input Measured voltage. -in1_min Minimum Voltage. -in1_max Maximum voltage. -in1_min_alarm Voltage low alarm. -in1_max_alarm Voltage high alarm. -in1_highest Historical maximum voltage. -in1_reset_history Write any value to reset history. +inX_label "vin1" or "vout1" depending on chip variant and + configuration. On ADM1075, ADM1293, and ADM1294, + vout1 reports the voltage on the VAUX pin. +inX_input Measured voltage. +inX_min Minimum Voltage. +inX_max Maximum voltage. +inX_min_alarm Voltage low alarm. +inX_max_alarm Voltage high alarm. +inX_highest Historical maximum voltage. +inX_reset_history Write any value to reset history. curr1_label "iout1" curr1_input Measured current. @@ -86,7 +90,9 @@ curr1_reset_history Write any value to reset history. power1_label "pin1" power1_input Input power. +power1_input_lowest Lowest observed input power. ADM1293 and ADM1294 only. +power1_input_highest Highest observed input power. power1_reset_history Write any value to reset history. - Power attributes are supported on ADM1075 and ADM1276 - only. + Power attributes are supported on ADM1075, ADM1276, + ADM1293, and ADM1294. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 9f7dbd1..67901cb 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -30,8 +30,8 @@ config SENSORS_ADM1275 default n help If you say yes here you get hardware monitoring support for Analog - Devices ADM1075, ADM1275, and ADM1276 Hot-Swap Controller and Digital - Power Monitors. + Devices ADM1075, ADM1275, ADM1276, ADM1293, and ADM1294 Hot-Swap + Controller and Digital Power Monitors. This driver can also be built as a module. If so, the module will be called adm1275. diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 1c19a2e..188af4c 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -24,7 +24,11 @@ #include #include "pmbus.h" -enum chips { adm1075, adm1275, adm1276 }; +enum chips { adm1075, adm1275, adm1276, adm1293, adm1294 }; + +#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) +#define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5) +#define ADM1293_MFR_STATUS_VAUX_OV_WARN BIT(6) #define ADM1275_PEAK_IOUT 0xd0 #define ADM1275_PEAK_VIN 0xd1 @@ -37,18 +41,30 @@ enum chips { adm1075, adm1275, adm1276 }; #define ADM1075_IRANGE_25 BIT(3) #define ADM1075_IRANGE_MASK (BIT(3) | BIT(4)) +#define ADM1293_IRANGE_25 0 +#define ADM1293_IRANGE_50 BIT(6) +#define ADM1293_IRANGE_100 BIT(7) +#define ADM1293_IRANGE_200 (BIT(6) | BIT(7)) +#define ADM1293_IRANGE_MASK (BIT(6) | BIT(7)) + +#define ADM1293_VIN_SEL_012 BIT(2) +#define ADM1293_VIN_SEL_074 BIT(3) +#define ADM1293_VIN_SEL_210 (BIT(2) | BIT(3)) +#define ADM1293_VIN_SEL_MASK (BIT(2) | BIT(3)) + +#define ADM1293_VAUX_EN BIT(1) + #define ADM1275_IOUT_WARN2_LIMIT 0xd7 #define ADM1275_DEVICE_CONFIG 0xd8 #define ADM1275_IOUT_WARN2_SELECT BIT(4) #define ADM1276_PEAK_PIN 0xda - -#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) - #define ADM1075_READ_VAUX 0xdd #define ADM1075_VAUX_OV_WARN_LIMIT 0xde #define ADM1075_VAUX_UV_WARN_LIMIT 0xdf +#define ADM1293_IOUT_MIN 0xe3 +#define ADM1293_PIN_MIN 0xe4 #define ADM1075_VAUX_STATUS 0xf6 #define ADM1075_VAUX_OV_WARN BIT(7) @@ -60,6 +76,9 @@ struct adm1275_data { bool have_uc_fault; bool have_vout; bool have_vaux_status; + bool have_mfr_vaux_status; + bool have_iout_min; + bool have_pin_min; bool have_pin_max; struct pmbus_driver_info info; }; @@ -94,6 +113,28 @@ static const struct coefficients adm1276_coefficients[] = { [4] = { 2115, 0, -1 }, /* power, vrange not set */ }; +static const struct coefficients adm1293_coefficients[] = { + [0] = { 3333, -1, 0 }, /* voltage, vrange 1.2V */ + [1] = { 5552, -5, -1 }, /* voltage, vrange 7.4V */ + [2] = { 19604, -50, -2 }, /* voltage, vrange 21V */ + [3] = { 8000, -100, -2 }, /* current, irange25 */ + [4] = { 4000, -100, -2 }, /* current, irange50 */ + [5] = { 20000, -1000, -3 }, /* current, irange100 */ + [6] = { 10000, -1000, -3 }, /* current, irange200 */ + [7] = { 10417, 0, -1 }, /* power, 1.2V, irange25 */ + [8] = { 5208, 0, -1 }, /* power, 1.2V, irange50 */ + [9] = { 26042, 0, -2 }, /* power, 1.2V, irange100 */ + [10] = { 13021, 0, -2 }, /* power, 1.2V, irange200 */ + [11] = { 17351, 0, -2 }, /* power, 7.4V, irange25 */ + [12] = { 8676, 0, -2 }, /* power, 7.4V, irange50 */ + [13] = { 4338, 0, -2 }, /* power, 7.4V, irange100 */ + [14] = { 21689, 0, -3 }, /* power, 7.4V, irange200 */ + [15] = { 6126, 0, -2 }, /* power, 21V, irange25 */ + [16] = { 30631, 0, -3 }, /* power, 21V, irange50 */ + [17] = { 15316, 0, -3 }, /* power, 21V, irange100 */ + [18] = { 7658, 0, -3 }, /* power, 21V, irange200 */ +}; + static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); @@ -131,6 +172,11 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) return -ENODATA; ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX); break; + case PMBUS_VIRT_READ_IOUT_MIN: + if (!data->have_iout_min) + return -ENXIO; + ret = pmbus_read_word_data(client, 0, ADM1293_IOUT_MIN); + break; case PMBUS_VIRT_READ_IOUT_MAX: ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT); break; @@ -140,6 +186,11 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) case PMBUS_VIRT_READ_VIN_MAX: ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN); break; + case PMBUS_VIRT_READ_PIN_MIN: + if (!data->have_pin_min) + return -ENXIO; + ret = pmbus_read_word_data(client, 0, ADM1293_PIN_MIN); + break; case PMBUS_VIRT_READ_PIN_MAX: if (!data->have_pin_max) return -ENXIO; @@ -163,6 +214,8 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, u16 word) { + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + const struct adm1275_data *data = to_adm1275_data(info); int ret; if (page) @@ -176,6 +229,9 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, break; case PMBUS_VIRT_RESET_IOUT_HISTORY: ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0); + if (!ret && data->have_iout_min) + ret = pmbus_write_word_data(client, 0, + ADM1293_IOUT_MIN, 0); break; case PMBUS_VIRT_RESET_VOUT_HISTORY: ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0); @@ -185,6 +241,9 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, break; case PMBUS_VIRT_RESET_PIN_HISTORY: ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0); + if (!ret && data->have_pin_min) + ret = pmbus_write_word_data(client, 0, + ADM1293_PIN_MIN, 0); break; default: ret = -ENODATA; @@ -231,6 +290,15 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) ret |= PB_VOLTAGE_OV_WARNING; if (mfr_status & ADM1075_VAUX_UV_WARN) ret |= PB_VOLTAGE_UV_WARNING; + } else if (data->have_mfr_vaux_status) { + mfr_status = pmbus_read_byte_data(client, page, + PMBUS_STATUS_MFR_SPECIFIC); + if (mfr_status < 0) + return mfr_status; + if (mfr_status & ADM1293_MFR_STATUS_VAUX_OV_WARN) + ret |= PB_VOLTAGE_OV_WARNING; + if (mfr_status & ADM1293_MFR_STATUS_VAUX_UV_WARN) + ret |= PB_VOLTAGE_UV_WARNING; } break; default: @@ -244,6 +312,8 @@ static const struct i2c_device_id adm1275_id[] = { { "adm1075", adm1075 }, { "adm1275", adm1275 }, { "adm1276", adm1276 }, + { "adm1293", adm1293 }, + { "adm1294", adm1294 }, { } }; MODULE_DEVICE_TABLE(i2c, adm1275_id); @@ -258,7 +328,7 @@ static int adm1275_probe(struct i2c_client *client, struct adm1275_data *data; const struct i2c_device_id *mid; const struct coefficients *coefficients; - int vindex = -1, cindex = -1, pindex = -1; + int vindex = -1, voindex = -1, cindex = -1, pindex = -1; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA @@ -390,17 +460,72 @@ static int adm1275_probe(struct i2c_client *client, info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; break; + case adm1293: + case adm1294: + data->have_iout_min = true; + data->have_pin_min = true; + data->have_pin_max = true; + data->have_mfr_vaux_status = true; + + coefficients = adm1293_coefficients; + + voindex = 0; + switch (config & ADM1293_VIN_SEL_MASK) { + case ADM1293_VIN_SEL_012: /* 1.2V */ + vindex = 0; + break; + case ADM1293_VIN_SEL_074: /* 7.4V */ + vindex = 1; + break; + case ADM1293_VIN_SEL_210: /* 21V */ + vindex = 2; + break; + default: /* disabled */ + break; + } + + switch (config & ADM1293_IRANGE_MASK) { + case ADM1293_IRANGE_25: + cindex = 3; + break; + case ADM1293_IRANGE_50: + cindex = 4; + break; + case ADM1293_IRANGE_100: + cindex = 5; + break; + case ADM1293_IRANGE_200: + cindex = 6; + break; + } + + if (vindex >= 0) + pindex = 7 + vindex * 4 + (cindex - 3); + + if (config & ADM1293_VAUX_EN) + info->func[0] |= + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; + + info->func[0] |= PMBUS_HAVE_PIN | + PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; + + break; default: dev_err(&client->dev, "Unsupported device\n"); return -ENODEV; } + + if (voindex < 0) + voindex = vindex; if (vindex >= 0) { info->m[PSC_VOLTAGE_IN] = coefficients[vindex].m; info->b[PSC_VOLTAGE_IN] = coefficients[vindex].b; info->R[PSC_VOLTAGE_IN] = coefficients[vindex].R; - info->m[PSC_VOLTAGE_OUT] = coefficients[vindex].m; - info->b[PSC_VOLTAGE_OUT] = coefficients[vindex].b; - info->R[PSC_VOLTAGE_OUT] = coefficients[vindex].R; + } + if (voindex >= 0) { + info->m[PSC_VOLTAGE_OUT] = coefficients[voindex].m; + info->b[PSC_VOLTAGE_OUT] = coefficients[voindex].b; + info->R[PSC_VOLTAGE_OUT] = coefficients[voindex].R; } if (cindex >= 0) { info->m[PSC_CURRENT_OUT] = coefficients[cindex].m; -- cgit v1.1 From aeaa4d9f812bfd841643b37f65c6b6597045be37 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 8 Jun 2015 11:01:50 -0700 Subject: hwmon: (ltc2978) LTM4676 supports CLEAR_PEAKS Use the CLEAR_PEAKS command on LTM4676. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/ltc2978.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 0835050..33081d1 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -313,7 +313,7 @@ static int ltc2978_clear_peaks(struct i2c_client *client, int page, { int ret; - if (id == ltc3880 || id == ltc3883) + if (id == ltc3880 || id == ltc3883 || id == ltm4676) ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); else ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); -- cgit v1.1 From a1dc86ebd2f2eb6652c8be9311c16acccd1708f8 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sun, 19 Jul 2015 00:29:14 +0200 Subject: hwmon: (lm70) add device tree support Allow the lm70 to be probed from a device tree. Signed-off-by: Rabin Vincent Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/lm70.txt | 21 +++++++++++++++ drivers/hwmon/lm70.c | 34 +++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/hwmon/lm70.txt diff --git a/Documentation/devicetree/bindings/hwmon/lm70.txt b/Documentation/devicetree/bindings/hwmon/lm70.txt new file mode 100644 index 0000000..e7fd921 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/lm70.txt @@ -0,0 +1,21 @@ +* LM70/TMP121/LM71/LM74 thermometer. + +Required properties: +- compatible: one of + "ti,lm70" + "ti,tmp121" + "ti,lm71" + "ti,lm74" + +See Documentation/devicetree/bindings/spi/spi-bus.txt for more required and +optional properties. + +Example: + +spi_master { + temperature-sensor@0 { + compatible = "ti,lm70"; + reg = <0>; + spi-max-frequency = <1000000>; + }; +}; diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 97204dc..9296e9d 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -37,6 +37,7 @@ #include #include #include +#include #define DRVNAME "lm70" @@ -130,11 +131,41 @@ ATTRIBUTE_GROUPS(lm70); /*----------------------------------------------------------------------*/ +#ifdef CONFIG_OF +static const struct of_device_id lm70_of_ids[] = { + { + .compatible = "ti,lm70", + .data = (void *) LM70_CHIP_LM70, + }, + { + .compatible = "ti,tmp121", + .data = (void *) LM70_CHIP_TMP121, + }, + { + .compatible = "ti,lm71", + .data = (void *) LM70_CHIP_LM71, + }, + { + .compatible = "ti,lm74", + .data = (void *) LM70_CHIP_LM74, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, lm70_of_ids); +#endif + static int lm70_probe(struct spi_device *spi) { - int chip = spi_get_device_id(spi)->driver_data; + const struct of_device_id *match; struct device *hwmon_dev; struct lm70 *p_lm70; + int chip; + + match = of_match_device(lm70_of_ids, &spi->dev); + if (match) + chip = (int)(uintptr_t)match->data; + else + chip = spi_get_device_id(spi)->driver_data; /* signaling is SPI_MODE_0 */ if (spi->mode & (SPI_CPOL | SPI_CPHA)) @@ -169,6 +200,7 @@ static struct spi_driver lm70_driver = { .driver = { .name = "lm70", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lm70_of_ids), }, .id_table = lm70_ids, .probe = lm70_probe, -- cgit v1.1 From 1c6e8f6ba89c59270db223284d47e3c928c6fbfc Mon Sep 17 00:00:00 2001 From: Constantine Shulyupin Date: Tue, 28 Jul 2015 01:01:07 +0300 Subject: hwmon: (nct7802) Add auto_point attributes Introduced REG_PWM, pwm[1..3]_auto_point[1..5]_temp, pwm[1..3]_auto_point[1..5]_pwm, nct7802_auto_point_attrs, nct7802_auto_point_group, updated nct7802_regmap_is_volatile Signed-off-by: Constantine Shulyupin Signed-off-by: Guenter Roeck --- Documentation/hwmon/nct7802 | 3 +- drivers/hwmon/nct7802.c | 130 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 127 insertions(+), 6 deletions(-) diff --git a/Documentation/hwmon/nct7802 b/Documentation/hwmon/nct7802 index 2e00f5e..5438deb 100644 --- a/Documentation/hwmon/nct7802 +++ b/Documentation/hwmon/nct7802 @@ -17,8 +17,7 @@ This driver implements support for the Nuvoton NCT7802Y hardware monitoring chip. NCT7802Y supports 6 temperature sensors, 5 voltage sensors, and 3 fan speed sensors. -The chip also supports intelligent fan speed control. This functionality is -not currently supported by the driver. +Smart Fan™ speed control is available via pwmX_auto_point attributes. Tested Boards and BIOS Versions ------------------------------- diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index f4908bb..3ce33d2 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -53,6 +53,7 @@ static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = { #define REG_PECI_ENABLE 0x23 #define REG_FAN_ENABLE 0x24 #define REG_VMON_ENABLE 0x25 +#define REG_PWM(x) (0x60 + (x)) #define REG_SMARTFAN_EN(x) (0x64 + (x) / 2) #define SMARTFAN_EN_SHIFT(x) ((x) % 2 * 4) #define REG_VENDOR_ID 0xfd @@ -130,6 +131,9 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, unsigned int val; int ret; + if (!attr->index) + return sprintf(buf, "255\n"); + ret = regmap_read(data->regmap, attr->index, &val); if (ret < 0) return ret; @@ -826,9 +830,12 @@ static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO, show_pwm_mode, NULL, 1); static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2); /* 7.2.91... Fan Control Output Value */ -static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x60); -static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x61); -static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x62); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, + REG_PWM(0)); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, + REG_PWM(1)); +static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, + REG_PWM(2)); /* 7.2.95... Temperature to Fan mapping Relationships Register */ static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, @@ -893,11 +900,125 @@ static struct attribute_group nct7802_pwm_group = { .attrs = nct7802_pwm_attrs, }; +/* 7.2.115... 0x80-0x83, 0x84 Temperature (X-axis) transition */ +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x80, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x81, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x82, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x83, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point5_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x84, 0); + +/* 7.2.120... 0x85-0x88 PWM (Y-axis) transition */ +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x85); +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x86); +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x87); +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x88); +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm, NULL, 0); + +/* 7.2.124 Table 2 X-axis Transition Point 1 Register */ +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x90, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x91, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x92, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x93, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point5_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x94, 0); + +/* 7.2.129 Table 2 Y-axis Transition Point 1 Register */ +static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x95); +static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x96); +static SENSOR_DEVICE_ATTR(pwm2_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x97); +static SENSOR_DEVICE_ATTR(pwm2_auto_point4_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x98); +static SENSOR_DEVICE_ATTR(pwm2_auto_point5_pwm, S_IRUGO, show_pwm, NULL, 0); + +/* 7.2.133 Table 3 X-axis Transition Point 1 Register */ +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA0, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA1, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA2, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA3, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point5_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA4, 0); + +/* 7.2.138 Table 3 Y-axis Transition Point 1 Register */ +static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0xA5); +static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0xA6); +static SENSOR_DEVICE_ATTR(pwm3_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0xA7); +static SENSOR_DEVICE_ATTR(pwm3_auto_point4_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0xA8); +static SENSOR_DEVICE_ATTR(pwm3_auto_point5_pwm, S_IRUGO, show_pwm, NULL, 0); + +static struct attribute *nct7802_auto_point_attrs[] = { + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr, + + &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr, + + &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point5_temp.dev_attr.attr, + + &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point5_pwm.dev_attr.attr, + + &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point5_temp.dev_attr.attr, + + &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point5_pwm.dev_attr.attr, + + NULL +}; + +static struct attribute_group nct7802_auto_point_group = { + .attrs = nct7802_auto_point_attrs, +}; + static const struct attribute_group *nct7802_groups[] = { &nct7802_temp_group, &nct7802_in_group, &nct7802_fan_group, &nct7802_pwm_group, + &nct7802_auto_point_group, NULL }; @@ -945,7 +1066,8 @@ static int nct7802_detect(struct i2c_client *client, static bool nct7802_regmap_is_volatile(struct device *dev, unsigned int reg) { - return reg != REG_BANK && reg <= 0x20; + return (reg != REG_BANK && reg <= 0x20) || + (reg >= REG_PWM(0) && reg <= REG_PWM(2)); } static const struct regmap_config nct7802_regmap_config = { -- cgit v1.1 From ead8080351c988b9c4bb5ec261d7b4c97ebb2773 Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Wed, 5 Aug 2015 12:53:08 -0700 Subject: hwmon: (it87) Add support for IT8732F Add support for the IT8732F. This chip is pretty similar to IT8721F, with the main difference being that the ADC LSB is 10.9 mV instead of 12 mV. Signed-off-by: Justin Maggard Signed-off-by: Guenter Roeck --- Documentation/hwmon/it87 | 35 ++++++++++++++++++++++------------- drivers/hwmon/Kconfig | 4 ++-- drivers/hwmon/it87.c | 43 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index e872948..733296d 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -38,6 +38,10 @@ Supported chips: Prefix: 'it8728' Addresses scanned: from Super I/O config space (8 I/O ports) Datasheet: Not publicly available + * IT8732F + Prefix: 'it8732' + Addresses scanned: from Super I/O config space (8 I/O ports) + Datasheet: Not publicly available * IT8771E Prefix: 'it8771' Addresses scanned: from Super I/O config space (8 I/O ports) @@ -111,9 +115,9 @@ Description ----------- This driver implements support for the IT8603E, IT8620E, IT8623E, IT8705F, -IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, -IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, and SiS950 -chips. +IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F, +IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, and +SiS950 chips. These chips are 'Super I/O chips', supporting floppy disks, infrared ports, joysticks and other miscellaneous stuff. For hardware monitoring, they @@ -137,10 +141,10 @@ The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E and later IT8712F revisions have support for 2 additional fans. The additional fans are supported by the driver. -The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E, IT8781F, IT8782F, IT8783E/F, -and late IT8712F and IT8705F also have optional 16-bit tachometer counters -for fans 1 to 3. This is better (no more fan clock divider mess) but not -compatible with the older chips and revisions. The 16-bit tachometer mode +The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E, IT8732F, IT8781F, IT8782F, +IT8783E/F, and late IT8712F and IT8705F also have optional 16-bit tachometer +counters for fans 1 to 3. This is better (no more fan clock divider mess) but +not compatible with the older chips and revisions. The 16-bit tachometer mode is enabled by the driver when one of the above chips is detected. The IT8726F is just bit enhanced IT8716F with additional hardware @@ -159,6 +163,9 @@ IT8728F. It only supports 16-bit fan mode. The IT8790E supports up to 3 fans. 16-bit fan mode is always enabled. +The IT8732F supports a closed-loop mode for fan control, but this is not +currently implemented by the driver. + Temperatures are measured in degrees Celsius. An alarm is triggered once when the Overtemperature Shutdown limit is crossed. @@ -173,12 +180,14 @@ is done. Voltage sensors (also known as IN sensors) report their values in volts. An alarm is triggered if the voltage has crossed a programmable minimum or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. All voltage -inputs can measure voltages between 0 and 4.08 volts, with a resolution of -0.016 volt (except IT8603E, IT8721F/IT8758E and IT8728F: 0.012 volt.) The -battery voltage in8 does not have limit registers. - -On the IT8603E, IT8721F/IT8758E, IT8781F, IT8782F, and IT8783E/F, some +zero'; this is important for negative voltage measurements. On most chips, all +voltage inputs can measure voltages between 0 and 4.08 volts, with a resolution +of 0.016 volt. IT8603E, IT8721F/IT8758E and IT8728F can measure between 0 and +3.06 volts, with a resolution of 0.012 volt. IT8732F can measure between 0 and +2.8 volts with a resolution of 0.0109 volt. The battery voltage in8 does not +have limit registers. + +On the IT8603E, IT8721F/IT8758E, IT8732F, IT8781F, IT8782F, and IT8783E/F, some voltage inputs are internal and scaled inside the chip: * in3 (optional) * in7 (optional for IT8781F, IT8782F, and IT8783E/F) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 7c65b73..500b262 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -609,8 +609,8 @@ config SENSORS_IT87 depends on !PPC select HWMON_VID help - If you say yes here you get support for ITE IT8705F, IT8712F, - IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, + If you say yes here you get support for ITE IT8705F, IT8712F, IT8716F, + IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F, IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, IT8603E, IT8620E, and IT8623E sensor chips, and the SiS950 clone. diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index d0ee556..1896e26 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -21,6 +21,7 @@ * IT8721F Super I/O chip w/LPC interface * IT8726F Super I/O chip w/LPC interface * IT8728F Super I/O chip w/LPC interface + * IT8732F Super I/O chip w/LPC interface * IT8758E Super I/O chip w/LPC interface * IT8771E Super I/O chip w/LPC interface * IT8772E Super I/O chip w/LPC interface @@ -69,8 +70,9 @@ #define DRVNAME "it87" -enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771, - it8772, it8781, it8782, it8783, it8786, it8790, it8603, it8620 }; +enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732, + it8771, it8772, it8781, it8782, it8783, it8786, it8790, it8603, + it8620 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -148,6 +150,7 @@ static inline void superio_exit(void) #define IT8721F_DEVID 0x8721 #define IT8726F_DEVID 0x8726 #define IT8728F_DEVID 0x8728 +#define IT8732F_DEVID 0x8732 #define IT8771E_DEVID 0x8771 #define IT8772E_DEVID 0x8772 #define IT8781F_DEVID 0x8781 @@ -265,6 +268,7 @@ struct it87_devices { #define FEAT_VID (1 << 9) /* Set if chip supports VID */ #define FEAT_IN7_INTERNAL (1 << 10) /* Set if in7 is internal */ #define FEAT_SIX_FANS (1 << 11) /* Supports six fans */ +#define FEAT_10_9MV_ADC (1 << 12) static const struct it87_devices it87_devices[] = { [it87] = { @@ -315,6 +319,15 @@ static const struct it87_devices it87_devices[] = { | FEAT_IN7_INTERNAL, .peci_mask = 0x07, }, + [it8732] = { + .name = "it8732", + .suffix = "F", + .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI + | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL, + .peci_mask = 0x07, + .old_peci_mask = 0x02, /* Actually reports PCH */ + }, [it8771] = { .name = "it8771", .suffix = "E", @@ -391,6 +404,7 @@ static const struct it87_devices it87_devices[] = { #define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS) #define has_12mv_adc(data) ((data)->features & FEAT_12MV_ADC) +#define has_10_9mv_adc(data) ((data)->features & FEAT_10_9MV_ADC) #define has_newer_autopwm(data) ((data)->features & FEAT_NEWER_AUTOPWM) #define has_old_autopwm(data) ((data)->features & FEAT_OLD_AUTOPWM) #define has_temp_offset(data) ((data)->features & FEAT_TEMP_OFFSET) @@ -475,7 +489,14 @@ struct it87_data { static int adc_lsb(const struct it87_data *data, int nr) { - int lsb = has_12mv_adc(data) ? 12 : 16; + int lsb; + + if (has_12mv_adc(data)) + lsb = 120; + else if (has_10_9mv_adc(data)) + lsb = 109; + else + lsb = 160; if (data->in_scaled & (1 << nr)) lsb <<= 1; return lsb; @@ -483,13 +504,13 @@ static int adc_lsb(const struct it87_data *data, int nr) static u8 in_to_reg(const struct it87_data *data, int nr, long val) { - val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr)); + val = DIV_ROUND_CLOSEST(val * 10, adc_lsb(data, nr)); return clamp_val(val, 0, 255); } static int in_from_reg(const struct it87_data *data, int nr, int val) { - return val * adc_lsb(data, nr); + return DIV_ROUND_CLOSEST(val * adc_lsb(data, nr), 10); } static inline u8 FAN_TO_REG(long rpm, int div) @@ -1515,9 +1536,14 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr, }; struct it87_data *data = dev_get_drvdata(dev); int nr = to_sensor_dev_attr(attr)->index; + const char *label; - return sprintf(buf, "%s\n", has_12mv_adc(data) ? labels_it8721[nr] - : labels[nr]); + if (has_12mv_adc(data) || has_10_9mv_adc(data)) + label = labels_it8721[nr]; + else + label = labels[nr]; + + return sprintf(buf, "%s\n", label); } static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); @@ -1853,6 +1879,9 @@ static int __init it87_find(unsigned short *address, case IT8728F_DEVID: sio_data->type = it8728; break; + case IT8732F_DEVID: + sio_data->type = it8732; + break; case IT8771E_DEVID: sio_data->type = it8771; break; -- cgit v1.1 From 068c227056b9223fea1a759e08db2558d5cbb5ad Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 20 Jul 2015 09:47:33 -0700 Subject: hwmon: (pmbus) Add support for VR12 Newer chips such as MAX20751 support VR12. Add support for it. Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus.c | 1 + drivers/hwmon/pmbus/pmbus.h | 2 ++ drivers/hwmon/pmbus/pmbus_core.c | 16 ++++++++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 554d024..bbfa35d 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -129,6 +129,7 @@ static int pmbus_identify(struct i2c_client *client, break; case 1: info->format[PSC_VOLTAGE_OUT] = vid; + info->vrm_version = vr11; break; case 2: info->format[PSC_VOLTAGE_OUT] = direct; diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 2427f6e..eece5f5 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -338,10 +338,12 @@ enum pmbus_sensor_classes { #define PMBUS_HAVE_STATUS_VMON (1 << 19) enum pmbus_data_format { linear = 0, direct, vid }; +enum vrm_version { vr11 = 0, vr12 }; struct pmbus_driver_info { int pages; /* Total number of pages */ enum pmbus_data_format format[PSC_NUM_CLASSES]; + enum vrm_version vrm_version; /* * Support one set of coefficients for each sensor type * Used for chips providing data in direct mode. diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 306a1b1..3981981 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -515,16 +515,24 @@ static long pmbus_reg2data_direct(struct pmbus_data *data, /* * Convert VID sensor values to milli- or micro-units * depending on sensor type. - * We currently only support VR11. */ static long pmbus_reg2data_vid(struct pmbus_data *data, struct pmbus_sensor *sensor) { long val = sensor->data; + long rv = 0; - if (val < 0x02 || val > 0xb2) - return 0; - return DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); + switch (data->info->vrm_version) { + case vr11: + if (val >= 0x02 && val <= 0xb2) + rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); + break; + case vr12: + if (val >= 0x01) + rv = 250 + (val - 1) * 5; + break; + } + return rv; } static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) -- cgit v1.1 From 1f61cab8a729e00af77b51b44c3a8dc8ef3b3eb9 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 8 Jun 2015 11:15:23 -0700 Subject: hwmon: (pmbus) Add support for MAX20751 MAX20751 is a multiphase power controller with internal buck converter. It uses VR12.0 to report the output voltage. This requires an explicit driver, since the VR version can not be auto-detected. The chip supports a manufacturer specific command to fine-tune the output voltage. This command is not currently supported. Signed-off-by: Guenter Roeck --- Documentation/hwmon/max20751 | 77 ++++++++++++++++++++++++++++++++++++++++++ MAINTAINERS | 7 ++++ drivers/hwmon/pmbus/Kconfig | 10 ++++++ drivers/hwmon/pmbus/Makefile | 1 + drivers/hwmon/pmbus/max20751.c | 64 +++++++++++++++++++++++++++++++++++ 5 files changed, 159 insertions(+) create mode 100644 Documentation/hwmon/max20751 create mode 100644 drivers/hwmon/pmbus/max20751.c diff --git a/Documentation/hwmon/max20751 b/Documentation/hwmon/max20751 new file mode 100644 index 0000000..f9fa25e --- /dev/null +++ b/Documentation/hwmon/max20751 @@ -0,0 +1,77 @@ +Kernel driver max20751 +====================== + +Supported chips: + * maxim MAX20751 + Prefix: 'max20751' + Addresses scanned: - + Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX20751.pdf + Application note: http://pdfserv.maximintegrated.com/en/an/AN5941.pdf + +Author: Guenter Roeck + + +Description +----------- + +This driver supports MAX20751 Multiphase Master with PMBus Interface +and Internal Buck Converter. + +The driver is a client driver to the core PMBus driver. +Please see Documentation/hwmon/pmbus for details on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices for +details. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. + + +Sysfs entries +------------- + +The following attributes are supported. + +in1_label "vin1" +in1_input Measured voltage. +in1_min Minimum input voltage. +in1_max Maximum input voltage. +in1_lcrit Critical minimum input voltage. +in1_crit Critical maximum input voltage. +in1_min_alarm Input voltage low alarm. +in1_lcrit_alarm Input voltage critical low alarm. +in1_min_alarm Input voltage low alarm. +in1_max_alarm Input voltage high alarm. + +in2_label "vout1" +in2_input Measured voltage. +in2_min Minimum output voltage. +in2_max Maximum output voltage. +in2_lcrit Critical minimum output voltage. +in2_crit Critical maximum output voltage. +in2_min_alarm Output voltage low alarm. +in2_lcrit_alarm Output voltage critical low alarm. +in2_min_alarm Output voltage low alarm. +in2_max_alarm Output voltage high alarm. + +curr1_input Measured output current. +curr1_label "iout1" +curr1_max Maximum output current. +curr1_alarm Current high alarm. + +temp1_input Measured temperature. +temp1_max Maximum temperature. +temp1_crit Critical high temperature. +temp1_max_alarm Chip temperature high alarm. +temp1_crit_alarm Chip temperature critical high alarm. + +power1_input Output power. +power1_label "pout1" diff --git a/MAINTAINERS b/MAINTAINERS index a9ae6c1..6a406b6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6539,6 +6539,13 @@ S: Maintained F: Documentation/hwmon/max16065 F: drivers/hwmon/max16065.c +MAX20751 HARDWARE MONITOR DRIVER +M: Guenter Roeck +L: lm-sensors@lm-sensors.org +S: Maintained +F: Documentation/hwmon/max20751 +F: drivers/hwmon/max20751.c + MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER M: "Hans J. Koch" L: lm-sensors@lm-sensors.org diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 67901cb..6e1e6fe 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -73,6 +73,16 @@ config SENSORS_MAX16064 This driver can also be built as a module. If so, the module will be called max16064. +config SENSORS_MAX20751 + tristate "Maxim MAX20751" + default n + help + If you say yes here you get hardware monitoring support for Maxim + MAX20751. + + This driver can also be built as a module. If so, the module will + be called max20751. + config SENSORS_MAX34440 tristate "Maxim MAX34440 and compatibles" default n diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index 1454293..bce046d 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o obj-$(CONFIG_SENSORS_LM25066) += lm25066.o obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o obj-$(CONFIG_SENSORS_MAX16064) += max16064.o +obj-$(CONFIG_SENSORS_MAX20751) += max20751.o obj-$(CONFIG_SENSORS_MAX34440) += max34440.o obj-$(CONFIG_SENSORS_MAX8688) += max8688.o obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c new file mode 100644 index 0000000..ab74aea --- /dev/null +++ b/drivers/hwmon/pmbus/max20751.c @@ -0,0 +1,64 @@ +/* + * Hardware monitoring driver for Maxim MAX20751 + * + * Copyright (c) 2015 Guenter Roeck + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "pmbus.h" + +static struct pmbus_driver_info max20751_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = vid, + .vrm_version = vr12, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_POUT, +}; + +static int max20751_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return pmbus_do_probe(client, id, &max20751_info); +} + +static const struct i2c_device_id max20751_id[] = { + {"max20751", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, max20751_id); + +static struct i2c_driver max20751_driver = { + .driver = { + .name = "max20751", + }, + .probe = max20751_probe, + .remove = pmbus_do_remove, + .id_table = max20751_id, +}; + +module_i2c_driver(max20751_driver); + +MODULE_AUTHOR("Guenter Roeck "); +MODULE_DESCRIPTION("PMBus driver for Maxim MAX20751"); +MODULE_LICENSE("GPL"); -- cgit v1.1 From cfca3789e0678c57e09dfb1a09fdfce427b7c92e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 7 Aug 2015 20:55:59 -0700 Subject: hwmon: (pmbus) Add device IDs for TPS544{B,C}2{0,5} Add device IDs and references for Texas Instruments TPS544B20, TPS544B25, TPS544C20, and TPS544C25 to the generic PMBus driver. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- Documentation/hwmon/pmbus | 8 ++++++-- drivers/hwmon/pmbus/Kconfig | 3 ++- drivers/hwmon/pmbus/pmbus.c | 4 ++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus index a3557da..b397675 100644 --- a/Documentation/hwmon/pmbus +++ b/Documentation/hwmon/pmbus @@ -23,11 +23,15 @@ Supported chips: http://www.lineagepower.com/oem/pdf/PDT012A0X.pdf http://www.lineagepower.com/oem/pdf/UDT020A0X.pdf http://www.lineagepower.com/oem/pdf/MDT040A0X.pdf - * Texas Instruments TPS40400 - Prefixes: 'tps40400' + * Texas Instruments TPS40400, TPS544B20, TPS544B25, TPS544C20, TPS544C25 + Prefixes: 'tps40400', 'tps544b20', 'tps544b25', 'tps544c20', 'tps544c25' Addresses scanned: - Datasheets: http://www.ti.com/lit/gpn/tps40400 + http://www.ti.com/lit/gpn/tps544b20 + http://www.ti.com/lit/gpn/tps544b25 + http://www.ti.com/lit/gpn/tps544c20 + http://www.ti.com/lit/gpn/tps544c25 * Generic PMBus devices Prefix: 'pmbus' Addresses scanned: - diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 6e1e6fe..2b3242c 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -20,7 +20,8 @@ config SENSORS_PMBUS help If you say yes here you get hardware monitoring support for generic PMBus devices, including but not limited to ADP4000, BMR453, BMR454, - MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, UDT020, and TPS40400. + MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, TPS40400, TPS544B20, + TPS544B25, TPS544C20, TPS544C25, and UDT020. This driver can also be built as a module. If so, the module will be called pmbus. diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index bbfa35d..0a74991 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -194,6 +194,10 @@ static const struct i2c_device_id pmbus_id[] = { {"pdt012", 1}, {"pmbus", 0}, {"tps40400", 1}, + {"tps544b20", 1}, + {"tps544b25", 1}, + {"tps544c20", 1}, + {"tps544c25", 1}, {"udt020", 1}, {} }; -- cgit v1.1 From 33836ee98533fd27baa89dabca48f8d4e69dd438 Mon Sep 17 00:00:00 2001 From: yalin wang Date: Mon, 10 Aug 2015 22:41:43 +0800 Subject: hwmon:change sht15_reverse() This change sht15_reverse() to be generic bitrev8(). Signed-off-by: yalin wang Signed-off-by: Guenter Roeck --- drivers/hwmon/sht15.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 497a7f8..a2fdbb7 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -33,6 +33,7 @@ #include #include #include +#include /* Commands */ #define SHT15_MEASURE_TEMP 0x03 @@ -173,19 +174,6 @@ struct sht15_data { }; /** - * sht15_reverse() - reverse a byte - * @byte: byte to reverse. - */ -static u8 sht15_reverse(u8 byte) -{ - u8 i, c; - - for (c = 0, i = 0; i < 8; i++) - c |= (!!(byte & (1 << i))) << (7 - i); - return c; -} - -/** * sht15_crc8() - compute crc8 * @data: sht15 specific data. * @value: sht15 retrieved data. @@ -196,7 +184,7 @@ static u8 sht15_crc8(struct sht15_data *data, const u8 *value, int len) { - u8 crc = sht15_reverse(data->val_status & 0x0F); + u8 crc = bitrev8(data->val_status & 0x0F); while (len--) { crc = sht15_crc8_table[*value ^ crc]; @@ -477,7 +465,7 @@ static int sht15_update_status(struct sht15_data *data) if (data->checksumming) { sht15_ack(data); - dev_checksum = sht15_reverse(sht15_read_byte(data)); + dev_checksum = bitrev8(sht15_read_byte(data)); checksum_vals[0] = SHT15_READ_STATUS; checksum_vals[1] = status; data->checksum_ok = (sht15_crc8(data, checksum_vals, 2) @@ -864,7 +852,7 @@ static void sht15_bh_read_data(struct work_struct *work_s) */ if (sht15_ack(data)) goto wakeup; - dev_checksum = sht15_reverse(sht15_read_byte(data)); + dev_checksum = bitrev8(sht15_read_byte(data)); checksum_vals[0] = (data->state == SHT15_READING_TEMP) ? SHT15_MEASURE_TEMP : SHT15_MEASURE_RH; checksum_vals[1] = (u8) (val >> 8); -- cgit v1.1 From 836954dadcb351d65cf96584f22c9e437169bd49 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 8 Jun 2015 10:14:00 -0700 Subject: hwmon: (ltc2978) Move code to read chip ID into separate function Verifying the chip type is getting more complicated with new chips, since not all chips support the same mechanism to read the chip type. Move the code into a separate function to simplify adding support for those chips. Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/ltc2978.c | 48 ++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 33081d1..7e10fbf 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -388,10 +388,36 @@ static const struct regulator_desc ltc2978_reg_desc[] = { }; #endif /* CONFIG_SENSORS_LTC2978_REGULATOR */ +static int ltc2978_get_id(struct i2c_client *client) +{ + int chip_id; + + chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID); + if (chip_id < 0) + return chip_id; + + if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) + return ltc2974; + else if (chip_id == LTC2977_ID) + return ltc2977; + else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2 || + chip_id == LTC2978A_ID) + return ltc2978; + else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) + return ltc3880; + else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) + return ltc3883; + else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID) + return ltm4676; + + dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); + return -ENODEV; +} + static int ltc2978_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int chip_id, i; + int i, chip_id; struct ltc2978_data *data; struct pmbus_driver_info *info; @@ -404,27 +430,11 @@ static int ltc2978_probe(struct i2c_client *client, if (!data) return -ENOMEM; - chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID); + chip_id = ltc2978_get_id(client); if (chip_id < 0) return chip_id; - if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) { - data->id = ltc2974; - } else if (chip_id == LTC2977_ID) { - data->id = ltc2977; - } else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2 || - chip_id == LTC2978A_ID) { - data->id = ltc2978; - } else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) { - data->id = ltc3880; - } else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) { - data->id = ltc3883; - } else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID) { - data->id = ltm4676; - } else { - dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); - return -ENODEV; - } + data->id = chip_id; if (data->id != id->driver_data) dev_warn(&client->dev, "Device mismatch: Configured %s, detected %s\n", -- cgit v1.1 From bf89386f166b18c21b2b7a2c5b6e496726c4f25f Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 8 Jun 2015 10:29:45 -0700 Subject: 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 --- .../devicetree/bindings/hwmon/ltc2978.txt | 3 +- Documentation/hwmon/ltc2978 | 26 ++++++----- drivers/hwmon/pmbus/ltc2978.c | 50 +++++++++++++++++++--- 3 files changed, 62 insertions(+), 17 deletions(-) diff --git a/Documentation/devicetree/bindings/hwmon/ltc2978.txt b/Documentation/devicetree/bindings/hwmon/ltc2978.txt index ed2f09d..230389f 100644 --- a/Documentation/devicetree/bindings/hwmon/ltc2978.txt +++ b/Documentation/devicetree/bindings/hwmon/ltc2978.txt @@ -6,6 +6,7 @@ Required properties: * "lltc,ltc2977" * "lltc,ltc2978" * "lltc,ltc3880" + * "lltc,ltc3882" * "lltc,ltc3883" * "lltc,ltm4676" - reg: I2C slave address @@ -20,7 +21,7 @@ Valid names of regulators depend on number of supplies supported per device: * ltc2974 : vout0 - vout3 * ltc2977 : vout0 - vout7 * ltc2978 : vout0 - vout7 - * ltc3880 : vout0 - vout1 + * ltc3880, ltc3882 : vout0 - vout1 * ltc3883 : vout0 * ltm4676 : vout0 - vout1 diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978 index 686c078..521ee8a 100644 --- a/Documentation/hwmon/ltc2978 +++ b/Documentation/hwmon/ltc2978 @@ -19,6 +19,10 @@ Supported chips: Prefix: 'ltc3880' Addresses scanned: - Datasheet: http://www.linear.com/product/ltc3880 + * Linear Technology LTC3882 + Prefix: 'ltc3882' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltc3882 * Linear Technology LTC3883 Prefix: 'ltc3883' Addresses scanned: - @@ -34,11 +38,12 @@ Author: Guenter Roeck Description ----------- -LTC2974 is a quad digital power supply manager. LTC2978 is an octal power supply -monitor. LTC2977 is a pin compatible replacement for LTC2978. LTC3880 is a dual -output poly-phase step-down DC/DC controller. LTC3883 is a single phase -step-down DC/DC controller. LTM4676 is a dual 13A or single 26A uModule -regulator. +LTC2974 is a quad digital power supply managers. +LTC2978 is an octal power supply monitor. +LTC2977 is a pin compatible replacement for LTC2978. +LTC3880 and LTC3882 are dual output poly-phase step-down DC/DC controllers. +LTC3883 is a single phase step-down DC/DC controller. +LTM4676 is a dual 13A or single 26A uModule regulator. Usage Notes @@ -80,7 +85,7 @@ in[N]_label "vout[1-8]". LTC2974: N=2-5 LTC2977: N=2-9 LTC2978: N=2-9 - LTC3880, LTM4676: N=2-3 + LTC3880, LTC3882, LTM4676: N=2-3 LTC3883: N=2 in[N]_input Measured output voltage. in[N]_min Minimum output voltage. @@ -100,8 +105,9 @@ temp[N]_input Measured temperature. and temp5 reports the chip temperature. On LTC2977 and LTC2978, only one temperature measurement is supported and reports the chip temperature. - On LTC3880 and LTM4676, temp1 and temp2 report external - temperatures, and temp3 reports the chip temperature. + On LTC3880, LTC3882, and LTM4676, temp1 and temp2 + report external temperatures, and temp3 reports + the chip temperature. On LTC3883, temp1 reports an external temperature, and temp2 reports the chip temperature. temp[N]_min Mimimum temperature. LTC2974, LCT2977, and LTC2978 only. @@ -128,7 +134,7 @@ power[N]_label "pout[1-4]". LTC2974: N=1-4 LTC2977: Not supported LTC2978: Not supported - LTC3880, LTM4676: N=1-2 + LTC3880, LTC3882, LTM4676: N=1-2 LTC3883: N=2 power[N]_input Measured output power. @@ -143,7 +149,7 @@ curr[N]_label "iout[1-4]". LTC2974: N=1-4 LTC2977: not supported LTC2978: not supported - LTC3880, LTM4676: N=2-3 + LTC3880, LTC3882, LTM4676: N=2-3 LTC3883: N=2 curr[N]_input Measured output current. curr[N]_max Maximum output current. diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 7e10fbf..28e1e73 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -25,13 +25,13 @@ #include #include "pmbus.h" -enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 }; +enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltm4676 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd #define LTC2978_MFR_VIN_PEAK 0xde #define LTC2978_MFR_TEMPERATURE_PEAK 0xdf -#define LTC2978_MFR_SPECIAL_ID 0xe7 +#define LTC2978_MFR_SPECIAL_ID 0xe7 /* Not on LTC3882 */ /* LTC2974, LCT2977, and LTC2978 */ #define LTC2978_MFR_VOUT_MIN 0xfb @@ -42,7 +42,7 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 }; #define LTC2974_MFR_IOUT_PEAK 0xd7 #define LTC2974_MFR_IOUT_MIN 0xd8 -/* LTC3880, LTC3883, and LTM4676 */ +/* LTC3880, LTC3882, LTC3883, and LTM4676 */ #define LTC3880_MFR_IOUT_PEAK 0xd7 #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 @@ -313,7 +313,7 @@ static int ltc2978_clear_peaks(struct i2c_client *client, int page, { int ret; - if (id == ltc3880 || id == ltc3883 || id == ltm4676) + if (id == ltc3880 || id == ltc3882 || id == ltc3883 || id == ltm4676) ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); else ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); @@ -369,6 +369,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc2977", ltc2977}, {"ltc2978", ltc2978}, {"ltc3880", ltc3880}, + {"ltc3882", ltc3882}, {"ltc3883", ltc3883}, {"ltm4676", ltm4676}, {} @@ -393,8 +394,30 @@ static int ltc2978_get_id(struct i2c_client *client) int chip_id; chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID); - if (chip_id < 0) - return chip_id; + if (chip_id < 0) { + const struct i2c_device_id *id; + u8 buf[I2C_SMBUS_BLOCK_MAX]; + int ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BLOCK_DATA)) + return -ENODEV; + + ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf); + if (ret < 0) + return ret; + if (ret < 3 || strncmp(buf, "LTC", 3)) + return -ENODEV; + + ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf); + if (ret < 0) + return ret; + for (id = <c2978_id[0]; strlen(id->name); id++) { + if (!strncasecmp(id->name, buf, strlen(id->name))) + return (int)id->driver_data; + } + return -ENODEV; + } if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) return ltc2974; @@ -498,6 +521,20 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; break; + case ltc3882: + info->read_word_data = ltc3880_read_word_data; + info->pages = LTC3880_NUM_PAGES; + info->func[0] = PMBUS_HAVE_VIN + | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP + | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; + info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_POUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; + break; case ltc3883: info->read_word_data = ltc3883_read_word_data; info->pages = LTC3883_NUM_PAGES; @@ -530,6 +567,7 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc2977" }, { .compatible = "lltc,ltc2978" }, { .compatible = "lltc,ltc3880" }, + { .compatible = "lltc,ltc3882" }, { .compatible = "lltc,ltc3883" }, { .compatible = "lltc,ltm4676" }, { } -- cgit v1.1 From e8047a2686d32854e4b82bd5d328da61025fb01a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 7 Aug 2015 01:04:56 -0700 Subject: hwmon: (ltc2978) Add additional chip IDs for LTM4676 and LTM4676A Per datasheet, the chip ID for LTM4676 is 0x448x. This was observed in real systems. In addition to that, chip ID 0x4401 was observed as well. Research shows that the chip ID has been changed from 0x440x to 0x448x in datasheet revision C. Add support for the additional chip ID. Also add the chip ID for LTM4676A, which is functionally identical to LTM4676. Reported-by: Ananda Babu Nettam Cc: Ananda Babu Nettam Cc: Amit U Jain Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/ltc2978.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 28e1e73..acbfe3e 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -60,7 +60,9 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltm4676 }; #define LTC3880_ID_MASK 0xff00 #define LTC3883_ID 0x4300 #define LTC3883_ID_MASK 0xff00 -#define LTM4676_ID 0x4480 /* datasheet claims 0x440X */ +#define LTM4676_ID 0x4400 +#define LTM4676_ID_2 0x4480 +#define LTM4676A_ID 0x47E0 #define LTM4676_ID_MASK 0xfff0 #define LTC2974_NUM_PAGES 4 @@ -430,7 +432,9 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3880; else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) return ltc3883; - else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID) + else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID || + (chip_id & LTM4676_ID_MASK) == LTM4676_ID_2 || + (chip_id & LTM4676_ID_MASK) == LTM4676A_ID) return ltm4676; dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); -- cgit v1.1 From 15398566f0ea95c66d202b8705dba4f59b9ba01c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 7 Aug 2015 09:06:37 -0700 Subject: hwmon: (ltc2978) Add support for LTC3887 LTC3887 is an enhanced version of LTC3880 and supports the same commands. Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/ltc2978.txt | 1 + Documentation/hwmon/ltc2978 | 19 ++++++++++++------- drivers/hwmon/pmbus/Kconfig | 3 ++- drivers/hwmon/pmbus/ltc2978.c | 19 ++++++++++++++----- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Documentation/devicetree/bindings/hwmon/ltc2978.txt b/Documentation/devicetree/bindings/hwmon/ltc2978.txt index 230389f..c1d23c1 100644 --- a/Documentation/devicetree/bindings/hwmon/ltc2978.txt +++ b/Documentation/devicetree/bindings/hwmon/ltc2978.txt @@ -8,6 +8,7 @@ Required properties: * "lltc,ltc3880" * "lltc,ltc3882" * "lltc,ltc3883" + * "lltc,ltc3887" * "lltc,ltm4676" - reg: I2C slave address diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978 index 521ee8a..ff13099 100644 --- a/Documentation/hwmon/ltc2978 +++ b/Documentation/hwmon/ltc2978 @@ -27,6 +27,10 @@ Supported chips: Prefix: 'ltc3883' Addresses scanned: - Datasheet: http://www.linear.com/product/ltc3883 + * Linear Technology LTC3887 + Prefix: 'ltc3887' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltc3887 * Linear Technology LTM4676 Prefix: 'ltm4676' Addresses scanned: - @@ -41,7 +45,8 @@ Description LTC2974 is a quad digital power supply managers. LTC2978 is an octal power supply monitor. LTC2977 is a pin compatible replacement for LTC2978. -LTC3880 and LTC3882 are dual output poly-phase step-down DC/DC controllers. +LTC3880, LTC3882, and LTC3887 are dual output poly-phase step-down DC/DC +controllers. LTC3883 is a single phase step-down DC/DC controller. LTM4676 is a dual 13A or single 26A uModule regulator. @@ -85,7 +90,7 @@ in[N]_label "vout[1-8]". LTC2974: N=2-5 LTC2977: N=2-9 LTC2978: N=2-9 - LTC3880, LTC3882, LTM4676: N=2-3 + LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 LTC3883: N=2 in[N]_input Measured output voltage. in[N]_min Minimum output voltage. @@ -105,8 +110,8 @@ temp[N]_input Measured temperature. and temp5 reports the chip temperature. On LTC2977 and LTC2978, only one temperature measurement is supported and reports the chip temperature. - On LTC3880, LTC3882, and LTM4676, temp1 and temp2 - report external temperatures, and temp3 reports + On LTC3880, LTC3882, LTC3887, and LTM4676, temp1 and + temp2 report external temperatures, and temp3 reports the chip temperature. On LTC3883, temp1 reports an external temperature, and temp2 reports the chip temperature. @@ -134,11 +139,11 @@ power[N]_label "pout[1-4]". LTC2974: N=1-4 LTC2977: Not supported LTC2978: Not supported - LTC3880, LTC3882, LTM4676: N=1-2 + LTC3880, LTC3882, LTC3887, LTM4676: N=1-2 LTC3883: N=2 power[N]_input Measured output power. -curr1_label "iin". LTC3880, LTC3883, and LTM4676 only. +curr1_label "iin". LTC3880, LTC3883, LTC3887, and LTM4676 only. curr1_input Measured input current. curr1_max Maximum input current. curr1_max_alarm Input current high alarm. @@ -149,7 +154,7 @@ curr[N]_label "iout[1-4]". LTC2974: N=1-4 LTC2977: not supported LTC2978: not supported - LTC3880, LTC3882, LTM4676: N=2-3 + LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 LTC3883: N=2 curr[N]_input Measured output current. curr[N]_max Maximum output current. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 2b3242c..43b6de9 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -52,7 +52,8 @@ config SENSORS_LTC2978 default n help If you say yes here you get hardware monitoring support for Linear - Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676. + Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, LTC3887, + and LTM4676. This driver can also be built as a module. If so, the module will be called ltc2978. diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index acbfe3e..0756d8a 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -1,6 +1,6 @@ /* * Hardware monitoring driver for LTC2974, LTC2977, LTC2978, LTC3880, - * LTC3883, and LTM4676 + * LTC3883, LTC3887. and LTM4676 * * Copyright (c) 2011 Ericsson AB. * Copyright (c) 2013, 2014 Guenter Roeck @@ -25,7 +25,8 @@ #include #include "pmbus.h" -enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltm4676 }; +enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltc3887, + ltm4676 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -42,7 +43,7 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltm4676 }; #define LTC2974_MFR_IOUT_PEAK 0xd7 #define LTC2974_MFR_IOUT_MIN 0xd8 -/* LTC3880, LTC3882, LTC3883, and LTM4676 */ +/* LTC3880, LTC3882, LTC3883, LTC3887, and LTM4676 */ #define LTC3880_MFR_IOUT_PEAK 0xd7 #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 @@ -60,9 +61,11 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltm4676 }; #define LTC3880_ID_MASK 0xff00 #define LTC3883_ID 0x4300 #define LTC3883_ID_MASK 0xff00 +#define LTC3887_ID 0x4700 +#define LTC3887_ID_MASK 0xff00 #define LTM4676_ID 0x4400 #define LTM4676_ID_2 0x4480 -#define LTM4676A_ID 0x47E0 +#define LTM4676A_ID 0x47e0 #define LTM4676_ID_MASK 0xfff0 #define LTC2974_NUM_PAGES 4 @@ -315,7 +318,8 @@ static int ltc2978_clear_peaks(struct i2c_client *client, int page, { int ret; - if (id == ltc3880 || id == ltc3882 || id == ltc3883 || id == ltm4676) + if (id == ltc3880 || id == ltc3882 || id == ltc3883 || id == ltc3887 || + id == ltm4676) ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); else ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); @@ -373,6 +377,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc3880", ltc3880}, {"ltc3882", ltc3882}, {"ltc3883", ltc3883}, + {"ltc3887", ltc3887}, {"ltm4676", ltm4676}, {} }; @@ -432,6 +437,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3880; else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) return ltc3883; + else if ((chip_id & LTC3887_ID_MASK) == LTC3887_ID) + return ltc3887; else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID || (chip_id & LTM4676_ID_MASK) == LTM4676_ID_2 || (chip_id & LTM4676_ID_MASK) == LTM4676A_ID) @@ -511,6 +518,7 @@ static int ltc2978_probe(struct i2c_client *client, } break; case ltc3880: + case ltc3887: case ltm4676: info->read_word_data = ltc3880_read_word_data; info->pages = LTC3880_NUM_PAGES; @@ -573,6 +581,7 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc3880" }, { .compatible = "lltc,ltc3882" }, { .compatible = "lltc,ltc3883" }, + { .compatible = "lltc,ltc3887" }, { .compatible = "lltc,ltm4676" }, { } }; -- cgit v1.1 From 649ca820dab3d76e12408b74af3e8e97abb07ae0 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 8 Jun 2015 09:56:20 -0700 Subject: hwmon: (ltc2978) Add support for LTC2975 LTC2975 is mostly compatible to LTC2974, but supports input current and power measurement. Tested-by: Michael Jones Signed-off-by: Guenter Roeck --- .../devicetree/bindings/hwmon/ltc2978.txt | 3 +- Documentation/hwmon/ltc2978 | 47 ++++++---- drivers/hwmon/pmbus/Kconfig | 4 +- drivers/hwmon/pmbus/ltc2978.c | 104 +++++++++++++++++++-- 4 files changed, 125 insertions(+), 33 deletions(-) diff --git a/Documentation/devicetree/bindings/hwmon/ltc2978.txt b/Documentation/devicetree/bindings/hwmon/ltc2978.txt index c1d23c1..e434d5f 100644 --- a/Documentation/devicetree/bindings/hwmon/ltc2978.txt +++ b/Documentation/devicetree/bindings/hwmon/ltc2978.txt @@ -3,6 +3,7 @@ ltc2978 Required properties: - compatible: should contain one of: * "lltc,ltc2974" + * "lltc,ltc2975" * "lltc,ltc2977" * "lltc,ltc2978" * "lltc,ltc3880" @@ -19,7 +20,7 @@ Optional properties: standard binding for regulators; see regulator.txt. Valid names of regulators depend on number of supplies supported per device: - * ltc2974 : vout0 - vout3 + * ltc2974, ltc2975 : vout0 - vout3 * ltc2977 : vout0 - vout7 * ltc2978 : vout0 - vout7 * ltc3880, ltc3882 : vout0 - vout1 diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978 index ff13099..7e98288 100644 --- a/Documentation/hwmon/ltc2978 +++ b/Documentation/hwmon/ltc2978 @@ -6,6 +6,10 @@ Supported chips: Prefix: 'ltc2974' Addresses scanned: - Datasheet: http://www.linear.com/product/ltc2974 + * Linear Technology LTC2975 + Prefix: 'ltc2975' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltc2975 * Linear Technology LTC2977 Prefix: 'ltc2977' Addresses scanned: - @@ -42,7 +46,7 @@ Author: Guenter Roeck Description ----------- -LTC2974 is a quad digital power supply managers. +LTC2974 and LTC2975 are quad digital power supply managers. LTC2978 is an octal power supply monitor. LTC2977 is a pin compatible replacement for LTC2978. LTC3880, LTC3882, and LTC3887 are dual output poly-phase step-down DC/DC @@ -71,23 +75,23 @@ in1_label "vin" in1_input Measured input voltage. in1_min Minimum input voltage. in1_max Maximum input voltage. - LTC2974, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, and LTC2978 only. in1_lcrit Critical minimum input voltage. - LTC2974, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, and LTC2978 only. in1_crit Critical maximum input voltage. in1_min_alarm Input voltage low alarm. in1_max_alarm Input voltage high alarm. - LTC2974, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, and LTC2978 only. in1_lcrit_alarm Input voltage critical low alarm. - LTC2974, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, and LTC2978 only. in1_crit_alarm Input voltage critical high alarm. in1_lowest Lowest input voltage. - LTC2974, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, and LTC2978 only. in1_highest Highest input voltage. in1_reset_history Reset input voltage history. in[N]_label "vout[1-8]". - LTC2974: N=2-5 + LTC2974, LTC2975: N=2-5 LTC2977: N=2-9 LTC2978: N=2-9 LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 @@ -101,13 +105,14 @@ in[N]_min_alarm Output voltage low alarm. in[N]_max_alarm Output voltage high alarm. in[N]_lcrit_alarm Output voltage critical low alarm. in[N]_crit_alarm Output voltage critical high alarm. -in[N]_lowest Lowest output voltage. LTC2974 and LTC2978 only. +in[N]_lowest Lowest output voltage. LTC2974, LTC2975, + and LTC2978 only. in[N]_highest Highest output voltage. in[N]_reset_history Reset output voltage history. temp[N]_input Measured temperature. - On LTC2974, temp[1-4] report external temperatures, - and temp5 reports the chip temperature. + On LTC2974 and LTC2975, temp[1-4] report external + temperatures, and temp5 reports the chip temperature. On LTC2977 and LTC2978, only one temperature measurement is supported and reports the chip temperature. On LTC3880, LTC3882, LTC3887, and LTM4676, temp1 and @@ -120,23 +125,24 @@ temp[N]_max Maximum temperature. temp[N]_lcrit Critical low temperature. temp[N]_crit Critical high temperature. temp[N]_min_alarm Temperature low alarm. - LTC2974, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, and LTC2978 only. temp[N]_max_alarm Temperature high alarm. temp[N]_lcrit_alarm Temperature critical low alarm. temp[N]_crit_alarm Temperature critical high alarm. temp[N]_lowest Lowest measured temperature. - LTC2974, LTC2977, and LTC2978 only. - Not supported for chip temperature sensor on LTC2974. + LTC2974, LTC2975, LTC2977, and LTC2978 only. + Not supported for chip temperature sensor on LTC2974 and + LTC2975. temp[N]_highest Highest measured temperature. Not supported for chip - temperature sensor on LTC2974. + temperature sensor on LTC2974 and LTC2975. temp[N]_reset_history Reset temperature history. Not supported for chip - temperature sensor on LTC2974. + temperature sensor on LTC2974 and LTC2975. power1_label "pin". LTC3883 only. power1_input Measured input power. power[N]_label "pout[1-4]". - LTC2974: N=1-4 + LTC2974, LTC2975: N=1-4 LTC2977: Not supported LTC2978: Not supported LTC3880, LTC3882, LTC3887, LTM4676: N=1-2 @@ -151,7 +157,7 @@ curr1_highest Highest input current. LTC3883 only. curr1_reset_history Reset input current history. LTC3883 only. curr[N]_label "iout[1-4]". - LTC2974: N=1-4 + LTC2974, LTC2975: N=1-4 LTC2977: not supported LTC2978: not supported LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 @@ -159,10 +165,11 @@ curr[N]_label "iout[1-4]". curr[N]_input Measured output current. curr[N]_max Maximum output current. curr[N]_crit Critical high output current. -curr[N]_lcrit Critical low output current. LTC2974 only. +curr[N]_lcrit Critical low output current. LTC2974 and LTC2975 only. curr[N]_max_alarm Output current high alarm. curr[N]_crit_alarm Output current critical high alarm. -curr[N]_lcrit_alarm Output current critical low alarm. LTC2974 only. -curr[N]_lowest Lowest output current. LTC2974 only. +curr[N]_lcrit_alarm Output current critical low alarm. + LTC2974 and LTC2975 only. +curr[N]_lowest Lowest output current. LTC2974 and LTC2975 only. curr[N]_highest Highest output current. curr[N]_reset_history Reset output current history. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 43b6de9..8279727 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -52,8 +52,8 @@ config SENSORS_LTC2978 default n help If you say yes here you get hardware monitoring support for Linear - Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, LTC3887, - and LTM4676. + Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC3880, LTC3883, + LTC3887, and LTM4676. This driver can also be built as a module. If so, the module will be called ltc2978. diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 0756d8a..e153ffd 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -1,9 +1,8 @@ /* - * Hardware monitoring driver for LTC2974, LTC2977, LTC2978, LTC3880, - * LTC3883, LTC3887. and LTM4676 + * Hardware monitoring driver for LTC2978 and compatible chips. * * Copyright (c) 2011 Ericsson AB. - * Copyright (c) 2013, 2014 Guenter Roeck + * Copyright (c) 2013, 2014, 2015 Guenter Roeck * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,8 +24,8 @@ #include #include "pmbus.h" -enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltc3887, - ltm4676 }; +enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, + ltc3887, ltm4676 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -34,12 +33,12 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltc3887, #define LTC2978_MFR_TEMPERATURE_PEAK 0xdf #define LTC2978_MFR_SPECIAL_ID 0xe7 /* Not on LTC3882 */ -/* LTC2974, LCT2977, and LTC2978 */ +/* LTC2974, LTC2975, LCT2977, and LTC2978 */ #define LTC2978_MFR_VOUT_MIN 0xfb #define LTC2978_MFR_VIN_MIN 0xfc #define LTC2978_MFR_TEMPERATURE_MIN 0xfd -/* LTC2974 only */ +/* LTC2974, LTC2975 */ #define LTC2974_MFR_IOUT_PEAK 0xd7 #define LTC2974_MFR_IOUT_MIN 0xd8 @@ -51,8 +50,15 @@ enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, ltc3887, /* LTC3883 only */ #define LTC3883_MFR_IIN_PEAK 0xe1 +/* LTC2975 only */ +#define LTC2975_MFR_IIN_PEAK 0xc4 +#define LTC2975_MFR_IIN_MIN 0xc5 +#define LTC2975_MFR_PIN_PEAK 0xc6 +#define LTC2975_MFR_PIN_MIN 0xc7 + #define LTC2974_ID_REV1 0x0212 #define LTC2974_ID_REV2 0x0213 +#define LTC2975_ID 0x0223 #define LTC2977_ID 0x0130 #define LTC2978_ID_REV1 0x0121 #define LTC2978_ID_REV2 0x0122 @@ -87,7 +93,8 @@ struct ltc2978_data { u16 temp_min[LTC2974_NUM_PAGES], temp_max[LTC2974_NUM_PAGES]; u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES]; u16 iout_min[LTC2974_NUM_PAGES], iout_max[LTC2974_NUM_PAGES]; - u16 iin_max; + u16 iin_min, iin_max; + u16 pin_min, pin_max; u16 temp2_max; struct pmbus_driver_info info; }; @@ -246,6 +253,60 @@ static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg) return ret; } +static int ltc2975_read_word_data(struct i2c_client *client, int page, int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct ltc2978_data *data = to_ltc2978_data(info); + int ret; + + switch (reg) { + case PMBUS_VIRT_READ_IIN_MAX: + ret = pmbus_read_word_data(client, page, LTC2975_MFR_IIN_PEAK); + if (ret >= 0) { + if (lin11_to_val(ret) + > lin11_to_val(data->iin_max)) + data->iin_max = ret; + ret = data->iin_max; + } + break; + case PMBUS_VIRT_READ_IIN_MIN: + ret = pmbus_read_word_data(client, page, LTC2975_MFR_IIN_MIN); + if (ret >= 0) { + if (lin11_to_val(ret) + < lin11_to_val(data->iin_min)) + data->iin_min = ret; + ret = data->iin_min; + } + break; + case PMBUS_VIRT_READ_PIN_MAX: + ret = pmbus_read_word_data(client, page, LTC2975_MFR_PIN_PEAK); + if (ret >= 0) { + if (lin11_to_val(ret) + > lin11_to_val(data->pin_max)) + data->pin_max = ret; + ret = data->pin_max; + } + break; + case PMBUS_VIRT_READ_PIN_MIN: + ret = pmbus_read_word_data(client, page, LTC2975_MFR_PIN_MIN); + if (ret >= 0) { + if (lin11_to_val(ret) + < lin11_to_val(data->pin_min)) + data->pin_min = ret; + ret = data->pin_min; + } + break; + case PMBUS_VIRT_RESET_IIN_HISTORY: + case PMBUS_VIRT_RESET_PIN_HISTORY: + ret = 0; + break; + default: + ret = ltc2978_read_word_data(client, page, reg); + break; + } + return ret; +} + static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); @@ -337,7 +398,13 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, switch (reg) { case PMBUS_VIRT_RESET_IIN_HISTORY: data->iin_max = 0x7c00; - ret = ltc2978_clear_peaks(client, page, data->id); + data->iin_min = 0x7bff; + ret = ltc2978_clear_peaks(client, 0, data->id); + break; + case PMBUS_VIRT_RESET_PIN_HISTORY: + data->pin_max = 0x7c00; + data->pin_min = 0x7bff; + ret = ltc2978_clear_peaks(client, 0, data->id); break; case PMBUS_VIRT_RESET_IOUT_HISTORY: data->iout_max[page] = 0x7c00; @@ -372,6 +439,7 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, static const struct i2c_device_id ltc2978_id[] = { {"ltc2974", ltc2974}, + {"ltc2975", ltc2975}, {"ltc2977", ltc2977}, {"ltc2978", ltc2978}, {"ltc3880", ltc3880}, @@ -428,6 +496,8 @@ static int ltc2978_get_id(struct i2c_client *client) if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) return ltc2974; + else if (chip_id == LTC2975_ID) + return ltc2975; else if (chip_id == LTC2977_ID) return ltc2977; else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2 || @@ -505,6 +575,19 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; } break; + case ltc2975: + info->read_word_data = ltc2975_read_word_data; + info->pages = LTC2974_NUM_PAGES; + info->func[0] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN + | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_TEMP2; + for (i = 0; i < info->pages; i++) { + info->func[i] |= PMBUS_HAVE_VOUT + | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; + } + break; case ltc2977: case ltc2978: info->read_word_data = ltc2978_read_word_data; @@ -576,6 +659,7 @@ static int ltc2978_probe(struct i2c_client *client, #ifdef CONFIG_OF static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc2974" }, + { .compatible = "lltc,ltc2975" }, { .compatible = "lltc,ltc2977" }, { .compatible = "lltc,ltc2978" }, { .compatible = "lltc,ltc3880" }, @@ -601,5 +685,5 @@ static struct i2c_driver ltc2978_driver = { module_i2c_driver(ltc2978_driver); MODULE_AUTHOR("Guenter Roeck"); -MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, LTC3883, and LTM4676"); +MODULE_DESCRIPTION("PMBus driver for LTC2978 and comppatible chips"); MODULE_LICENSE("GPL"); -- cgit v1.1 From 2238835c5ce9f8eae5cb4dd6a6c05a6c82743282 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 12 Aug 2015 21:05:38 -0700 Subject: hwmon: (pmbus) Convert command register definitions to enum This will simplify adding new virtual commands. Tested-by: Michael Jones Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus.h | 282 ++++++++++++++++++++++---------------------- 1 file changed, 142 insertions(+), 140 deletions(-) diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index eece5f5..f1cb15c 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -27,106 +27,107 @@ /* * Registers */ -#define PMBUS_PAGE 0x00 -#define PMBUS_OPERATION 0x01 -#define PMBUS_ON_OFF_CONFIG 0x02 -#define PMBUS_CLEAR_FAULTS 0x03 -#define PMBUS_PHASE 0x04 - -#define PMBUS_CAPABILITY 0x19 -#define PMBUS_QUERY 0x1A - -#define PMBUS_VOUT_MODE 0x20 -#define PMBUS_VOUT_COMMAND 0x21 -#define PMBUS_VOUT_TRIM 0x22 -#define PMBUS_VOUT_CAL_OFFSET 0x23 -#define PMBUS_VOUT_MAX 0x24 -#define PMBUS_VOUT_MARGIN_HIGH 0x25 -#define PMBUS_VOUT_MARGIN_LOW 0x26 -#define PMBUS_VOUT_TRANSITION_RATE 0x27 -#define PMBUS_VOUT_DROOP 0x28 -#define PMBUS_VOUT_SCALE_LOOP 0x29 -#define PMBUS_VOUT_SCALE_MONITOR 0x2A - -#define PMBUS_COEFFICIENTS 0x30 -#define PMBUS_POUT_MAX 0x31 - -#define PMBUS_FAN_CONFIG_12 0x3A -#define PMBUS_FAN_COMMAND_1 0x3B -#define PMBUS_FAN_COMMAND_2 0x3C -#define PMBUS_FAN_CONFIG_34 0x3D -#define PMBUS_FAN_COMMAND_3 0x3E -#define PMBUS_FAN_COMMAND_4 0x3F - -#define PMBUS_VOUT_OV_FAULT_LIMIT 0x40 -#define PMBUS_VOUT_OV_FAULT_RESPONSE 0x41 -#define PMBUS_VOUT_OV_WARN_LIMIT 0x42 -#define PMBUS_VOUT_UV_WARN_LIMIT 0x43 -#define PMBUS_VOUT_UV_FAULT_LIMIT 0x44 -#define PMBUS_VOUT_UV_FAULT_RESPONSE 0x45 -#define PMBUS_IOUT_OC_FAULT_LIMIT 0x46 -#define PMBUS_IOUT_OC_FAULT_RESPONSE 0x47 -#define PMBUS_IOUT_OC_LV_FAULT_LIMIT 0x48 -#define PMBUS_IOUT_OC_LV_FAULT_RESPONSE 0x49 -#define PMBUS_IOUT_OC_WARN_LIMIT 0x4A -#define PMBUS_IOUT_UC_FAULT_LIMIT 0x4B -#define PMBUS_IOUT_UC_FAULT_RESPONSE 0x4C - -#define PMBUS_OT_FAULT_LIMIT 0x4F -#define PMBUS_OT_FAULT_RESPONSE 0x50 -#define PMBUS_OT_WARN_LIMIT 0x51 -#define PMBUS_UT_WARN_LIMIT 0x52 -#define PMBUS_UT_FAULT_LIMIT 0x53 -#define PMBUS_UT_FAULT_RESPONSE 0x54 -#define PMBUS_VIN_OV_FAULT_LIMIT 0x55 -#define PMBUS_VIN_OV_FAULT_RESPONSE 0x56 -#define PMBUS_VIN_OV_WARN_LIMIT 0x57 -#define PMBUS_VIN_UV_WARN_LIMIT 0x58 -#define PMBUS_VIN_UV_FAULT_LIMIT 0x59 - -#define PMBUS_IIN_OC_FAULT_LIMIT 0x5B -#define PMBUS_IIN_OC_WARN_LIMIT 0x5D - -#define PMBUS_POUT_OP_FAULT_LIMIT 0x68 -#define PMBUS_POUT_OP_WARN_LIMIT 0x6A -#define PMBUS_PIN_OP_WARN_LIMIT 0x6B - -#define PMBUS_STATUS_BYTE 0x78 -#define PMBUS_STATUS_WORD 0x79 -#define PMBUS_STATUS_VOUT 0x7A -#define PMBUS_STATUS_IOUT 0x7B -#define PMBUS_STATUS_INPUT 0x7C -#define PMBUS_STATUS_TEMPERATURE 0x7D -#define PMBUS_STATUS_CML 0x7E -#define PMBUS_STATUS_OTHER 0x7F -#define PMBUS_STATUS_MFR_SPECIFIC 0x80 -#define PMBUS_STATUS_FAN_12 0x81 -#define PMBUS_STATUS_FAN_34 0x82 - -#define PMBUS_READ_VIN 0x88 -#define PMBUS_READ_IIN 0x89 -#define PMBUS_READ_VCAP 0x8A -#define PMBUS_READ_VOUT 0x8B -#define PMBUS_READ_IOUT 0x8C -#define PMBUS_READ_TEMPERATURE_1 0x8D -#define PMBUS_READ_TEMPERATURE_2 0x8E -#define PMBUS_READ_TEMPERATURE_3 0x8F -#define PMBUS_READ_FAN_SPEED_1 0x90 -#define PMBUS_READ_FAN_SPEED_2 0x91 -#define PMBUS_READ_FAN_SPEED_3 0x92 -#define PMBUS_READ_FAN_SPEED_4 0x93 -#define PMBUS_READ_DUTY_CYCLE 0x94 -#define PMBUS_READ_FREQUENCY 0x95 -#define PMBUS_READ_POUT 0x96 -#define PMBUS_READ_PIN 0x97 - -#define PMBUS_REVISION 0x98 -#define PMBUS_MFR_ID 0x99 -#define PMBUS_MFR_MODEL 0x9A -#define PMBUS_MFR_REVISION 0x9B -#define PMBUS_MFR_LOCATION 0x9C -#define PMBUS_MFR_DATE 0x9D -#define PMBUS_MFR_SERIAL 0x9E +enum pmbus_regs { + PMBUS_PAGE = 0x00, + PMBUS_OPERATION = 0x01, + PMBUS_ON_OFF_CONFIG = 0x02, + PMBUS_CLEAR_FAULTS = 0x03, + PMBUS_PHASE = 0x04, + + PMBUS_CAPABILITY = 0x19, + PMBUS_QUERY = 0x1A, + + PMBUS_VOUT_MODE = 0x20, + PMBUS_VOUT_COMMAND = 0x21, + PMBUS_VOUT_TRIM = 0x22, + PMBUS_VOUT_CAL_OFFSET = 0x23, + PMBUS_VOUT_MAX = 0x24, + PMBUS_VOUT_MARGIN_HIGH = 0x25, + PMBUS_VOUT_MARGIN_LOW = 0x26, + PMBUS_VOUT_TRANSITION_RATE = 0x27, + PMBUS_VOUT_DROOP = 0x28, + PMBUS_VOUT_SCALE_LOOP = 0x29, + PMBUS_VOUT_SCALE_MONITOR = 0x2A, + + PMBUS_COEFFICIENTS = 0x30, + PMBUS_POUT_MAX = 0x31, + + PMBUS_FAN_CONFIG_12 = 0x3A, + PMBUS_FAN_COMMAND_1 = 0x3B, + PMBUS_FAN_COMMAND_2 = 0x3C, + PMBUS_FAN_CONFIG_34 = 0x3D, + PMBUS_FAN_COMMAND_3 = 0x3E, + PMBUS_FAN_COMMAND_4 = 0x3F, + + PMBUS_VOUT_OV_FAULT_LIMIT = 0x40, + PMBUS_VOUT_OV_FAULT_RESPONSE = 0x41, + PMBUS_VOUT_OV_WARN_LIMIT = 0x42, + PMBUS_VOUT_UV_WARN_LIMIT = 0x43, + PMBUS_VOUT_UV_FAULT_LIMIT = 0x44, + PMBUS_VOUT_UV_FAULT_RESPONSE = 0x45, + PMBUS_IOUT_OC_FAULT_LIMIT = 0x46, + PMBUS_IOUT_OC_FAULT_RESPONSE = 0x47, + PMBUS_IOUT_OC_LV_FAULT_LIMIT = 0x48, + PMBUS_IOUT_OC_LV_FAULT_RESPONSE = 0x49, + PMBUS_IOUT_OC_WARN_LIMIT = 0x4A, + PMBUS_IOUT_UC_FAULT_LIMIT = 0x4B, + PMBUS_IOUT_UC_FAULT_RESPONSE = 0x4C, + + PMBUS_OT_FAULT_LIMIT = 0x4F, + PMBUS_OT_FAULT_RESPONSE = 0x50, + PMBUS_OT_WARN_LIMIT = 0x51, + PMBUS_UT_WARN_LIMIT = 0x52, + PMBUS_UT_FAULT_LIMIT = 0x53, + PMBUS_UT_FAULT_RESPONSE = 0x54, + PMBUS_VIN_OV_FAULT_LIMIT = 0x55, + PMBUS_VIN_OV_FAULT_RESPONSE = 0x56, + PMBUS_VIN_OV_WARN_LIMIT = 0x57, + PMBUS_VIN_UV_WARN_LIMIT = 0x58, + PMBUS_VIN_UV_FAULT_LIMIT = 0x59, + + PMBUS_IIN_OC_FAULT_LIMIT = 0x5B, + PMBUS_IIN_OC_WARN_LIMIT = 0x5D, + + PMBUS_POUT_OP_FAULT_LIMIT = 0x68, + PMBUS_POUT_OP_WARN_LIMIT = 0x6A, + PMBUS_PIN_OP_WARN_LIMIT = 0x6B, + + PMBUS_STATUS_BYTE = 0x78, + PMBUS_STATUS_WORD = 0x79, + PMBUS_STATUS_VOUT = 0x7A, + PMBUS_STATUS_IOUT = 0x7B, + PMBUS_STATUS_INPUT = 0x7C, + PMBUS_STATUS_TEMPERATURE = 0x7D, + PMBUS_STATUS_CML = 0x7E, + PMBUS_STATUS_OTHER = 0x7F, + PMBUS_STATUS_MFR_SPECIFIC = 0x80, + PMBUS_STATUS_FAN_12 = 0x81, + PMBUS_STATUS_FAN_34 = 0x82, + + PMBUS_READ_VIN = 0x88, + PMBUS_READ_IIN = 0x89, + PMBUS_READ_VCAP = 0x8A, + PMBUS_READ_VOUT = 0x8B, + PMBUS_READ_IOUT = 0x8C, + PMBUS_READ_TEMPERATURE_1 = 0x8D, + PMBUS_READ_TEMPERATURE_2 = 0x8E, + PMBUS_READ_TEMPERATURE_3 = 0x8F, + PMBUS_READ_FAN_SPEED_1 = 0x90, + PMBUS_READ_FAN_SPEED_2 = 0x91, + PMBUS_READ_FAN_SPEED_3 = 0x92, + PMBUS_READ_FAN_SPEED_4 = 0x93, + PMBUS_READ_DUTY_CYCLE = 0x94, + PMBUS_READ_FREQUENCY = 0x95, + PMBUS_READ_POUT = 0x96, + PMBUS_READ_PIN = 0x97, + + PMBUS_REVISION = 0x98, + PMBUS_MFR_ID = 0x99, + PMBUS_MFR_MODEL = 0x9A, + PMBUS_MFR_REVISION = 0x9B, + PMBUS_MFR_LOCATION = 0x9C, + PMBUS_MFR_DATE = 0x9D, + PMBUS_MFR_SERIAL = 0x9E, /* * Virtual registers. @@ -148,46 +149,47 @@ * the calling PMBus core code will abort if the chip driver returns an error * code when reading or writing virtual registers. */ -#define PMBUS_VIRT_BASE 0x100 -#define PMBUS_VIRT_READ_TEMP_AVG (PMBUS_VIRT_BASE + 0) -#define PMBUS_VIRT_READ_TEMP_MIN (PMBUS_VIRT_BASE + 1) -#define PMBUS_VIRT_READ_TEMP_MAX (PMBUS_VIRT_BASE + 2) -#define PMBUS_VIRT_RESET_TEMP_HISTORY (PMBUS_VIRT_BASE + 3) -#define PMBUS_VIRT_READ_VIN_AVG (PMBUS_VIRT_BASE + 4) -#define PMBUS_VIRT_READ_VIN_MIN (PMBUS_VIRT_BASE + 5) -#define PMBUS_VIRT_READ_VIN_MAX (PMBUS_VIRT_BASE + 6) -#define PMBUS_VIRT_RESET_VIN_HISTORY (PMBUS_VIRT_BASE + 7) -#define PMBUS_VIRT_READ_IIN_AVG (PMBUS_VIRT_BASE + 8) -#define PMBUS_VIRT_READ_IIN_MIN (PMBUS_VIRT_BASE + 9) -#define PMBUS_VIRT_READ_IIN_MAX (PMBUS_VIRT_BASE + 10) -#define PMBUS_VIRT_RESET_IIN_HISTORY (PMBUS_VIRT_BASE + 11) -#define PMBUS_VIRT_READ_PIN_AVG (PMBUS_VIRT_BASE + 12) -#define PMBUS_VIRT_READ_PIN_MIN (PMBUS_VIRT_BASE + 13) -#define PMBUS_VIRT_READ_PIN_MAX (PMBUS_VIRT_BASE + 14) -#define PMBUS_VIRT_RESET_PIN_HISTORY (PMBUS_VIRT_BASE + 15) -#define PMBUS_VIRT_READ_POUT_AVG (PMBUS_VIRT_BASE + 16) -#define PMBUS_VIRT_READ_POUT_MIN (PMBUS_VIRT_BASE + 17) -#define PMBUS_VIRT_READ_POUT_MAX (PMBUS_VIRT_BASE + 18) -#define PMBUS_VIRT_RESET_POUT_HISTORY (PMBUS_VIRT_BASE + 19) -#define PMBUS_VIRT_READ_VOUT_AVG (PMBUS_VIRT_BASE + 20) -#define PMBUS_VIRT_READ_VOUT_MIN (PMBUS_VIRT_BASE + 21) -#define PMBUS_VIRT_READ_VOUT_MAX (PMBUS_VIRT_BASE + 22) -#define PMBUS_VIRT_RESET_VOUT_HISTORY (PMBUS_VIRT_BASE + 23) -#define PMBUS_VIRT_READ_IOUT_AVG (PMBUS_VIRT_BASE + 24) -#define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 25) -#define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 26) -#define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 27) -#define PMBUS_VIRT_READ_TEMP2_AVG (PMBUS_VIRT_BASE + 28) -#define PMBUS_VIRT_READ_TEMP2_MIN (PMBUS_VIRT_BASE + 29) -#define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 30) -#define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 31) - -#define PMBUS_VIRT_READ_VMON (PMBUS_VIRT_BASE + 32) -#define PMBUS_VIRT_VMON_UV_WARN_LIMIT (PMBUS_VIRT_BASE + 33) -#define PMBUS_VIRT_VMON_OV_WARN_LIMIT (PMBUS_VIRT_BASE + 34) -#define PMBUS_VIRT_VMON_UV_FAULT_LIMIT (PMBUS_VIRT_BASE + 35) -#define PMBUS_VIRT_VMON_OV_FAULT_LIMIT (PMBUS_VIRT_BASE + 36) -#define PMBUS_VIRT_STATUS_VMON (PMBUS_VIRT_BASE + 37) + PMBUS_VIRT_BASE = 0x100, + PMBUS_VIRT_READ_TEMP_AVG, + PMBUS_VIRT_READ_TEMP_MIN, + PMBUS_VIRT_READ_TEMP_MAX, + PMBUS_VIRT_RESET_TEMP_HISTORY, + PMBUS_VIRT_READ_VIN_AVG, + PMBUS_VIRT_READ_VIN_MIN, + PMBUS_VIRT_READ_VIN_MAX, + PMBUS_VIRT_RESET_VIN_HISTORY, + PMBUS_VIRT_READ_IIN_AVG, + PMBUS_VIRT_READ_IIN_MIN, + PMBUS_VIRT_READ_IIN_MAX, + PMBUS_VIRT_RESET_IIN_HISTORY, + PMBUS_VIRT_READ_PIN_AVG, + PMBUS_VIRT_READ_PIN_MIN, + PMBUS_VIRT_READ_PIN_MAX, + PMBUS_VIRT_RESET_PIN_HISTORY, + PMBUS_VIRT_READ_POUT_AVG, + PMBUS_VIRT_READ_POUT_MIN, + PMBUS_VIRT_READ_POUT_MAX, + PMBUS_VIRT_RESET_POUT_HISTORY, + PMBUS_VIRT_READ_VOUT_AVG, + PMBUS_VIRT_READ_VOUT_MIN, + PMBUS_VIRT_READ_VOUT_MAX, + PMBUS_VIRT_RESET_VOUT_HISTORY, + PMBUS_VIRT_READ_IOUT_AVG, + PMBUS_VIRT_READ_IOUT_MIN, + PMBUS_VIRT_READ_IOUT_MAX, + PMBUS_VIRT_RESET_IOUT_HISTORY, + PMBUS_VIRT_READ_TEMP2_AVG, + PMBUS_VIRT_READ_TEMP2_MIN, + PMBUS_VIRT_READ_TEMP2_MAX, + PMBUS_VIRT_RESET_TEMP2_HISTORY, + + PMBUS_VIRT_READ_VMON, + PMBUS_VIRT_VMON_UV_WARN_LIMIT, + PMBUS_VIRT_VMON_OV_WARN_LIMIT, + PMBUS_VIRT_VMON_UV_FAULT_LIMIT, + PMBUS_VIRT_VMON_OV_FAULT_LIMIT, + PMBUS_VIRT_STATUS_VMON, +}; /* * OPERATION -- cgit v1.1 From 8582bcc8ebb21375b37f337c58ca783b997a0355 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 15 Aug 2015 17:02:09 -0700 Subject: hwmon: (ltc2978) Introduce feature flags It is becoming cumbersom to track per-chip feature support. Introduce feature flag to simplify the code. Tested-by: Michael Jones Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/ltc2978.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index e153ffd..48cbb57 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -97,10 +97,14 @@ struct ltc2978_data { u16 pin_min, pin_max; u16 temp2_max; struct pmbus_driver_info info; + u32 features; }; - #define to_ltc2978_data(x) container_of(x, struct ltc2978_data, info) +#define FEAT_CLEAR_PEAKS BIT(0) + +#define has_clear_peaks(d) ((d)->features & FEAT_CLEAR_PEAKS) + static inline int lin11_to_val(int data) { s16 e = ((s16)data) >> 11; @@ -374,13 +378,12 @@ static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg) return ret; } -static int ltc2978_clear_peaks(struct i2c_client *client, int page, - enum chips id) +static int ltc2978_clear_peaks(struct ltc2978_data *data, + struct i2c_client *client, int page) { int ret; - if (id == ltc3880 || id == ltc3882 || id == ltc3883 || id == ltc3887 || - id == ltm4676) + if (has_clear_peaks(data)) ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); else ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); @@ -399,36 +402,36 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, case PMBUS_VIRT_RESET_IIN_HISTORY: data->iin_max = 0x7c00; data->iin_min = 0x7bff; - ret = ltc2978_clear_peaks(client, 0, data->id); + ret = ltc2978_clear_peaks(data, client, 0); break; case PMBUS_VIRT_RESET_PIN_HISTORY: data->pin_max = 0x7c00; data->pin_min = 0x7bff; - ret = ltc2978_clear_peaks(client, 0, data->id); + ret = ltc2978_clear_peaks(data, client, 0); break; case PMBUS_VIRT_RESET_IOUT_HISTORY: data->iout_max[page] = 0x7c00; data->iout_min[page] = 0xfbff; - ret = ltc2978_clear_peaks(client, page, data->id); + ret = ltc2978_clear_peaks(data, client, page); break; case PMBUS_VIRT_RESET_TEMP2_HISTORY: data->temp2_max = 0x7c00; - ret = ltc2978_clear_peaks(client, page, data->id); + ret = ltc2978_clear_peaks(data, client, page); break; case PMBUS_VIRT_RESET_VOUT_HISTORY: data->vout_min[page] = 0xffff; data->vout_max[page] = 0; - ret = ltc2978_clear_peaks(client, page, data->id); + ret = ltc2978_clear_peaks(data, client, page); break; case PMBUS_VIRT_RESET_VIN_HISTORY: data->vin_min = 0x7bff; data->vin_max = 0x7c00; - ret = ltc2978_clear_peaks(client, page, data->id); + ret = ltc2978_clear_peaks(data, client, page); break; case PMBUS_VIRT_RESET_TEMP_HISTORY: data->temp_min[page] = 0x7bff; data->temp_max[page] = 0x7c00; - ret = ltc2978_clear_peaks(client, page, data->id); + ret = ltc2978_clear_peaks(data, client, page); break; default: ret = -ENODATA; @@ -603,6 +606,7 @@ static int ltc2978_probe(struct i2c_client *client, case ltc3880: case ltc3887: case ltm4676: + data->features |= FEAT_CLEAR_PEAKS; info->read_word_data = ltc3880_read_word_data; info->pages = LTC3880_NUM_PAGES; info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN @@ -617,6 +621,7 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; break; case ltc3882: + data->features |= FEAT_CLEAR_PEAKS; info->read_word_data = ltc3880_read_word_data; info->pages = LTC3880_NUM_PAGES; info->func[0] = PMBUS_HAVE_VIN @@ -631,6 +636,7 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; break; case ltc3883: + data->features |= FEAT_CLEAR_PEAKS; info->read_word_data = ltc3883_read_word_data; info->pages = LTC3883_NUM_PAGES; info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN -- cgit v1.1 From ee847a252664f54d06bcc6ab2864322cbcb52692 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 15 Aug 2015 17:17:53 -0700 Subject: hwmon: (ltc2978) Introduce helper functions for min and max values The code used to determine historic low and high peaks is repeated several times. Introduce helper functions to simplify it. Tested-by: Michael Jones Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/ltc2978.c | 148 ++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 91 deletions(-) diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 48cbb57..c3b7166 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -118,6 +118,34 @@ static inline int lin11_to_val(int data) return (e < 0 ? m >> -e : m << e); } +static int ltc_get_max(struct ltc2978_data *data, struct i2c_client *client, + int page, int reg, u16 *pmax) +{ + int ret; + + ret = pmbus_read_word_data(client, page, reg); + if (ret >= 0) { + if (lin11_to_val(ret) > lin11_to_val(*pmax)) + *pmax = ret; + ret = *pmax; + } + return ret; +} + +static int ltc_get_min(struct ltc2978_data *data, struct i2c_client *client, + int page, int reg, u16 *pmin) +{ + int ret; + + ret = pmbus_read_word_data(client, page, reg); + if (ret >= 0) { + if (lin11_to_val(ret) < lin11_to_val(*pmin)) + *pmin = ret; + ret = *pmin; + } + return ret; +} + static int ltc2978_read_word_data_common(struct i2c_client *client, int page, int reg) { @@ -127,12 +155,8 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page, switch (reg) { case PMBUS_VIRT_READ_VIN_MAX: - ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_PEAK); - if (ret >= 0) { - if (lin11_to_val(ret) > lin11_to_val(data->vin_max)) - data->vin_max = ret; - ret = data->vin_max; - } + ret = ltc_get_max(data, client, page, LTC2978_MFR_VIN_PEAK, + &data->vin_max); break; case PMBUS_VIRT_READ_VOUT_MAX: ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK); @@ -147,14 +171,9 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page, } break; case PMBUS_VIRT_READ_TEMP_MAX: - ret = pmbus_read_word_data(client, page, - LTC2978_MFR_TEMPERATURE_PEAK); - if (ret >= 0) { - if (lin11_to_val(ret) - > lin11_to_val(data->temp_max[page])) - data->temp_max[page] = ret; - ret = data->temp_max[page]; - } + ret = ltc_get_max(data, client, page, + LTC2978_MFR_TEMPERATURE_PEAK, + &data->temp_max[page]); break; case PMBUS_VIRT_RESET_VOUT_HISTORY: case PMBUS_VIRT_RESET_VIN_HISTORY: @@ -176,12 +195,8 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg) switch (reg) { case PMBUS_VIRT_READ_VIN_MIN: - ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_MIN); - if (ret >= 0) { - if (lin11_to_val(ret) < lin11_to_val(data->vin_min)) - data->vin_min = ret; - ret = data->vin_min; - } + ret = ltc_get_min(data, client, page, LTC2978_MFR_VIN_MIN, + &data->vin_min); break; case PMBUS_VIRT_READ_VOUT_MIN: ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_MIN); @@ -200,14 +215,9 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg) } break; case PMBUS_VIRT_READ_TEMP_MIN: - ret = pmbus_read_word_data(client, page, - LTC2978_MFR_TEMPERATURE_MIN); - if (ret >= 0) { - if (lin11_to_val(ret) - < lin11_to_val(data->temp_min[page])) - data->temp_min[page] = ret; - ret = data->temp_min[page]; - } + ret = ltc_get_min(data, client, page, + LTC2978_MFR_TEMPERATURE_MIN, + &data->temp_min[page]); break; case PMBUS_VIRT_READ_IOUT_MAX: case PMBUS_VIRT_RESET_IOUT_HISTORY: @@ -230,22 +240,12 @@ static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg) switch (reg) { case PMBUS_VIRT_READ_IOUT_MAX: - ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_PEAK); - if (ret >= 0) { - if (lin11_to_val(ret) - > lin11_to_val(data->iout_max[page])) - data->iout_max[page] = ret; - ret = data->iout_max[page]; - } + ret = ltc_get_max(data, client, page, LTC2974_MFR_IOUT_PEAK, + &data->iout_max[page]); break; case PMBUS_VIRT_READ_IOUT_MIN: - ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_MIN); - if (ret >= 0) { - if (lin11_to_val(ret) - < lin11_to_val(data->iout_min[page])) - data->iout_min[page] = ret; - ret = data->iout_min[page]; - } + ret = ltc_get_min(data, client, page, LTC2974_MFR_IOUT_MIN, + &data->iout_min[page]); break; case PMBUS_VIRT_RESET_IOUT_HISTORY: ret = 0; @@ -265,40 +265,20 @@ static int ltc2975_read_word_data(struct i2c_client *client, int page, int reg) switch (reg) { case PMBUS_VIRT_READ_IIN_MAX: - ret = pmbus_read_word_data(client, page, LTC2975_MFR_IIN_PEAK); - if (ret >= 0) { - if (lin11_to_val(ret) - > lin11_to_val(data->iin_max)) - data->iin_max = ret; - ret = data->iin_max; - } + ret = ltc_get_max(data, client, page, LTC2975_MFR_IIN_PEAK, + &data->iin_max); break; case PMBUS_VIRT_READ_IIN_MIN: - ret = pmbus_read_word_data(client, page, LTC2975_MFR_IIN_MIN); - if (ret >= 0) { - if (lin11_to_val(ret) - < lin11_to_val(data->iin_min)) - data->iin_min = ret; - ret = data->iin_min; - } + ret = ltc_get_min(data, client, page, LTC2975_MFR_IIN_MIN, + &data->iin_min); break; case PMBUS_VIRT_READ_PIN_MAX: - ret = pmbus_read_word_data(client, page, LTC2975_MFR_PIN_PEAK); - if (ret >= 0) { - if (lin11_to_val(ret) - > lin11_to_val(data->pin_max)) - data->pin_max = ret; - ret = data->pin_max; - } + ret = ltc_get_max(data, client, page, LTC2975_MFR_PIN_PEAK, + &data->pin_max); break; case PMBUS_VIRT_READ_PIN_MIN: - ret = pmbus_read_word_data(client, page, LTC2975_MFR_PIN_MIN); - if (ret >= 0) { - if (lin11_to_val(ret) - < lin11_to_val(data->pin_min)) - data->pin_min = ret; - ret = data->pin_min; - } + ret = ltc_get_min(data, client, page, LTC2975_MFR_PIN_MIN, + &data->pin_min); break; case PMBUS_VIRT_RESET_IIN_HISTORY: case PMBUS_VIRT_RESET_PIN_HISTORY: @@ -319,22 +299,13 @@ static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg) switch (reg) { case PMBUS_VIRT_READ_IOUT_MAX: - ret = pmbus_read_word_data(client, page, LTC3880_MFR_IOUT_PEAK); - if (ret >= 0) { - if (lin11_to_val(ret) - > lin11_to_val(data->iout_max[page])) - data->iout_max[page] = ret; - ret = data->iout_max[page]; - } + ret = ltc_get_max(data, client, page, LTC3880_MFR_IOUT_PEAK, + &data->iout_max[page]); break; case PMBUS_VIRT_READ_TEMP2_MAX: - ret = pmbus_read_word_data(client, page, - LTC3880_MFR_TEMPERATURE2_PEAK); - if (ret >= 0) { - if (lin11_to_val(ret) > lin11_to_val(data->temp2_max)) - data->temp2_max = ret; - ret = data->temp2_max; - } + ret = ltc_get_max(data, client, page, + LTC3880_MFR_TEMPERATURE2_PEAK, + &data->temp2_max); break; case PMBUS_VIRT_READ_VIN_MIN: case PMBUS_VIRT_READ_VOUT_MIN: @@ -360,13 +331,8 @@ static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg) switch (reg) { case PMBUS_VIRT_READ_IIN_MAX: - ret = pmbus_read_word_data(client, page, LTC3883_MFR_IIN_PEAK); - if (ret >= 0) { - if (lin11_to_val(ret) - > lin11_to_val(data->iin_max)) - data->iin_max = ret; - ret = data->iin_max; - } + ret = ltc_get_max(data, client, page, LTC3883_MFR_IIN_PEAK, + &data->iin_max); break; case PMBUS_VIRT_RESET_IIN_HISTORY: ret = 0; -- cgit v1.1 From 00c83371911836c47654e1de5b4706a0e578922a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Aug 2015 06:21:01 -0700 Subject: hwmon: (ltc2978) Use correct ID mask to detect all chips Per information from Linear Technologies, the ID mask is 12 bit for all chips of this series. Use this mask to detect chips to ensure that all chip revisions are detected. Suggested-by: Michael Jones Tested-by: Michael Jones Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/ltc2978.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index c3b7166..cc84ef5 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -56,23 +56,18 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, #define LTC2975_MFR_PIN_PEAK 0xc6 #define LTC2975_MFR_PIN_MIN 0xc7 -#define LTC2974_ID_REV1 0x0212 -#define LTC2974_ID_REV2 0x0213 -#define LTC2975_ID 0x0223 +#define LTC2978_ID_MASK 0xfff0 + +#define LTC2974_ID 0x0210 +#define LTC2975_ID 0x0220 #define LTC2977_ID 0x0130 -#define LTC2978_ID_REV1 0x0121 -#define LTC2978_ID_REV2 0x0122 -#define LTC2978A_ID 0x0124 -#define LTC3880_ID 0x4000 -#define LTC3880_ID_MASK 0xff00 +#define LTC2978_ID 0x0120 +#define LTC3880_ID 0x4020 #define LTC3883_ID 0x4300 -#define LTC3883_ID_MASK 0xff00 #define LTC3887_ID 0x4700 -#define LTC3887_ID_MASK 0xff00 -#define LTM4676_ID 0x4400 -#define LTM4676_ID_2 0x4480 +#define LTM4676_ID_REV1 0x4400 +#define LTM4676_ID_REV2 0x4480 #define LTM4676A_ID 0x47e0 -#define LTM4676_ID_MASK 0xfff0 #define LTC2974_NUM_PAGES 4 #define LTC2978_NUM_PAGES 8 @@ -463,24 +458,24 @@ static int ltc2978_get_id(struct i2c_client *client) return -ENODEV; } - if (chip_id == LTC2974_ID_REV1 || chip_id == LTC2974_ID_REV2) + chip_id &= LTC2978_ID_MASK; + + if (chip_id == LTC2974_ID) return ltc2974; else if (chip_id == LTC2975_ID) return ltc2975; else if (chip_id == LTC2977_ID) return ltc2977; - else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2 || - chip_id == LTC2978A_ID) + else if (chip_id == LTC2978_ID) return ltc2978; - else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) + else if (chip_id == LTC3880_ID) return ltc3880; - else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) + else if (chip_id == LTC3883_ID) return ltc3883; - else if ((chip_id & LTC3887_ID_MASK) == LTC3887_ID) + else if (chip_id == LTC3887_ID) return ltc3887; - else if ((chip_id & LTM4676_ID_MASK) == LTM4676_ID || - (chip_id & LTM4676_ID_MASK) == LTM4676_ID_2 || - (chip_id & LTM4676_ID_MASK) == LTM4676A_ID) + else if (chip_id == LTM4676_ID_REV1 || chip_id == LTM4676_ID_REV2 || + chip_id == LTM4676A_ID) return ltm4676; dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); -- cgit v1.1 From acb092cdf9a285fd4706bc6ffd5f99840d53bba5 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Aug 2015 06:27:56 -0700 Subject: hwmon: (ltc2978) Add missing chip IDs for LTC2978 and LTC3882 Add additional chip ID for an older revision of LTC2978, as well as two chip IDs for LTC3882. Turns out the LTC3882 does support the LTC2978_MFR_SPECIAL_ID register, and reading it returns its chip ID, but the register is undocumented. Suggested-by: Michael Jones Tested-by: Michael Jones Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/ltc2978.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index cc84ef5..e9d3f82 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -31,7 +31,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, #define LTC2978_MFR_VOUT_PEAK 0xdd #define LTC2978_MFR_VIN_PEAK 0xde #define LTC2978_MFR_TEMPERATURE_PEAK 0xdf -#define LTC2978_MFR_SPECIAL_ID 0xe7 /* Not on LTC3882 */ +#define LTC2978_MFR_SPECIAL_ID 0xe7 /* Undocumented on LTC3882 */ /* LTC2974, LTC2975, LCT2977, and LTC2978 */ #define LTC2978_MFR_VOUT_MIN 0xfb @@ -61,8 +61,11 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, #define LTC2974_ID 0x0210 #define LTC2975_ID 0x0220 #define LTC2977_ID 0x0130 -#define LTC2978_ID 0x0120 +#define LTC2978_ID_REV1 0x0110 /* Early revision */ +#define LTC2978_ID_REV2 0x0120 #define LTC3880_ID 0x4020 +#define LTC3882_ID 0x4200 +#define LTC3882_ID_D1 0x4240 /* Dash 1 */ #define LTC3883_ID 0x4300 #define LTC3887_ID 0x4700 #define LTM4676_ID_REV1 0x4400 @@ -466,10 +469,12 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc2975; else if (chip_id == LTC2977_ID) return ltc2977; - else if (chip_id == LTC2978_ID) + else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) return ltc2978; else if (chip_id == LTC3880_ID) return ltc3880; + else if (chip_id == LTC3882_ID || chip_id == LTC3882_ID_D1) + return ltc3882; else if (chip_id == LTC3883_ID) return ltc3883; else if (chip_id == LTC3887_ID) -- cgit v1.1 From 52aae6af71e0e78e25c64e13266917bb323984d5 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Aug 2015 06:38:01 -0700 Subject: hwmon: (ltc2978) Add support for LTC2980 and LTM2987 LTC2980 and LTM2987 are command compatible to LTC2977. They consist of two LTC2977 on a single die, and are instantiated as two separate chips, each supporting eight channels. Suggested-by: Michael Jones Tested-by: Michael Jones Signed-off-by: Guenter Roeck --- .../devicetree/bindings/hwmon/ltc2978.txt | 4 +- Documentation/hwmon/ltc2978 | 49 ++++++++++++++++------ drivers/hwmon/pmbus/Kconfig | 4 +- drivers/hwmon/pmbus/ltc2978.c | 20 +++++++-- 4 files changed, 58 insertions(+), 19 deletions(-) diff --git a/Documentation/devicetree/bindings/hwmon/ltc2978.txt b/Documentation/devicetree/bindings/hwmon/ltc2978.txt index e434d5f..5dc2691 100644 --- a/Documentation/devicetree/bindings/hwmon/ltc2978.txt +++ b/Documentation/devicetree/bindings/hwmon/ltc2978.txt @@ -6,10 +6,12 @@ Required properties: * "lltc,ltc2975" * "lltc,ltc2977" * "lltc,ltc2978" + * "lltc,ltc2980" * "lltc,ltc3880" * "lltc,ltc3882" * "lltc,ltc3883" * "lltc,ltc3887" + * "lltc,ltm2987" * "lltc,ltm4676" - reg: I2C slave address @@ -21,7 +23,7 @@ Optional properties: Valid names of regulators depend on number of supplies supported per device: * ltc2974, ltc2975 : vout0 - vout3 - * ltc2977 : vout0 - vout7 + * ltc2977, ltc2980, ltm2987 : vout0 - vout7 * ltc2978 : vout0 - vout7 * ltc3880, ltc3882 : vout0 - vout1 * ltc3883 : vout0 diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978 index 7e98288..1583553 100644 --- a/Documentation/hwmon/ltc2978 +++ b/Documentation/hwmon/ltc2978 @@ -19,6 +19,10 @@ Supported chips: Addresses scanned: - Datasheet: http://www.linear.com/product/ltc2978 http://www.linear.com/product/ltc2978a + * Linear Technology LTC2980 + Prefix: 'ltc2980' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltc2980 * Linear Technology LTC3880 Prefix: 'ltc3880' Addresses scanned: - @@ -35,6 +39,10 @@ Supported chips: Prefix: 'ltc3887' Addresses scanned: - Datasheet: http://www.linear.com/product/ltc3887 + * Linear Technology LTM2987 + Prefix: 'ltm2987' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltm2987 * Linear Technology LTM4676 Prefix: 'ltm4676' Addresses scanned: - @@ -49,9 +57,15 @@ Description LTC2974 and LTC2975 are quad digital power supply managers. LTC2978 is an octal power supply monitor. LTC2977 is a pin compatible replacement for LTC2978. +LTC2980 is a 16-channel Power System Manager, consisting of two LTC2977 +in a single die. The chip is instantiated and reported as two separate chips +on two different I2C bus addresses. LTC3880, LTC3882, and LTC3887 are dual output poly-phase step-down DC/DC controllers. LTC3883 is a single phase step-down DC/DC controller. +LTM2987 is a 16-channel Power System Manager with two LTC2977 plus +additional components on a single die. The chip is instantiated and reported +as two separate chips on two different I2C bus addresses. LTM4676 is a dual 13A or single 26A uModule regulator. @@ -75,24 +89,29 @@ in1_label "vin" in1_input Measured input voltage. in1_min Minimum input voltage. in1_max Maximum input voltage. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and + LTM2987 only. in1_lcrit Critical minimum input voltage. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and + LTM2987 only. in1_crit Critical maximum input voltage. in1_min_alarm Input voltage low alarm. in1_max_alarm Input voltage high alarm. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and + LTM2987 only. in1_lcrit_alarm Input voltage critical low alarm. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and + LTM2987 only. in1_crit_alarm Input voltage critical high alarm. in1_lowest Lowest input voltage. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and + LTM2987 only. in1_highest Highest input voltage. in1_reset_history Reset input voltage history. in[N]_label "vout[1-8]". LTC2974, LTC2975: N=2-5 - LTC2977: N=2-9 + LTC2977, LTC2980, LTM2987: N=2-9 LTC2978: N=2-9 LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 LTC3883: N=2 @@ -113,24 +132,28 @@ in[N]_reset_history Reset output voltage history. temp[N]_input Measured temperature. On LTC2974 and LTC2975, temp[1-4] report external temperatures, and temp5 reports the chip temperature. - On LTC2977 and LTC2978, only one temperature measurement - is supported and reports the chip temperature. + On LTC2977, LTC2980, LTC2978, and LTM2987, only one + temperature measurement is supported and reports + the chip temperature. On LTC3880, LTC3882, LTC3887, and LTM4676, temp1 and temp2 report external temperatures, and temp3 reports the chip temperature. On LTC3883, temp1 reports an external temperature, and temp2 reports the chip temperature. -temp[N]_min Mimimum temperature. LTC2974, LCT2977, and LTC2978 only. +temp[N]_min Mimimum temperature. LTC2974, LCT2977, LTM2980, LTC2978, + and LTM2987 only. temp[N]_max Maximum temperature. temp[N]_lcrit Critical low temperature. temp[N]_crit Critical high temperature. temp[N]_min_alarm Temperature low alarm. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTM2980, LTC2978, and + LTM2987 only. temp[N]_max_alarm Temperature high alarm. temp[N]_lcrit_alarm Temperature critical low alarm. temp[N]_crit_alarm Temperature critical high alarm. temp[N]_lowest Lowest measured temperature. - LTC2974, LTC2975, LTC2977, and LTC2978 only. + LTC2974, LTC2975, LTC2977, LTM2980, LTC2978, and + LTM2987 only. Not supported for chip temperature sensor on LTC2974 and LTC2975. temp[N]_highest Highest measured temperature. Not supported for chip @@ -143,7 +166,7 @@ power1_input Measured input power. power[N]_label "pout[1-4]". LTC2974, LTC2975: N=1-4 - LTC2977: Not supported + LTC2977, LTC2980, LTM2987: Not supported LTC2978: Not supported LTC3880, LTC3882, LTC3887, LTM4676: N=1-2 LTC3883: N=2 @@ -158,7 +181,7 @@ curr1_reset_history Reset input current history. LTC3883 only. curr[N]_label "iout[1-4]". LTC2974, LTC2975: N=1-4 - LTC2977: not supported + LTC2977, LTC2980, LTM2987: not supported LTC2978: not supported LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 LTC3883: N=2 diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 8279727..af778ae 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -52,8 +52,8 @@ config SENSORS_LTC2978 default n help If you say yes here you get hardware monitoring support for Linear - Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC3880, LTC3883, - LTC3887, and LTM4676. + Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880, + LTC3883, LTC3887, LTCM2987, and LTM4676. This driver can also be built as a module. If so, the module will be called ltc2978. diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index e9d3f82..48dcde0 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -24,8 +24,8 @@ #include #include "pmbus.h" -enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, - ltc3887, ltm4676 }; +enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, + ltc3883, ltc3887, ltm2987, ltm4676 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -33,7 +33,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, #define LTC2978_MFR_TEMPERATURE_PEAK 0xdf #define LTC2978_MFR_SPECIAL_ID 0xe7 /* Undocumented on LTC3882 */ -/* LTC2974, LTC2975, LCT2977, and LTC2978 */ +/* LTC2974, LTC2975, LCT2977, LTC2980, LTC2978, and LTM2987 */ #define LTC2978_MFR_VOUT_MIN 0xfb #define LTC2978_MFR_VIN_MIN 0xfc #define LTC2978_MFR_TEMPERATURE_MIN 0xfd @@ -63,11 +63,15 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc3880, ltc3882, ltc3883, #define LTC2977_ID 0x0130 #define LTC2978_ID_REV1 0x0110 /* Early revision */ #define LTC2978_ID_REV2 0x0120 +#define LTC2980_ID_A 0x8030 /* A/B for two die IDs */ +#define LTC2980_ID_B 0x8040 #define LTC3880_ID 0x4020 #define LTC3882_ID 0x4200 #define LTC3882_ID_D1 0x4240 /* Dash 1 */ #define LTC3883_ID 0x4300 #define LTC3887_ID 0x4700 +#define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ +#define LTM2987_ID_B 0x8020 #define LTM4676_ID_REV1 0x4400 #define LTM4676_ID_REV2 0x4480 #define LTM4676A_ID 0x47e0 @@ -409,10 +413,12 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc2975", ltc2975}, {"ltc2977", ltc2977}, {"ltc2978", ltc2978}, + {"ltc2980", ltc2980}, {"ltc3880", ltc3880}, {"ltc3882", ltc3882}, {"ltc3883", ltc3883}, {"ltc3887", ltc3887}, + {"ltm2987", ltm2987}, {"ltm4676", ltm4676}, {} }; @@ -471,6 +477,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc2977; else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) return ltc2978; + else if (chip_id == LTC2980_ID_A || chip_id == LTC2980_ID_B) + return ltc2980; else if (chip_id == LTC3880_ID) return ltc3880; else if (chip_id == LTC3882_ID || chip_id == LTC3882_ID_D1) @@ -479,6 +487,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3883; else if (chip_id == LTC3887_ID) return ltc3887; + else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B) + return ltm2987; else if (chip_id == LTM4676_ID_REV1 || chip_id == LTM4676_ID_REV2 || chip_id == LTM4676A_ID) return ltm4676; @@ -559,6 +569,8 @@ static int ltc2978_probe(struct i2c_client *client, break; case ltc2977: case ltc2978: + case ltc2980: + case ltm2987: info->read_word_data = ltc2978_read_word_data; info->pages = LTC2978_NUM_PAGES; info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT @@ -634,10 +646,12 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc2975" }, { .compatible = "lltc,ltc2977" }, { .compatible = "lltc,ltc2978" }, + { .compatible = "lltc,ltc2980" }, { .compatible = "lltc,ltc3880" }, { .compatible = "lltc,ltc3882" }, { .compatible = "lltc,ltc3883" }, { .compatible = "lltc,ltc3887" }, + { .compatible = "lltc,ltm2987" }, { .compatible = "lltc,ltm4676" }, { } }; -- cgit v1.1 From 228b687d9e20f367e4d5ea8723e3abbf0892db61 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Aug 2015 07:21:43 -0700 Subject: hwmon: (ltc2978) Add support for LTC3886 LTC3886 is a is a dual PolyPhase DC/DC synchronous step-down switching regulator controller. It is mostly command compatible to LTC3883, but supports two phases instead of one. Suggested-by: Michael Jones Tested-by: Michael Jones Signed-off-by: Guenter Roeck --- .../devicetree/bindings/hwmon/ltc2978.txt | 3 ++- Documentation/hwmon/ltc2978 | 23 +++++++++++++-------- drivers/hwmon/pmbus/Kconfig | 2 +- drivers/hwmon/pmbus/ltc2978.c | 24 ++++++++++++++++++++-- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/Documentation/devicetree/bindings/hwmon/ltc2978.txt b/Documentation/devicetree/bindings/hwmon/ltc2978.txt index 5dc2691..a7afbf6 100644 --- a/Documentation/devicetree/bindings/hwmon/ltc2978.txt +++ b/Documentation/devicetree/bindings/hwmon/ltc2978.txt @@ -10,6 +10,7 @@ Required properties: * "lltc,ltc3880" * "lltc,ltc3882" * "lltc,ltc3883" + * "lltc,ltc3886" * "lltc,ltc3887" * "lltc,ltm2987" * "lltc,ltm4676" @@ -25,7 +26,7 @@ Valid names of regulators depend on number of supplies supported per device: * ltc2974, ltc2975 : vout0 - vout3 * ltc2977, ltc2980, ltm2987 : vout0 - vout7 * ltc2978 : vout0 - vout7 - * ltc3880, ltc3882 : vout0 - vout1 + * ltc3880, ltc3882, ltc3886 : vout0 - vout1 * ltc3883 : vout0 * ltm4676 : vout0 - vout1 diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978 index 1583553..f997aa5 100644 --- a/Documentation/hwmon/ltc2978 +++ b/Documentation/hwmon/ltc2978 @@ -35,6 +35,10 @@ Supported chips: Prefix: 'ltc3883' Addresses scanned: - Datasheet: http://www.linear.com/product/ltc3883 + * Linear Technology LTC3886 + Prefix: 'ltc3886' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltc3886 * Linear Technology LTC3887 Prefix: 'ltc3887' Addresses scanned: - @@ -60,8 +64,8 @@ LTC2977 is a pin compatible replacement for LTC2978. LTC2980 is a 16-channel Power System Manager, consisting of two LTC2977 in a single die. The chip is instantiated and reported as two separate chips on two different I2C bus addresses. -LTC3880, LTC3882, and LTC3887 are dual output poly-phase step-down DC/DC -controllers. +LTC3880, LTC3882, LTC3886, and LTC3887 are dual output poly-phase step-down +DC/DC controllers. LTC3883 is a single phase step-down DC/DC controller. LTM2987 is a 16-channel Power System Manager with two LTC2977 plus additional components on a single die. The chip is instantiated and reported @@ -113,7 +117,7 @@ in[N]_label "vout[1-8]". LTC2974, LTC2975: N=2-5 LTC2977, LTC2980, LTM2987: N=2-9 LTC2978: N=2-9 - LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 + LTC3880, LTC3882, LTC23886 LTC3887, LTM4676: N=2-3 LTC3883: N=2 in[N]_input Measured output voltage. in[N]_min Minimum output voltage. @@ -161,29 +165,30 @@ temp[N]_highest Highest measured temperature. Not supported for chip temp[N]_reset_history Reset temperature history. Not supported for chip temperature sensor on LTC2974 and LTC2975. -power1_label "pin". LTC3883 only. +power1_label "pin". LTC3883 and LTC3886 only. power1_input Measured input power. power[N]_label "pout[1-4]". LTC2974, LTC2975: N=1-4 LTC2977, LTC2980, LTM2987: Not supported LTC2978: Not supported - LTC3880, LTC3882, LTC3887, LTM4676: N=1-2 + LTC3880, LTC3882, LTC3886, LTC3887, LTM4676: N=1-2 LTC3883: N=2 power[N]_input Measured output power. -curr1_label "iin". LTC3880, LTC3883, LTC3887, and LTM4676 only. +curr1_label "iin". LTC3880, LTC3883, LTC3886, LTC3887, and LTM4676 + only. curr1_input Measured input current. curr1_max Maximum input current. curr1_max_alarm Input current high alarm. -curr1_highest Highest input current. LTC3883 only. -curr1_reset_history Reset input current history. LTC3883 only. +curr1_highest Highest input current. LTC3883 and LTC3886 only. +curr1_reset_history Reset input current history. LTC3883 and LTC3886 only. curr[N]_label "iout[1-4]". LTC2974, LTC2975: N=1-4 LTC2977, LTC2980, LTM2987: not supported LTC2978: not supported - LTC3880, LTC3882, LTC3887, LTM4676: N=2-3 + LTC3880, LTC3882, LTC3886, LTC3887, LTM4676: N=2-3 LTC3883: N=2 curr[N]_input Measured output current. curr[N]_max Maximum output current. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index af778ae..5ebc362 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -53,7 +53,7 @@ config SENSORS_LTC2978 help If you say yes here you get hardware monitoring support for Linear Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880, - LTC3883, LTC3887, LTCM2987, and LTM4676. + LTC3883, LTC3886, LTC3887, LTCM2987, and LTM4676. This driver can also be built as a module. If so, the module will be called ltc2978. diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 48dcde0..60fe8f9 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -25,7 +25,7 @@ #include "pmbus.h" enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, - ltc3883, ltc3887, ltm2987, ltm4676 }; + ltc3883, ltc3886, ltc3887, ltm2987, ltm4676 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -47,7 +47,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 -/* LTC3883 only */ +/* LTC3883 and LTC3886 only */ #define LTC3883_MFR_IIN_PEAK 0xe1 /* LTC2975 only */ @@ -69,6 +69,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTC3882_ID 0x4200 #define LTC3882_ID_D1 0x4240 /* Dash 1 */ #define LTC3883_ID 0x4300 +#define LTC3886_ID 0x4600 #define LTC3887_ID 0x4700 #define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ #define LTM2987_ID_B 0x8020 @@ -417,6 +418,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc3880", ltc3880}, {"ltc3882", ltc3882}, {"ltc3883", ltc3883}, + {"ltc3886", ltc3886}, {"ltc3887", ltc3887}, {"ltm2987", ltm2987}, {"ltm4676", ltm4676}, @@ -485,6 +487,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3882; else if (chip_id == LTC3883_ID) return ltc3883; + else if (chip_id == LTC3886_ID) + return ltc3886; else if (chip_id == LTC3887_ID) return ltc3887; else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B) @@ -624,6 +628,21 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; break; + case ltc3886: + data->features |= FEAT_CLEAR_PEAKS; + info->read_word_data = ltc3883_read_word_data; + info->pages = LTC3880_NUM_PAGES; + info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN + | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP + | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; + info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_POUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; + break; default: return -ENODEV; } @@ -650,6 +669,7 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc3880" }, { .compatible = "lltc,ltc3882" }, { .compatible = "lltc,ltc3883" }, + { .compatible = "lltc,ltc3886" }, { .compatible = "lltc,ltc3887" }, { .compatible = "lltc,ltm2987" }, { .compatible = "lltc,ltm4676" }, -- cgit v1.1 From 2c052d4280ca48fddc7a9ffd2329ada3628cab86 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Aug 2015 16:17:24 -0700 Subject: hwmon: (pmbus) Use BIT macro Using the BIT macro makes the code a little easier to read. Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/lm25066.c | 7 +- drivers/hwmon/pmbus/max34440.c | 9 ++- drivers/hwmon/pmbus/max8688.c | 19 ++--- drivers/hwmon/pmbus/pmbus.h | 163 +++++++++++++++++++++-------------------- drivers/hwmon/pmbus/zl6100.c | 11 +-- 5 files changed, 107 insertions(+), 102 deletions(-) diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index a26b1d1..a3d912cd 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -19,6 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include @@ -42,15 +43,15 @@ enum chips { lm25056, lm25063, lm25066, lm5064, lm5066 }; #define LM25066_READ_AVG_IIN 0xde #define LM25066_READ_AVG_PIN 0xdf -#define LM25066_DEV_SETUP_CL (1 << 4) /* Current limit */ +#define LM25066_DEV_SETUP_CL BIT(4) /* Current limit */ /* LM25056 only */ #define LM25056_VAUX_OV_WARN_LIMIT 0xe3 #define LM25056_VAUX_UV_WARN_LIMIT 0xe4 -#define LM25056_MFR_STS_VAUX_OV_WARN (1 << 1) -#define LM25056_MFR_STS_VAUX_UV_WARN (1 << 0) +#define LM25056_MFR_STS_VAUX_OV_WARN BIT(1) +#define LM25056_MFR_STS_VAUX_UV_WARN BIT(0) /* LM25063 only */ diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index 7e930c3..74a1f6f 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -19,6 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include @@ -38,10 +39,10 @@ enum chips { max34440, max34441, max34446, max34460, max34461 }; #define MAX34446_MFR_IOUT_AVG 0xe2 #define MAX34446_MFR_TEMPERATURE_AVG 0xe3 -#define MAX34440_STATUS_OC_WARN (1 << 0) -#define MAX34440_STATUS_OC_FAULT (1 << 1) -#define MAX34440_STATUS_OT_FAULT (1 << 5) -#define MAX34440_STATUS_OT_WARN (1 << 6) +#define MAX34440_STATUS_OC_WARN BIT(0) +#define MAX34440_STATUS_OC_FAULT BIT(1) +#define MAX34440_STATUS_OT_FAULT BIT(5) +#define MAX34440_STATUS_OT_WARN BIT(6) struct max34440_data { int id; diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index f04454a..dd4883a 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -18,6 +18,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include @@ -30,15 +31,15 @@ #define MAX8688_MFR_TEMPERATURE_PEAK 0xd6 #define MAX8688_MFG_STATUS 0xd8 -#define MAX8688_STATUS_OC_FAULT (1 << 4) -#define MAX8688_STATUS_OV_FAULT (1 << 5) -#define MAX8688_STATUS_OV_WARNING (1 << 8) -#define MAX8688_STATUS_UV_FAULT (1 << 9) -#define MAX8688_STATUS_UV_WARNING (1 << 10) -#define MAX8688_STATUS_UC_FAULT (1 << 11) -#define MAX8688_STATUS_OC_WARNING (1 << 12) -#define MAX8688_STATUS_OT_FAULT (1 << 13) -#define MAX8688_STATUS_OT_WARNING (1 << 14) +#define MAX8688_STATUS_OC_FAULT BIT(4) +#define MAX8688_STATUS_OV_FAULT BIT(5) +#define MAX8688_STATUS_OV_WARNING BIT(8) +#define MAX8688_STATUS_UV_FAULT BIT(9) +#define MAX8688_STATUS_UV_WARNING BIT(10) +#define MAX8688_STATUS_UC_FAULT BIT(11) +#define MAX8688_STATUS_OC_WARNING BIT(12) +#define MAX8688_STATUS_OT_FAULT BIT(13) +#define MAX8688_STATUS_OT_WARNING BIT(14) static int max8688_read_word_data(struct i2c_client *client, int page, int reg) { diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index f1cb15c..bfcb13b 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -19,11 +19,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include - #ifndef PMBUS_H #define PMBUS_H +#include +#include + /* * Registers */ @@ -194,13 +195,13 @@ enum pmbus_regs { /* * OPERATION */ -#define PB_OPERATION_CONTROL_ON (1<<7) +#define PB_OPERATION_CONTROL_ON BIT(7) /* * CAPABILITY */ -#define PB_CAPABILITY_SMBALERT (1<<4) -#define PB_CAPABILITY_ERROR_CHECK (1<<7) +#define PB_CAPABILITY_SMBALERT BIT(4) +#define PB_CAPABILITY_ERROR_CHECK BIT(7) /* * VOUT_MODE @@ -215,94 +216,94 @@ enum pmbus_regs { /* * Fan configuration */ -#define PB_FAN_2_PULSE_MASK ((1 << 0) | (1 << 1)) -#define PB_FAN_2_RPM (1 << 2) -#define PB_FAN_2_INSTALLED (1 << 3) -#define PB_FAN_1_PULSE_MASK ((1 << 4) | (1 << 5)) -#define PB_FAN_1_RPM (1 << 6) -#define PB_FAN_1_INSTALLED (1 << 7) +#define PB_FAN_2_PULSE_MASK (BIT(0) | BIT(1)) +#define PB_FAN_2_RPM BIT(2) +#define PB_FAN_2_INSTALLED BIT(3) +#define PB_FAN_1_PULSE_MASK (BIT(4) | BIT(5)) +#define PB_FAN_1_RPM BIT(6) +#define PB_FAN_1_INSTALLED BIT(7) /* * STATUS_BYTE, STATUS_WORD (lower) */ -#define PB_STATUS_NONE_ABOVE (1<<0) -#define PB_STATUS_CML (1<<1) -#define PB_STATUS_TEMPERATURE (1<<2) -#define PB_STATUS_VIN_UV (1<<3) -#define PB_STATUS_IOUT_OC (1<<4) -#define PB_STATUS_VOUT_OV (1<<5) -#define PB_STATUS_OFF (1<<6) -#define PB_STATUS_BUSY (1<<7) +#define PB_STATUS_NONE_ABOVE BIT(0) +#define PB_STATUS_CML BIT(1) +#define PB_STATUS_TEMPERATURE BIT(2) +#define PB_STATUS_VIN_UV BIT(3) +#define PB_STATUS_IOUT_OC BIT(4) +#define PB_STATUS_VOUT_OV BIT(5) +#define PB_STATUS_OFF BIT(6) +#define PB_STATUS_BUSY BIT(7) /* * STATUS_WORD (upper) */ -#define PB_STATUS_UNKNOWN (1<<8) -#define PB_STATUS_OTHER (1<<9) -#define PB_STATUS_FANS (1<<10) -#define PB_STATUS_POWER_GOOD_N (1<<11) -#define PB_STATUS_WORD_MFR (1<<12) -#define PB_STATUS_INPUT (1<<13) -#define PB_STATUS_IOUT_POUT (1<<14) -#define PB_STATUS_VOUT (1<<15) +#define PB_STATUS_UNKNOWN BIT(8) +#define PB_STATUS_OTHER BIT(9) +#define PB_STATUS_FANS BIT(10) +#define PB_STATUS_POWER_GOOD_N BIT(11) +#define PB_STATUS_WORD_MFR BIT(12) +#define PB_STATUS_INPUT BIT(13) +#define PB_STATUS_IOUT_POUT BIT(14) +#define PB_STATUS_VOUT BIT(15) /* * STATUS_IOUT */ -#define PB_POUT_OP_WARNING (1<<0) -#define PB_POUT_OP_FAULT (1<<1) -#define PB_POWER_LIMITING (1<<2) -#define PB_CURRENT_SHARE_FAULT (1<<3) -#define PB_IOUT_UC_FAULT (1<<4) -#define PB_IOUT_OC_WARNING (1<<5) -#define PB_IOUT_OC_LV_FAULT (1<<6) -#define PB_IOUT_OC_FAULT (1<<7) +#define PB_POUT_OP_WARNING BIT(0) +#define PB_POUT_OP_FAULT BIT(1) +#define PB_POWER_LIMITING BIT(2) +#define PB_CURRENT_SHARE_FAULT BIT(3) +#define PB_IOUT_UC_FAULT BIT(4) +#define PB_IOUT_OC_WARNING BIT(5) +#define PB_IOUT_OC_LV_FAULT BIT(6) +#define PB_IOUT_OC_FAULT BIT(7) /* * STATUS_VOUT, STATUS_INPUT */ -#define PB_VOLTAGE_UV_FAULT (1<<4) -#define PB_VOLTAGE_UV_WARNING (1<<5) -#define PB_VOLTAGE_OV_WARNING (1<<6) -#define PB_VOLTAGE_OV_FAULT (1<<7) +#define PB_VOLTAGE_UV_FAULT BIT(4) +#define PB_VOLTAGE_UV_WARNING BIT(5) +#define PB_VOLTAGE_OV_WARNING BIT(6) +#define PB_VOLTAGE_OV_FAULT BIT(7) /* * STATUS_INPUT */ -#define PB_PIN_OP_WARNING (1<<0) -#define PB_IIN_OC_WARNING (1<<1) -#define PB_IIN_OC_FAULT (1<<2) +#define PB_PIN_OP_WARNING BIT(0) +#define PB_IIN_OC_WARNING BIT(1) +#define PB_IIN_OC_FAULT BIT(2) /* * STATUS_TEMPERATURE */ -#define PB_TEMP_UT_FAULT (1<<4) -#define PB_TEMP_UT_WARNING (1<<5) -#define PB_TEMP_OT_WARNING (1<<6) -#define PB_TEMP_OT_FAULT (1<<7) +#define PB_TEMP_UT_FAULT BIT(4) +#define PB_TEMP_UT_WARNING BIT(5) +#define PB_TEMP_OT_WARNING BIT(6) +#define PB_TEMP_OT_FAULT BIT(7) /* * STATUS_FAN */ -#define PB_FAN_AIRFLOW_WARNING (1<<0) -#define PB_FAN_AIRFLOW_FAULT (1<<1) -#define PB_FAN_FAN2_SPEED_OVERRIDE (1<<2) -#define PB_FAN_FAN1_SPEED_OVERRIDE (1<<3) -#define PB_FAN_FAN2_WARNING (1<<4) -#define PB_FAN_FAN1_WARNING (1<<5) -#define PB_FAN_FAN2_FAULT (1<<6) -#define PB_FAN_FAN1_FAULT (1<<7) +#define PB_FAN_AIRFLOW_WARNING BIT(0) +#define PB_FAN_AIRFLOW_FAULT BIT(1) +#define PB_FAN_FAN2_SPEED_OVERRIDE BIT(2) +#define PB_FAN_FAN1_SPEED_OVERRIDE BIT(3) +#define PB_FAN_FAN2_WARNING BIT(4) +#define PB_FAN_FAN1_WARNING BIT(5) +#define PB_FAN_FAN2_FAULT BIT(6) +#define PB_FAN_FAN1_FAULT BIT(7) /* * CML_FAULT_STATUS */ -#define PB_CML_FAULT_OTHER_MEM_LOGIC (1<<0) -#define PB_CML_FAULT_OTHER_COMM (1<<1) -#define PB_CML_FAULT_PROCESSOR (1<<3) -#define PB_CML_FAULT_MEMORY (1<<4) -#define PB_CML_FAULT_PACKET_ERROR (1<<5) -#define PB_CML_FAULT_INVALID_DATA (1<<6) -#define PB_CML_FAULT_INVALID_COMMAND (1<<7) +#define PB_CML_FAULT_OTHER_MEM_LOGIC BIT(0) +#define PB_CML_FAULT_OTHER_COMM BIT(1) +#define PB_CML_FAULT_PROCESSOR BIT(3) +#define PB_CML_FAULT_MEMORY BIT(4) +#define PB_CML_FAULT_PACKET_ERROR BIT(5) +#define PB_CML_FAULT_INVALID_DATA BIT(6) +#define PB_CML_FAULT_INVALID_COMMAND BIT(7) enum pmbus_sensor_classes { PSC_VOLTAGE_IN = 0, @@ -318,26 +319,26 @@ enum pmbus_sensor_classes { #define PMBUS_PAGES 32 /* Per PMBus specification */ /* Functionality bit mask */ -#define PMBUS_HAVE_VIN (1 << 0) -#define PMBUS_HAVE_VCAP (1 << 1) -#define PMBUS_HAVE_VOUT (1 << 2) -#define PMBUS_HAVE_IIN (1 << 3) -#define PMBUS_HAVE_IOUT (1 << 4) -#define PMBUS_HAVE_PIN (1 << 5) -#define PMBUS_HAVE_POUT (1 << 6) -#define PMBUS_HAVE_FAN12 (1 << 7) -#define PMBUS_HAVE_FAN34 (1 << 8) -#define PMBUS_HAVE_TEMP (1 << 9) -#define PMBUS_HAVE_TEMP2 (1 << 10) -#define PMBUS_HAVE_TEMP3 (1 << 11) -#define PMBUS_HAVE_STATUS_VOUT (1 << 12) -#define PMBUS_HAVE_STATUS_IOUT (1 << 13) -#define PMBUS_HAVE_STATUS_INPUT (1 << 14) -#define PMBUS_HAVE_STATUS_TEMP (1 << 15) -#define PMBUS_HAVE_STATUS_FAN12 (1 << 16) -#define PMBUS_HAVE_STATUS_FAN34 (1 << 17) -#define PMBUS_HAVE_VMON (1 << 18) -#define PMBUS_HAVE_STATUS_VMON (1 << 19) +#define PMBUS_HAVE_VIN BIT(0) +#define PMBUS_HAVE_VCAP BIT(1) +#define PMBUS_HAVE_VOUT BIT(2) +#define PMBUS_HAVE_IIN BIT(3) +#define PMBUS_HAVE_IOUT BIT(4) +#define PMBUS_HAVE_PIN BIT(5) +#define PMBUS_HAVE_POUT BIT(6) +#define PMBUS_HAVE_FAN12 BIT(7) +#define PMBUS_HAVE_FAN34 BIT(8) +#define PMBUS_HAVE_TEMP BIT(9) +#define PMBUS_HAVE_TEMP2 BIT(10) +#define PMBUS_HAVE_TEMP3 BIT(11) +#define PMBUS_HAVE_STATUS_VOUT BIT(12) +#define PMBUS_HAVE_STATUS_IOUT BIT(13) +#define PMBUS_HAVE_STATUS_INPUT BIT(14) +#define PMBUS_HAVE_STATUS_TEMP BIT(15) +#define PMBUS_HAVE_STATUS_FAN12 BIT(16) +#define PMBUS_HAVE_STATUS_FAN34 BIT(17) +#define PMBUS_HAVE_VMON BIT(18) +#define PMBUS_HAVE_STATUS_VMON BIT(19) enum pmbus_data_format { linear = 0, direct, vid }; enum vrm_version { vr11 = 0, vr12 }; diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index 8196441..771802d 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -19,6 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include @@ -44,16 +45,16 @@ struct zl6100_data { #define ZL6100_MFR_CONFIG 0xd0 #define ZL6100_DEVICE_ID 0xe4 -#define ZL6100_MFR_XTEMP_ENABLE (1 << 7) +#define ZL6100_MFR_XTEMP_ENABLE BIT(7) #define MFR_VMON_OV_FAULT_LIMIT 0xf5 #define MFR_VMON_UV_FAULT_LIMIT 0xf6 #define MFR_READ_VMON 0xf7 -#define VMON_UV_WARNING (1 << 5) -#define VMON_OV_WARNING (1 << 4) -#define VMON_UV_FAULT (1 << 1) -#define VMON_OV_FAULT (1 << 0) +#define VMON_UV_WARNING BIT(5) +#define VMON_OV_WARNING BIT(4) +#define VMON_UV_FAULT BIT(1) +#define VMON_OV_FAULT BIT(0) #define ZL6100_WAIT_TIME 1000 /* uS */ -- cgit v1.1 From d830e27dac26b4f084c5ed2282666527f90db0ed Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Aug 2015 16:26:21 -0700 Subject: hwmon: (pmbus) Enable PEC if the controller supports it PMBus controllers optionally support PEC. Configure the driver to use it if available to improve operational security. Suggested-by: Michael Jones Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus_core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 3981981..ba59eae 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -1751,6 +1751,11 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, } } + /* Enable PEC if the controller supports it */ + ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); + if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) + client->flags |= I2C_CLIENT_PEC; + pmbus_clear_faults(client); if (info->identify) { -- cgit v1.1 From e04d1ce9bbb49862fd8266da764f5ebf67baaac0 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Mon, 17 Aug 2015 17:45:32 -0700 Subject: hwmon: (ltc2978) Add polling for chips requiring it Some of the LTC chips supported by this driver have to be polled to ensure that they are ready to accept commands. Signed-off-by: Michael Jones [Guenter Roeck: simplifications and formatting changes] Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/ltc2978.c | 111 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 101 insertions(+), 10 deletions(-) diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 60fe8f9..f1c69c9 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -3,6 +3,7 @@ * * Copyright (c) 2011 Ericsson AB. * Copyright (c) 2013, 2014, 2015 Guenter Roeck + * Copyright (c) 2015 Linear Technology * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,6 +16,8 @@ * GNU General Public License for more details. */ +#include +#include #include #include #include @@ -32,6 +35,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTC2978_MFR_VIN_PEAK 0xde #define LTC2978_MFR_TEMPERATURE_PEAK 0xdf #define LTC2978_MFR_SPECIAL_ID 0xe7 /* Undocumented on LTC3882 */ +#define LTC2978_MFR_COMMON 0xef /* LTC2974, LTC2975, LCT2977, LTC2980, LTC2978, and LTM2987 */ #define LTC2978_MFR_VOUT_MIN 0xfb @@ -82,6 +86,11 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTC3880_NUM_PAGES 2 #define LTC3883_NUM_PAGES 1 +#define LTC_POLL_TIMEOUT 100 /* in milli-seconds */ + +#define LTC_NOT_BUSY BIT(5) +#define LTC_NOT_PENDING BIT(4) + /* * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which * happens pretty much each time chip data is updated. Raw peak data therefore @@ -105,8 +114,81 @@ struct ltc2978_data { #define to_ltc2978_data(x) container_of(x, struct ltc2978_data, info) #define FEAT_CLEAR_PEAKS BIT(0) +#define FEAT_NEEDS_POLLING BIT(1) #define has_clear_peaks(d) ((d)->features & FEAT_CLEAR_PEAKS) +#define needs_polling(d) ((d)->features & FEAT_NEEDS_POLLING) + +static int ltc_wait_ready(struct i2c_client *client) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(LTC_POLL_TIMEOUT); + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct ltc2978_data *data = to_ltc2978_data(info); + int status; + u8 mask; + + if (!needs_polling(data)) + return 0; + + /* + * LTC3883 does not support LTC_NOT_PENDING, even though + * the datasheet claims that it does. + */ + mask = LTC_NOT_BUSY; + if (data->id != ltc3883) + mask |= LTC_NOT_PENDING; + + do { + status = pmbus_read_byte_data(client, 0, LTC2978_MFR_COMMON); + if (status == -EBADMSG || status == -ENXIO) { + /* PEC error or NACK: chip may be busy, try again */ + usleep_range(50, 100); + continue; + } + if (status < 0) + return status; + + if ((status & mask) == mask) + return 0; + + usleep_range(50, 100); + } while (time_before(jiffies, timeout)); + + return -ETIMEDOUT; +} + +static int ltc_read_word_data(struct i2c_client *client, int page, int reg) +{ + int ret; + + ret = ltc_wait_ready(client); + if (ret < 0) + return ret; + + return pmbus_read_word_data(client, page, reg); +} + +static int ltc_read_byte_data(struct i2c_client *client, int page, int reg) +{ + int ret; + + ret = ltc_wait_ready(client); + if (ret < 0) + return ret; + + return pmbus_read_byte_data(client, page, reg); +} + +static int ltc_write_byte(struct i2c_client *client, int page, u8 byte) +{ + int ret; + + ret = ltc_wait_ready(client); + if (ret < 0) + return ret; + + return pmbus_write_byte(client, page, byte); +} static inline int lin11_to_val(int data) { @@ -126,7 +208,7 @@ static int ltc_get_max(struct ltc2978_data *data, struct i2c_client *client, { int ret; - ret = pmbus_read_word_data(client, page, reg); + ret = ltc_read_word_data(client, page, reg); if (ret >= 0) { if (lin11_to_val(ret) > lin11_to_val(*pmax)) *pmax = ret; @@ -140,7 +222,7 @@ static int ltc_get_min(struct ltc2978_data *data, struct i2c_client *client, { int ret; - ret = pmbus_read_word_data(client, page, reg); + ret = ltc_read_word_data(client, page, reg); if (ret >= 0) { if (lin11_to_val(ret) < lin11_to_val(*pmin)) *pmin = ret; @@ -162,7 +244,7 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page, &data->vin_max); break; case PMBUS_VIRT_READ_VOUT_MAX: - ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK); + ret = ltc_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK); if (ret >= 0) { /* * VOUT is 16 bit unsigned with fixed exponent, @@ -184,6 +266,9 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page, ret = 0; break; default: + ret = ltc_wait_ready(client); + if (ret < 0) + return ret; ret = -ENODATA; break; } @@ -202,7 +287,7 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg) &data->vin_min); break; case PMBUS_VIRT_READ_VOUT_MIN: - ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_MIN); + ret = ltc_read_word_data(client, page, LTC2978_MFR_VOUT_MIN); if (ret >= 0) { /* * VOUT_MIN is known to not be supported on some lots @@ -353,9 +438,9 @@ static int ltc2978_clear_peaks(struct ltc2978_data *data, int ret; if (has_clear_peaks(data)) - ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); + ret = ltc_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); else - ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); + ret = ltc_write_byte(client, page, PMBUS_CLEAR_FAULTS); return ret; } @@ -403,6 +488,9 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, ret = ltc2978_clear_peaks(data, client, page); break; default: + ret = ltc_wait_ready(client); + if (ret < 0) + return ret; ret = -ENODATA; break; } @@ -530,6 +618,9 @@ static int ltc2978_probe(struct i2c_client *client, info = &data->info; info->write_word_data = ltc2978_write_word_data; + info->write_byte = ltc_write_byte; + info->read_word_data = ltc_read_word_data; + info->read_byte_data = ltc_read_byte_data; data->vin_min = 0x7bff; data->vin_max = 0x7c00; @@ -588,7 +679,7 @@ static int ltc2978_probe(struct i2c_client *client, case ltc3880: case ltc3887: case ltm4676: - data->features |= FEAT_CLEAR_PEAKS; + data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING; info->read_word_data = ltc3880_read_word_data; info->pages = LTC3880_NUM_PAGES; info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN @@ -603,7 +694,7 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; break; case ltc3882: - data->features |= FEAT_CLEAR_PEAKS; + data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING; info->read_word_data = ltc3880_read_word_data; info->pages = LTC3880_NUM_PAGES; info->func[0] = PMBUS_HAVE_VIN @@ -618,7 +709,7 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; break; case ltc3883: - data->features |= FEAT_CLEAR_PEAKS; + data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING; info->read_word_data = ltc3883_read_word_data; info->pages = LTC3883_NUM_PAGES; info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN @@ -629,7 +720,7 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; break; case ltc3886: - data->features |= FEAT_CLEAR_PEAKS; + data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING; info->read_word_data = ltc3883_read_word_data; info->pages = LTC3880_NUM_PAGES; info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN -- cgit v1.1 From ccf2dc51bc4a715670641aa5af0d4636acd8e0cd Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 17 Aug 2015 20:08:09 -0700 Subject: hwmon: (ltc2978) Add support for LTM4675 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LTM2975 is a dual 9A or single 18A μModule regulator. It is register compatible with LTM4676. Signed-off-by: Guenter Roeck --- Documentation/hwmon/ltc2978 | 24 ++++++++++++++++-------- drivers/hwmon/pmbus/Kconfig | 2 +- drivers/hwmon/pmbus/ltc2978.c | 10 ++++++++-- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978 index f997aa5..9a49d3c 100644 --- a/Documentation/hwmon/ltc2978 +++ b/Documentation/hwmon/ltc2978 @@ -47,6 +47,10 @@ Supported chips: Prefix: 'ltm2987' Addresses scanned: - Datasheet: http://www.linear.com/product/ltm2987 + * Linear Technology LTM4675 + Prefix: 'ltm4675' + Addresses scanned: - + Datasheet: http://www.linear.com/product/ltm4675 * Linear Technology LTM4676 Prefix: 'ltm4676' Addresses scanned: - @@ -70,6 +74,7 @@ LTC3883 is a single phase step-down DC/DC controller. LTM2987 is a 16-channel Power System Manager with two LTC2977 plus additional components on a single die. The chip is instantiated and reported as two separate chips on two different I2C bus addresses. +LTM4675 is a dual 9A or single 18A μModule regulator LTM4676 is a dual 13A or single 26A uModule regulator. @@ -117,7 +122,8 @@ in[N]_label "vout[1-8]". LTC2974, LTC2975: N=2-5 LTC2977, LTC2980, LTM2987: N=2-9 LTC2978: N=2-9 - LTC3880, LTC3882, LTC23886 LTC3887, LTM4676: N=2-3 + LTC3880, LTC3882, LTC23886 LTC3887, LTM4675, LTM4676: + N=2-3 LTC3883: N=2 in[N]_input Measured output voltage. in[N]_min Minimum output voltage. @@ -139,9 +145,9 @@ temp[N]_input Measured temperature. On LTC2977, LTC2980, LTC2978, and LTM2987, only one temperature measurement is supported and reports the chip temperature. - On LTC3880, LTC3882, LTC3887, and LTM4676, temp1 and - temp2 report external temperatures, and temp3 reports - the chip temperature. + On LTC3880, LTC3882, LTC3887, LTM4675, and LTM4676, + temp1 and temp2 report external temperatures, and temp3 + reports the chip temperature. On LTC3883, temp1 reports an external temperature, and temp2 reports the chip temperature. temp[N]_min Mimimum temperature. LTC2974, LCT2977, LTM2980, LTC2978, @@ -172,12 +178,13 @@ power[N]_label "pout[1-4]". LTC2974, LTC2975: N=1-4 LTC2977, LTC2980, LTM2987: Not supported LTC2978: Not supported - LTC3880, LTC3882, LTC3886, LTC3887, LTM4676: N=1-2 + LTC3880, LTC3882, LTC3886, LTC3887, LTM4675, LTM4676: + N=1-2 LTC3883: N=2 power[N]_input Measured output power. -curr1_label "iin". LTC3880, LTC3883, LTC3886, LTC3887, and LTM4676 - only. +curr1_label "iin". LTC3880, LTC3883, LTC3886, LTC3887, LTM4675, + and LTM4676 only. curr1_input Measured input current. curr1_max Maximum input current. curr1_max_alarm Input current high alarm. @@ -188,7 +195,8 @@ curr[N]_label "iout[1-4]". LTC2974, LTC2975: N=1-4 LTC2977, LTC2980, LTM2987: not supported LTC2978: not supported - LTC3880, LTC3882, LTC3886, LTC3887, LTM4676: N=2-3 + LTC3880, LTC3882, LTC3886, LTC3887, LTM4675, LTM4676: + N=2-3 LTC3883: N=2 curr[N]_input Measured output current. curr[N]_max Maximum output current. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 5ebc362..df6ebb2 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -53,7 +53,7 @@ config SENSORS_LTC2978 help If you say yes here you get hardware monitoring support for Linear Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880, - LTC3883, LTC3886, LTC3887, LTCM2987, and LTM4676. + LTC3883, LTC3886, LTC3887, LTCM2987, LTM4675, and LTM4676. This driver can also be built as a module. If so, the module will be called ltc2978. diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index f1c69c9..58b789c 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -28,7 +28,7 @@ #include "pmbus.h" enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, - ltc3883, ltc3886, ltc3887, ltm2987, ltm4676 }; + ltc3883, ltc3886, ltc3887, ltm2987, ltm4675, ltm4676 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -46,7 +46,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTC2974_MFR_IOUT_PEAK 0xd7 #define LTC2974_MFR_IOUT_MIN 0xd8 -/* LTC3880, LTC3882, LTC3883, LTC3887, and LTM4676 */ +/* LTC3880, LTC3882, LTC3883, LTC3887, LTM4675, and LTM4676 */ #define LTC3880_MFR_IOUT_PEAK 0xd7 #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 @@ -77,6 +77,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTC3887_ID 0x4700 #define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ #define LTM2987_ID_B 0x8020 +#define LTM4675_ID 0x47a0 #define LTM4676_ID_REV1 0x4400 #define LTM4676_ID_REV2 0x4480 #define LTM4676A_ID 0x47e0 @@ -509,6 +510,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc3886", ltc3886}, {"ltc3887", ltc3887}, {"ltm2987", ltm2987}, + {"ltm4675", ltm4675}, {"ltm4676", ltm4676}, {} }; @@ -581,6 +583,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3887; else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B) return ltm2987; + else if (chip_id == LTM4675_ID) + return ltm4675; else if (chip_id == LTM4676_ID_REV1 || chip_id == LTM4676_ID_REV2 || chip_id == LTM4676A_ID) return ltm4676; @@ -678,6 +682,7 @@ static int ltc2978_probe(struct i2c_client *client, break; case ltc3880: case ltc3887: + case ltm4675: case ltm4676: data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING; info->read_word_data = ltc3880_read_word_data; @@ -763,6 +768,7 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc3886" }, { .compatible = "lltc,ltc3887" }, { .compatible = "lltc,ltm2987" }, + { .compatible = "lltc,ltm4675" }, { .compatible = "lltc,ltm4676" }, { } }; -- cgit v1.1 From 5dc087254acf12bf6908a924539fb624891e8b24 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Thu, 27 Aug 2015 16:07:32 +0800 Subject: hwmon: (fam15h_power) Add support for AMD Carrizo AMD Carrizo(Fam15h, M60h) processors can report power1_crit (ProcessorPwrWatts) and power1_input (CurrPwrWatts) values. And this patch adds support for CZ. Signed-off-by: Huang Rui Signed-off-by: Guenter Roeck --- drivers/hwmon/fam15h_power.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index 3057dfc..0753810 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -233,6 +233,7 @@ static int fam15h_power_probe(struct pci_dev *pdev, static const struct pci_device_id fam15h_power_id_table[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F4) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) }, {} -- cgit v1.1 From d83e92b3af602c6ebb6d25d5232ecba73201a0e5 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Thu, 27 Aug 2015 16:07:33 +0800 Subject: hwmon: (fam15h_power) Rename fam15h_power_is_internal_node0 function We rename fam15h_power_is_internal_node0() function to should_load_on_this_node(), because it may not be node0 from KV and on, and they are single-node processors. Signed-off-by: Huang Rui Signed-off-by: Guenter Roeck --- drivers/hwmon/fam15h_power.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index 0753810..820adf1 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -117,7 +117,7 @@ static const struct attribute_group fam15h_power_group = { }; __ATTRIBUTE_GROUPS(fam15h_power); -static bool fam15h_power_is_internal_node0(struct pci_dev *f4) +static bool should_load_on_this_node(struct pci_dev *f4) { u32 val; @@ -214,7 +214,7 @@ static int fam15h_power_probe(struct pci_dev *pdev, */ tweak_runavg_range(pdev); - if (!fam15h_power_is_internal_node0(pdev)) + if (!should_load_on_this_node(pdev)) return -ENODEV; data = devm_kzalloc(dev, sizeof(struct fam15h_power_data), GFP_KERNEL); -- cgit v1.1 From e9cd4d55d16f880ddf436fbae8c0c82ce0a928d5 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Thu, 27 Aug 2015 16:07:35 +0800 Subject: hwmon: (fam15h_power) Update running_avg_capture bit field to 28 On Carrizo and later platforms, running_avg_capture bit field is extended to 4:31 (28 bits) from 4:25. Signed-off-by: Huang Rui Signed-off-by: Guenter Roeck --- drivers/hwmon/fam15h_power.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index 820adf1..4117490 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -59,8 +59,19 @@ static ssize_t show_power(struct device *dev, pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5), REG_TDP_RUNNING_AVERAGE, &val); - running_avg_capture = (val >> 4) & 0x3fffff; - running_avg_capture = sign_extend32(running_avg_capture, 21); + + /* + * On Carrizo and later platforms, TdpRunAvgAccCap bit field + * is extended to 4:31 from 4:25. + */ + if (boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model >= 0x60) { + running_avg_capture = val >> 4; + running_avg_capture = sign_extend32(running_avg_capture, 27); + } else { + running_avg_capture = (val >> 4) & 0x3fffff; + running_avg_capture = sign_extend32(running_avg_capture, 21); + } + running_avg_range = (val & 0xf) + 1; pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5), -- cgit v1.1 From 5aeb5d205e122b70742df94a7d51a3502f1a8277 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Thu, 27 Aug 2015 16:07:37 +0800 Subject: hwmon: (fam15h_power) Add documentation for new processors support This patch updates description of fam15h_power driver, its scope is extended to family 16h processsors. Signed-off-by: Huang Rui Signed-off-by: Guenter Roeck --- Documentation/hwmon/fam15h_power | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Documentation/hwmon/fam15h_power b/Documentation/hwmon/fam15h_power index 8065481..e2b1b69 100644 --- a/Documentation/hwmon/fam15h_power +++ b/Documentation/hwmon/fam15h_power @@ -3,12 +3,13 @@ Kernel driver fam15h_power Supported chips: * AMD Family 15h Processors +* AMD Family 16h Processors Prefix: 'fam15h_power' Addresses scanned: PCI space Datasheets: BIOS and Kernel Developer's Guide (BKDG) For AMD Family 15h Processors - (not yet published) + BIOS and Kernel Developer's Guide (BKDG) For AMD Family 16h Processors Author: Andreas Herrmann @@ -16,10 +17,11 @@ Description ----------- This driver permits reading of registers providing power information -of AMD Family 15h processors. +of AMD Family 15h and 16h processors. -For AMD Family 15h processors the following power values can be -calculated using different processor northbridge function registers: +For AMD Family 15h and 16h processors the following power values can +be calculated using different processor northbridge function +registers: * BasePwrWatts: Specifies in watts the maximum amount of power consumed by the processor for NB and logic external to the core. -- cgit v1.1 From 1ed32160dba643e61504b334f45b002198c88254 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Thu, 27 Aug 2015 16:07:38 +0800 Subject: hwmon: (fam15h_power) Add ratio of Tsample to the PTSC period This patch adds a member (cpu_pwr_sample_ratio) of fam15h_power_data, that represents the ratio of compute unit power accumulator sample period to the PTSC counter period. Tsample: compute unit power accumulator sample period Tref: the performance timestamp counter period PTSC: performance timestamp counter Signed-off-by: Huang Rui Signed-off-by: Guenter Roeck --- drivers/hwmon/fam15h_power.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index 4117490..e80ee23 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -46,6 +46,7 @@ struct fam15h_power_data { unsigned int tdp_to_watts; unsigned int base_tdp; unsigned int processor_pwr_watts; + unsigned int cpu_pwr_sample_ratio; }; static ssize_t show_power(struct device *dev, @@ -188,7 +189,7 @@ static int fam15h_power_resume(struct pci_dev *pdev) static void fam15h_power_init_data(struct pci_dev *f4, struct fam15h_power_data *data) { - u32 val; + u32 val, eax, ebx, ecx, edx; u64 tmp; pci_read_config_dword(f4, REG_PROCESSOR_TDP, &val); @@ -209,6 +210,19 @@ static void fam15h_power_init_data(struct pci_dev *f4, /* convert to microWatt */ data->processor_pwr_watts = (tmp * 15625) >> 10; + + cpuid(0x80000007, &eax, &ebx, &ecx, &edx); + + /* CPUID Fn8000_0007:EDX[12] indicates to support accumulated power */ + if (!(edx & BIT(12))) + return; + + /* + * determine the ratio of the compute unit power accumulator + * sample period to the PTSC counter period by executing CPUID + * Fn8000_0007:ECX + */ + data->cpu_pwr_sample_ratio = ecx; } static int fam15h_power_probe(struct pci_dev *pdev, -- cgit v1.1