On Fri, Apr 23, 2021 at 05:33:28PM +0200, Erik Rosen wrote: > Add support for Renesas ZL8802 Dual Channel/Dual Phase PMBus DC/DC > Digital Controller as well as ZLS1003 and ZLS4009 custom DC/DC > controller chips. > > Signed-off-by: Erik Rosen <erik.rosen@xxxxxxxxxxxxx> Applied to hwmon-next. Thanks, Guenter > --- > drivers/hwmon/pmbus/zl6100.c | 94 ++++++++++++++++++++++++++++++------ > 1 file changed, 80 insertions(+), 14 deletions(-) > > diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c > index 69120ca7aaa8..757039bb8a62 100644 > --- a/drivers/hwmon/pmbus/zl6100.c > +++ b/drivers/hwmon/pmbus/zl6100.c > @@ -18,7 +18,7 @@ > #include "pmbus.h" > > enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105, > - zl9101, zl9117 }; > + zl8802, zl9101, zl9117, zls1003, zls4009 }; > > struct zl6100_data { > int id; > @@ -34,6 +34,13 @@ struct zl6100_data { > > #define ZL6100_MFR_XTEMP_ENABLE BIT(7) > > +#define ZL8802_MFR_USER_GLOBAL_CONFIG 0xe9 > +#define ZL8802_MFR_TMON_ENABLE BIT(12) > +#define ZL8802_MFR_USER_CONFIG 0xd1 > +#define ZL8802_MFR_XTEMP_ENABLE_2 BIT(1) > +#define ZL8802_MFR_DDC_CONFIG 0xd3 > +#define ZL8802_MFR_PHASES_MASK 0x0007 > + > #define MFR_VMON_OV_FAULT_LIMIT 0xf5 > #define MFR_VMON_UV_FAULT_LIMIT 0xf6 > #define MFR_READ_VMON 0xf7 > @@ -132,7 +139,7 @@ static int zl6100_read_word_data(struct i2c_client *client, int page, > struct zl6100_data *data = to_zl6100_data(info); > int ret, vreg; > > - if (page > 0) > + if (page >= info->pages) > return -ENXIO; > > if (data->id == zl2005) { > @@ -191,7 +198,7 @@ static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg) > struct zl6100_data *data = to_zl6100_data(info); > int ret, status; > > - if (page > 0) > + if (page >= info->pages) > return -ENXIO; > > zl6100_wait(data); > @@ -230,7 +237,7 @@ static int zl6100_write_word_data(struct i2c_client *client, int page, int reg, > struct zl6100_data *data = to_zl6100_data(info); > int ret, vreg; > > - if (page > 0) > + if (page >= info->pages) > return -ENXIO; > > switch (reg) { > @@ -271,7 +278,7 @@ static int zl6100_write_byte(struct i2c_client *client, int page, u8 value) > struct zl6100_data *data = to_zl6100_data(info); > int ret; > > - if (page > 0) > + if (page >= info->pages) > return -ENXIO; > > zl6100_wait(data); > @@ -287,6 +294,10 @@ static const struct i2c_device_id zl6100_id[] = { > {"bmr462", zl2008}, > {"bmr463", zl2008}, > {"bmr464", zl2008}, > + {"bmr465", zls4009}, > + {"bmr466", zls1003}, > + {"bmr467", zls4009}, > + {"bmr469", zl8802}, > {"zl2004", zl2004}, > {"zl2005", zl2005}, > {"zl2006", zl2006}, > @@ -295,15 +306,18 @@ static const struct i2c_device_id zl6100_id[] = { > {"zl2106", zl2106}, > {"zl6100", zl6100}, > {"zl6105", zl6105}, > + {"zl8802", zl8802}, > {"zl9101", zl9101}, > {"zl9117", zl9117}, > + {"zls1003", zls1003}, > + {"zls4009", zls4009}, > { } > }; > MODULE_DEVICE_TABLE(i2c, zl6100_id); > > static int zl6100_probe(struct i2c_client *client) > { > - int ret; > + int ret, i; > struct zl6100_data *data; > struct pmbus_driver_info *info; > u8 device_id[I2C_SMBUS_BLOCK_MAX + 1]; > @@ -367,18 +381,70 @@ static int zl6100_probe(struct i2c_client *client) > | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; > > /* > - * ZL2004, ZL9101M, and ZL9117M support monitoring an extra voltage > - * (VMON for ZL2004, VDRV for ZL9101M and ZL9117M). Report it as vmon. > + * ZL2004, ZL8802, ZL9101M, ZL9117M and ZLS4009 support monitoring > + * an extra voltage (VMON for ZL2004, ZL8802 and ZLS4009, > + * VDRV for ZL9101M and ZL9117M). Report it as vmon. > */ > - if (data->id == zl2004 || data->id == zl9101 || data->id == zl9117) > + if (data->id == zl2004 || data->id == zl8802 || data->id == zl9101 || > + data->id == zl9117 || data->id == zls4009) > info->func[0] |= PMBUS_HAVE_VMON | PMBUS_HAVE_STATUS_VMON; > > - ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG); > - if (ret < 0) > - return ret; > + /* > + * ZL8802 has two outputs that can be used either independently or in > + * a current sharing configuration. The driver uses the DDC_CONFIG > + * register to check if the module is running with independent or > + * shared outputs. If the module is in shared output mode, only one > + * output voltage will be reported. > + */ > + if (data->id == zl8802) { > + info->pages = 2; > + info->func[0] |= PMBUS_HAVE_IIN; > + > + ret = i2c_smbus_read_word_data(client, ZL8802_MFR_DDC_CONFIG); > + if (ret < 0) > + return ret; > + > + data->access = ktime_get(); > + zl6100_wait(data); > + > + if (ret & ZL8802_MFR_PHASES_MASK) > + info->func[1] |= PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; > + else > + info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT > + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; > > - if (ret & ZL6100_MFR_XTEMP_ENABLE) > - info->func[0] |= PMBUS_HAVE_TEMP2; > + for (i = 0; i < 2; i++) { > + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i); > + if (ret < 0) > + return ret; > + > + data->access = ktime_get(); > + zl6100_wait(data); > + > + ret = i2c_smbus_read_word_data(client, ZL8802_MFR_USER_CONFIG); > + if (ret < 0) > + return ret; > + > + if (ret & ZL8802_MFR_XTEMP_ENABLE_2) > + info->func[i] |= PMBUS_HAVE_TEMP2; > + > + data->access = ktime_get(); > + zl6100_wait(data); > + } > + ret = i2c_smbus_read_word_data(client, ZL8802_MFR_USER_GLOBAL_CONFIG); > + if (ret < 0) > + return ret; > + > + if (ret & ZL8802_MFR_TMON_ENABLE) > + info->func[0] |= PMBUS_HAVE_TEMP3; > + } else { > + ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG); > + if (ret < 0) > + return ret; > + > + if (ret & ZL6100_MFR_XTEMP_ENABLE) > + info->func[0] |= PMBUS_HAVE_TEMP2; > + } > > data->access = ktime_get(); > zl6100_wait(data);