hwmon: (pmbus/max16601) Add support for MAX16508

MAX16508 is quite similar to MAX16601, except that it does not support
the DEFAULT_NUM_POP register and we thus can not dynamically determine
the number of populated phases.

Cc: Alex Qiu <xqiu@google.com>
Cc: Ugur Usug <Ugur.Usug@maximintegrated.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20210125185327.93282-2-linux@roeck-us.net
Reviewed-by: Alex Qiu <xqiu@google.com>
Tested-by: Alex Qiu <xqiu@google.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
Guenter Roeck 2021-01-25 10:53:27 -08:00
parent 220c404dc7
commit 66102281f9
3 changed files with 67 additions and 25 deletions

View File

@ -5,6 +5,14 @@ Kernel driver max16601
Supported chips: Supported chips:
* Maxim MAX16508
Prefix: 'max16508'
Addresses scanned: -
Datasheet: Not published
* Maxim MAX16601 * Maxim MAX16601
Prefix: 'max16601' Prefix: 'max16601'
@ -19,8 +27,8 @@ Author: Guenter Roeck <linux@roeck-us.net>
Description Description
----------- -----------
This driver supports the MAX16601 VR13.HC Dual-Output Voltage Regulator This driver supports the MAX16508 VR13 Dual-Output Voltage Regulator
Chipset. as well as the MAX16601 VR13.HC Dual-Output Voltage Regulator chipsets.
The driver is a client driver to the core PMBus driver. The driver is a client driver to the core PMBus driver.
Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers. Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers.

View File

@ -158,10 +158,10 @@ config SENSORS_MAX16064
be called max16064. be called max16064.
config SENSORS_MAX16601 config SENSORS_MAX16601
tristate "Maxim MAX16601" tristate "Maxim MAX16508, MAX16601"
help help
If you say yes here you get hardware monitoring support for Maxim 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 This driver can also be built as a module. If so, the module will
be called max16601. be called max16601.

View File

@ -1,11 +1,11 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* Hardware monitoring driver for Maxim MAX16601 * Hardware monitoring driver for Maxim MAX16508 and MAX16601.
* *
* Implementation notes: * Implementation notes:
* *
* Ths chip supports two rails, VCORE and VSA. Telemetry information for the * This chip series supports two rails, VCORE and VSA. Telemetry information
* two rails is reported in two subsequent I2C addresses. The driver * 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 * instantiates a dummy I2C client at the second I2C address to report
* information for the VSA rail in a single instance of the driver. * 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. * Telemetry for the VSA rail is reported to the PMBus core in PMBus page 2.
@ -31,6 +31,8 @@
#include "pmbus.h" #include "pmbus.h"
enum chips { max16508, max16601 };
#define REG_DEFAULT_NUM_POP 0xc4 #define REG_DEFAULT_NUM_POP 0xc4
#define REG_SETPT_DVID 0xd1 #define REG_SETPT_DVID 0xd1
#define DAC_10MV_MODE BIT(4) #define DAC_10MV_MODE BIT(4)
@ -44,6 +46,7 @@
#define MAX16601_NUM_PHASES 8 #define MAX16601_NUM_PHASES 8
struct max16601_data { struct max16601_data {
enum chips id;
struct pmbus_driver_info info; struct pmbus_driver_info info;
struct i2c_client *vsa; struct i2c_client *vsa;
int iout_avg_pkg; int iout_avg_pkg;
@ -188,6 +191,7 @@ static int max16601_write_word(struct i2c_client *client, int page, int reg,
static int max16601_identify(struct i2c_client *client, static int max16601_identify(struct i2c_client *client,
struct pmbus_driver_info *info) struct pmbus_driver_info *info)
{ {
struct max16601_data *data = to_max16601_data(info);
int reg; int reg;
reg = i2c_smbus_read_byte_data(client, REG_SETPT_DVID); reg = i2c_smbus_read_byte_data(client, REG_SETPT_DVID);
@ -198,6 +202,9 @@ static int max16601_identify(struct i2c_client *client,
else else
info->vrm_version[0] = vr12; info->vrm_version[0] = vr12;
if (data->id != max16601)
return 0;
reg = i2c_smbus_read_byte_data(client, REG_DEFAULT_NUM_POP); reg = i2c_smbus_read_byte_data(client, REG_DEFAULT_NUM_POP);
if (reg < 0) if (reg < 0)
return reg; return reg;
@ -254,28 +261,61 @@ static void max16601_remove(void *_data)
i2c_unregister_device(data->vsa); 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; struct device *dev = &client->dev;
u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
struct max16601_data *data; enum chips id;
int ret; int ret;
ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf);
if (ret < 0 || ret < 11)
return -ENODEV;
/*
* 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, if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_READ_BYTE_DATA |
I2C_FUNC_SMBUS_READ_BLOCK_DATA)) I2C_FUNC_SMBUS_READ_BLOCK_DATA))
return -ENODEV; return -ENODEV;
ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); chip_id = max16601_get_id(client);
if (ret < 0) if (chip_id < 0)
return -ENODEV; return chip_id;
/* PMBUS_IC_DEVICE_ID is expected to return "MAX16601y.xx" */ id = i2c_match_id(max16601_id, client);
if (ret < 11 || strncmp(buf, "MAX16601", 8)) { if (chip_id != id->driver_data)
buf[ret] = '\0'; dev_warn(&client->dev,
dev_err(dev, "Unsupported chip '%s'\n", buf); "Device mismatch: Configured %s (%d), detected %d\n",
return -ENODEV; id->name, (int) id->driver_data, chip_id);
}
ret = i2c_smbus_read_byte_data(client, REG_PHASE_ID); ret = i2c_smbus_read_byte_data(client, REG_PHASE_ID);
if (ret < 0) if (ret < 0)
@ -290,6 +330,7 @@ static int max16601_probe(struct i2c_client *client)
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
data->id = chip_id;
data->iout_avg_pkg = 0xfc00; data->iout_avg_pkg = 0xfc00;
data->vsa = i2c_new_dummy_device(client->adapter, client->addr + 1); data->vsa = i2c_new_dummy_device(client->adapter, client->addr + 1);
if (IS_ERR(data->vsa)) { if (IS_ERR(data->vsa)) {
@ -305,13 +346,6 @@ static int max16601_probe(struct i2c_client *client)
return pmbus_do_probe(client, &data->info); 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 = { static struct i2c_driver max16601_driver = {
.driver = { .driver = {
.name = "max16601", .name = "max16601",