diff options
Diffstat (limited to 'drivers/hwmon/pmbus')
-rw-r--r-- | drivers/hwmon/pmbus/Kconfig | 4 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/ibm-cffps.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/lm25066.c | 5 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max16601.c | 91 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max31785.c | 13 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/pmbus_core.c | 12 |
6 files changed, 89 insertions, 38 deletions
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 03606d4298a4..32d2fc850621 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -158,10 +158,10 @@ config SENSORS_MAX16064 be called max16064. config SENSORS_MAX16601 - tristate "Maxim MAX16601" + tristate "Maxim MAX16508, MAX16601" help If you say yes here you get hardware monitoring support for Maxim - MAX16601. + MAX16508 and MAX16601. This driver can also be built as a module. If so, the module will be called max16601. diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index d6bbbb223871..ffde5aaa5036 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -472,7 +472,7 @@ static struct pmbus_driver_info ibm_cffps_info[] = { }; static struct pmbus_platform_data ibm_cffps_pdata = { - .flags = PMBUS_SKIP_STATUS_CHECK, + .flags = PMBUS_SKIP_STATUS_CHECK | PMBUS_NO_CAPABILITY, }; static int ibm_cffps_probe(struct i2c_client *client) diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index c75a6bf39641..e9a66fd9e144 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -371,21 +371,18 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg, case PMBUS_VIN_OV_WARN_LIMIT: word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit); ret = pmbus_write_word_data(client, 0, reg, word); - pmbus_clear_cache(client); break; case PMBUS_IIN_OC_WARN_LIMIT: word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit); ret = pmbus_write_word_data(client, 0, LM25066_MFR_IIN_OC_WARN_LIMIT, word); - pmbus_clear_cache(client); break; case PMBUS_PIN_OP_WARN_LIMIT: word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit); ret = pmbus_write_word_data(client, 0, LM25066_MFR_PIN_OP_WARN_LIMIT, word); - pmbus_clear_cache(client); break; case PMBUS_VIRT_VMON_UV_WARN_LIMIT: /* Adjust from VIN coefficients (for LM25056) */ @@ -393,7 +390,6 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg, word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit); ret = pmbus_write_word_data(client, 0, LM25056_VAUX_UV_WARN_LIMIT, word); - pmbus_clear_cache(client); break; case PMBUS_VIRT_VMON_OV_WARN_LIMIT: /* Adjust from VIN coefficients (for LM25056) */ @@ -401,7 +397,6 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg, word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit); ret = pmbus_write_word_data(client, 0, LM25056_VAUX_OV_WARN_LIMIT, word); - pmbus_clear_cache(client); break; case PMBUS_VIRT_RESET_PIN_HISTORY: ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK); diff --git a/drivers/hwmon/pmbus/max16601.c b/drivers/hwmon/pmbus/max16601.c index a960b86e72d2..0d1204c2dd54 100644 --- a/drivers/hwmon/pmbus/max16601.c +++ b/drivers/hwmon/pmbus/max16601.c @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Hardware monitoring driver for Maxim MAX16601 + * Hardware monitoring driver for Maxim MAX16508 and MAX16601. * * Implementation notes: * - * Ths chip supports two rails, VCORE and VSA. Telemetry information for the - * two rails is reported in two subsequent I2C addresses. The driver + * This chip series supports two rails, VCORE and VSA. Telemetry information + * for the two rails is reported in two subsequent I2C addresses. The driver * instantiates a dummy I2C client at the second I2C address to report * information for the VSA rail in a single instance of the driver. * Telemetry for the VSA rail is reported to the PMBus core in PMBus page 2. @@ -31,6 +31,9 @@ #include "pmbus.h" +enum chips { max16508, max16601 }; + +#define REG_DEFAULT_NUM_POP 0xc4 #define REG_SETPT_DVID 0xd1 #define DAC_10MV_MODE BIT(4) #define REG_IOUT_AVG_PK 0xee @@ -40,7 +43,10 @@ #define CORE_RAIL_INDICATOR BIT(7) #define REG_PHASE_REPORTING 0xf4 +#define MAX16601_NUM_PHASES 8 + struct max16601_data { + enum chips id; struct pmbus_driver_info info; struct i2c_client *vsa; int iout_avg_pkg; @@ -185,6 +191,7 @@ static int max16601_write_word(struct i2c_client *client, int page, int reg, static int max16601_identify(struct i2c_client *client, struct pmbus_driver_info *info) { + struct max16601_data *data = to_max16601_data(info); int reg; reg = i2c_smbus_read_byte_data(client, REG_SETPT_DVID); @@ -195,6 +202,21 @@ static int max16601_identify(struct i2c_client *client, else info->vrm_version[0] = vr12; + if (data->id != max16601) + return 0; + + reg = i2c_smbus_read_byte_data(client, REG_DEFAULT_NUM_POP); + if (reg < 0) + return reg; + + /* + * If REG_DEFAULT_NUM_POP returns 0, we don't know how many phases + * are populated. Stick with the default in that case. + */ + reg &= 0x0f; + if (reg && reg <= MAX16601_NUM_PHASES) + info->phases[0] = reg; + return 0; } @@ -216,7 +238,7 @@ static struct pmbus_driver_info max16601_info = { .func[2] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_PAGE_VIRTUAL, - .phases[0] = 8, + .phases[0] = MAX16601_NUM_PHASES, .pfunc[0] = PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP, .pfunc[1] = PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT, .pfunc[2] = PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP, @@ -239,28 +261,61 @@ static void max16601_remove(void *_data) i2c_unregister_device(data->vsa); } -static int max16601_probe(struct i2c_client *client) +static const struct i2c_device_id max16601_id[] = { + {"max16508", max16508}, + {"max16601", max16601}, + {} +}; +MODULE_DEVICE_TABLE(i2c, max16601_id); + +static int max16601_get_id(struct i2c_client *client) { struct device *dev = &client->dev; u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; - struct max16601_data *data; + enum chips id; int ret; - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_BYTE_DATA | - I2C_FUNC_SMBUS_READ_BLOCK_DATA)) - return -ENODEV; - ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); - if (ret < 0) + if (ret < 0 || ret < 11) return -ENODEV; - /* PMBUS_IC_DEVICE_ID is expected to return "MAX16601y.xx" */ - if (ret < 11 || strncmp(buf, "MAX16601", 8)) { + /* + * PMBUS_IC_DEVICE_ID is expected to return "MAX16601y.xx" + * or "MAX16500y.xx". + */ + if (!strncmp(buf, "MAX16500", 8)) { + id = max16508; + } else if (!strncmp(buf, "MAX16601", 8)) { + id = max16601; + } else { buf[ret] = '\0'; dev_err(dev, "Unsupported chip '%s'\n", buf); return -ENODEV; } + return id; +} + +static int max16601_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + const struct i2c_device_id *id; + struct max16601_data *data; + int ret, chip_id; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA | + I2C_FUNC_SMBUS_READ_BLOCK_DATA)) + return -ENODEV; + + chip_id = max16601_get_id(client); + if (chip_id < 0) + return chip_id; + + id = i2c_match_id(max16601_id, client); + if (chip_id != id->driver_data) + dev_warn(&client->dev, + "Device mismatch: Configured %s (%d), detected %d\n", + id->name, (int) id->driver_data, chip_id); ret = i2c_smbus_read_byte_data(client, REG_PHASE_ID); if (ret < 0) @@ -275,6 +330,7 @@ static int max16601_probe(struct i2c_client *client) if (!data) return -ENOMEM; + data->id = chip_id; data->iout_avg_pkg = 0xfc00; data->vsa = i2c_new_dummy_device(client->adapter, client->addr + 1); if (IS_ERR(data->vsa)) { @@ -290,13 +346,6 @@ static int max16601_probe(struct i2c_client *client) return pmbus_do_probe(client, &data->info); } -static const struct i2c_device_id max16601_id[] = { - {"max16601", 0}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, max16601_id); - static struct i2c_driver max16601_driver = { .driver = { .name = "max16601", diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c index e5a9f4019cd5..17489abc49d5 100644 --- a/drivers/hwmon/pmbus/max31785.c +++ b/drivers/hwmon/pmbus/max31785.c @@ -17,6 +17,7 @@ enum max31785_regs { #define MAX31785 0x3030 #define MAX31785A 0x3040 +#define MAX31785B 0x3061 #define MFR_FAN_CONFIG_DUAL_TACH BIT(12) @@ -329,7 +330,7 @@ static int max31785_probe(struct i2c_client *client) struct device *dev = &client->dev; struct pmbus_driver_info *info; bool dual_tach = false; - s64 ret; + int ret; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | @@ -350,12 +351,14 @@ static int max31785_probe(struct i2c_client *client) if (ret < 0) return ret; - if (ret == MAX31785A) { + if (ret == MAX31785A || ret == MAX31785B) { dual_tach = true; } else if (ret == MAX31785) { - if (!strcmp("max31785a", client->name)) - dev_warn(dev, "Expected max3175a, found max31785: cannot provide secondary tachometer readings\n"); + if (!strcmp("max31785a", client->name) || + !strcmp("max31785b", client->name)) + dev_warn(dev, "Expected max31785a/b, found max31785: cannot provide secondary tachometer readings\n"); } else { + dev_err(dev, "Unrecognized MAX31785 revision: %x\n", ret); return -ENODEV; } @@ -371,6 +374,7 @@ static int max31785_probe(struct i2c_client *client) static const struct i2c_device_id max31785_id[] = { { "max31785", 0 }, { "max31785a", 0 }, + { "max31785b", 0 }, { }, }; @@ -379,6 +383,7 @@ MODULE_DEVICE_TABLE(i2c, max31785_id); static const struct of_device_id max31785_of_match[] = { { .compatible = "maxim,max31785" }, { .compatible = "maxim,max31785a" }, + { .compatible = "maxim,max31785b" }, { }, }; diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 192442b3b7a2..aadea85fe630 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -974,7 +974,7 @@ static ssize_t pmbus_set_sensor(struct device *dev, if (ret < 0) rv = ret; else - sensor->data = regval; + sensor->data = -ENODATA; mutex_unlock(&data->update_lock); return rv; } @@ -1262,7 +1262,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client, * which global bit is set) for this page is accessible. */ if (!ret && attr->gbit && - (!upper || (upper && data->has_status_word)) && + (!upper || data->has_status_word) && pmbus_check_status_register(client, page)) { ret = pmbus_add_boolean(data, name, "alarm", index, NULL, NULL, @@ -2204,9 +2204,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; + if (!(data->flags & PMBUS_NO_CAPABILITY)) { + ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); + if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) + client->flags |= I2C_CLIENT_PEC; + } /* * Check if the chip is write protected. If it is, we can not clear |