diff options
-rw-r--r-- | drivers/hwmon/pmbus/adm1275.c | 6 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max16064.c | 6 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max34440.c | 18 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max8688.c | 8 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/pmbus.c | 34 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/pmbus.h | 7 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/pmbus_core.c | 60 |
7 files changed, 105 insertions, 34 deletions
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 8bc1bd66372..71770ffbdaf 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -50,9 +50,9 @@ static int adm1275_probe(struct i2c_client *client, } info->pages = 1; - info->direct[PSC_VOLTAGE_IN] = true; - info->direct[PSC_VOLTAGE_OUT] = true; - info->direct[PSC_CURRENT_OUT] = true; + 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; diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c index 1d6d717060d..78e20bca53a 100644 --- a/drivers/hwmon/pmbus/max16064.c +++ b/drivers/hwmon/pmbus/max16064.c @@ -27,9 +27,9 @@ static struct pmbus_driver_info max16064_info = { .pages = 4, - .direct[PSC_VOLTAGE_IN] = true, - .direct[PSC_VOLTAGE_OUT] = true, - .direct[PSC_TEMPERATURE] = true, + .format[PSC_VOLTAGE_IN] = direct, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_TEMPERATURE] = direct, .m[PSC_VOLTAGE_IN] = 19995, .b[PSC_VOLTAGE_IN] = 0, .R[PSC_VOLTAGE_IN] = -1, diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index db11e1a175b..2e30046a116 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -72,10 +72,10 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg) static struct pmbus_driver_info max34440_info[] = { [max34440] = { .pages = 14, - .direct[PSC_VOLTAGE_IN] = true, - .direct[PSC_VOLTAGE_OUT] = true, - .direct[PSC_TEMPERATURE] = true, - .direct[PSC_CURRENT_OUT] = true, + .format[PSC_VOLTAGE_IN] = direct, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_TEMPERATURE] = direct, + .format[PSC_CURRENT_OUT] = direct, .m[PSC_VOLTAGE_IN] = 1, .b[PSC_VOLTAGE_IN] = 0, .R[PSC_VOLTAGE_IN] = 3, /* R = 0 in datasheet reflects mV */ @@ -112,11 +112,11 @@ static struct pmbus_driver_info max34440_info[] = { }, [max34441] = { .pages = 12, - .direct[PSC_VOLTAGE_IN] = true, - .direct[PSC_VOLTAGE_OUT] = true, - .direct[PSC_TEMPERATURE] = true, - .direct[PSC_CURRENT_OUT] = true, - .direct[PSC_FAN] = true, + .format[PSC_VOLTAGE_IN] = direct, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_TEMPERATURE] = direct, + .format[PSC_CURRENT_OUT] = direct, + .format[PSC_FAN] = direct, .m[PSC_VOLTAGE_IN] = 1, .b[PSC_VOLTAGE_IN] = 0, .R[PSC_VOLTAGE_IN] = 3, diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index 7fb93f4e9f2..ddc8a64c2ba 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -91,10 +91,10 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg) static struct pmbus_driver_info max8688_info = { .pages = 1, - .direct[PSC_VOLTAGE_IN] = true, - .direct[PSC_VOLTAGE_OUT] = true, - .direct[PSC_TEMPERATURE] = true, - .direct[PSC_CURRENT_OUT] = true, + .format[PSC_VOLTAGE_IN] = direct, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_TEMPERATURE] = direct, + .format[PSC_CURRENT_OUT] = direct, .m[PSC_VOLTAGE_IN] = 19995, .b[PSC_VOLTAGE_IN] = 0, .R[PSC_VOLTAGE_IN] = -1, diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 9b1f0c37ef7..4d8e31bcd7a 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -96,6 +96,8 @@ static void pmbus_find_sensor_groups(struct i2c_client *client, static int pmbus_identify(struct i2c_client *client, struct pmbus_driver_info *info) { + int ret = 0; + if (!info->pages) { /* * Check if the PAGE command is supported. If it is, @@ -117,6 +119,27 @@ static int pmbus_identify(struct i2c_client *client, } } + if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) { + int vout_mode; + + vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); + if (vout_mode >= 0 && vout_mode != 0xff) { + switch (vout_mode >> 5) { + case 0: + break; + case 1: + info->format[PSC_VOLTAGE_OUT] = vid; + break; + case 2: + info->format[PSC_VOLTAGE_OUT] = direct; + break; + default: + ret = -ENODEV; + goto abort; + } + } + } + /* * We should check if the COEFFICIENTS register is supported. * If it is, and the chip is configured for direct mode, we can read @@ -125,13 +148,18 @@ static int pmbus_identify(struct i2c_client *client, * * To do this, we will need access to a chip which actually supports the * COEFFICIENTS command, since the command is too complex to implement - * without testing it. + * without testing it. Until then, abort if a chip configured for direct + * mode was detected. */ + if (info->format[PSC_VOLTAGE_OUT] == direct) { + ret = -ENODEV; + goto abort; + } /* Try to find sensor groups */ pmbus_find_sensor_groups(client, info); - - return 0; +abort: + return ret; } static int pmbus_probe(struct i2c_client *client, diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 50647ab7235..cc5b6a23260 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -266,11 +266,11 @@ enum pmbus_sensor_classes { #define PMBUS_HAVE_STATUS_FAN12 (1 << 16) #define PMBUS_HAVE_STATUS_FAN34 (1 << 17) +enum pmbus_data_format { linear = 0, direct, vid }; + struct pmbus_driver_info { int pages; /* Total number of pages */ - bool direct[PSC_NUM_CLASSES]; - /* true if device uses direct data format - for the given sensor class */ + enum pmbus_data_format format[PSC_NUM_CLASSES]; /* * Support one set of coefficients for each sensor type * Used for chips providing data in direct mode. @@ -299,6 +299,7 @@ struct pmbus_driver_info { int pmbus_set_page(struct i2c_client *client, u8 page); int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg); +int pmbus_read_byte_data(struct i2c_client *client, u8 page, u8 reg); void pmbus_clear_faults(struct i2c_client *client); bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 8e31a8e2c74..cef763c7da3 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -197,7 +197,7 @@ int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg) } EXPORT_SYMBOL_GPL(pmbus_read_word_data); -static int pmbus_read_byte_data(struct i2c_client *client, u8 page, u8 reg) +int pmbus_read_byte_data(struct i2c_client *client, u8 page, u8 reg) { int rv; @@ -207,6 +207,7 @@ static int pmbus_read_byte_data(struct i2c_client *client, u8 page, u8 reg) return i2c_smbus_read_byte_data(client, reg); } +EXPORT_SYMBOL_GPL(pmbus_read_byte_data); static void pmbus_clear_fault_page(struct i2c_client *client, int page) { @@ -443,15 +444,37 @@ static long pmbus_reg2data_direct(struct pmbus_data *data, return (val - b) / m; } +/* + * 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; + + if (val < 0x02 || val > 0xb2) + return 0; + return DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); +} + static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) { long val; - if (data->info->direct[sensor->class]) + switch (data->info->format[sensor->class]) { + case direct: val = pmbus_reg2data_direct(data, sensor); - else + break; + case vid: + val = pmbus_reg2data_vid(data, sensor); + break; + case linear: + default: val = pmbus_reg2data_linear(data, sensor); - + break; + } return val; } @@ -561,16 +584,31 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data, return val; } +static u16 pmbus_data2reg_vid(struct pmbus_data *data, + enum pmbus_sensor_classes class, long val) +{ + val = SENSORS_LIMIT(val, 500, 1600); + + return 2 + DIV_ROUND_CLOSEST((1600 - val) * 100, 625); +} + static u16 pmbus_data2reg(struct pmbus_data *data, enum pmbus_sensor_classes class, long val) { u16 regval; - if (data->info->direct[class]) + switch (data->info->format[class]) { + case direct: regval = pmbus_data2reg_direct(data, class, val); - else + break; + case vid: + regval = pmbus_data2reg_vid(data, class, val); + break; + case linear: + default: regval = pmbus_data2reg_linear(data, class, val); - + break; + } return regval; } @@ -1380,7 +1418,7 @@ static int pmbus_identify_common(struct i2c_client *client, */ switch (vout_mode >> 5) { case 0: /* linear mode */ - if (data->info->direct[PSC_VOLTAGE_OUT]) + if (data->info->format[PSC_VOLTAGE_OUT] != linear) return -ENODEV; exponent = vout_mode & 0x1f; @@ -1389,8 +1427,12 @@ static int pmbus_identify_common(struct i2c_client *client, exponent |= ~0x1f; data->exponent = exponent; break; + case 1: /* VID mode */ + if (data->info->format[PSC_VOLTAGE_OUT] != vid) + return -ENODEV; + break; case 2: /* direct mode */ - if (!data->info->direct[PSC_VOLTAGE_OUT]) + if (data->info->format[PSC_VOLTAGE_OUT] != direct) return -ENODEV; break; default: |