diff options
Diffstat (limited to 'drivers/hwmon/pmbus')
-rw-r--r-- | drivers/hwmon/pmbus/Kconfig | 21 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/adm1275.c | 37 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/ibm-cffps.c | 29 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/ir35221.c | 23 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/isl68137.c | 114 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/lm25066.c | 39 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/ltc2978.c | 130 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/ltc3815.c | 20 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max16064.c | 7 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max20730.c | 3 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max31785.c | 6 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max34440.c | 25 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max8688.c | 17 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/pmbus.c | 4 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/pmbus.h | 20 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/pmbus_core.c | 119 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/tps53679.c | 172 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/ucd9000.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/xdpe12284.c | 5 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/zl6100.c | 5 |
20 files changed, 616 insertions, 182 deletions
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index a9ea06204767..de12a565006d 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -92,10 +92,10 @@ config SENSORS_IRPS5401 be called irps5401. config SENSORS_ISL68137 - tristate "Intersil ISL68137" + tristate "Renesas Digital Multiphase Voltage Regulators" help - If you say yes here you get hardware monitoring support for Intersil - ISL68137. + If you say yes here you get hardware monitoring support for Renesas + digital multiphase voltage regulators. This driver can also be built as a module. If so, the module will be called isl68137. @@ -113,8 +113,8 @@ config SENSORS_LTC2978 tristate "Linear Technologies LTC2978 and compatibles" help If you say yes here you get hardware monitoring support for Linear - Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880, - LTC3883, LTC3886, LTC3887, LTCM2987, LTM4675, and LTM4676. + Technology LTC2972, LTC2974, LTC2975, LTC2977, LTC2978, LTC2979, + LTC2980, and LTM2987. This driver can also be built as a module. If so, the module will be called ltc2978. @@ -123,9 +123,10 @@ config SENSORS_LTC2978_REGULATOR bool "Regulator support for LTC2978 and compatibles" depends on SENSORS_LTC2978 && REGULATOR help - If you say yes here you get regulator support for Linear - Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, LTM4676 - and LTM4686. + If you say yes here you get regulator support for Linear Technology + LTC3880, LTC3883, LTC3884, LTC3886, LTC3887, LTC3889, LTC7880, + LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, LTM4686, + and LTM4700. config SENSORS_LTC3815 tristate "Linear Technologies LTC3815" @@ -209,10 +210,10 @@ config SENSORS_TPS40422 be called tps40422. config SENSORS_TPS53679 - tristate "TI TPS53679, TPS53688" + tristate "TI TPS53647, TPS53667, TPS53679, TPS53681, TPS53688" help If you say yes here you get hardware monitoring support for TI - TPS53679, TPS53688 + TPS53647, TPS53667, TPS53679, TPS53681, and TPS53688. This driver can also be built as a module. If so, the module will be called tps53679. diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 5caa37fbfc18..e25f541227da 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -226,7 +226,8 @@ static int adm1275_write_pmon_config(const struct adm1275_data *data, return ret; } -static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) +static int adm1275_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); const struct adm1275_data *data = to_adm1275_data(info); @@ -239,58 +240,68 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) case PMBUS_IOUT_UC_FAULT_LIMIT: if (!data->have_uc_fault) return -ENXIO; - ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); + ret = pmbus_read_word_data(client, 0, 0xff, + ADM1275_IOUT_WARN2_LIMIT); break; case PMBUS_IOUT_OC_FAULT_LIMIT: if (!data->have_oc_fault) return -ENXIO; - ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); + ret = pmbus_read_word_data(client, 0, 0xff, + ADM1275_IOUT_WARN2_LIMIT); break; case PMBUS_VOUT_OV_WARN_LIMIT: if (data->have_vout) return -ENODATA; - ret = pmbus_read_word_data(client, 0, + ret = pmbus_read_word_data(client, 0, 0xff, ADM1075_VAUX_OV_WARN_LIMIT); break; case PMBUS_VOUT_UV_WARN_LIMIT: if (data->have_vout) return -ENODATA; - ret = pmbus_read_word_data(client, 0, + ret = pmbus_read_word_data(client, 0, 0xff, ADM1075_VAUX_UV_WARN_LIMIT); break; case PMBUS_READ_VOUT: if (data->have_vout) return -ENODATA; - ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX); + ret = pmbus_read_word_data(client, 0, 0xff, + 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); + ret = pmbus_read_word_data(client, 0, 0xff, + ADM1293_IOUT_MIN); break; case PMBUS_VIRT_READ_IOUT_MAX: - ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT); + ret = pmbus_read_word_data(client, 0, 0xff, + ADM1275_PEAK_IOUT); break; case PMBUS_VIRT_READ_VOUT_MAX: - ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VOUT); + ret = pmbus_read_word_data(client, 0, 0xff, + ADM1275_PEAK_VOUT); break; case PMBUS_VIRT_READ_VIN_MAX: - ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN); + ret = pmbus_read_word_data(client, 0, 0xff, + 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); + ret = pmbus_read_word_data(client, 0, 0xff, + ADM1293_PIN_MIN); break; case PMBUS_VIRT_READ_PIN_MAX: if (!data->have_pin_max) return -ENXIO; - ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN); + ret = pmbus_read_word_data(client, 0, 0xff, + ADM1276_PEAK_PIN); break; case PMBUS_VIRT_READ_TEMP_MAX: if (!data->have_temp_max) return -ENXIO; - ret = pmbus_read_word_data(client, 0, ADM1278_PEAK_TEMP); + ret = pmbus_read_word_data(client, 0, 0xff, + ADM1278_PEAK_TEMP); break; case PMBUS_VIRT_RESET_IOUT_HISTORY: case PMBUS_VIRT_RESET_VOUT_HISTORY: diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index 3795fe55b84f..7d300f2f338d 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -33,9 +33,12 @@ #define CFFPS_INPUT_HISTORY_CMD 0xD6 #define CFFPS_INPUT_HISTORY_SIZE 100 +#define CFFPS_CCIN_REVISION GENMASK(7, 0) +#define CFFPS_CCIN_REVISION_LEGACY 0xde #define CFFPS_CCIN_VERSION GENMASK(15, 8) #define CFFPS_CCIN_VERSION_1 0x2b #define CFFPS_CCIN_VERSION_2 0x2e +#define CFFPS_CCIN_VERSION_3 0x51 /* STATUS_MFR_SPECIFIC bits */ #define CFFPS_MFR_FAN_FAULT BIT(0) @@ -148,7 +151,7 @@ static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf, struct ibm_cffps *psu = to_psu(idxp, idx); char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 }; - pmbus_set_page(psu->client, 0); + pmbus_set_page(psu->client, 0, 0xff); switch (idx) { case CFFPS_DEBUGFS_INPUT_HISTORY: @@ -247,7 +250,7 @@ static ssize_t ibm_cffps_debugfs_write(struct file *file, switch (idx) { case CFFPS_DEBUGFS_ON_OFF_CONFIG: - pmbus_set_page(psu->client, 0); + pmbus_set_page(psu->client, 0, 0xff); rc = simple_write_to_buffer(&data, 1, ppos, buf, count); if (rc <= 0) @@ -325,13 +328,13 @@ static int ibm_cffps_read_byte_data(struct i2c_client *client, int page, } static int ibm_cffps_read_word_data(struct i2c_client *client, int page, - int reg) + int phase, int reg) { int rc, mfr; switch (reg) { case PMBUS_STATUS_WORD: - rc = pmbus_read_word_data(client, page, reg); + rc = pmbus_read_word_data(client, page, phase, reg); if (rc < 0) return rc; @@ -348,7 +351,8 @@ static int ibm_cffps_read_word_data(struct i2c_client *client, int page, rc |= PB_STATUS_OFF; break; case PMBUS_VIRT_READ_VMON: - rc = pmbus_read_word_data(client, page, CFFPS_12VCS_VOUT_CMD); + rc = pmbus_read_word_data(client, page, phase, + CFFPS_12VCS_VOUT_CMD); break; default: rc = -ENODATA; @@ -379,7 +383,7 @@ static int ibm_cffps_led_brightness_set(struct led_classdev *led_cdev, dev_dbg(&psu->client->dev, "LED brightness set: %d. Command: %d.\n", brightness, next_led_state); - pmbus_set_page(psu->client, 0); + pmbus_set_page(psu->client, 0, 0xff); rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD, next_led_state); @@ -401,7 +405,7 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev, dev_dbg(&psu->client->dev, "LED blink set.\n"); - pmbus_set_page(psu->client, 0); + pmbus_set_page(psu->client, 0, 0xff); rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD, CFFPS_LED_BLINK); @@ -485,11 +489,14 @@ static int ibm_cffps_probe(struct i2c_client *client, vs = (enum versions)id->driver_data; if (vs == cffps_unknown) { + u16 ccin_revision = 0; u16 ccin_version = CFFPS_CCIN_VERSION_1; int ccin = i2c_smbus_read_word_swapped(client, CFFPS_CCIN_CMD); - if (ccin > 0) + if (ccin > 0) { + ccin_revision = FIELD_GET(CFFPS_CCIN_REVISION, ccin); ccin_version = FIELD_GET(CFFPS_CCIN_VERSION, ccin); + } switch (ccin_version) { default: @@ -499,6 +506,12 @@ static int ibm_cffps_probe(struct i2c_client *client, case CFFPS_CCIN_VERSION_2: vs = cffps2; break; + case CFFPS_CCIN_VERSION_3: + if (ccin_revision == CFFPS_CCIN_REVISION_LEGACY) + vs = cffps1; + else + vs = cffps2; + break; } /* Set the client name to include the version number. */ diff --git a/drivers/hwmon/pmbus/ir35221.c b/drivers/hwmon/pmbus/ir35221.c index 0d878bcd6d26..3eea3e006a96 100644 --- a/drivers/hwmon/pmbus/ir35221.c +++ b/drivers/hwmon/pmbus/ir35221.c @@ -21,37 +21,42 @@ #define IR35221_MFR_IOUT_VALLEY 0xcb #define IR35221_MFR_TEMP_VALLEY 0xcc -static int ir35221_read_word_data(struct i2c_client *client, int page, int reg) +static int ir35221_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { int ret; switch (reg) { case PMBUS_VIRT_READ_VIN_MAX: - ret = pmbus_read_word_data(client, page, IR35221_MFR_VIN_PEAK); + ret = pmbus_read_word_data(client, page, phase, + IR35221_MFR_VIN_PEAK); break; case PMBUS_VIRT_READ_VOUT_MAX: - ret = pmbus_read_word_data(client, page, IR35221_MFR_VOUT_PEAK); + ret = pmbus_read_word_data(client, page, phase, + IR35221_MFR_VOUT_PEAK); break; case PMBUS_VIRT_READ_IOUT_MAX: - ret = pmbus_read_word_data(client, page, IR35221_MFR_IOUT_PEAK); + ret = pmbus_read_word_data(client, page, phase, + IR35221_MFR_IOUT_PEAK); break; case PMBUS_VIRT_READ_TEMP_MAX: - ret = pmbus_read_word_data(client, page, IR35221_MFR_TEMP_PEAK); + ret = pmbus_read_word_data(client, page, phase, + IR35221_MFR_TEMP_PEAK); break; case PMBUS_VIRT_READ_VIN_MIN: - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, IR35221_MFR_VIN_VALLEY); break; case PMBUS_VIRT_READ_VOUT_MIN: - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, IR35221_MFR_VOUT_VALLEY); break; case PMBUS_VIRT_READ_IOUT_MIN: - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, IR35221_MFR_IOUT_VALLEY); break; case PMBUS_VIRT_READ_TEMP_MIN: - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, IR35221_MFR_TEMP_VALLEY); break; default: diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c index 515596c92fe1..4d2315208bb5 100644 --- a/drivers/hwmon/pmbus/isl68137.c +++ b/drivers/hwmon/pmbus/isl68137.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Hardware monitoring driver for Intersil ISL68137 + * Hardware monitoring driver for Renesas Digital Multiphase Voltage Regulators * * Copyright (c) 2017 Google Inc + * Copyright (c) 2020 Renesas Electronics America * */ @@ -14,9 +15,19 @@ #include <linux/module.h> #include <linux/string.h> #include <linux/sysfs.h> + #include "pmbus.h" #define ISL68137_VOUT_AVS 0x30 +#define RAA_DMPVR2_READ_VMON 0xc8 + +enum versions { + isl68137, + raa_dmpvr2_1rail, + raa_dmpvr2_2rail, + raa_dmpvr2_3rail, + raa_dmpvr2_hv, +}; static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, int page, @@ -49,7 +60,8 @@ static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client, * enabling AVS control is the workaround. */ if (op_val == ISL68137_VOUT_AVS) { - rc = pmbus_read_word_data(client, page, PMBUS_VOUT_COMMAND); + rc = pmbus_read_word_data(client, page, 0xff, + PMBUS_VOUT_COMMAND); if (rc < 0) return rc; @@ -98,13 +110,31 @@ static const struct attribute_group enable_group = { .attrs = enable_attrs, }; -static const struct attribute_group *attribute_groups[] = { +static const struct attribute_group *isl68137_attribute_groups[] = { &enable_group, NULL, }; -static struct pmbus_driver_info isl68137_info = { - .pages = 2, +static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + int ret; + + switch (reg) { + case PMBUS_VIRT_READ_VMON: + ret = pmbus_read_word_data(client, page, phase, + RAA_DMPVR2_READ_VMON); + break; + default: + ret = -ENODATA; + break; + } + + return ret; +} + +static struct pmbus_driver_info raa_dmpvr_info = { + .pages = 3, .format[PSC_VOLTAGE_IN] = direct, .format[PSC_VOLTAGE_OUT] = direct, .format[PSC_CURRENT_IN] = direct, @@ -113,7 +143,7 @@ static struct pmbus_driver_info isl68137_info = { .format[PSC_TEMPERATURE] = direct, .m[PSC_VOLTAGE_IN] = 1, .b[PSC_VOLTAGE_IN] = 0, - .R[PSC_VOLTAGE_IN] = 3, + .R[PSC_VOLTAGE_IN] = 2, .m[PSC_VOLTAGE_OUT] = 1, .b[PSC_VOLTAGE_OUT] = 0, .R[PSC_VOLTAGE_OUT] = 3, @@ -133,24 +163,76 @@ static struct pmbus_driver_info isl68137_info = { | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT - | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, - .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT - | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, - .groups = attribute_groups, + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT + | PMBUS_HAVE_VMON, + .func[1] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT + | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, + .func[2] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT + | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, }; static int isl68137_probe(struct i2c_client *client, const struct i2c_device_id *id) { - return pmbus_do_probe(client, id, &isl68137_info); + struct pmbus_driver_info *info; + + info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + memcpy(info, &raa_dmpvr_info, sizeof(*info)); + + switch (id->driver_data) { + case isl68137: + info->pages = 2; + info->R[PSC_VOLTAGE_IN] = 3; + info->func[0] &= ~PMBUS_HAVE_VMON; + info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_POUT; + info->groups = isl68137_attribute_groups; + break; + case raa_dmpvr2_1rail: + info->pages = 1; + info->read_word_data = raa_dmpvr2_read_word_data; + break; + case raa_dmpvr2_2rail: + info->pages = 2; + info->read_word_data = raa_dmpvr2_read_word_data; + break; + case raa_dmpvr2_3rail: + info->read_word_data = raa_dmpvr2_read_word_data; + break; + case raa_dmpvr2_hv: + info->pages = 1; + info->R[PSC_VOLTAGE_IN] = 1; + info->m[PSC_VOLTAGE_OUT] = 2; + info->R[PSC_VOLTAGE_OUT] = 2; + info->m[PSC_CURRENT_IN] = 2; + info->m[PSC_POWER] = 2; + info->R[PSC_POWER] = -1; + info->read_word_data = raa_dmpvr2_read_word_data; + break; + default: + return -ENODEV; + } + + return pmbus_do_probe(client, id, info); } -static const struct i2c_device_id isl68137_id[] = { - {"isl68137", 0}, +static const struct i2c_device_id raa_dmpvr_id[] = { + {"isl68137", isl68137}, + {"raa_dmpvr2_1rail", raa_dmpvr2_1rail}, + {"raa_dmpvr2_2rail", raa_dmpvr2_2rail}, + {"raa_dmpvr2_3rail", raa_dmpvr2_3rail}, + {"raa_dmpvr2_hv", raa_dmpvr2_hv}, {} }; -MODULE_DEVICE_TABLE(i2c, isl68137_id); +MODULE_DEVICE_TABLE(i2c, raa_dmpvr_id); /* This is the driver that will be inserted */ static struct i2c_driver isl68137_driver = { @@ -159,11 +241,11 @@ static struct i2c_driver isl68137_driver = { }, .probe = isl68137_probe, .remove = pmbus_do_remove, - .id_table = isl68137_id, + .id_table = raa_dmpvr_id, }; module_i2c_driver(isl68137_driver); MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>"); -MODULE_DESCRIPTION("PMBus driver for Intersil ISL68137"); +MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators"); MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index 05fce86f1f81..9e4cf0800186 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -211,7 +211,8 @@ struct lm25066_data { #define to_lm25066_data(x) container_of(x, struct lm25066_data, info) -static int lm25066_read_word_data(struct i2c_client *client, int page, int reg) +static int lm25066_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); const struct lm25066_data *data = to_lm25066_data(info); @@ -219,7 +220,7 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg) switch (reg) { case PMBUS_VIRT_READ_VMON: - ret = pmbus_read_word_data(client, 0, LM25066_READ_VAUX); + ret = pmbus_read_word_data(client, 0, 0xff, LM25066_READ_VAUX); if (ret < 0) break; /* Adjust returned value to match VIN coefficients */ @@ -244,33 +245,40 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg) } break; case PMBUS_READ_IIN: - ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN); + ret = pmbus_read_word_data(client, 0, 0xff, + LM25066_MFR_READ_IIN); break; case PMBUS_READ_PIN: - ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_PIN); + ret = pmbus_read_word_data(client, 0, 0xff, + LM25066_MFR_READ_PIN); break; case PMBUS_IIN_OC_WARN_LIMIT: - ret = pmbus_read_word_data(client, 0, + ret = pmbus_read_word_data(client, 0, 0xff, LM25066_MFR_IIN_OC_WARN_LIMIT); break; case PMBUS_PIN_OP_WARN_LIMIT: - ret = pmbus_read_word_data(client, 0, + ret = pmbus_read_word_data(client, 0, 0xff, LM25066_MFR_PIN_OP_WARN_LIMIT); break; case PMBUS_VIRT_READ_VIN_AVG: - ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VIN); + ret = pmbus_read_word_data(client, 0, 0xff, + LM25066_READ_AVG_VIN); break; case PMBUS_VIRT_READ_VOUT_AVG: - ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VOUT); + ret = pmbus_read_word_data(client, 0, 0xff, + LM25066_READ_AVG_VOUT); break; case PMBUS_VIRT_READ_IIN_AVG: - ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_IIN); + ret = pmbus_read_word_data(client, 0, 0xff, + LM25066_READ_AVG_IIN); break; case PMBUS_VIRT_READ_PIN_AVG: - ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_PIN); + ret = pmbus_read_word_data(client, 0, 0xff, + LM25066_READ_AVG_PIN); break; case PMBUS_VIRT_READ_PIN_MAX: - ret = pmbus_read_word_data(client, 0, LM25066_READ_PIN_PEAK); + ret = pmbus_read_word_data(client, 0, 0xff, + LM25066_READ_PIN_PEAK); break; case PMBUS_VIRT_RESET_PIN_HISTORY: ret = 0; @@ -288,13 +296,14 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg) return ret; } -static int lm25056_read_word_data(struct i2c_client *client, int page, int reg) +static int lm25056_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { int ret; switch (reg) { case PMBUS_VIRT_VMON_UV_WARN_LIMIT: - ret = pmbus_read_word_data(client, 0, + ret = pmbus_read_word_data(client, 0, 0xff, LM25056_VAUX_UV_WARN_LIMIT); if (ret < 0) break; @@ -302,7 +311,7 @@ static int lm25056_read_word_data(struct i2c_client *client, int page, int reg) ret = DIV_ROUND_CLOSEST(ret * 293, 6140); break; case PMBUS_VIRT_VMON_OV_WARN_LIMIT: - ret = pmbus_read_word_data(client, 0, + ret = pmbus_read_word_data(client, 0, 0xff, LM25056_VAUX_OV_WARN_LIMIT); if (ret < 0) break; @@ -310,7 +319,7 @@ static int lm25056_read_word_data(struct i2c_client *client, int page, int reg) ret = DIV_ROUND_CLOSEST(ret * 293, 6140); break; default: - ret = lm25066_read_word_data(client, page, reg); + ret = lm25066_read_word_data(client, page, phase, reg); break; } return ret; diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index a91ed01abb68..7b0e6b37e247 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -19,8 +19,15 @@ #include <linux/regulator/driver.h> #include "pmbus.h" -enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, - ltc3883, ltc3886, ltc3887, ltm2987, ltm4675, ltm4676, ltm4686 }; +enum chips { + /* Managers */ + ltc2972, ltc2974, ltc2975, ltc2977, ltc2978, ltc2979, ltc2980, + /* Controllers */ + ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7880, + /* Modules */ + ltm2987, ltm4664, ltm4675, ltm4676, ltm4677, ltm4678, ltm4680, ltm4686, + ltm4700, +}; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -43,9 +50,10 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 -/* LTC3883 and LTC3886 only */ +/* LTC3883, LTC3884, LTC3886, LTC3889 and LTC7880 only */ #define LTC3883_MFR_IIN_PEAK 0xe1 + /* LTC2975 only */ #define LTC2975_MFR_IIN_PEAK 0xc4 #define LTC2975_MFR_IIN_MIN 0xc5 @@ -54,27 +62,41 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, #define LTC2978_ID_MASK 0xfff0 +#define LTC2972_ID 0x0310 #define LTC2974_ID 0x0210 #define LTC2975_ID 0x0220 #define LTC2977_ID 0x0130 #define LTC2978_ID_REV1 0x0110 /* Early revision */ #define LTC2978_ID_REV2 0x0120 +#define LTC2979_ID_A 0x8060 +#define LTC2979_ID_B 0x8070 #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 LTC3884_ID 0x4C00 #define LTC3886_ID 0x4600 #define LTC3887_ID 0x4700 #define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ #define LTM2987_ID_B 0x8020 +#define LTC3889_ID 0x4900 +#define LTC7880_ID 0x49E0 +#define LTM4664_ID 0x4120 #define LTM4675_ID 0x47a0 #define LTM4676_ID_REV1 0x4400 #define LTM4676_ID_REV2 0x4480 #define LTM4676A_ID 0x47e0 +#define LTM4677_ID_REV1 0x47B0 +#define LTM4677_ID_REV2 0x47D0 +#define LTM4678_ID_REV1 0x4100 +#define LTM4678_ID_REV2 0x4110 +#define LTM4680_ID 0x4140 #define LTM4686_ID 0x4770 +#define LTM4700_ID 0x4130 +#define LTC2972_NUM_PAGES 2 #define LTC2974_NUM_PAGES 4 #define LTC2978_NUM_PAGES 8 #define LTC3880_NUM_PAGES 2 @@ -151,7 +173,8 @@ static int ltc_wait_ready(struct i2c_client *client) return -ETIMEDOUT; } -static int ltc_read_word_data(struct i2c_client *client, int page, int reg) +static int ltc_read_word_data(struct i2c_client *client, int page, int phase, + int reg) { int ret; @@ -159,7 +182,7 @@ static int ltc_read_word_data(struct i2c_client *client, int page, int reg) if (ret < 0) return ret; - return pmbus_read_word_data(client, page, reg); + return pmbus_read_word_data(client, page, 0xff, reg); } static int ltc_read_byte_data(struct i2c_client *client, int page, int reg) @@ -202,7 +225,7 @@ static int ltc_get_max(struct ltc2978_data *data, struct i2c_client *client, { int ret; - ret = ltc_read_word_data(client, page, reg); + ret = ltc_read_word_data(client, page, 0xff, reg); if (ret >= 0) { if (lin11_to_val(ret) > lin11_to_val(*pmax)) *pmax = ret; @@ -216,7 +239,7 @@ static int ltc_get_min(struct ltc2978_data *data, struct i2c_client *client, { int ret; - ret = ltc_read_word_data(client, page, reg); + ret = ltc_read_word_data(client, page, 0xff, reg); if (ret >= 0) { if (lin11_to_val(ret) < lin11_to_val(*pmin)) *pmin = ret; @@ -238,7 +261,8 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page, &data->vin_max); break; case PMBUS_VIRT_READ_VOUT_MAX: - ret = ltc_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK); + ret = ltc_read_word_data(client, page, 0xff, + LTC2978_MFR_VOUT_PEAK); if (ret >= 0) { /* * VOUT is 16 bit unsigned with fixed exponent, @@ -269,7 +293,8 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page, return ret; } -static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg) +static int ltc2978_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); struct ltc2978_data *data = to_ltc2978_data(info); @@ -281,7 +306,8 @@ 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 = ltc_read_word_data(client, page, LTC2978_MFR_VOUT_MIN); + ret = ltc_read_word_data(client, page, phase, + LTC2978_MFR_VOUT_MIN); if (ret >= 0) { /* * VOUT_MIN is known to not be supported on some lots @@ -314,7 +340,8 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg) return ret; } -static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg) +static int ltc2974_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); struct ltc2978_data *data = to_ltc2978_data(info); @@ -333,13 +360,14 @@ static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg) ret = 0; break; default: - ret = ltc2978_read_word_data(client, page, reg); + ret = ltc2978_read_word_data(client, page, phase, reg); break; } return ret; } -static int ltc2975_read_word_data(struct i2c_client *client, int page, int reg) +static int ltc2975_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); struct ltc2978_data *data = to_ltc2978_data(info); @@ -367,13 +395,14 @@ static int ltc2975_read_word_data(struct i2c_client *client, int page, int reg) ret = 0; break; default: - ret = ltc2978_read_word_data(client, page, reg); + ret = ltc2978_read_word_data(client, page, phase, reg); break; } return ret; } -static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg) +static int ltc3880_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); struct ltc2978_data *data = to_ltc2978_data(info); @@ -405,7 +434,8 @@ static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg) return ret; } -static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg) +static int ltc3883_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); struct ltc2978_data *data = to_ltc2978_data(info); @@ -420,7 +450,7 @@ static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg) ret = 0; break; default: - ret = ltc3880_read_word_data(client, page, reg); + ret = ltc3880_read_word_data(client, page, phase, reg); break; } return ret; @@ -492,20 +522,30 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, } static const struct i2c_device_id ltc2978_id[] = { + {"ltc2972", ltc2972}, {"ltc2974", ltc2974}, {"ltc2975", ltc2975}, {"ltc2977", ltc2977}, {"ltc2978", ltc2978}, + {"ltc2979", ltc2979}, {"ltc2980", ltc2980}, {"ltc3880", ltc3880}, {"ltc3882", ltc3882}, {"ltc3883", ltc3883}, + {"ltc3884", ltc3884}, {"ltc3886", ltc3886}, {"ltc3887", ltc3887}, + {"ltc3889", ltc3889}, + {"ltc7880", ltc7880}, {"ltm2987", ltm2987}, + {"ltm4664", ltm4664}, {"ltm4675", ltm4675}, {"ltm4676", ltm4676}, + {"ltm4677", ltm4677}, + {"ltm4678", ltm4678}, + {"ltm4680", ltm4680}, {"ltm4686", ltm4686}, + {"ltm4700", ltm4700}, {} }; MODULE_DEVICE_TABLE(i2c, ltc2978_id); @@ -555,7 +595,9 @@ static int ltc2978_get_id(struct i2c_client *client) chip_id &= LTC2978_ID_MASK; - if (chip_id == LTC2974_ID) + if (chip_id == LTC2972_ID) + return ltc2972; + else if (chip_id == LTC2974_ID) return ltc2974; else if (chip_id == LTC2975_ID) return ltc2975; @@ -563,6 +605,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 == LTC2979_ID_A || chip_id == LTC2979_ID_B) + return ltc2979; else if (chip_id == LTC2980_ID_A || chip_id == LTC2980_ID_B) return ltc2980; else if (chip_id == LTC3880_ID) @@ -571,19 +615,35 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3882; else if (chip_id == LTC3883_ID) return ltc3883; + else if (chip_id == LTC3884_ID) + return ltc3884; else if (chip_id == LTC3886_ID) return ltc3886; else if (chip_id == LTC3887_ID) return ltc3887; + else if (chip_id == LTC3889_ID) + return ltc3889; + else if (chip_id == LTC7880_ID) + return ltc7880; else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B) return ltm2987; + else if (chip_id == LTM4664_ID) + return ltm4664; 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; + else if (chip_id == LTM4677_ID_REV1 || chip_id == LTM4677_ID_REV2) + return ltm4677; + else if (chip_id == LTM4678_ID_REV1 || chip_id == LTM4678_ID_REV2) + return ltm4678; + else if (chip_id == LTM4680_ID) + return ltm4680; else if (chip_id == LTM4686_ID) return ltm4686; + else if (chip_id == LTM4700_ID) + return ltm4700; dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); return -ENODEV; @@ -637,6 +697,19 @@ static int ltc2978_probe(struct i2c_client *client, data->temp2_max = 0x7c00; switch (data->id) { + case ltc2972: + info->read_word_data = ltc2975_read_word_data; + info->pages = LTC2972_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 ltc2974: info->read_word_data = ltc2974_read_word_data; info->pages = LTC2974_NUM_PAGES; @@ -662,8 +735,10 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; } break; + case ltc2977: case ltc2978: + case ltc2979: case ltc2980: case ltm2987: info->read_word_data = ltc2978_read_word_data; @@ -680,6 +755,7 @@ static int ltc2978_probe(struct i2c_client *client, case ltc3887: case ltm4675: case ltm4676: + case ltm4677: case ltm4686: data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING; info->read_word_data = ltc3880_read_word_data; @@ -721,7 +797,14 @@ 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 ltc3884: case ltc3886: + case ltc3889: + case ltc7880: + case ltm4664: + case ltm4678: + case ltm4680: + case ltm4700: data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING; info->read_word_data = ltc3883_read_word_data; info->pages = LTC3880_NUM_PAGES; @@ -752,22 +835,33 @@ static int ltc2978_probe(struct i2c_client *client, return pmbus_do_probe(client, id, info); } + #ifdef CONFIG_OF static const struct of_device_id ltc2978_of_match[] = { + { .compatible = "lltc,ltc2972" }, { .compatible = "lltc,ltc2974" }, { .compatible = "lltc,ltc2975" }, { .compatible = "lltc,ltc2977" }, { .compatible = "lltc,ltc2978" }, + { .compatible = "lltc,ltc2979" }, { .compatible = "lltc,ltc2980" }, { .compatible = "lltc,ltc3880" }, { .compatible = "lltc,ltc3882" }, { .compatible = "lltc,ltc3883" }, + { .compatible = "lltc,ltc3884" }, { .compatible = "lltc,ltc3886" }, { .compatible = "lltc,ltc3887" }, + { .compatible = "lltc,ltc3889" }, + { .compatible = "lltc,ltc7880" }, { .compatible = "lltc,ltm2987" }, + { .compatible = "lltc,ltm4664" }, { .compatible = "lltc,ltm4675" }, { .compatible = "lltc,ltm4676" }, + { .compatible = "lltc,ltm4677" }, + { .compatible = "lltc,ltm4678" }, + { .compatible = "lltc,ltm4680" }, { .compatible = "lltc,ltm4686" }, + { .compatible = "lltc,ltm4700" }, { } }; MODULE_DEVICE_TABLE(of, ltc2978_of_match); diff --git a/drivers/hwmon/pmbus/ltc3815.c b/drivers/hwmon/pmbus/ltc3815.c index b83a18a58364..3036263e0a66 100644 --- a/drivers/hwmon/pmbus/ltc3815.c +++ b/drivers/hwmon/pmbus/ltc3815.c @@ -55,7 +55,7 @@ static int ltc3815_write_byte(struct i2c_client *client, int page, u8 reg) * LTC3815 does not support the CLEAR_FAULTS command. * Emulate it by clearing the status register. */ - ret = pmbus_read_word_data(client, 0, PMBUS_STATUS_WORD); + ret = pmbus_read_word_data(client, 0, 0xff, PMBUS_STATUS_WORD); if (ret > 0) { pmbus_write_word_data(client, 0, PMBUS_STATUS_WORD, ret); @@ -69,25 +69,31 @@ static int ltc3815_write_byte(struct i2c_client *client, int page, u8 reg) return ret; } -static int ltc3815_read_word_data(struct i2c_client *client, int page, int reg) +static int ltc3815_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { int ret; switch (reg) { case PMBUS_VIRT_READ_VIN_MAX: - ret = pmbus_read_word_data(client, page, LTC3815_MFR_VIN_PEAK); + ret = pmbus_read_word_data(client, page, phase, + LTC3815_MFR_VIN_PEAK); break; case PMBUS_VIRT_READ_VOUT_MAX: - ret = pmbus_read_word_data(client, page, LTC3815_MFR_VOUT_PEAK); + ret = pmbus_read_word_data(client, page, phase, + LTC3815_MFR_VOUT_PEAK); break; case PMBUS_VIRT_READ_TEMP_MAX: - ret = pmbus_read_word_data(client, page, LTC3815_MFR_TEMP_PEAK); + ret = pmbus_read_word_data(client, page, phase, + LTC3815_MFR_TEMP_PEAK); break; case PMBUS_VIRT_READ_IOUT_MAX: - ret = pmbus_read_word_data(client, page, LTC3815_MFR_IOUT_PEAK); + ret = pmbus_read_word_data(client, page, phase, + LTC3815_MFR_IOUT_PEAK); break; case PMBUS_VIRT_READ_IIN_MAX: - ret = pmbus_read_word_data(client, page, LTC3815_MFR_IIN_PEAK); + ret = pmbus_read_word_data(client, page, phase, + LTC3815_MFR_IIN_PEAK); break; case PMBUS_VIRT_RESET_VOUT_HISTORY: case PMBUS_VIRT_RESET_VIN_HISTORY: diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c index b3e7b8d2e69d..288e93f74c28 100644 --- a/drivers/hwmon/pmbus/max16064.c +++ b/drivers/hwmon/pmbus/max16064.c @@ -15,17 +15,18 @@ #define MAX16064_MFR_VOUT_PEAK 0xd4 #define MAX16064_MFR_TEMPERATURE_PEAK 0xd6 -static int max16064_read_word_data(struct i2c_client *client, int page, int reg) +static int max16064_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { int ret; switch (reg) { case PMBUS_VIRT_READ_VOUT_MAX: - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, MAX16064_MFR_VOUT_PEAK); break; case PMBUS_VIRT_READ_TEMP_MAX: - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, MAX16064_MFR_TEMPERATURE_PEAK); break; case PMBUS_VIRT_RESET_VOUT_HISTORY: diff --git a/drivers/hwmon/pmbus/max20730.c b/drivers/hwmon/pmbus/max20730.c index 294e2212f61e..c0bb05487e0e 100644 --- a/drivers/hwmon/pmbus/max20730.c +++ b/drivers/hwmon/pmbus/max20730.c @@ -85,7 +85,8 @@ static u32 max_current[][5] = { [max20743] = { 18900, 24100, 29200, 34100 }, }; -static int max20730_read_word_data(struct i2c_client *client, int page, int reg) +static int max20730_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); const struct max20730_data *data = to_max20730_data(info); diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c index 254b0f98c755..d9aa5c873d21 100644 --- a/drivers/hwmon/pmbus/max31785.c +++ b/drivers/hwmon/pmbus/max31785.c @@ -72,7 +72,7 @@ static int max31785_read_long_data(struct i2c_client *client, int page, cmdbuf[0] = reg; - rc = pmbus_set_page(client, page); + rc = pmbus_set_page(client, page, 0xff); if (rc < 0) return rc; @@ -110,7 +110,7 @@ static int max31785_get_pwm_mode(struct i2c_client *client, int page) if (config < 0) return config; - command = pmbus_read_word_data(client, page, PMBUS_FAN_COMMAND_1); + command = pmbus_read_word_data(client, page, 0xff, PMBUS_FAN_COMMAND_1); if (command < 0) return command; @@ -126,7 +126,7 @@ static int max31785_get_pwm_mode(struct i2c_client *client, int page) } static int max31785_read_word_data(struct i2c_client *client, int page, - int reg) + int phase, int reg) { u32 val; int rv; diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index 5c63a6600729..18b4e071067f 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -41,7 +41,8 @@ struct max34440_data { #define to_max34440_data(x) container_of(x, struct max34440_data, info) -static int max34440_read_word_data(struct i2c_client *client, int page, int reg) +static int max34440_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { int ret; const struct pmbus_driver_info *info = pmbus_get_driver_info(client); @@ -49,44 +50,44 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg) switch (reg) { case PMBUS_VIRT_READ_VOUT_MIN: - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, MAX34440_MFR_VOUT_MIN); break; case PMBUS_VIRT_READ_VOUT_MAX: - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, MAX34440_MFR_VOUT_PEAK); break; case PMBUS_VIRT_READ_IOUT_AVG: if (data->id != max34446 && data->id != max34451) return -ENXIO; - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, MAX34446_MFR_IOUT_AVG); break; case PMBUS_VIRT_READ_IOUT_MAX: - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, MAX34440_MFR_IOUT_PEAK); break; case PMBUS_VIRT_READ_POUT_AVG: if (data->id != max34446) return -ENXIO; - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, MAX34446_MFR_POUT_AVG); break; case PMBUS_VIRT_READ_POUT_MAX: if (data->id != max34446) return -ENXIO; - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, MAX34446_MFR_POUT_PEAK); break; case PMBUS_VIRT_READ_TEMP_AVG: if (data->id != max34446 && data->id != max34460 && data->id != max34461) return -ENXIO; - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, MAX34446_MFR_TEMPERATURE_AVG); break; case PMBUS_VIRT_READ_TEMP_MAX: - ret = pmbus_read_word_data(client, page, + ret = pmbus_read_word_data(client, page, phase, MAX34440_MFR_TEMPERATURE_PEAK); break; case PMBUS_VIRT_RESET_POUT_HISTORY: @@ -159,14 +160,14 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg) int mfg_status; if (page >= 0) { - ret = pmbus_set_page(client, page); + ret = pmbus_set_page(client, page, 0xff); if (ret < 0) return ret; } switch (reg) { case PMBUS_STATUS_IOUT: - mfg_status = pmbus_read_word_data(client, 0, + mfg_status = pmbus_read_word_data(client, 0, 0xff, PMBUS_STATUS_MFR_SPECIFIC); if (mfg_status < 0) return mfg_status; @@ -176,7 +177,7 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg) ret |= PB_IOUT_OC_FAULT; break; case PMBUS_STATUS_TEMPERATURE: - mfg_status = pmbus_read_word_data(client, 0, + mfg_status = pmbus_read_word_data(client, 0, 0xff, PMBUS_STATUS_MFR_SPECIFIC); if (mfg_status < 0) return mfg_status; diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index bc5f4cb6450e..643ccfc05106 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -28,7 +28,8 @@ #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) +static int max8688_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { int ret; @@ -37,13 +38,15 @@ static int max8688_read_word_data(struct i2c_client *client, int page, int reg) switch (reg) { case PMBUS_VIRT_READ_VOUT_MAX: - ret = pmbus_read_word_data(client, 0, MAX8688_MFR_VOUT_PEAK); + ret = pmbus_read_word_data(client, 0, 0xff, + MAX8688_MFR_VOUT_PEAK); break; case PMBUS_VIRT_READ_IOUT_MAX: - ret = pmbus_read_word_data(client, 0, MAX8688_MFR_IOUT_PEAK); + ret = pmbus_read_word_data(client, 0, 0xff, + MAX8688_MFR_IOUT_PEAK); break; case PMBUS_VIRT_READ_TEMP_MAX: - ret = pmbus_read_word_data(client, 0, + ret = pmbus_read_word_data(client, 0, 0xff, MAX8688_MFR_TEMPERATURE_PEAK); break; case PMBUS_VIRT_RESET_VOUT_HISTORY: @@ -94,7 +97,7 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg) switch (reg) { case PMBUS_STATUS_VOUT: - mfg_status = pmbus_read_word_data(client, 0, + mfg_status = pmbus_read_word_data(client, 0, 0xff, MAX8688_MFG_STATUS); if (mfg_status < 0) return mfg_status; @@ -108,7 +111,7 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg) ret |= PB_VOLTAGE_OV_FAULT; break; case PMBUS_STATUS_IOUT: - mfg_status = pmbus_read_word_data(client, 0, + mfg_status = pmbus_read_word_data(client, 0, 0xff, MAX8688_MFG_STATUS); if (mfg_status < 0) return mfg_status; @@ -120,7 +123,7 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg) ret |= PB_IOUT_OC_FAULT; break; case PMBUS_STATUS_TEMPERATURE: - mfg_status = pmbus_read_word_data(client, 0, + mfg_status = pmbus_read_word_data(client, 0, 0xff, MAX8688_MFG_STATUS); if (mfg_status < 0) return mfg_status; diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 51e8312b6c2d..6d384e8ee1db 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -102,10 +102,10 @@ static int pmbus_identify(struct i2c_client *client, int page; for (page = 1; page < PMBUS_PAGES; page++) { - if (pmbus_set_page(client, page) < 0) + if (pmbus_set_page(client, page, 0xff) < 0) break; } - pmbus_set_page(client, 0); + pmbus_set_page(client, 0, 0xff); info->pages = page; } else { info->pages = 1; diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 13b34bd67f23..18e06fc6c53f 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -119,6 +119,9 @@ enum pmbus_regs { PMBUS_MFR_DATE = 0x9D, PMBUS_MFR_SERIAL = 0x9E, + PMBUS_IC_DEVICE_ID = 0xAD, + PMBUS_IC_DEVICE_REV = 0xAE, + /* * Virtual registers. * Useful to support attributes which are not supported by standard PMBus @@ -359,6 +362,7 @@ enum pmbus_sensor_classes { }; #define PMBUS_PAGES 32 /* Per PMBus specification */ +#define PMBUS_PHASES 8 /* Maximum number of phases per page */ /* Functionality bit mask */ #define PMBUS_HAVE_VIN BIT(0) @@ -385,13 +389,15 @@ enum pmbus_sensor_classes { #define PMBUS_HAVE_PWM34 BIT(21) #define PMBUS_HAVE_SAMPLES BIT(22) -#define PMBUS_PAGE_VIRTUAL BIT(31) +#define PMBUS_PHASE_VIRTUAL BIT(30) /* Phases on this page are virtual */ +#define PMBUS_PAGE_VIRTUAL BIT(31) /* Page is virtual */ enum pmbus_data_format { linear = 0, direct, vid }; enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv }; struct pmbus_driver_info { int pages; /* Total number of pages */ + u8 phases[PMBUS_PAGES]; /* Number of phases per page */ enum pmbus_data_format format[PSC_NUM_CLASSES]; enum vrm_version vrm_version[PMBUS_PAGES]; /* vrm version per page */ /* @@ -403,6 +409,7 @@ struct pmbus_driver_info { int R[PSC_NUM_CLASSES]; /* exponent */ u32 func[PMBUS_PAGES]; /* Functionality, per page */ + u32 pfunc[PMBUS_PHASES];/* Functionality, per phase */ /* * The following functions map manufacturing specific register values * to PMBus standard register values. Specify only if mapping is @@ -415,7 +422,8 @@ struct pmbus_driver_info { * the standard register. */ int (*read_byte_data)(struct i2c_client *client, int page, int reg); - int (*read_word_data)(struct i2c_client *client, int page, int reg); + int (*read_word_data)(struct i2c_client *client, int page, int phase, + int reg); int (*write_word_data)(struct i2c_client *client, int page, int reg, u16 word); int (*write_byte)(struct i2c_client *client, int page, u8 value); @@ -454,9 +462,11 @@ extern const struct regulator_ops pmbus_regulator_ops; /* Function declarations */ void pmbus_clear_cache(struct i2c_client *client); -int pmbus_set_page(struct i2c_client *client, int page); -int pmbus_read_word_data(struct i2c_client *client, int page, u8 reg); -int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, u16 word); +int pmbus_set_page(struct i2c_client *client, int page, int phase); +int pmbus_read_word_data(struct i2c_client *client, int page, int phase, + u8 reg); +int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, + u16 word); int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg); int pmbus_write_byte(struct i2c_client *client, int page, u8 value); int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index d9c17feb7b4a..8d321bf7d15b 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -49,6 +49,7 @@ struct pmbus_sensor { char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */ struct device_attribute attribute; u8 page; /* page number */ + u8 phase; /* phase number, 0xff for all phases */ u16 reg; /* register */ enum pmbus_sensor_classes class; /* sensor class */ bool update; /* runtime sensor update needed */ @@ -109,6 +110,7 @@ struct pmbus_data { int (*read_status)(struct i2c_client *client, int page); u8 currpage; + u8 currphase; /* current phase, 0xff for all */ }; struct pmbus_debugfs_entry { @@ -146,15 +148,16 @@ void pmbus_clear_cache(struct i2c_client *client) } EXPORT_SYMBOL_GPL(pmbus_clear_cache); -int pmbus_set_page(struct i2c_client *client, int page) +int pmbus_set_page(struct i2c_client *client, int page, int phase) { struct pmbus_data *data = i2c_get_clientdata(client); int rv; - if (page < 0 || page == data->currpage) + if (page < 0) return 0; - if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL)) { + if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL) && + data->info->pages > 1 && page != data->currpage) { rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); if (rv < 0) return rv; @@ -166,9 +169,17 @@ int pmbus_set_page(struct i2c_client *client, int page) if (rv != page) return -EIO; } - data->currpage = page; + if (data->info->phases[page] && data->currphase != phase && + !(data->info->func[page] & PMBUS_PHASE_VIRTUAL)) { + rv = i2c_smbus_write_byte_data(client, PMBUS_PHASE, + phase); + if (rv) + return rv; + } + data->currphase = phase; + return 0; } EXPORT_SYMBOL_GPL(pmbus_set_page); @@ -177,7 +188,7 @@ int pmbus_write_byte(struct i2c_client *client, int page, u8 value) { int rv; - rv = pmbus_set_page(client, page); + rv = pmbus_set_page(client, page, 0xff); if (rv < 0) return rv; @@ -208,7 +219,7 @@ int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, { int rv; - rv = pmbus_set_page(client, page); + rv = pmbus_set_page(client, page, 0xff); if (rv < 0) return rv; @@ -286,11 +297,11 @@ int pmbus_update_fan(struct i2c_client *client, int page, int id, } EXPORT_SYMBOL_GPL(pmbus_update_fan); -int pmbus_read_word_data(struct i2c_client *client, int page, u8 reg) +int pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg) { int rv; - rv = pmbus_set_page(client, page); + rv = pmbus_set_page(client, page, phase); if (rv < 0) return rv; @@ -320,14 +331,15 @@ static int pmbus_read_virt_reg(struct i2c_client *client, int page, int reg) * _pmbus_read_word_data() is similar to pmbus_read_word_data(), but checks if * a device specific mapping function exists and calls it if necessary. */ -static int _pmbus_read_word_data(struct i2c_client *client, int page, int reg) +static int _pmbus_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { struct pmbus_data *data = i2c_get_clientdata(client); const struct pmbus_driver_info *info = data->info; int status; if (info->read_word_data) { - status = info->read_word_data(client, page, reg); + status = info->read_word_data(client, page, phase, reg); if (status != -ENODATA) return status; } @@ -335,14 +347,20 @@ static int _pmbus_read_word_data(struct i2c_client *client, int page, int reg) if (reg >= PMBUS_VIRT_BASE) return pmbus_read_virt_reg(client, page, reg); - return pmbus_read_word_data(client, page, reg); + return pmbus_read_word_data(client, page, phase, reg); +} + +/* Same as above, but without phase parameter, for use in check functions */ +static int __pmbus_read_word_data(struct i2c_client *client, int page, int reg) +{ + return _pmbus_read_word_data(client, page, 0xff, reg); } int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg) { int rv; - rv = pmbus_set_page(client, page); + rv = pmbus_set_page(client, page, 0xff); if (rv < 0) return rv; @@ -354,7 +372,7 @@ int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value) { int rv; - rv = pmbus_set_page(client, page); + rv = pmbus_set_page(client, page, 0xff); if (rv < 0) return rv; @@ -440,7 +458,7 @@ static int pmbus_get_fan_rate(struct i2c_client *client, int page, int id, have_rpm = !!(config & pmbus_fan_rpm_mask[id]); if (want_rpm == have_rpm) - return pmbus_read_word_data(client, page, + return pmbus_read_word_data(client, page, 0xff, pmbus_fan_command_registers[id]); /* Can't sensibly map between RPM and PWM, just return zero */ @@ -530,7 +548,7 @@ EXPORT_SYMBOL_GPL(pmbus_check_byte_register); bool pmbus_check_word_register(struct i2c_client *client, int page, int reg) { - return pmbus_check_register(client, _pmbus_read_word_data, page, reg); + return pmbus_check_register(client, __pmbus_read_word_data, page, reg); } EXPORT_SYMBOL_GPL(pmbus_check_word_register); @@ -595,6 +613,7 @@ static struct pmbus_data *pmbus_update_device(struct device *dev) sensor->data = _pmbus_read_word_data(client, sensor->page, + sensor->phase, sensor->reg); } pmbus_clear_faults(client); @@ -1076,7 +1095,8 @@ static int pmbus_add_boolean(struct pmbus_data *data, static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, const char *name, const char *type, - int seq, int page, int reg, + int seq, int page, int phase, + int reg, enum pmbus_sensor_classes class, bool update, bool readonly, bool convert) @@ -1100,6 +1120,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, readonly = true; sensor->page = page; + sensor->phase = phase; sensor->reg = reg; sensor->class = class; sensor->update = update; @@ -1119,7 +1140,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, static int pmbus_add_label(struct pmbus_data *data, const char *name, int seq, - const char *lstring, int index) + const char *lstring, int index, int phase) { struct pmbus_label *label; struct device_attribute *a; @@ -1131,11 +1152,21 @@ static int pmbus_add_label(struct pmbus_data *data, a = &label->attribute; snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq); - if (!index) - strncpy(label->label, lstring, sizeof(label->label) - 1); - else - snprintf(label->label, sizeof(label->label), "%s%d", lstring, - index); + if (!index) { + if (phase == 0xff) + strncpy(label->label, lstring, + sizeof(label->label) - 1); + else + snprintf(label->label, sizeof(label->label), "%s.%d", + lstring, phase); + } else { + if (phase == 0xff) + snprintf(label->label, sizeof(label->label), "%s%d", + lstring, index); + else + snprintf(label->label, sizeof(label->label), "%s%d.%d", + lstring, index, phase); + } pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL); return pmbus_add_attribute(data, &a->attr); @@ -1200,7 +1231,7 @@ static int pmbus_add_limit_attrs(struct i2c_client *client, for (i = 0; i < nlimit; i++) { if (pmbus_check_word_register(client, page, l->reg)) { curr = pmbus_add_sensor(data, name, l->attr, index, - page, l->reg, attr->class, + page, 0xff, l->reg, attr->class, attr->update || l->update, false, true); if (!curr) @@ -1227,7 +1258,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client, struct pmbus_data *data, const struct pmbus_driver_info *info, const char *name, - int index, int page, + int index, int page, int phase, const struct pmbus_sensor_attr *attr, bool paged) { @@ -1237,15 +1268,16 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client, if (attr->label) { ret = pmbus_add_label(data, name, index, attr->label, - paged ? page + 1 : 0); + paged ? page + 1 : 0, phase); if (ret) return ret; } - base = pmbus_add_sensor(data, name, "input", index, page, attr->reg, - attr->class, true, true, true); + base = pmbus_add_sensor(data, name, "input", index, page, phase, + attr->reg, attr->class, true, true, true); if (!base) return -ENOMEM; - if (attr->sfunc) { + /* No limit and alarm attributes for phase specific sensors */ + if (attr->sfunc && phase == 0xff) { ret = pmbus_add_limit_attrs(client, data, info, name, index, page, base, attr); if (ret < 0) @@ -1315,10 +1347,25 @@ static int pmbus_add_sensor_attrs(struct i2c_client *client, continue; ret = pmbus_add_sensor_attrs_one(client, data, info, name, index, page, - attrs, paged); + 0xff, attrs, paged); if (ret) return ret; index++; + if (info->phases[page]) { + int phase; + + for (phase = 0; phase < info->phases[page]; + phase++) { + if (!(info->pfunc[phase] & attrs->func)) + continue; + ret = pmbus_add_sensor_attrs_one(client, + data, info, name, index, page, + phase, attrs, paged); + if (ret) + return ret; + index++; + } + } } attrs++; } @@ -1822,7 +1869,7 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client, struct pmbus_sensor *sensor; sensor = pmbus_add_sensor(data, "fan", "target", index, page, - PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN, + PMBUS_VIRT_FAN_TARGET_1 + id, 0xff, PSC_FAN, false, false, true); if (!sensor) @@ -1833,14 +1880,14 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client, return 0; sensor = pmbus_add_sensor(data, "pwm", NULL, index, page, - PMBUS_VIRT_PWM_1 + id, PSC_PWM, + PMBUS_VIRT_PWM_1 + id, 0xff, PSC_PWM, false, false, true); if (!sensor) return -ENOMEM; sensor = pmbus_add_sensor(data, "pwm", "enable", index, page, - PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM, + PMBUS_VIRT_PWM_ENABLE_1 + id, 0xff, PSC_PWM, true, false, false); if (!sensor) @@ -1882,7 +1929,7 @@ static int pmbus_add_fan_attributes(struct i2c_client *client, continue; if (pmbus_add_sensor(data, "fan", "input", index, - page, pmbus_fan_registers[f], + page, pmbus_fan_registers[f], 0xff, PSC_FAN, true, true, true) == NULL) return -ENOMEM; @@ -1964,7 +2011,7 @@ static ssize_t pmbus_show_samples(struct device *dev, struct i2c_client *client = to_i2c_client(dev->parent); struct pmbus_samples_reg *reg = to_samples_reg(devattr); - val = _pmbus_read_word_data(client, reg->page, reg->attr->reg); + val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg); if (val < 0) return val; @@ -2120,7 +2167,7 @@ static int pmbus_read_status_byte(struct i2c_client *client, int page) static int pmbus_read_status_word(struct i2c_client *client, int page) { - return _pmbus_read_word_data(client, page, PMBUS_STATUS_WORD); + return _pmbus_read_word_data(client, page, 0xff, PMBUS_STATUS_WORD); } static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, @@ -2482,6 +2529,8 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, if (pdata) data->flags = pdata->flags; data->info = info; + data->currpage = 0xff; + data->currphase = 0xfe; ret = pmbus_init_common(client, data, info); if (ret < 0) diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index 9c22e9013dd7..157c99ffb52b 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -6,13 +6,21 @@ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com> */ +#include <linux/bits.h> #include <linux/err.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_device.h> #include "pmbus.h" +enum chips { + tps53647, tps53667, tps53679, tps53681, tps53688 +}; + +#define TPS53647_PAGE_NUM 1 + #define TPS53679_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */ #define TPS53679_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */ #define TPS53679_PROT_VR13_10MV 0x04 /* VR13.0 mode, 10-mV DAC */ @@ -20,13 +28,19 @@ #define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */ #define TPS53679_PAGE_NUM 2 -static int tps53679_identify(struct i2c_client *client, - struct pmbus_driver_info *info) +#define TPS53681_DEVICE_ID 0x81 + +#define TPS53681_PMBUS_REVISION 0x33 + +#define TPS53681_MFR_SPECIFIC_20 0xe4 /* Number of phases, per page */ + +static int tps53679_identify_mode(struct i2c_client *client, + struct pmbus_driver_info *info) { u8 vout_params; int i, ret; - for (i = 0; i < TPS53679_PAGE_NUM; i++) { + for (i = 0; i < info->pages; i++) { /* Read the register with VOUT scaling value.*/ ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); if (ret < 0) @@ -52,48 +66,180 @@ static int tps53679_identify(struct i2c_client *client, return 0; } +static int tps53679_identify_phases(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + int ret; + + /* On TPS53681, only channel A provides per-phase output current */ + ret = pmbus_read_byte_data(client, 0, TPS53681_MFR_SPECIFIC_20); + if (ret < 0) + return ret; + info->phases[0] = (ret & 0x07) + 1; + + return 0; +} + +static int tps53679_identify_chip(struct i2c_client *client, + u8 revision, u16 id) +{ + u8 buf[I2C_SMBUS_BLOCK_MAX]; + int ret; + + ret = pmbus_read_byte_data(client, 0, PMBUS_REVISION); + if (ret < 0) + return ret; + if (ret != revision) { + dev_err(&client->dev, "Unexpected PMBus revision 0x%x\n", ret); + return -ENODEV; + } + + ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); + if (ret < 0) + return ret; + if (ret != 1 || buf[0] != id) { + dev_err(&client->dev, "Unexpected device ID 0x%x\n", buf[0]); + return -ENODEV; + } + return 0; +} + +/* + * Common identification function for chips with multi-phase support. + * Since those chips have special configuration registers, we want to have + * some level of reassurance that we are really talking with the chip + * being probed. Check PMBus revision and chip ID. + */ +static int tps53679_identify_multiphase(struct i2c_client *client, + struct pmbus_driver_info *info, + int pmbus_rev, int device_id) +{ + int ret; + + ret = tps53679_identify_chip(client, pmbus_rev, device_id); + if (ret < 0) + return ret; + + ret = tps53679_identify_mode(client, info); + if (ret < 0) + return ret; + + return tps53679_identify_phases(client, info); +} + +static int tps53679_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + return tps53679_identify_mode(client, info); +} + +static int tps53681_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + return tps53679_identify_multiphase(client, info, + TPS53681_PMBUS_REVISION, + TPS53681_DEVICE_ID); +} + +static int tps53681_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + /* + * For reading the total output current (READ_IOUT) for all phases, + * the chip datasheet is a bit vague. It says "PHASE must be set to + * FFh to access all phases simultaneously. PHASE may also be set to + * 80h readack (!) the total phase current". + * Experiments show that the command does _not_ report the total + * current for all phases if the phase is set to 0xff. Instead, it + * appears to report the current of one of the phases. Override phase + * parameter with 0x80 when reading the total output current on page 0. + */ + if (reg == PMBUS_READ_IOUT && page == 0 && phase == 0xff) + return pmbus_read_word_data(client, page, 0x80, reg); + return -ENODATA; +} + static struct pmbus_driver_info tps53679_info = { - .pages = TPS53679_PAGE_NUM, .format[PSC_VOLTAGE_IN] = linear, .format[PSC_VOLTAGE_OUT] = vid, .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 | + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | + PMBUS_HAVE_STATUS_INPUT | + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT, - .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT, - .identify = tps53679_identify, + .pfunc[0] = PMBUS_HAVE_IOUT, + .pfunc[1] = PMBUS_HAVE_IOUT, + .pfunc[2] = PMBUS_HAVE_IOUT, + .pfunc[3] = PMBUS_HAVE_IOUT, + .pfunc[4] = PMBUS_HAVE_IOUT, + .pfunc[5] = PMBUS_HAVE_IOUT, }; static int tps53679_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct pmbus_driver_info *info; + enum chips chip_id; + + if (dev->of_node) + chip_id = (enum chips)of_device_get_match_data(dev); + else + chip_id = id->driver_data; - info = devm_kmemdup(&client->dev, &tps53679_info, sizeof(*info), - GFP_KERNEL); + info = devm_kmemdup(dev, &tps53679_info, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; + switch (chip_id) { + case tps53647: + case tps53667: + info->pages = TPS53647_PAGE_NUM; + info->identify = tps53679_identify; + break; + case tps53679: + case tps53688: + info->pages = TPS53679_PAGE_NUM; + info->identify = tps53679_identify; + break; + case tps53681: + info->pages = TPS53679_PAGE_NUM; + info->phases[0] = 6; + info->identify = tps53681_identify; + info->read_word_data = tps53681_read_word_data; + break; + default: + return -ENODEV; + } + return pmbus_do_probe(client, id, info); } static const struct i2c_device_id tps53679_id[] = { - {"tps53679", 0}, - {"tps53688", 0}, + {"tps53647", tps53647}, + {"tps53667", tps53667}, + {"tps53679", tps53679}, + {"tps53681", tps53681}, + {"tps53688", tps53688}, {} }; MODULE_DEVICE_TABLE(i2c, tps53679_id); static const struct of_device_id __maybe_unused tps53679_of_match[] = { - {.compatible = "ti,tps53679"}, - {.compatible = "ti,tps53688"}, + {.compatible = "ti,tps53647", .data = (void *)tps53647}, + {.compatible = "ti,tps53667", .data = (void *)tps53667}, + {.compatible = "ti,tps53679", .data = (void *)tps53679}, + {.compatible = "ti,tps53681", .data = (void *)tps53681}, + {.compatible = "ti,tps53688", .data = (void *)tps53688}, {} }; MODULE_DEVICE_TABLE(of, tps53679_of_match); diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index 23ea3415f166..81f4c4f166cd 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -370,7 +370,7 @@ static void ucd9000_probe_gpio(struct i2c_client *client, #ifdef CONFIG_DEBUG_FS static int ucd9000_get_mfr_status(struct i2c_client *client, u8 *buffer) { - int ret = pmbus_set_page(client, 0); + int ret = pmbus_set_page(client, 0, 0xff); if (ret < 0) return ret; diff --git a/drivers/hwmon/pmbus/xdpe12284.c b/drivers/hwmon/pmbus/xdpe12284.c index 660556b89e9f..d5103fc9e269 100644 --- a/drivers/hwmon/pmbus/xdpe12284.c +++ b/drivers/hwmon/pmbus/xdpe12284.c @@ -18,7 +18,8 @@ #define XDPE122_AMD_625MV 0x10 /* AMD mode 6.25mV */ #define XDPE122_PAGE_NUM 2 -static int xdpe122_read_word_data(struct i2c_client *client, int page, int reg) +static int xdpe122_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); long val; @@ -29,7 +30,7 @@ static int xdpe122_read_word_data(struct i2c_client *client, int page, int reg) switch (reg) { case PMBUS_VOUT_OV_FAULT_LIMIT: case PMBUS_VOUT_UV_FAULT_LIMIT: - ret = pmbus_read_word_data(client, page, reg); + ret = pmbus_read_word_data(client, page, phase, reg); if (ret < 0) return ret; diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index 190b898e404a..3a827d0a881d 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -125,7 +125,8 @@ static inline void zl6100_wait(const struct zl6100_data *data) } } -static int zl6100_read_word_data(struct i2c_client *client, int page, int reg) +static int zl6100_read_word_data(struct i2c_client *client, int page, + int phase, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); struct zl6100_data *data = to_zl6100_data(info); @@ -167,7 +168,7 @@ static int zl6100_read_word_data(struct i2c_client *client, int page, int reg) } zl6100_wait(data); - ret = pmbus_read_word_data(client, page, vreg); + ret = pmbus_read_word_data(client, page, phase, vreg); data->access = ktime_get(); if (ret < 0) return ret; |