diff options
Diffstat (limited to 'drivers/hwmon/pmbus')
-rw-r--r-- | drivers/hwmon/pmbus/Kconfig | 9 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/adm1275.c | 71 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/pmbus.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/zl6100.c | 43 |
4 files changed, 91 insertions, 34 deletions
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 4b26f51920b..cfec923f42b 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -19,8 +19,8 @@ config SENSORS_PMBUS default y help If you say yes here you get hardware monitoring support for generic - PMBus devices, including but not limited to ADP4000, BMR450, BMR451, - BMR453, BMR454, NCP4200, and NCP4208. + PMBus devices, including but not limited to ADP4000, BMR453, BMR454, + NCP4200, and NCP4208. This driver can also be built as a module. If so, the module will be called pmbus. @@ -113,8 +113,9 @@ config SENSORS_ZL6100 default n help If you say yes here you get hardware monitoring support for Intersil - ZL2004, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, and ZL6105 Digital - DC/DC Controllers. + ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, and ZL6105 + Digital DC/DC Controllers, as well as for Ericsson BMR450, BMR451, + BMR462, BMR463, and BMR464. This driver can also be built as a module. If so, the module will be called zl6100. diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 980a4d9d502..81c7c2ead6f 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -170,35 +170,71 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) return ret; } +static const struct i2c_device_id adm1275_id[] = { + { "adm1275", adm1275 }, + { "adm1276", adm1276 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adm1275_id); + static int adm1275_probe(struct i2c_client *client, const struct i2c_device_id *id) { + u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; int config, device_config; int ret; struct pmbus_driver_info *info; struct adm1275_data *data; + const struct i2c_device_id *mid; if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_BYTE_DATA)) + I2C_FUNC_SMBUS_READ_BYTE_DATA + | I2C_FUNC_SMBUS_BLOCK_DATA)) return -ENODEV; - data = kzalloc(sizeof(struct adm1275_data), GFP_KERNEL); - if (!data) - return -ENOMEM; + ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer); + if (ret < 0) { + dev_err(&client->dev, "Failed to read Manufacturer ID\n"); + return ret; + } + if (ret != 3 || strncmp(block_buffer, "ADI", 3)) { + dev_err(&client->dev, "Unsupported Manufacturer ID\n"); + return -ENODEV; + } - config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); - if (config < 0) { - ret = config; - goto err_mem; + ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer); + if (ret < 0) { + dev_err(&client->dev, "Failed to read Manufacturer Model\n"); + return ret; + } + for (mid = adm1275_id; mid->name[0]; mid++) { + if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) + break; + } + if (!mid->name[0]) { + dev_err(&client->dev, "Unsupported device\n"); + return -ENODEV; } + if (id->driver_data != mid->driver_data) + dev_notice(&client->dev, + "Device mismatch: Configured %s, detected %s\n", + id->name, mid->name); + + config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); + if (config < 0) + return config; + device_config = i2c_smbus_read_byte_data(client, ADM1275_DEVICE_CONFIG); - if (device_config < 0) { - ret = device_config; - goto err_mem; - } + if (device_config < 0) + return device_config; + + data = kzalloc(sizeof(struct adm1275_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->id = mid->driver_data; - data->id = id->driver_data; info = &data->info; info->pages = 1; @@ -233,7 +269,7 @@ static int adm1275_probe(struct i2c_client *client, if (device_config & ADM1275_IOUT_WARN2_SELECT) data->have_oc_fault = true; - switch (id->driver_data) { + switch (data->id) { case adm1275: if (config & ADM1275_VIN_VOUT_SELECT) info->func[0] |= @@ -281,13 +317,6 @@ static int adm1275_remove(struct i2c_client *client) return 0; } -static const struct i2c_device_id adm1275_id[] = { - { "adm1275", adm1275 }, - { "adm1276", adm1276 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, adm1275_id); - static struct i2c_driver adm1275_driver = { .driver = { .name = "adm1275", diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 995e873197e..18a385e753d 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -200,8 +200,6 @@ static int pmbus_remove(struct i2c_client *client) */ static const struct i2c_device_id pmbus_id[] = { {"adp4000", 1}, - {"bmr450", 1}, - {"bmr451", 1}, {"bmr453", 1}, {"bmr454", 1}, {"ncp4200", 1}, diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index 2bc980006f8..48c7b4a716a 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -28,7 +28,7 @@ #include <linux/delay.h> #include "pmbus.h" -enum chips { zl2004, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105 }; +enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105 }; struct zl6100_data { int id; @@ -38,8 +38,11 @@ struct zl6100_data { #define to_zl6100_data(x) container_of(x, struct zl6100_data, info) +#define ZL6100_MFR_CONFIG 0xd0 #define ZL6100_DEVICE_ID 0xe4 +#define ZL6100_MFR_XTEMP_ENABLE (1 << 7) + #define ZL6100_WAIT_TIME 1000 /* uS */ static ushort delay = ZL6100_WAIT_TIME; @@ -65,6 +68,19 @@ static int zl6100_read_word_data(struct i2c_client *client, int page, int reg) if (page || reg >= PMBUS_VIRT_BASE) return -ENXIO; + if (data->id == zl2005) { + /* + * Limit register detection is not reliable on ZL2005. + * Make sure registers are not erroneously detected. + */ + switch (reg) { + case PMBUS_VOUT_OV_WARN_LIMIT: + case PMBUS_VOUT_UV_WARN_LIMIT: + case PMBUS_IOUT_OC_WARN_LIMIT: + return -ENXIO; + } + } + zl6100_wait(data); ret = pmbus_read_word_data(client, page, reg); data->access = ktime_get(); @@ -122,7 +138,13 @@ static int zl6100_write_byte(struct i2c_client *client, int page, u8 value) } static const struct i2c_device_id zl6100_id[] = { + {"bmr450", zl2005}, + {"bmr451", zl2005}, + {"bmr462", zl2008}, + {"bmr463", zl2008}, + {"bmr464", zl2008}, {"zl2004", zl2004}, + {"zl2005", zl2005}, {"zl2006", zl2006}, {"zl2008", zl2008}, {"zl2105", zl2105}, @@ -143,7 +165,7 @@ static int zl6100_probe(struct i2c_client *client, const struct i2c_device_id *mid; if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_BYTE_DATA + I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_READ_BLOCK_DATA)) return -ENODEV; @@ -177,8 +199,9 @@ static int zl6100_probe(struct i2c_client *client, data->id = mid->driver_data; /* - * ZL2008, ZL2105, and ZL6100 are known to require a wait time + * ZL2005, ZL2008, ZL2105, and ZL6100 are known to require a wait time * between I2C accesses. ZL2004 and ZL6105 are known to be safe. + * Other chips have not yet been tested. * * Only clear the wait time for chips known to be safe. The wait time * can be cleared later for additional chips if tests show that it @@ -190,12 +213,9 @@ static int zl6100_probe(struct i2c_client *client, /* * Since there was a direct I2C device access above, wait before * accessing the chip again. - * Set the timestamp, wait, then set it again. This should provide - * enough buffer time to be safe. */ data->access = ktime_get(); zl6100_wait(data); - data->access = ktime_get(); info = &data->info; @@ -203,7 +223,16 @@ static int zl6100_probe(struct i2c_client *client, info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT - | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; + + ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG); + if (ret < 0) + goto err_mem; + if (ret & ZL6100_MFR_XTEMP_ENABLE) + info->func[0] |= PMBUS_HAVE_TEMP2; + + data->access = ktime_get(); + zl6100_wait(data); info->read_word_data = zl6100_read_word_data; info->read_byte_data = zl6100_read_byte_data; |