// 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.
#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 MAX16601_NUM_PHASES 8
struct max16601_data {
+ enum chips id;
struct pmbus_driver_info info;
struct i2c_client *vsa;
int iout_avg_pkg;
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);
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;
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)
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)) {
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",