summaryrefslogtreecommitdiff
path: root/drivers/hwmon/pmbus
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/pmbus')
-rw-r--r--drivers/hwmon/pmbus/Kconfig4
-rw-r--r--drivers/hwmon/pmbus/ibm-cffps.c2
-rw-r--r--drivers/hwmon/pmbus/lm25066.c5
-rw-r--r--drivers/hwmon/pmbus/max16601.c91
-rw-r--r--drivers/hwmon/pmbus/max31785.c13
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c12
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