diff options
Diffstat (limited to 'drivers/hwmon/pmbus')
32 files changed, 2030 insertions, 284 deletions
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index e35db489b76f..a25faf69fce3 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -26,6 +26,17 @@ config SENSORS_PMBUS This driver can also be built as a module. If so, the module will be called pmbus. +config SENSORS_ADM1266 + tristate "Analog Devices ADM1266 Sequencer" + select CRC8 + depends on GPIOLIB + help + If you say yes here you get hardware monitoring support for Analog + Devices ADM1266 Cascadable Super Sequencer. + + This driver can also be built as a module. If so, the module will + be called adm1266. + config SENSORS_ADM1275 tristate "Analog Devices ADM1275 and compatibles" help @@ -200,6 +211,15 @@ config SENSORS_MAX8688 This driver can also be built as a module. If so, the module will be called max8688. +config SENSORS_MP2975 + tristate "MPS MP2975" + help + If you say yes here you get hardware monitoring support for MPS + MP2975 Dual Loop Digital Multi-Phase Controller. + + This driver can also be built as a module. If so, the module will + be called mp2975. + config SENSORS_PXE1610 tristate "Infineon PXE1610" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index c4b15db996ad..4c97ad0bd791 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PMBUS) += pmbus_core.o obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o +obj-$(CONFIG_SENSORS_ADM1266) += adm1266.o obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o @@ -23,6 +24,7 @@ obj-$(CONFIG_SENSORS_MAX20751) += max20751.o obj-$(CONFIG_SENSORS_MAX31785) += max31785.o obj-$(CONFIG_SENSORS_MAX34440) += max34440.o obj-$(CONFIG_SENSORS_MAX8688) += max8688.o +obj-$(CONFIG_SENSORS_MP2975) += mp2975.o obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c new file mode 100644 index 000000000000..c7b373ba92f2 --- /dev/null +++ b/drivers/hwmon/pmbus/adm1266.c @@ -0,0 +1,513 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ADM1266 - Cascadable Super Sequencer with Margin + * Control and Fault Recording + * + * Copyright 2020 Analog Devices Inc. + */ + +#include <linux/bitfield.h> +#include <linux/crc8.h> +#include <linux/debugfs.h> +#include <linux/gpio/driver.h> +#include <linux/i2c.h> +#include <linux/i2c-smbus.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/nvmem-consumer.h> +#include <linux/nvmem-provider.h> +#include "pmbus.h" +#include <linux/slab.h> +#include <linux/timekeeping.h> + +#define ADM1266_BLACKBOX_CONFIG 0xD3 +#define ADM1266_PDIO_CONFIG 0xD4 +#define ADM1266_READ_STATE 0xD9 +#define ADM1266_READ_BLACKBOX 0xDE +#define ADM1266_SET_RTC 0xDF +#define ADM1266_GPIO_CONFIG 0xE1 +#define ADM1266_BLACKBOX_INFO 0xE6 +#define ADM1266_PDIO_STATUS 0xE9 +#define ADM1266_GPIO_STATUS 0xEA + +/* ADM1266 GPIO defines */ +#define ADM1266_GPIO_NR 9 +#define ADM1266_GPIO_FUNCTIONS(x) FIELD_GET(BIT(0), x) +#define ADM1266_GPIO_INPUT_EN(x) FIELD_GET(BIT(2), x) +#define ADM1266_GPIO_OUTPUT_EN(x) FIELD_GET(BIT(3), x) +#define ADM1266_GPIO_OPEN_DRAIN(x) FIELD_GET(BIT(4), x) + +/* ADM1266 PDIO defines */ +#define ADM1266_PDIO_NR 16 +#define ADM1266_PDIO_PIN_CFG(x) FIELD_GET(GENMASK(15, 13), x) +#define ADM1266_PDIO_GLITCH_FILT(x) FIELD_GET(GENMASK(12, 9), x) +#define ADM1266_PDIO_OUT_CFG(x) FIELD_GET(GENMASK(2, 0), x) + +#define ADM1266_BLACKBOX_OFFSET 0 +#define ADM1266_BLACKBOX_SIZE 64 + +#define ADM1266_PMBUS_BLOCK_MAX 255 + +struct adm1266_data { + struct pmbus_driver_info info; + struct gpio_chip gc; + const char *gpio_names[ADM1266_GPIO_NR + ADM1266_PDIO_NR]; + struct i2c_client *client; + struct dentry *debugfs_dir; + struct nvmem_config nvmem_config; + struct nvmem_device *nvmem; + u8 *dev_mem; + struct mutex buf_mutex; + u8 write_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned; + u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned; +}; + +static const struct nvmem_cell_info adm1266_nvmem_cells[] = { + { + .name = "blackbox", + .offset = ADM1266_BLACKBOX_OFFSET, + .bytes = 2048, + }, +}; + +DECLARE_CRC8_TABLE(pmbus_crc_table); + +/* + * Different from Block Read as it sends data and waits for the slave to + * return a value dependent on that data. The protocol is simply a Write Block + * followed by a Read Block without the Read-Block command field and the + * Write-Block STOP bit. + */ +static int adm1266_pmbus_block_xfer(struct adm1266_data *data, u8 cmd, u8 w_len, u8 *data_w, + u8 *data_r) +{ + struct i2c_client *client = data->client; + struct i2c_msg msgs[2] = { + { + .addr = client->addr, + .flags = I2C_M_DMA_SAFE, + .buf = data->write_buf, + .len = w_len + 2, + }, + { + .addr = client->addr, + .flags = I2C_M_RD | I2C_M_DMA_SAFE, + .buf = data->read_buf, + .len = ADM1266_PMBUS_BLOCK_MAX + 2, + } + }; + u8 addr; + u8 crc; + int ret; + + mutex_lock(&data->buf_mutex); + + msgs[0].buf[0] = cmd; + msgs[0].buf[1] = w_len; + memcpy(&msgs[0].buf[2], data_w, w_len); + + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret != 2) { + if (ret >= 0) + ret = -EPROTO; + + mutex_unlock(&data->buf_mutex); + + return ret; + } + + if (client->flags & I2C_CLIENT_PEC) { + addr = i2c_8bit_addr_from_msg(&msgs[0]); + crc = crc8(pmbus_crc_table, &addr, 1, 0); + crc = crc8(pmbus_crc_table, msgs[0].buf, msgs[0].len, crc); + + addr = i2c_8bit_addr_from_msg(&msgs[1]); + crc = crc8(pmbus_crc_table, &addr, 1, crc); + crc = crc8(pmbus_crc_table, msgs[1].buf, msgs[1].buf[0] + 1, crc); + + if (crc != msgs[1].buf[msgs[1].buf[0] + 1]) { + mutex_unlock(&data->buf_mutex); + return -EBADMSG; + } + } + + memcpy(data_r, &msgs[1].buf[1], msgs[1].buf[0]); + + ret = msgs[1].buf[0]; + mutex_unlock(&data->buf_mutex); + + return ret; +} + +static const unsigned int adm1266_gpio_mapping[ADM1266_GPIO_NR][2] = { + {1, 0}, + {2, 1}, + {3, 2}, + {4, 8}, + {5, 9}, + {6, 10}, + {7, 11}, + {8, 6}, + {9, 7}, +}; + +static const char *adm1266_names[ADM1266_GPIO_NR + ADM1266_PDIO_NR] = { + "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", "GPIO6", "GPIO7", "GPIO8", + "GPIO9", "PDIO1", "PDIO2", "PDIO3", "PDIO4", "PDIO5", "PDIO6", + "PDIO7", "PDIO8", "PDIO9", "PDIO10", "PDIO11", "PDIO12", "PDIO13", + "PDIO14", "PDIO15", "PDIO16", +}; + +static int adm1266_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct adm1266_data *data = gpiochip_get_data(chip); + u8 read_buf[I2C_SMBUS_BLOCK_MAX + 1]; + unsigned long pins_status; + unsigned int pmbus_cmd; + int ret; + + if (offset < ADM1266_GPIO_NR) + pmbus_cmd = ADM1266_GPIO_STATUS; + else + pmbus_cmd = ADM1266_PDIO_STATUS; + + ret = i2c_smbus_read_block_data(data->client, pmbus_cmd, read_buf); + if (ret < 0) + return ret; + + pins_status = read_buf[0] + (read_buf[1] << 8); + if (offset < ADM1266_GPIO_NR) + return test_bit(adm1266_gpio_mapping[offset][1], &pins_status); + + return test_bit(offset - ADM1266_GPIO_NR, &pins_status); +} + +static int adm1266_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct adm1266_data *data = gpiochip_get_data(chip); + u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1]; + unsigned long status; + unsigned int gpio_nr; + int ret; + + ret = i2c_smbus_read_block_data(data->client, ADM1266_GPIO_STATUS, read_buf); + if (ret < 0) + return ret; + + status = read_buf[0] + (read_buf[1] << 8); + + *bits = 0; + for_each_set_bit(gpio_nr, mask, ADM1266_GPIO_NR) { + if (test_bit(adm1266_gpio_mapping[gpio_nr][1], &status)) + set_bit(gpio_nr, bits); + } + + ret = i2c_smbus_read_block_data(data->client, ADM1266_PDIO_STATUS, read_buf); + if (ret < 0) + return ret; + + status = read_buf[0] + (read_buf[1] << 8); + + *bits = 0; + for_each_set_bit_from(gpio_nr, mask, ADM1266_GPIO_NR + ADM1266_PDIO_STATUS) { + if (test_bit(gpio_nr - ADM1266_GPIO_NR, &status)) + set_bit(gpio_nr, bits); + } + + return 0; +} + +static void adm1266_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + struct adm1266_data *data = gpiochip_get_data(chip); + u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1]; + unsigned long gpio_config; + unsigned long pdio_config; + unsigned long pin_cfg; + u8 write_cmd; + int ret; + int i; + + for (i = 0; i < ADM1266_GPIO_NR; i++) { + write_cmd = adm1266_gpio_mapping[i][1]; + ret = adm1266_pmbus_block_xfer(data, ADM1266_GPIO_CONFIG, 1, &write_cmd, read_buf); + if (ret != 2) + return; + + gpio_config = read_buf[0]; + seq_puts(s, adm1266_names[i]); + + seq_puts(s, " ( "); + if (!ADM1266_GPIO_FUNCTIONS(gpio_config)) { + seq_puts(s, "high-Z )\n"); + continue; + } + if (ADM1266_GPIO_INPUT_EN(gpio_config)) + seq_puts(s, "input "); + if (ADM1266_GPIO_OUTPUT_EN(gpio_config)) + seq_puts(s, "output "); + if (ADM1266_GPIO_OPEN_DRAIN(gpio_config)) + seq_puts(s, "open-drain )\n"); + else + seq_puts(s, "push-pull )\n"); + } + + write_cmd = 0xFF; + ret = adm1266_pmbus_block_xfer(data, ADM1266_PDIO_CONFIG, 1, &write_cmd, read_buf); + if (ret != 32) + return; + + for (i = 0; i < ADM1266_PDIO_NR; i++) { + seq_puts(s, adm1266_names[ADM1266_GPIO_NR + i]); + + pdio_config = read_buf[2 * i]; + pdio_config += (read_buf[2 * i + 1] << 8); + pin_cfg = ADM1266_PDIO_PIN_CFG(pdio_config); + + seq_puts(s, " ( "); + if (!pin_cfg || pin_cfg > 5) { + seq_puts(s, "high-Z )\n"); + continue; + } + + if (pin_cfg & BIT(0)) + seq_puts(s, "output "); + + if (pin_cfg & BIT(1)) + seq_puts(s, "input "); + + seq_puts(s, ")\n"); + } +} + +static int adm1266_config_gpio(struct adm1266_data *data) +{ + const char *name = dev_name(&data->client->dev); + char *gpio_name; + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(data->gpio_names); i++) { + gpio_name = devm_kasprintf(&data->client->dev, GFP_KERNEL, "adm1266-%x-%s", + data->client->addr, adm1266_names[i]); + if (!gpio_name) + return -ENOMEM; + + data->gpio_names[i] = gpio_name; + } + + data->gc.label = name; + data->gc.parent = &data->client->dev; + data->gc.owner = THIS_MODULE; + data->gc.base = -1; + data->gc.names = data->gpio_names; + data->gc.ngpio = ARRAY_SIZE(data->gpio_names); + data->gc.get = adm1266_gpio_get; + data->gc.get_multiple = adm1266_gpio_get_multiple; + data->gc.dbg_show = adm1266_gpio_dbg_show; + + ret = devm_gpiochip_add_data(&data->client->dev, &data->gc, data); + if (ret) + dev_err(&data->client->dev, "GPIO registering failed (%d)\n", ret); + + return ret; +} + +static int adm1266_state_read(struct seq_file *s, void *pdata) +{ + struct device *dev = s->private; + struct i2c_client *client = to_i2c_client(dev); + int ret; + + ret = i2c_smbus_read_word_data(client, ADM1266_READ_STATE); + if (ret < 0) + return ret; + + seq_printf(s, "%d\n", ret); + + return 0; +} + +static void adm1266_init_debugfs(struct adm1266_data *data) +{ + struct dentry *root; + + root = pmbus_get_debugfs_dir(data->client); + if (!root) + return; + + data->debugfs_dir = debugfs_create_dir(data->client->name, root); + if (!data->debugfs_dir) + return; + + debugfs_create_devm_seqfile(&data->client->dev, "sequencer_state", data->debugfs_dir, + adm1266_state_read); +} + +static int adm1266_nvmem_read_blackbox(struct adm1266_data *data, u8 *read_buff) +{ + int record_count; + char index; + u8 buf[5]; + int ret; + + ret = i2c_smbus_read_block_data(data->client, ADM1266_BLACKBOX_INFO, buf); + if (ret < 0) + return ret; + + if (ret != 4) + return -EIO; + + record_count = buf[3]; + + for (index = 0; index < record_count; index++) { + ret = adm1266_pmbus_block_xfer(data, ADM1266_READ_BLACKBOX, 1, &index, read_buff); + if (ret < 0) + return ret; + + if (ret != ADM1266_BLACKBOX_SIZE) + return -EIO; + + read_buff += ADM1266_BLACKBOX_SIZE; + } + + return 0; +} + +static int adm1266_nvmem_read(void *priv, unsigned int offset, void *val, size_t bytes) +{ + struct adm1266_data *data = priv; + int ret; + + if (offset + bytes > data->nvmem_config.size) + return -EINVAL; + + if (offset == 0) { + memset(data->dev_mem, 0, data->nvmem_config.size); + + ret = adm1266_nvmem_read_blackbox(data, data->dev_mem); + if (ret) { + dev_err(&data->client->dev, "Could not read blackbox!"); + return ret; + } + } + + memcpy(val, data->dev_mem + offset, bytes); + + return 0; +} + +static int adm1266_config_nvmem(struct adm1266_data *data) +{ + data->nvmem_config.name = dev_name(&data->client->dev); + data->nvmem_config.dev = &data->client->dev; + data->nvmem_config.root_only = true; + data->nvmem_config.read_only = true; + data->nvmem_config.owner = THIS_MODULE; + data->nvmem_config.reg_read = adm1266_nvmem_read; + data->nvmem_config.cells = adm1266_nvmem_cells; + data->nvmem_config.ncells = ARRAY_SIZE(adm1266_nvmem_cells); + data->nvmem_config.priv = data; + data->nvmem_config.stride = 1; + data->nvmem_config.word_size = 1; + data->nvmem_config.size = adm1266_nvmem_cells[0].bytes; + + data->dev_mem = devm_kzalloc(&data->client->dev, data->nvmem_config.size, GFP_KERNEL); + if (!data->dev_mem) + return -ENOMEM; + + data->nvmem = devm_nvmem_register(&data->client->dev, &data->nvmem_config); + if (IS_ERR(data->nvmem)) { + dev_err(&data->client->dev, "Could not register nvmem!"); + return PTR_ERR(data->nvmem); + } + + return 0; +} + +static int adm1266_set_rtc(struct adm1266_data *data) +{ + time64_t kt; + char write_buf[6]; + int i; + + kt = ktime_get_seconds(); + + memset(write_buf, 0, sizeof(write_buf)); + + for (i = 0; i < 4; i++) + write_buf[2 + i] = (kt >> (i * 8)) & 0xFF; + + return i2c_smbus_write_block_data(data->client, ADM1266_SET_RTC, sizeof(write_buf), + write_buf); +} + +static int adm1266_probe(struct i2c_client *client) +{ + struct adm1266_data *data; + int ret; + int i; + + data = devm_kzalloc(&client->dev, sizeof(struct adm1266_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + data->info.pages = 17; + data->info.format[PSC_VOLTAGE_OUT] = linear; + for (i = 0; i < data->info.pages; i++) + data->info.func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; + + crc8_populate_msb(pmbus_crc_table, 0x7); + mutex_init(&data->buf_mutex); + + ret = adm1266_config_gpio(data); + if (ret < 0) + return ret; + + ret = adm1266_set_rtc(data); + if (ret < 0) + return ret; + + ret = adm1266_config_nvmem(data); + if (ret < 0) + return ret; + + ret = pmbus_do_probe(client, &data->info); + if (ret) + return ret; + + adm1266_init_debugfs(data); + + return 0; +} + +static const struct of_device_id adm1266_of_match[] = { + { .compatible = "adi,adm1266" }, + { } +}; +MODULE_DEVICE_TABLE(of, adm1266_of_match); + +static const struct i2c_device_id adm1266_id[] = { + { "adm1266", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adm1266_id); + +static struct i2c_driver adm1266_driver = { + .driver = { + .name = "adm1266", + .of_match_table = adm1266_of_match, + }, + .probe_new = adm1266_probe, + .remove = pmbus_do_remove, + .id_table = adm1266_id, +}; + +module_i2c_driver(adm1266_driver); + +MODULE_AUTHOR("Alexandru Tachici <alexandru.tachici@analog.com>"); +MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1266"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 651846650a9c..e7997f37b266 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -462,8 +462,7 @@ static const struct i2c_device_id adm1275_id[] = { }; MODULE_DEVICE_TABLE(i2c, adm1275_id); -static int adm1275_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adm1275_probe(struct i2c_client *client) { s32 (*config_read_fn)(const struct i2c_client *client, u8 reg); u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; @@ -506,10 +505,10 @@ static int adm1275_probe(struct i2c_client *client, return -ENODEV; } - if (id->driver_data != mid->driver_data) + if (strcmp(client->name, mid->name) != 0) dev_notice(&client->dev, "Device mismatch: Configured %s, detected %s\n", - id->name, mid->name); + client->name, mid->name); if (mid->driver_data == adm1272 || mid->driver_data == adm1278 || mid->driver_data == adm1293 || mid->driver_data == adm1294) @@ -790,14 +789,14 @@ static int adm1275_probe(struct i2c_client *client, info->R[PSC_TEMPERATURE] = coefficients[tindex].R; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static struct i2c_driver adm1275_driver = { .driver = { .name = "adm1275", }, - .probe = adm1275_probe, + .probe_new = adm1275_probe, .remove = pmbus_do_remove, .id_table = adm1275_id, }; diff --git a/drivers/hwmon/pmbus/bel-pfe.c b/drivers/hwmon/pmbus/bel-pfe.c index f236e18f45a5..2c5b853d6c7f 100644 --- a/drivers/hwmon/pmbus/bel-pfe.c +++ b/drivers/hwmon/pmbus/bel-pfe.c @@ -87,12 +87,13 @@ static struct pmbus_driver_info pfe_driver_info[] = { }, }; -static int pfe_pmbus_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static const struct i2c_device_id pfe_device_id[]; + +static int pfe_pmbus_probe(struct i2c_client *client) { int model; - model = (int)id->driver_data; + model = (int)i2c_match_id(pfe_device_id, client)->driver_data; /* * PFE3000-12-069RA devices may not stay in page 0 during device @@ -104,7 +105,7 @@ static int pfe_pmbus_probe(struct i2c_client *client, i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); } - return pmbus_do_probe(client, id, &pfe_driver_info[model]); + return pmbus_do_probe(client, &pfe_driver_info[model]); } static const struct i2c_device_id pfe_device_id[] = { @@ -119,7 +120,7 @@ static struct i2c_driver pfe_pmbus_driver = { .driver = { .name = "bel-pfe", }, - .probe = pfe_pmbus_probe, + .probe_new = pfe_pmbus_probe, .remove = pmbus_do_remove, .id_table = pfe_device_id, }; diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index 7d300f2f338d..2fb7540ee952 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -91,6 +91,8 @@ struct ibm_cffps { struct led_classdev led; }; +static const struct i2c_device_id ibm_cffps_id[]; + #define to_psu(x, y) container_of((x), struct ibm_cffps, debugfs_entries[(y)]) static ssize_t ibm_cffps_read_input_history(struct ibm_cffps *psu, @@ -473,8 +475,7 @@ static struct pmbus_platform_data ibm_cffps_pdata = { .flags = PMBUS_SKIP_STATUS_CHECK, }; -static int ibm_cffps_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ibm_cffps_probe(struct i2c_client *client) { int i, rc; enum versions vs = cffps_unknown; @@ -482,11 +483,15 @@ static int ibm_cffps_probe(struct i2c_client *client, struct dentry *ibm_cffps_dir; struct ibm_cffps *psu; const void *md = of_device_get_match_data(&client->dev); + const struct i2c_device_id *id; - if (md) + if (md) { vs = (enum versions)md; - else if (id) - vs = (enum versions)id->driver_data; + } else { + id = i2c_match_id(ibm_cffps_id, client); + if (id) + vs = (enum versions)id->driver_data; + } if (vs == cffps_unknown) { u16 ccin_revision = 0; @@ -519,7 +524,7 @@ static int ibm_cffps_probe(struct i2c_client *client, } client->dev.platform_data = &ibm_cffps_pdata; - rc = pmbus_do_probe(client, id, &ibm_cffps_info[vs]); + rc = pmbus_do_probe(client, &ibm_cffps_info[vs]); if (rc) return rc; @@ -611,7 +616,7 @@ static struct i2c_driver ibm_cffps_driver = { .name = "ibm-cffps", .of_match_table = ibm_cffps_of_match, }, - .probe = ibm_cffps_probe, + .probe_new = ibm_cffps_probe, .remove = pmbus_do_remove, .id_table = ibm_cffps_id, }; diff --git a/drivers/hwmon/pmbus/inspur-ipsps.c b/drivers/hwmon/pmbus/inspur-ipsps.c index 42e01549184a..be493182174d 100644 --- a/drivers/hwmon/pmbus/inspur-ipsps.c +++ b/drivers/hwmon/pmbus/inspur-ipsps.c @@ -190,11 +190,10 @@ static struct pmbus_platform_data ipsps_pdata = { .flags = PMBUS_SKIP_STATUS_CHECK, }; -static int ipsps_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ipsps_probe(struct i2c_client *client) { client->dev.platform_data = &ipsps_pdata; - return pmbus_do_probe(client, id, &ipsps_info); + return pmbus_do_probe(client, &ipsps_info); } static const struct i2c_device_id ipsps_id[] = { @@ -216,7 +215,7 @@ static struct i2c_driver ipsps_driver = { .name = "inspur-ipsps", .of_match_table = of_match_ptr(ipsps_of_match), }, - .probe = ipsps_probe, + .probe_new = ipsps_probe, .remove = pmbus_do_remove, .id_table = ipsps_id, }; diff --git a/drivers/hwmon/pmbus/ir35221.c b/drivers/hwmon/pmbus/ir35221.c index 3eea3e006a96..5fadb1def49f 100644 --- a/drivers/hwmon/pmbus/ir35221.c +++ b/drivers/hwmon/pmbus/ir35221.c @@ -67,8 +67,7 @@ static int ir35221_read_word_data(struct i2c_client *client, int page, return ret; } -static int ir35221_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ir35221_probe(struct i2c_client *client) { struct pmbus_driver_info *info; u8 buf[I2C_SMBUS_BLOCK_MAX]; @@ -123,7 +122,7 @@ static int ir35221_probe(struct i2c_client *client, | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP; info->func[1] = info->func[0]; - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id ir35221_id[] = { @@ -137,7 +136,7 @@ static struct i2c_driver ir35221_driver = { .driver = { .name = "ir35221", }, - .probe = ir35221_probe, + .probe_new = ir35221_probe, .remove = pmbus_do_remove, .id_table = ir35221_id, }; diff --git a/drivers/hwmon/pmbus/ir38064.c b/drivers/hwmon/pmbus/ir38064.c index 1820f5077f66..9ac563ce7dd8 100644 --- a/drivers/hwmon/pmbus/ir38064.c +++ b/drivers/hwmon/pmbus/ir38064.c @@ -35,10 +35,9 @@ static struct pmbus_driver_info ir38064_info = { | PMBUS_HAVE_POUT, }; -static int ir38064_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ir38064_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &ir38064_info); + return pmbus_do_probe(client, &ir38064_info); } static const struct i2c_device_id ir38064_id[] = { @@ -53,7 +52,7 @@ static struct i2c_driver ir38064_driver = { .driver = { .name = "ir38064", }, - .probe = ir38064_probe, + .probe_new = ir38064_probe, .remove = pmbus_do_remove, .id_table = ir38064_id, }; diff --git a/drivers/hwmon/pmbus/irps5401.c b/drivers/hwmon/pmbus/irps5401.c index d37daa001fb3..44aeafcbd56c 100644 --- a/drivers/hwmon/pmbus/irps5401.c +++ b/drivers/hwmon/pmbus/irps5401.c @@ -38,10 +38,9 @@ static struct pmbus_driver_info irps5401_info = { .func[4] = IRPS5401_LDO_FUNC, }; -static int irps5401_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int irps5401_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &irps5401_info); + return pmbus_do_probe(client, &irps5401_info); } static const struct i2c_device_id irps5401_id[] = { @@ -55,7 +54,7 @@ static struct i2c_driver irps5401_driver = { .driver = { .name = "irps5401", }, - .probe = irps5401_probe, + .probe_new = irps5401_probe, .remove = pmbus_do_remove, .id_table = irps5401_id, }; diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c index 58aa95a3c010..7cad76e07f70 100644 --- a/drivers/hwmon/pmbus/isl68137.c +++ b/drivers/hwmon/pmbus/isl68137.c @@ -72,6 +72,8 @@ enum variants { raa_dmpvr2_hv, }; +static const struct i2c_device_id raa_dmpvr_id[]; + static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, int page, char *buf) @@ -218,8 +220,7 @@ static struct pmbus_driver_info raa_dmpvr_info = { | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, }; -static int isl68137_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int isl68137_probe(struct i2c_client *client) { struct pmbus_driver_info *info; @@ -228,7 +229,7 @@ static int isl68137_probe(struct i2c_client *client, return -ENOMEM; memcpy(info, &raa_dmpvr_info, sizeof(*info)); - switch (id->driver_data) { + switch (i2c_match_id(raa_dmpvr_id, client)->driver_data) { case raa_dmpvr1_2rail: info->pages = 2; info->R[PSC_VOLTAGE_IN] = 3; @@ -267,7 +268,7 @@ static int isl68137_probe(struct i2c_client *client, return -ENODEV; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id raa_dmpvr_id[] = { @@ -322,7 +323,7 @@ static struct i2c_driver isl68137_driver = { .driver = { .name = "isl68137", }, - .probe = isl68137_probe, + .probe_new = isl68137_probe, .remove = pmbus_do_remove, .id_table = raa_dmpvr_id, }; diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index 9e4cf0800186..429172a42902 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -211,6 +211,8 @@ struct lm25066_data { #define to_lm25066_data(x) container_of(x, struct lm25066_data, info) +static const struct i2c_device_id lm25066_id[]; + static int lm25066_read_word_data(struct i2c_client *client, int page, int phase, int reg) { @@ -416,8 +418,7 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg, return ret; } -static int lm25066_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm25066_probe(struct i2c_client *client) { int config; struct lm25066_data *data; @@ -437,7 +438,7 @@ static int lm25066_probe(struct i2c_client *client, if (config < 0) return config; - data->id = id->driver_data; + data->id = i2c_match_id(lm25066_id, client)->driver_data; info = &data->info; info->pages = 1; @@ -487,7 +488,7 @@ static int lm25066_probe(struct i2c_client *client, info->b[PSC_POWER] = coeff[PSC_POWER].b; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id lm25066_id[] = { @@ -506,7 +507,7 @@ static struct i2c_driver lm25066_driver = { .driver = { .name = "lm25066", }, - .probe = lm25066_probe, + .probe_new = lm25066_probe, .remove = pmbus_do_remove, .id_table = lm25066_id, }; diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 7b0e6b37e247..9a024cf70145 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -649,12 +649,12 @@ static int ltc2978_get_id(struct i2c_client *client) return -ENODEV; } -static int ltc2978_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc2978_probe(struct i2c_client *client) { int i, chip_id; struct ltc2978_data *data; struct pmbus_driver_info *info; + const struct i2c_device_id *id; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) @@ -670,11 +670,13 @@ static int ltc2978_probe(struct i2c_client *client, return chip_id; data->id = chip_id; + id = i2c_match_id(ltc2978_id, client); if (data->id != id->driver_data) dev_warn(&client->dev, - "Device mismatch: Configured %s, detected %s\n", + "Device mismatch: Configured %s (%d), detected %d\n", id->name, - ltc2978_id[data->id].name); + (int) id->driver_data, + chip_id); info = &data->info; info->write_word_data = ltc2978_write_word_data; @@ -832,7 +834,7 @@ static int ltc2978_probe(struct i2c_client *client, } #endif - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } @@ -872,7 +874,7 @@ static struct i2c_driver ltc2978_driver = { .name = "ltc2978", .of_match_table = of_match_ptr(ltc2978_of_match), }, - .probe = ltc2978_probe, + .probe_new = ltc2978_probe, .remove = pmbus_do_remove, .id_table = ltc2978_id, }; diff --git a/drivers/hwmon/pmbus/ltc3815.c b/drivers/hwmon/pmbus/ltc3815.c index 3036263e0a66..8328fb367ad6 100644 --- a/drivers/hwmon/pmbus/ltc3815.c +++ b/drivers/hwmon/pmbus/ltc3815.c @@ -178,8 +178,7 @@ static struct pmbus_driver_info ltc3815_info = { .write_word_data = ltc3815_write_word_data, }; -static int ltc3815_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ltc3815_probe(struct i2c_client *client) { int chip_id; @@ -193,14 +192,14 @@ static int ltc3815_probe(struct i2c_client *client, if ((chip_id & LTC3815_ID_MASK) != LTC3815_ID) return -ENODEV; - return pmbus_do_probe(client, id, <c3815_info); + return pmbus_do_probe(client, <c3815_info); } static struct i2c_driver ltc3815_driver = { .driver = { .name = "ltc3815", }, - .probe = ltc3815_probe, + .probe_new = ltc3815_probe, .remove = pmbus_do_remove, .id_table = ltc3815_id, }; diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c index 288e93f74c28..26e7f5ef9d7f 100644 --- a/drivers/hwmon/pmbus/max16064.c +++ b/drivers/hwmon/pmbus/max16064.c @@ -85,10 +85,9 @@ static struct pmbus_driver_info max16064_info = { .write_word_data = max16064_write_word_data, }; -static int max16064_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max16064_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &max16064_info); + return pmbus_do_probe(client, &max16064_info); } static const struct i2c_device_id max16064_id[] = { @@ -103,7 +102,7 @@ static struct i2c_driver max16064_driver = { .driver = { .name = "max16064", }, - .probe = max16064_probe, + .probe_new = max16064_probe, .remove = pmbus_do_remove, .id_table = max16064_id, }; diff --git a/drivers/hwmon/pmbus/max16601.c b/drivers/hwmon/pmbus/max16601.c index 51cdfaf9023c..71bb74e27a5c 100644 --- a/drivers/hwmon/pmbus/max16601.c +++ b/drivers/hwmon/pmbus/max16601.c @@ -239,8 +239,7 @@ static void max16601_remove(void *_data) i2c_unregister_device(data->vsa); } -static int max16601_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max16601_probe(struct i2c_client *client) { struct device *dev = &client->dev; u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; @@ -288,7 +287,7 @@ static int max16601_probe(struct i2c_client *client, data->info = max16601_info; - return pmbus_do_probe(client, id, &data->info); + return pmbus_do_probe(client, &data->info); } static const struct i2c_device_id max16601_id[] = { @@ -302,7 +301,7 @@ static struct i2c_driver max16601_driver = { .driver = { .name = "max16601", }, - .probe = max16601_probe, + .probe_new = max16601_probe, .remove = pmbus_do_remove, .id_table = max16601_id, }; diff --git a/drivers/hwmon/pmbus/max20730.c b/drivers/hwmon/pmbus/max20730.c index a151a2b588a5..57923d72490c 100644 --- a/drivers/hwmon/pmbus/max20730.c +++ b/drivers/hwmon/pmbus/max20730.c @@ -8,6 +8,7 @@ */ #include <linux/bits.h> +#include <linux/debugfs.h> #include <linux/err.h> #include <linux/i2c.h> #include <linux/init.h> @@ -26,16 +27,370 @@ enum chips { max20743 }; +enum { + MAX20730_DEBUGFS_VOUT_MIN = 0, + MAX20730_DEBUGFS_FREQUENCY, + MAX20730_DEBUGFS_PG_DELAY, + MAX20730_DEBUGFS_INTERNAL_GAIN, + MAX20730_DEBUGFS_BOOT_VOLTAGE, + MAX20730_DEBUGFS_OUT_V_RAMP_RATE, + MAX20730_DEBUGFS_OC_PROTECT_MODE, + MAX20730_DEBUGFS_SS_TIMING, + MAX20730_DEBUGFS_IMAX, + MAX20730_DEBUGFS_OPERATION, + MAX20730_DEBUGFS_ON_OFF_CONFIG, + MAX20730_DEBUGFS_SMBALERT_MASK, + MAX20730_DEBUGFS_VOUT_MODE, + MAX20730_DEBUGFS_VOUT_COMMAND, + MAX20730_DEBUGFS_VOUT_MAX, + MAX20730_DEBUGFS_NUM_ENTRIES +}; + struct max20730_data { enum chips id; struct pmbus_driver_info info; struct mutex lock; /* Used to protect against parallel writes */ u16 mfr_devset1; + u16 mfr_devset2; + u16 mfr_voutmin; + u32 vout_voltage_divider[2]; }; #define to_max20730_data(x) container_of(x, struct max20730_data, info) +#define VOLT_FROM_REG(val) DIV_ROUND_CLOSEST((val), 1 << 9) + +#define PMBUS_SMB_ALERT_MASK 0x1B + +#define MAX20730_MFR_VOUT_MIN 0xd1 #define MAX20730_MFR_DEVSET1 0xd2 +#define MAX20730_MFR_DEVSET2 0xd3 + +#define MAX20730_MFR_VOUT_MIN_MASK GENMASK(9, 0) +#define MAX20730_MFR_VOUT_MIN_BIT_POS 0 + +#define MAX20730_MFR_DEVSET1_RGAIN_MASK (BIT(13) | BIT(14)) +#define MAX20730_MFR_DEVSET1_OTP_MASK (BIT(11) | BIT(12)) +#define MAX20730_MFR_DEVSET1_VBOOT_MASK (BIT(8) | BIT(9)) +#define MAX20730_MFR_DEVSET1_OCP_MASK (BIT(5) | BIT(6)) +#define MAX20730_MFR_DEVSET1_FSW_MASK GENMASK(4, 2) +#define MAX20730_MFR_DEVSET1_TSTAT_MASK (BIT(0) | BIT(1)) + +#define MAX20730_MFR_DEVSET1_RGAIN_BIT_POS 13 +#define MAX20730_MFR_DEVSET1_OTP_BIT_POS 11 +#define MAX20730_MFR_DEVSET1_VBOOT_BIT_POS 8 +#define MAX20730_MFR_DEVSET1_OCP_BIT_POS 5 +#define MAX20730_MFR_DEVSET1_FSW_BIT_POS 2 +#define MAX20730_MFR_DEVSET1_TSTAT_BIT_POS 0 + +#define MAX20730_MFR_DEVSET2_IMAX_MASK GENMASK(10, 8) +#define MAX20730_MFR_DEVSET2_VRATE (BIT(6) | BIT(7)) +#define MAX20730_MFR_DEVSET2_OCPM_MASK BIT(5) +#define MAX20730_MFR_DEVSET2_SS_MASK (BIT(0) | BIT(1)) + +#define MAX20730_MFR_DEVSET2_IMAX_BIT_POS 8 +#define MAX20730_MFR_DEVSET2_VRATE_BIT_POS 6 +#define MAX20730_MFR_DEVSET2_OCPM_BIT_POS 5 +#define MAX20730_MFR_DEVSET2_SS_BIT_POS 0 + +#define DEBUG_FS_DATA_MAX 16 + +struct max20730_debugfs_data { + struct i2c_client *client; + int debugfs_entries[MAX20730_DEBUGFS_NUM_ENTRIES]; +}; + +#define to_psu(x, y) container_of((x), \ + struct max20730_debugfs_data, debugfs_entries[(y)]) + +#ifdef CONFIG_DEBUG_FS +static ssize_t max20730_debugfs_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int ret, len; + int *idxp = file->private_data; + int idx = *idxp; + struct max20730_debugfs_data *psu = to_psu(idxp, idx); + const struct pmbus_driver_info *info; + const struct max20730_data *data; + char tbuf[DEBUG_FS_DATA_MAX] = { 0 }; + u16 val; + + info = pmbus_get_driver_info(psu->client); + data = to_max20730_data(info); + + switch (idx) { + case MAX20730_DEBUGFS_VOUT_MIN: + ret = VOLT_FROM_REG(data->mfr_voutmin * 10000); + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d.%d\n", + ret / 10000, ret % 10000); + break; + case MAX20730_DEBUGFS_FREQUENCY: + val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_FSW_MASK) + >> MAX20730_MFR_DEVSET1_FSW_BIT_POS; + + if (val == 0) + ret = 400; + else if (val == 1) + ret = 500; + else if (val == 2 || val == 3) + ret = 600; + else if (val == 4) + ret = 700; + else if (val == 5) + ret = 800; + else + ret = 900; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_PG_DELAY: + val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_TSTAT_MASK) + >> MAX20730_MFR_DEVSET1_TSTAT_BIT_POS; + + if (val == 0) + len = strlcpy(tbuf, "2000\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "125\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "62.5\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "32\n", DEBUG_FS_DATA_MAX); + break; + case MAX20730_DEBUGFS_INTERNAL_GAIN: + val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_RGAIN_MASK) + >> MAX20730_MFR_DEVSET1_RGAIN_BIT_POS; + + if (data->id == max20734) { + /* AN6209 */ + if (val == 0) + len = strlcpy(tbuf, "0.8\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "3.2\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "1.6\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "6.4\n", DEBUG_FS_DATA_MAX); + } else if (data->id == max20730 || data->id == max20710) { + /* AN6042 or AN6140 */ + if (val == 0) + len = strlcpy(tbuf, "0.9\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "3.6\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "1.8\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "7.2\n", DEBUG_FS_DATA_MAX); + } else if (data->id == max20743) { + /* AN6042 */ + if (val == 0) + len = strlcpy(tbuf, "0.45\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "1.8\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "0.9\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "3.6\n", DEBUG_FS_DATA_MAX); + } else { + len = strlcpy(tbuf, "Not supported\n", DEBUG_FS_DATA_MAX); + } + break; + case MAX20730_DEBUGFS_BOOT_VOLTAGE: + val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_VBOOT_MASK) + >> MAX20730_MFR_DEVSET1_VBOOT_BIT_POS; + + if (val == 0) + len = strlcpy(tbuf, "0.6484\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "0.8984\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "1.0\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX); + break; + case MAX20730_DEBUGFS_OUT_V_RAMP_RATE: + val = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_VRATE) + >> MAX20730_MFR_DEVSET2_VRATE_BIT_POS; + + if (val == 0) + len = strlcpy(tbuf, "4\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "2\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "1\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX); + break; + case MAX20730_DEBUGFS_OC_PROTECT_MODE: + ret = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_OCPM_MASK) + >> MAX20730_MFR_DEVSET2_OCPM_BIT_POS; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_SS_TIMING: + val = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_SS_MASK) + >> MAX20730_MFR_DEVSET2_SS_BIT_POS; + + if (val == 0) + len = strlcpy(tbuf, "0.75\n", DEBUG_FS_DATA_MAX); + else if (val == 1) + len = strlcpy(tbuf, "1.5\n", DEBUG_FS_DATA_MAX); + else if (val == 2) + len = strlcpy(tbuf, "3\n", DEBUG_FS_DATA_MAX); + else + len = strlcpy(tbuf, "6\n", DEBUG_FS_DATA_MAX); + break; + case MAX20730_DEBUGFS_IMAX: + ret = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_IMAX_MASK) + >> MAX20730_MFR_DEVSET2_IMAX_BIT_POS; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_OPERATION: + ret = i2c_smbus_read_byte_data(psu->client, PMBUS_OPERATION); + if (ret < 0) + return ret; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_ON_OFF_CONFIG: + ret = i2c_smbus_read_byte_data(psu->client, PMBUS_ON_OFF_CONFIG); + if (ret < 0) + return ret; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_SMBALERT_MASK: + ret = i2c_smbus_read_word_data(psu->client, + PMBUS_SMB_ALERT_MASK); + if (ret < 0) + return ret; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_VOUT_MODE: + ret = i2c_smbus_read_byte_data(psu->client, PMBUS_VOUT_MODE); + if (ret < 0) + return ret; + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, "%d\n", ret); + break; + case MAX20730_DEBUGFS_VOUT_COMMAND: + ret = i2c_smbus_read_word_data(psu->client, PMBUS_VOUT_COMMAND); + if (ret < 0) + return ret; + + ret = VOLT_FROM_REG(ret * 10000); + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, + "%d.%d\n", ret / 10000, ret % 10000); + break; + case MAX20730_DEBUGFS_VOUT_MAX: + ret = i2c_smbus_read_word_data(psu->client, PMBUS_VOUT_MAX); + if (ret < 0) + return ret; + + ret = VOLT_FROM_REG(ret * 10000); + len = snprintf(tbuf, DEBUG_FS_DATA_MAX, + "%d.%d\n", ret / 10000, ret % 10000); + break; + default: + len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX); + } + + return simple_read_from_buffer(buf, count, ppos, tbuf, len); +} + +static const struct file_operations max20730_fops = { + .llseek = noop_llseek, + .read = max20730_debugfs_read, + .write = NULL, + .open = simple_open, +}; + +static int max20730_init_debugfs(struct i2c_client *client, + struct max20730_data *data) +{ + int ret, i; + struct dentry *debugfs; + struct dentry *max20730_dir; + struct max20730_debugfs_data *psu; + + ret = i2c_smbus_read_word_data(client, MAX20730_MFR_DEVSET2); + if (ret < 0) + return ret; + data->mfr_devset2 = ret; + + ret = i2c_smbus_read_word_data(client, MAX20730_MFR_VOUT_MIN); + if (ret < 0) + return ret; + data->mfr_voutmin = ret; + + psu = devm_kzalloc(&client->dev, sizeof(*psu), GFP_KERNEL); + if (!psu) + return -ENOMEM; + psu->client = client; + + debugfs = pmbus_get_debugfs_dir(client); + if (!debugfs) + return -ENOENT; + + max20730_dir = debugfs_create_dir(client->name, debugfs); + if (!max20730_dir) + return -ENOENT; + + for (i = 0; i < MAX20730_DEBUGFS_NUM_ENTRIES; ++i) + psu->debugfs_entries[i] = i; + + debugfs_create_file("vout_min", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_VOUT_MIN], + &max20730_fops); + debugfs_create_file("frequency", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_FREQUENCY], + &max20730_fops); + debugfs_create_file("power_good_delay", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_PG_DELAY], + &max20730_fops); + debugfs_create_file("internal_gain", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_INTERNAL_GAIN], + &max20730_fops); + debugfs_create_file("boot_voltage", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_BOOT_VOLTAGE], + &max20730_fops); + debugfs_create_file("out_voltage_ramp_rate", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_OUT_V_RAMP_RATE], + &max20730_fops); + debugfs_create_file("oc_protection_mode", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_OC_PROTECT_MODE], + &max20730_fops); + debugfs_create_file("soft_start_timing", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_SS_TIMING], + &max20730_fops); + debugfs_create_file("imax", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_IMAX], + &max20730_fops); + debugfs_create_file("operation", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_OPERATION], + &max20730_fops); + debugfs_create_file("on_off_config", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_ON_OFF_CONFIG], + &max20730_fops); + debugfs_create_file("smbalert_mask", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_SMBALERT_MASK], + &max20730_fops); + debugfs_create_file("vout_mode", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_VOUT_MODE], + &max20730_fops); + debugfs_create_file("vout_command", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_VOUT_COMMAND], + &max20730_fops); + debugfs_create_file("vout_max", 0444, max20730_dir, + &psu->debugfs_entries[MAX20730_DEBUGFS_VOUT_MAX], + &max20730_fops); + + return 0; +} +#else +static int max20730_init_debugfs(struct i2c_client *client, + struct max20730_data *data) +{ + return 0; +} +#endif /* CONFIG_DEBUG_FS */ + +static const struct i2c_device_id max20730_id[]; /* * Convert discreet value to direct data format. Strictly speaking, all passed @@ -114,6 +469,14 @@ static int max20730_read_word_data(struct i2c_client *client, int page, max_c = max_current[data->id][(data->mfr_devset1 >> 5) & 0x3]; ret = val_to_direct(max_c, PSC_CURRENT_OUT, info); break; + case PMBUS_READ_VOUT: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret > 0 && data->vout_voltage_divider[0] && data->vout_voltage_divider[1]) { + u64 temp = DIV_ROUND_CLOSEST_ULL((u64)ret * data->vout_voltage_divider[1], + data->vout_voltage_divider[0]); + ret = clamp_val(temp, 0, 0xffff); + } + break; default: ret = -ENODATA; break; @@ -295,8 +658,7 @@ static const struct pmbus_driver_info max20730_info[] = { }, }; -static int max20730_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max20730_probe(struct i2c_client *client) { struct device *dev = &client->dev; u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; @@ -356,7 +718,7 @@ static int max20730_probe(struct i2c_client *client, if (client->dev.of_node) chip_id = (enum chips)of_device_get_match_data(dev); else - chip_id = id->driver_data; + chip_id = i2c_match_id(max20730_id, client)->driver_data; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -364,13 +726,31 @@ static int max20730_probe(struct i2c_client *client, data->id = chip_id; mutex_init(&data->lock); memcpy(&data->info, &max20730_info[chip_id], sizeof(data->info)); + if (of_property_read_u32_array(client->dev.of_node, "vout-voltage-divider", + data->vout_voltage_divider, + ARRAY_SIZE(data->vout_voltage_divider)) != 0) + memset(data->vout_voltage_divider, 0, sizeof(data->vout_voltage_divider)); + if (data->vout_voltage_divider[1] < data->vout_voltage_divider[0]) { + dev_err(dev, + "The total resistance of voltage divider is less than output resistance\n"); + return -EINVAL; + } ret = i2c_smbus_read_word_data(client, MAX20730_MFR_DEVSET1); if (ret < 0) return ret; data->mfr_devset1 = ret; - return pmbus_do_probe(client, id, &data->info); + ret = pmbus_do_probe(client, &data->info); + if (ret < 0) + return ret; + + ret = max20730_init_debugfs(client, data); + if (ret) + dev_warn(dev, "Failed to register debugfs: %d\n", + ret); + + return 0; } static const struct i2c_device_id max20730_id[] = { @@ -398,7 +778,7 @@ static struct i2c_driver max20730_driver = { .name = "max20730", .of_match_table = max20730_of_match, }, - .probe = max20730_probe, + .probe_new = max20730_probe, .remove = pmbus_do_remove, .id_table = max20730_id, }; diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c index da3c38cb9a5c..921e92d82aec 100644 --- a/drivers/hwmon/pmbus/max20751.c +++ b/drivers/hwmon/pmbus/max20751.c @@ -26,10 +26,9 @@ static struct pmbus_driver_info max20751_info = { PMBUS_HAVE_POUT, }; -static int max20751_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max20751_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &max20751_info); + return pmbus_do_probe(client, &max20751_info); } static const struct i2c_device_id max20751_id[] = { @@ -43,7 +42,7 @@ static struct i2c_driver max20751_driver = { .driver = { .name = "max20751", }, - .probe = max20751_probe, + .probe_new = max20751_probe, .remove = pmbus_do_remove, .id_table = max20751_id, }; diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c index d9aa5c873d21..839b957bc03e 100644 --- a/drivers/hwmon/pmbus/max31785.c +++ b/drivers/hwmon/pmbus/max31785.c @@ -324,8 +324,7 @@ static int max31785_configure_dual_tach(struct i2c_client *client, return 0; } -static int max31785_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max31785_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct pmbus_driver_info *info; @@ -354,7 +353,7 @@ static int max31785_probe(struct i2c_client *client, if (ret == MAX31785A) { dual_tach = true; } else if (ret == MAX31785) { - if (!strcmp("max31785a", id->name)) + if (!strcmp("max31785a", client->name)) dev_warn(dev, "Expected max3175a, found max31785: cannot provide secondary tachometer readings\n"); } else { return -ENODEV; @@ -366,7 +365,7 @@ static int max31785_probe(struct i2c_client *client, return ret; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id max31785_id[] = { @@ -390,7 +389,7 @@ static struct i2c_driver max31785_driver = { .name = "max31785", .of_match_table = max31785_of_match, }, - .probe = max31785_probe, + .probe_new = max31785_probe, .remove = pmbus_do_remove, .id_table = max31785_id, }; diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index 18b4e071067f..f4cb196aaaf3 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -31,6 +31,13 @@ enum chips { max34440, max34441, max34446, max34451, max34460, max34461 }; #define MAX34440_STATUS_OT_FAULT BIT(5) #define MAX34440_STATUS_OT_WARN BIT(6) +/* + * The whole max344* family have IOUT_OC_WARN_LIMIT and IOUT_OC_FAULT_LIMIT + * swapped from the standard pmbus spec addresses. + */ +#define MAX34440_IOUT_OC_WARN_LIMIT 0x46 +#define MAX34440_IOUT_OC_FAULT_LIMIT 0x4A + #define MAX34451_MFR_CHANNEL_CONFIG 0xe4 #define MAX34451_MFR_CHANNEL_CONFIG_SEL_MASK 0x3f @@ -41,6 +48,8 @@ struct max34440_data { #define to_max34440_data(x) container_of(x, struct max34440_data, info) +static const struct i2c_device_id max34440_id[]; + static int max34440_read_word_data(struct i2c_client *client, int page, int phase, int reg) { @@ -49,6 +58,14 @@ static int max34440_read_word_data(struct i2c_client *client, int page, const struct max34440_data *data = to_max34440_data(info); switch (reg) { + case PMBUS_IOUT_OC_FAULT_LIMIT: + ret = pmbus_read_word_data(client, page, phase, + MAX34440_IOUT_OC_FAULT_LIMIT); + break; + case PMBUS_IOUT_OC_WARN_LIMIT: + ret = pmbus_read_word_data(client, page, phase, + MAX34440_IOUT_OC_WARN_LIMIT); + break; case PMBUS_VIRT_READ_VOUT_MIN: ret = pmbus_read_word_data(client, page, phase, MAX34440_MFR_VOUT_MIN); @@ -115,6 +132,14 @@ static int max34440_write_word_data(struct i2c_client *client, int page, int ret; switch (reg) { + case PMBUS_IOUT_OC_FAULT_LIMIT: + ret = pmbus_write_word_data(client, page, MAX34440_IOUT_OC_FAULT_LIMIT, + word); + break; + case PMBUS_IOUT_OC_WARN_LIMIT: + ret = pmbus_write_word_data(client, page, MAX34440_IOUT_OC_WARN_LIMIT, + word); + break; case PMBUS_VIRT_RESET_POUT_HISTORY: ret = pmbus_write_word_data(client, page, MAX34446_MFR_POUT_PEAK, 0); @@ -388,7 +413,6 @@ static struct pmbus_driver_info max34440_info[] = { .func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, - .read_byte_data = max34440_read_byte_data, .read_word_data = max34440_read_word_data, .write_word_data = max34440_write_word_data, }, @@ -419,7 +443,6 @@ static struct pmbus_driver_info max34440_info[] = { .func[15] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, - .read_byte_data = max34440_read_byte_data, .read_word_data = max34440_read_word_data, .write_word_data = max34440_write_word_data, }, @@ -455,14 +478,12 @@ static struct pmbus_driver_info max34440_info[] = { .func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, .func[21] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, - .read_byte_data = max34440_read_byte_data, .read_word_data = max34440_read_word_data, .write_word_data = max34440_write_word_data, }, }; -static int max34440_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max34440_probe(struct i2c_client *client) { struct max34440_data *data; int rv; @@ -471,8 +492,8 @@ static int max34440_probe(struct i2c_client *client, GFP_KERNEL); if (!data) return -ENOMEM; - data->id = id->driver_data; - data->info = max34440_info[id->driver_data]; + data->id = i2c_match_id(max34440_id, client)->driver_data; + data->info = max34440_info[data->id]; if (data->id == max34451) { rv = max34451_set_supported_funcs(client, data); @@ -480,7 +501,7 @@ static int max34440_probe(struct i2c_client *client, return rv; } - return pmbus_do_probe(client, id, &data->info); + return pmbus_do_probe(client, &data->info); } static const struct i2c_device_id max34440_id[] = { @@ -499,7 +520,7 @@ static struct i2c_driver max34440_driver = { .driver = { .name = "max34440", }, - .probe = max34440_probe, + .probe_new = max34440_probe, .remove = pmbus_do_remove, .id_table = max34440_id, }; diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index 643ccfc05106..4b2239a6afd3 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -165,10 +165,9 @@ static struct pmbus_driver_info max8688_info = { .write_word_data = max8688_write_word_data, }; -static int max8688_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max8688_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &max8688_info); + return pmbus_do_probe(client, &max8688_info); } static const struct i2c_device_id max8688_id[] = { @@ -183,7 +182,7 @@ static struct i2c_driver max8688_driver = { .driver = { .name = "max8688", }, - .probe = max8688_probe, + .probe_new = max8688_probe, .remove = pmbus_do_remove, .id_table = max8688_id, }; diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c new file mode 100644 index 000000000000..1c3e2a9453b1 --- /dev/null +++ b/drivers/hwmon/pmbus/mp2975.c @@ -0,0 +1,769 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers + * + * Copyright (C) 2020 Nvidia Technologies Ltd. + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include "pmbus.h" + +/* Vendor specific registers. */ +#define MP2975_MFR_APS_HYS_R2 0x0d +#define MP2975_MFR_SLOPE_TRIM3 0x1d +#define MP2975_MFR_VR_MULTI_CONFIG_R1 0x0d +#define MP2975_MFR_VR_MULTI_CONFIG_R2 0x1d +#define MP2975_MFR_APS_DECAY_ADV 0x56 +#define MP2975_MFR_DC_LOOP_CTRL 0x59 +#define MP2975_MFR_OCP_UCP_PHASE_SET 0x65 +#define MP2975_MFR_VR_CONFIG1 0x68 +#define MP2975_MFR_READ_CS1_2 0x82 +#define MP2975_MFR_READ_CS3_4 0x83 +#define MP2975_MFR_READ_CS5_6 0x84 +#define MP2975_MFR_READ_CS7_8 0x85 +#define MP2975_MFR_READ_CS9_10 0x86 +#define MP2975_MFR_READ_CS11_12 0x87 +#define MP2975_MFR_READ_IOUT_PK 0x90 +#define MP2975_MFR_READ_POUT_PK 0x91 +#define MP2975_MFR_READ_VREF_R1 0xa1 +#define MP2975_MFR_READ_VREF_R2 0xa3 +#define MP2975_MFR_OVP_TH_SET 0xe5 +#define MP2975_MFR_UVP_SET 0xe6 + +#define MP2975_VOUT_FORMAT BIT(15) +#define MP2975_VID_STEP_SEL_R1 BIT(4) +#define MP2975_IMVP9_EN_R1 BIT(13) +#define MP2975_VID_STEP_SEL_R2 BIT(3) +#define MP2975_IMVP9_EN_R2 BIT(12) +#define MP2975_PRT_THRES_DIV_OV_EN BIT(14) +#define MP2975_DRMOS_KCS GENMASK(13, 12) +#define MP2975_PROT_DEV_OV_OFF 10 +#define MP2975_PROT_DEV_OV_ON 5 +#define MP2975_SENSE_AMPL BIT(11) +#define MP2975_SENSE_AMPL_UNIT 1 +#define MP2975_SENSE_AMPL_HALF 2 +#define MP2975_VIN_UV_LIMIT_UNIT 8 + +#define MP2975_MAX_PHASE_RAIL1 8 +#define MP2975_MAX_PHASE_RAIL2 4 +#define MP2975_PAGE_NUM 2 + +#define MP2975_RAIL2_FUNC (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \ + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \ + PMBUS_PHASE_VIRTUAL) + +struct mp2975_data { + struct pmbus_driver_info info; + int vout_scale; + int vid_step[MP2975_PAGE_NUM]; + int vref[MP2975_PAGE_NUM]; + int vref_off[MP2975_PAGE_NUM]; + int vout_max[MP2975_PAGE_NUM]; + int vout_ov_fixed[MP2975_PAGE_NUM]; + int vout_format[MP2975_PAGE_NUM]; + int curr_sense_gain[MP2975_PAGE_NUM]; +}; + +#define to_mp2975_data(x) container_of(x, struct mp2975_data, info) + +static int mp2975_read_byte_data(struct i2c_client *client, int page, int reg) +{ + switch (reg) { + case PMBUS_VOUT_MODE: + /* + * Enforce VOUT direct format, since device allows to set the + * different formats for the different rails. Conversion from + * VID to direct provided by driver internally, in case it is + * necessary. + */ + return PB_VOUT_MODE_DIRECT; + default: + return -ENODATA; + } +} + +static int +mp2975_read_word_helper(struct i2c_client *client, int page, int phase, u8 reg, + u16 mask) +{ + int ret = pmbus_read_word_data(client, page, phase, reg); + + return (ret > 0) ? ret & mask : ret; +} + +static int +mp2975_vid2direct(int vrf, int val) +{ + switch (vrf) { + case vr12: + if (val >= 0x01) + return 250 + (val - 1) * 5; + break; + case vr13: + if (val >= 0x01) + return 500 + (val - 1) * 10; + break; + case imvp9: + if (val >= 0x01) + return 200 + (val - 1) * 10; + break; + default: + return -EINVAL; + } + return 0; +} + +static int +mp2975_read_phase(struct i2c_client *client, struct mp2975_data *data, + int page, int phase, u8 reg) +{ + int ph_curr, ret; + + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + + if (!((phase + 1) % MP2975_PAGE_NUM)) + ret >>= 8; + ret &= 0xff; + + /* + * Output value is calculated as: (READ_CSx / 80 – 1.23) / (Kcs * Rcs) + * where: + * - Kcs is the DrMOS current sense gain of power stage, which is + * obtained from the register MP2975_MFR_VR_CONFIG1, bits 13-12 with + * the following selection of DrMOS (data->curr_sense_gain[page]): + * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. + * - Rcs is the internal phase current sense resistor which is constant + * value 1kΩ. + */ + ph_curr = ret * 100 - 9800; + + /* + * Current phase sensing, providing by the device is not accurate + * for the light load. This because sampling of current occurrence of + * bit weight has a big deviation for light load. For handling such + * case phase current is represented as the maximum between the value + * calculated above and total rail current divided by number phases. + */ + ret = pmbus_read_word_data(client, page, phase, PMBUS_READ_IOUT); + if (ret < 0) + return ret; + + return max_t(int, DIV_ROUND_CLOSEST(ret, data->info.phases[page]), + DIV_ROUND_CLOSEST(ph_curr, data->curr_sense_gain[page])); +} + +static int +mp2975_read_phases(struct i2c_client *client, struct mp2975_data *data, + int page, int phase) +{ + int ret; + + if (page) { + switch (phase) { + case 0 ... 1: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS7_8); + break; + case 2 ... 3: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS9_10); + break; + case 4 ... 5: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS11_12); + break; + default: + return -ENODATA; + } + } else { + switch (phase) { + case 0 ... 1: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS1_2); + break; + case 2 ... 3: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS3_4); + break; + case 4 ... 5: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS5_6); + break; + case 6 ... 7: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS7_8); + break; + case 8 ... 9: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS9_10); + break; + case 10 ... 11: + ret = mp2975_read_phase(client, data, page, phase, + MP2975_MFR_READ_CS11_12); + break; + default: + return -ENODATA; + } + } + return ret; +} + +static int mp2975_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct mp2975_data *data = to_mp2975_data(info); + int ret; + + switch (reg) { + case PMBUS_OT_FAULT_LIMIT: + ret = mp2975_read_word_helper(client, page, phase, reg, + GENMASK(7, 0)); + break; + case PMBUS_VIN_OV_FAULT_LIMIT: + ret = mp2975_read_word_helper(client, page, phase, reg, + GENMASK(7, 0)); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST(ret, MP2975_VIN_UV_LIMIT_UNIT); + break; + case PMBUS_VOUT_OV_FAULT_LIMIT: + /* + * Register provides two values for over-voltage protection + * threshold for fixed (ovp2) and tracking (ovp1) modes. The + * minimum of these two values is provided as over-voltage + * fault alarm. + */ + ret = mp2975_read_word_helper(client, page, phase, + MP2975_MFR_OVP_TH_SET, + GENMASK(2, 0)); + if (ret < 0) + return ret; + + ret = min_t(int, data->vout_max[page] + 50 * (ret + 1), + data->vout_ov_fixed[page]); + break; + case PMBUS_VOUT_UV_FAULT_LIMIT: + ret = mp2975_read_word_helper(client, page, phase, + MP2975_MFR_UVP_SET, + GENMASK(2, 0)); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST(data->vref[page] * 10 - 50 * + (ret + 1) * data->vout_scale, 10); + break; + case PMBUS_READ_VOUT: + ret = mp2975_read_word_helper(client, page, phase, reg, + GENMASK(11, 0)); + if (ret < 0) + return ret; + + /* + * READ_VOUT can be provided in VID or direct format. The + * format type is specified by bit 15 of the register + * MP2975_MFR_DC_LOOP_CTRL. The driver enforces VOUT direct + * format, since device allows to set the different formats for + * the different rails and also all VOUT limits registers are + * provided in a direct format. In case format is VID - convert + * to direct. + */ + if (data->vout_format[page] == vid) + ret = mp2975_vid2direct(info->vrm_version[page], ret); + break; + case PMBUS_VIRT_READ_POUT_MAX: + ret = mp2975_read_word_helper(client, page, phase, + MP2975_MFR_READ_POUT_PK, + GENMASK(12, 0)); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST(ret, 4); + break; + case PMBUS_VIRT_READ_IOUT_MAX: + ret = mp2975_read_word_helper(client, page, phase, + MP2975_MFR_READ_IOUT_PK, + GENMASK(12, 0)); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST(ret, 4); + break; + case PMBUS_READ_IOUT: + ret = mp2975_read_phases(client, data, page, phase); + if (ret < 0) + return ret; + + break; + case PMBUS_UT_WARN_LIMIT: + case PMBUS_UT_FAULT_LIMIT: + case PMBUS_VIN_UV_WARN_LIMIT: + case PMBUS_VIN_UV_FAULT_LIMIT: + case PMBUS_VOUT_UV_WARN_LIMIT: + case PMBUS_VOUT_OV_WARN_LIMIT: + case PMBUS_VIN_OV_WARN_LIMIT: + case PMBUS_IIN_OC_FAULT_LIMIT: + case PMBUS_IOUT_OC_LV_FAULT_LIMIT: + case PMBUS_IIN_OC_WARN_LIMIT: + case PMBUS_IOUT_OC_WARN_LIMIT: + case PMBUS_IOUT_OC_FAULT_LIMIT: + case PMBUS_IOUT_UC_FAULT_LIMIT: + case PMBUS_POUT_OP_FAULT_LIMIT: + case PMBUS_POUT_OP_WARN_LIMIT: + case PMBUS_PIN_OP_WARN_LIMIT: + return -ENXIO; + default: + return -ENODATA; + } + + return ret; +} + +static int mp2975_identify_multiphase_rail2(struct i2c_client *client) +{ + int ret; + + /* + * Identify multiphase for rail 2 - could be from 0 to 4. + * In case phase number is zero – only page zero is supported + */ + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); + if (ret < 0) + return ret; + + /* Identify multiphase for rail 2 - could be from 0 to 4. */ + ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R2); + if (ret < 0) + return ret; + + ret &= GENMASK(2, 0); + return (ret >= 4) ? 4 : ret; +} + +static void mp2975_set_phase_rail1(struct pmbus_driver_info *info) +{ + int i; + + for (i = 0 ; i < info->phases[0]; i++) + info->pfunc[i] = PMBUS_HAVE_IOUT; +} + +static void +mp2975_set_phase_rail2(struct pmbus_driver_info *info, int num_phases) +{ + int i; + + /* Set phases for rail 2 from upper to lower. */ + for (i = 1; i <= num_phases; i++) + info->pfunc[MP2975_MAX_PHASE_RAIL1 - i] = PMBUS_HAVE_IOUT; +} + +static int +mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int num_phases2, ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); + if (ret < 0) + return ret; + + /* Identify multiphase for rail 1 - could be from 1 to 8. */ + ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R1); + if (ret <= 0) + return ret; + + info->phases[0] = ret & GENMASK(3, 0); + + /* + * The device provides a total of 8 PWM pins, and can be configured + * to different phase count applications for rail 1 and rail 2. + * Rail 1 can be set to 8 phases, while rail 2 can only be set to 4 + * phases at most. When rail 1’s phase count is configured as 0, rail + * 1 operates with 1-phase DCM. When rail 2 phase count is configured + * as 0, rail 2 is disabled. + */ + if (info->phases[0] > MP2975_MAX_PHASE_RAIL1) + return -EINVAL; + + mp2975_set_phase_rail1(info); + num_phases2 = min(MP2975_MAX_PHASE_RAIL1 - info->phases[0], + MP2975_MAX_PHASE_RAIL2); + if (info->phases[1] && info->phases[1] <= num_phases2) + mp2975_set_phase_rail2(info, num_phases2); + + return 0; +} + +static int +mp2975_identify_vid(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info, u32 reg, int page, + u32 imvp_bit, u32 vr_bit) +{ + int ret; + + /* Identify VID mode and step selection. */ + ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) + return ret; + + if (ret & imvp_bit) { + info->vrm_version[page] = imvp9; + data->vid_step[page] = MP2975_PROT_DEV_OV_OFF; + } else if (ret & vr_bit) { + info->vrm_version[page] = vr12; + data->vid_step[page] = MP2975_PROT_DEV_OV_ON; + } else { + info->vrm_version[page] = vr13; + data->vid_step[page] = MP2975_PROT_DEV_OV_OFF; + } + + return 0; +} + +static int +mp2975_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2); + if (ret < 0) + return ret; + + /* Identify VID mode for rail 1. */ + ret = mp2975_identify_vid(client, data, info, + MP2975_MFR_VR_MULTI_CONFIG_R1, 0, + MP2975_IMVP9_EN_R1, MP2975_VID_STEP_SEL_R1); + if (ret < 0) + return ret; + + /* Identify VID mode for rail 2, if connected. */ + if (info->phases[1]) + ret = mp2975_identify_vid(client, data, info, + MP2975_MFR_VR_MULTI_CONFIG_R2, 1, + MP2975_IMVP9_EN_R2, + MP2975_VID_STEP_SEL_R2); + return ret; +} + +static int +mp2975_current_sense_gain_get(struct i2c_client *client, + struct mp2975_data *data) +{ + int i, ret; + + /* + * Obtain DrMOS current sense gain of power stage from the register + * MP2975_MFR_VR_CONFIG1, bits 13-12. The value is selected as below: + * 00b - 5µA/A, 01b - 8.5µA/A, 10b - 9.7µA/A, 11b - 10µA/A. Other + * values are invalid. + */ + for (i = 0 ; i < data->info.pages; i++) { + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i); + if (ret < 0) + return ret; + ret = i2c_smbus_read_word_data(client, + MP2975_MFR_VR_CONFIG1); + if (ret < 0) + return ret; + + switch ((ret & MP2975_DRMOS_KCS) >> 12) { + case 0: + data->curr_sense_gain[i] = 50; + break; + case 1: + data->curr_sense_gain[i] = 85; + break; + case 2: + data->curr_sense_gain[i] = 97; + break; + default: + data->curr_sense_gain[i] = 100; + break; + } + } + + return 0; +} + +static int +mp2975_vref_get(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 3); + if (ret < 0) + return ret; + + /* Get voltage reference value for rail 1. */ + ret = i2c_smbus_read_word_data(client, MP2975_MFR_READ_VREF_R1); + if (ret < 0) + return ret; + + data->vref[0] = ret * data->vid_step[0]; + + /* Get voltage reference value for rail 2, if connected. */ + if (data->info.pages == MP2975_PAGE_NUM) { + ret = i2c_smbus_read_word_data(client, MP2975_MFR_READ_VREF_R2); + if (ret < 0) + return ret; + + data->vref[1] = ret * data->vid_step[1]; + } + return 0; +} + +static int +mp2975_vref_offset_get(struct i2c_client *client, struct mp2975_data *data, + int page) +{ + int ret; + + ret = i2c_smbus_read_word_data(client, MP2975_MFR_OVP_TH_SET); + if (ret < 0) + return ret; + + switch ((ret & GENMASK(5, 3)) >> 3) { + case 1: + data->vref_off[page] = 140; + break; + case 2: + data->vref_off[page] = 220; + break; + case 4: + data->vref_off[page] = 400; + break; + default: + return -EINVAL; + } + return 0; +} + +static int +mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info, int page) +{ + int ret; + + /* Get maximum reference voltage of VID-DAC in VID format. */ + ret = i2c_smbus_read_word_data(client, PMBUS_VOUT_MAX); + if (ret < 0) + return ret; + + data->vout_max[page] = mp2975_vid2direct(info->vrm_version[page], ret & + GENMASK(8, 0)); + return 0; +} + +static int +mp2975_identify_vout_format(struct i2c_client *client, + struct mp2975_data *data, int page) +{ + int ret; + + ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL); + if (ret < 0) + return ret; + + if (ret & MP2975_VOUT_FORMAT) + data->vout_format[page] = vid; + else + data->vout_format[page] = direct; + return 0; +} + +static int +mp2975_vout_ov_scale_get(struct i2c_client *client, struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int thres_dev, sense_ampl, ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); + if (ret < 0) + return ret; + + /* + * Get divider for over- and under-voltage protection thresholds + * configuration from the Advanced Options of Auto Phase Shedding and + * decay register. + */ + ret = i2c_smbus_read_word_data(client, MP2975_MFR_APS_DECAY_ADV); + if (ret < 0) + return ret; + thres_dev = ret & MP2975_PRT_THRES_DIV_OV_EN ? MP2975_PROT_DEV_OV_ON : + MP2975_PROT_DEV_OV_OFF; + + /* Select the gain of remote sense amplifier. */ + ret = i2c_smbus_read_word_data(client, PMBUS_VOUT_SCALE_LOOP); + if (ret < 0) + return ret; + sense_ampl = ret & MP2975_SENSE_AMPL ? MP2975_SENSE_AMPL_HALF : + MP2975_SENSE_AMPL_UNIT; + + data->vout_scale = sense_ampl * thres_dev; + + return 0; +} + +static int +mp2975_vout_per_rail_config_get(struct i2c_client *client, + struct mp2975_data *data, + struct pmbus_driver_info *info) +{ + int i, ret; + + for (i = 0; i < data->info.pages; i++) { + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i); + if (ret < 0) + return ret; + + /* Obtain voltage reference offsets. */ + ret = mp2975_vref_offset_get(client, data, i); + if (ret < 0) + return ret; + + /* Obtain maximum voltage values. */ + ret = mp2975_vout_max_get(client, data, info, i); + if (ret < 0) + return ret; + + /* + * Get VOUT format for READ_VOUT command : VID or direct. + * Pages on same device can be configured with different + * formats. + */ + ret = mp2975_identify_vout_format(client, data, i); + if (ret < 0) + return ret; + + /* + * Set over-voltage fixed value. Thresholds are provided as + * fixed value, and tracking value. The minimum of them are + * exposed as over-voltage critical threshold. + */ + data->vout_ov_fixed[i] = data->vref[i] + + DIV_ROUND_CLOSEST(data->vref_off[i] * + data->vout_scale, + 10); + } + + return 0; +} + +static struct pmbus_driver_info mp2975_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_TEMPERATURE] = direct, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = direct, + .format[PSC_POWER] = direct, + .m[PSC_TEMPERATURE] = 1, + .m[PSC_VOLTAGE_OUT] = 1, + .R[PSC_VOLTAGE_OUT] = 3, + .m[PSC_CURRENT_OUT] = 1, + .m[PSC_POWER] = 1, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT | + PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_PHASE_VIRTUAL, + .read_byte_data = mp2975_read_byte_data, + .read_word_data = mp2975_read_word_data, +}; + +static int mp2975_probe(struct i2c_client *client) +{ + struct pmbus_driver_info *info; + struct mp2975_data *data; + int ret; + + data = devm_kzalloc(&client->dev, sizeof(struct mp2975_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + memcpy(&data->info, &mp2975_info, sizeof(*info)); + info = &data->info; + + /* Identify multiphase configuration for rail 2. */ + ret = mp2975_identify_multiphase_rail2(client); + if (ret < 0) + return ret; + + if (ret) { + /* Two rails are connected. */ + data->info.pages = MP2975_PAGE_NUM; + data->info.phases[1] = ret; + data->info.func[1] = MP2975_RAIL2_FUNC; + } + + /* Identify multiphase configuration. */ + ret = mp2975_identify_multiphase(client, data, info); + if (ret) + return ret; + + /* Identify VID setting per rail. */ + ret = mp2975_identify_rails_vid(client, data, info); + if (ret < 0) + return ret; + + /* Obtain current sense gain of power stage. */ + ret = mp2975_current_sense_gain_get(client, data); + if (ret) + return ret; + + /* Obtain voltage reference values. */ + ret = mp2975_vref_get(client, data, info); + if (ret) + return ret; + + /* Obtain vout over-voltage scales. */ + ret = mp2975_vout_ov_scale_get(client, data, info); + if (ret < 0) + return ret; + + /* Obtain offsets, maximum and format for vout. */ + ret = mp2975_vout_per_rail_config_get(client, data, info); + if (ret) + return ret; + + return pmbus_do_probe(client, info); +} + +static const struct i2c_device_id mp2975_id[] = { + {"mp2975", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, mp2975_id); + +static const struct of_device_id __maybe_unused mp2975_of_match[] = { + {.compatible = "mps,mp2975"}, + {} +}; +MODULE_DEVICE_TABLE(of, mp2975_of_match); + +static struct i2c_driver mp2975_driver = { + .driver = { + .name = "mp2975", + .of_match_table = of_match_ptr(mp2975_of_match), + }, + .probe_new = mp2975_probe, + .remove = pmbus_do_remove, + .id_table = mp2975_id, +}; + +module_i2c_driver(mp2975_driver); + +MODULE_AUTHOR("Vadim Pasternak <vadimp@nvidia.com>"); +MODULE_DESCRIPTION("PMBus driver for MPS MP2975 device"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 6d384e8ee1db..20f1af9165c2 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -20,6 +20,8 @@ struct pmbus_device_info { u32 flags; }; +static const struct i2c_device_id pmbus_id[]; + /* * Find sensor groups and status registers on each page. */ @@ -159,8 +161,7 @@ abort: return ret; } -static int pmbus_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pmbus_probe(struct i2c_client *client) { struct pmbus_driver_info *info; struct pmbus_platform_data *pdata = NULL; @@ -171,7 +172,7 @@ static int pmbus_probe(struct i2c_client *client, if (!info) return -ENOMEM; - device_info = (struct pmbus_device_info *)id->driver_data; + device_info = (struct pmbus_device_info *)i2c_match_id(pmbus_id, client)->driver_data; if (device_info->flags & PMBUS_SKIP_STATUS_CHECK) { pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data), GFP_KERNEL); @@ -185,7 +186,7 @@ static int pmbus_probe(struct i2c_client *client, info->identify = pmbus_identify; dev->platform_data = pdata; - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct pmbus_device_info pmbus_info_one = { @@ -236,7 +237,7 @@ static struct i2c_driver pmbus_driver = { .driver = { .name = "pmbus", }, - .probe = pmbus_probe, + .probe_new = pmbus_probe, .remove = pmbus_do_remove, .id_table = pmbus_id, }; diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 18e06fc6c53f..88a5df2633fb 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -119,9 +119,22 @@ enum pmbus_regs { PMBUS_MFR_DATE = 0x9D, PMBUS_MFR_SERIAL = 0x9E, + PMBUS_MFR_VIN_MIN = 0xA0, + PMBUS_MFR_VIN_MAX = 0xA1, + PMBUS_MFR_IIN_MAX = 0xA2, + PMBUS_MFR_PIN_MAX = 0xA3, + PMBUS_MFR_VOUT_MIN = 0xA4, + PMBUS_MFR_VOUT_MAX = 0xA5, + PMBUS_MFR_IOUT_MAX = 0xA6, + PMBUS_MFR_POUT_MAX = 0xA7, + PMBUS_IC_DEVICE_ID = 0xAD, PMBUS_IC_DEVICE_REV = 0xAE, + PMBUS_MFR_MAX_TEMP_1 = 0xC0, + PMBUS_MFR_MAX_TEMP_2 = 0xC1, + PMBUS_MFR_MAX_TEMP_3 = 0xC2, + /* * Virtual registers. * Useful to support attributes which are not supported by standard PMBus @@ -476,8 +489,7 @@ int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, void pmbus_clear_faults(struct i2c_client *client); bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); -int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, - struct pmbus_driver_info *info); +int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info); int pmbus_do_remove(struct i2c_client *client); const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 44535add3a4a..170a9f82ca61 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -16,7 +16,6 @@ #include <linux/i2c.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> -#include <linux/jiffies.h> #include <linux/pmbus.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> @@ -27,21 +26,6 @@ * with each call to krealloc */ #define PMBUS_ATTR_ALLOC_SIZE 32 - -/* - * Index into status register array, per status register group - */ -#define PB_STATUS_BASE 0 -#define PB_STATUS_VOUT_BASE (PB_STATUS_BASE + PMBUS_PAGES) -#define PB_STATUS_IOUT_BASE (PB_STATUS_VOUT_BASE + PMBUS_PAGES) -#define PB_STATUS_FAN_BASE (PB_STATUS_IOUT_BASE + PMBUS_PAGES) -#define PB_STATUS_FAN34_BASE (PB_STATUS_FAN_BASE + PMBUS_PAGES) -#define PB_STATUS_TEMP_BASE (PB_STATUS_FAN34_BASE + PMBUS_PAGES) -#define PB_STATUS_INPUT_BASE (PB_STATUS_TEMP_BASE + PMBUS_PAGES) -#define PB_STATUS_VMON_BASE (PB_STATUS_INPUT_BASE + 1) - -#define PB_NUM_STATUS_REG (PB_STATUS_VMON_BASE + 1) - #define PMBUS_NAME_SIZE 24 struct pmbus_sensor { @@ -77,6 +61,21 @@ struct pmbus_label { #define to_pmbus_label(_attr) \ container_of(_attr, struct pmbus_label, attribute) +/* Macros for converting between sensor index and register/page/status mask */ + +#define PB_STATUS_MASK 0xffff +#define PB_REG_SHIFT 16 +#define PB_REG_MASK 0x3ff +#define PB_PAGE_SHIFT 26 +#define PB_PAGE_MASK 0x3f + +#define pb_reg_to_index(page, reg, mask) (((page) << PB_PAGE_SHIFT) | \ + ((reg) << PB_REG_SHIFT) | (mask)) + +#define pb_index_to_page(index) (((index) >> PB_PAGE_SHIFT) & PB_PAGE_MASK) +#define pb_index_to_reg(index) (((index) >> PB_REG_SHIFT) & PB_REG_MASK) +#define pb_index_to_mask(index) ((index) & PB_STATUS_MASK) + struct pmbus_data { struct device *dev; struct device *hwmon_dev; @@ -97,14 +96,6 @@ struct pmbus_data { struct pmbus_sensor *sensors; struct mutex update_lock; - bool valid; - unsigned long last_updated; /* in jiffies */ - - /* - * A single status register covers multiple attributes, - * so we keep them all together. - */ - u16 status[PB_NUM_STATUS_REG]; bool has_status_word; /* device uses STATUS_WORD register */ int (*read_status)(struct i2c_client *client, int page); @@ -143,8 +134,10 @@ static const int pmbus_fan_command_registers[] = { void pmbus_clear_cache(struct i2c_client *client) { struct pmbus_data *data = i2c_get_clientdata(client); + struct pmbus_sensor *sensor; - data->valid = false; + for (sensor = data->sensors; sensor; sensor = sensor->next) + sensor->data = -ENODATA; } EXPORT_SYMBOL_GPL(pmbus_clear_cache); @@ -560,68 +553,29 @@ const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client) } EXPORT_SYMBOL_GPL(pmbus_get_driver_info); -static struct _pmbus_status { - u32 func; - u16 base; - u16 reg; -} pmbus_status[] = { - { PMBUS_HAVE_STATUS_VOUT, PB_STATUS_VOUT_BASE, PMBUS_STATUS_VOUT }, - { PMBUS_HAVE_STATUS_IOUT, PB_STATUS_IOUT_BASE, PMBUS_STATUS_IOUT }, - { PMBUS_HAVE_STATUS_TEMP, PB_STATUS_TEMP_BASE, - PMBUS_STATUS_TEMPERATURE }, - { PMBUS_HAVE_STATUS_FAN12, PB_STATUS_FAN_BASE, PMBUS_STATUS_FAN_12 }, - { PMBUS_HAVE_STATUS_FAN34, PB_STATUS_FAN34_BASE, PMBUS_STATUS_FAN_34 }, -}; - -static struct pmbus_data *pmbus_update_device(struct device *dev) +static int pmbus_get_status(struct i2c_client *client, int page, int reg) { - struct i2c_client *client = to_i2c_client(dev->parent); struct pmbus_data *data = i2c_get_clientdata(client); - const struct pmbus_driver_info *info = data->info; - struct pmbus_sensor *sensor; - - mutex_lock(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - int i, j; - - for (i = 0; i < info->pages; i++) { - data->status[PB_STATUS_BASE + i] - = data->read_status(client, i); - for (j = 0; j < ARRAY_SIZE(pmbus_status); j++) { - struct _pmbus_status *s = &pmbus_status[j]; - - if (!(info->func[i] & s->func)) - continue; - data->status[s->base + i] - = _pmbus_read_byte_data(client, i, - s->reg); - } - } + int status; - if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) - data->status[PB_STATUS_INPUT_BASE] - = _pmbus_read_byte_data(client, 0, - PMBUS_STATUS_INPUT); - - if (info->func[0] & PMBUS_HAVE_STATUS_VMON) - data->status[PB_STATUS_VMON_BASE] - = _pmbus_read_byte_data(client, 0, - PMBUS_VIRT_STATUS_VMON); - - for (sensor = data->sensors; sensor; sensor = sensor->next) { - if (!data->valid || sensor->update) - sensor->data - = _pmbus_read_word_data(client, - sensor->page, - sensor->phase, - sensor->reg); - } - pmbus_clear_faults(client); - data->last_updated = jiffies; - data->valid = 1; + switch (reg) { + case PMBUS_STATUS_WORD: + status = data->read_status(client, page); + break; + default: + status = _pmbus_read_byte_data(client, page, reg); + break; } - mutex_unlock(&data->update_lock); - return data; + if (status < 0) + pmbus_clear_faults(client); + return status; +} + +static void pmbus_update_sensor_data(struct i2c_client *client, struct pmbus_sensor *sensor) +{ + if (sensor->data < 0 || sensor->update) + sensor->data = _pmbus_read_word_data(client, sensor->page, + sensor->phase, sensor->reg); } /* @@ -919,38 +873,51 @@ static u16 pmbus_data2reg(struct pmbus_data *data, * If a negative value is stored in any of the referenced registers, this value * reflects an error code which will be returned. */ -static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b, +static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b, int index) { + struct pmbus_data *data = i2c_get_clientdata(client); struct pmbus_sensor *s1 = b->s1; struct pmbus_sensor *s2 = b->s2; - u16 reg = (index >> 16) & 0xffff; - u16 mask = index & 0xffff; + u16 mask = pb_index_to_mask(index); + u8 page = pb_index_to_page(index); + u16 reg = pb_index_to_reg(index); int ret, status; u16 regval; - status = data->status[reg]; - if (status < 0) - return status; + mutex_lock(&data->update_lock); + status = pmbus_get_status(client, page, reg); + if (status < 0) { + ret = status; + goto unlock; + } + + if (s1) + pmbus_update_sensor_data(client, s1); + if (s2) + pmbus_update_sensor_data(client, s2); regval = status & mask; - if (!s1 && !s2) { - ret = !!regval; - } else if (!s1 || !s2) { - WARN(1, "Bad boolean descriptor %p: s1=%p, s2=%p\n", b, s1, s2); - return 0; - } else { + if (s1 && s2) { s64 v1, v2; - if (s1->data < 0) - return s1->data; - if (s2->data < 0) - return s2->data; + if (s1->data < 0) { + ret = s1->data; + goto unlock; + } + if (s2->data < 0) { + ret = s2->data; + goto unlock; + } v1 = pmbus_reg2data(data, s1); v2 = pmbus_reg2data(data, s2); ret = !!(regval && v1 >= v2); + } else { + ret = !!regval; } +unlock: + mutex_unlock(&data->update_lock); return ret; } @@ -959,10 +926,10 @@ static ssize_t pmbus_show_boolean(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct pmbus_boolean *boolean = to_pmbus_boolean(attr); - struct pmbus_data *data = pmbus_update_device(dev); + struct i2c_client *client = to_i2c_client(dev->parent); int val; - val = pmbus_get_boolean(data, boolean, attr->index); + val = pmbus_get_boolean(client, boolean, attr->index); if (val < 0) return val; return snprintf(buf, PAGE_SIZE, "%d\n", val); @@ -971,9 +938,11 @@ static ssize_t pmbus_show_boolean(struct device *dev, static ssize_t pmbus_show_sensor(struct device *dev, struct device_attribute *devattr, char *buf) { - struct pmbus_data *data = pmbus_update_device(dev); + struct i2c_client *client = to_i2c_client(dev->parent); struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + pmbus_update_sensor_data(client, sensor); if (sensor->data < 0) return sensor->data; @@ -1018,9 +987,9 @@ static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr) { if (data->num_attributes >= data->max_attributes - 1) { int new_max_attrs = data->max_attributes + PMBUS_ATTR_ALLOC_SIZE; - void *new_attrs = krealloc(data->group.attrs, - new_max_attrs * sizeof(void *), - GFP_KERNEL); + void *new_attrs = devm_krealloc(data->dev, data->group.attrs, + new_max_attrs * sizeof(void *), + GFP_KERNEL); if (!new_attrs) return -ENOMEM; data->group.attrs = new_attrs; @@ -1068,11 +1037,14 @@ static int pmbus_add_boolean(struct pmbus_data *data, const char *name, const char *type, int seq, struct pmbus_sensor *s1, struct pmbus_sensor *s2, - u16 reg, u16 mask) + u8 page, u16 reg, u16 mask) { struct pmbus_boolean *boolean; struct sensor_device_attribute *a; + if (WARN((s1 && !s2) || (!s1 && s2), "Bad s1/s2 parameters\n")) + return -EINVAL; + boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL); if (!boolean) return -ENOMEM; @@ -1084,7 +1056,7 @@ static int pmbus_add_boolean(struct pmbus_data *data, boolean->s1 = s1; boolean->s2 = s2; pmbus_attr_init(a, boolean->name, 0444, pmbus_show_boolean, NULL, - (reg << 16) | mask); + pb_reg_to_index(page, reg, mask)); return pmbus_add_attribute(data, &a->dev_attr.attr); } @@ -1121,6 +1093,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, sensor->class = class; sensor->update = update; sensor->convert = convert; + sensor->data = -ENODATA; pmbus_dev_attr_init(a, sensor->name, readonly ? 0444 : 0644, pmbus_show_sensor, pmbus_set_sensor); @@ -1201,7 +1174,7 @@ struct pmbus_sensor_attr { bool compare; /* true if compare function needed */ u32 func; /* sensor mask */ u32 sfunc; /* sensor status mask */ - int sbase; /* status base register */ + int sreg; /* status register */ const struct pmbus_limit_attr *limit;/* limit registers */ }; @@ -1239,7 +1212,7 @@ static int pmbus_add_limit_attrs(struct i2c_client *client, : NULL, attr->compare ? l->low ? base : curr : NULL, - attr->sbase + page, l->sbit); + page, attr->sreg, l->sbit); if (ret) return ret; have_alarm = 1; @@ -1289,7 +1262,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client, pmbus_check_status_register(client, page)) { ret = pmbus_add_boolean(data, name, "alarm", index, NULL, NULL, - PB_STATUS_BASE + page, + page, PMBUS_STATUS_WORD, attr->gbit); if (ret) return ret; @@ -1404,6 +1377,12 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_VIN_HISTORY, .attr = "reset_history", + }, { + .reg = PMBUS_MFR_VIN_MIN, + .attr = "rated_min", + }, { + .reg = PMBUS_MFR_VIN_MAX, + .attr = "rated_max", }, }; @@ -1467,7 +1446,13 @@ static const struct pmbus_limit_attr vout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_VOUT_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_VOUT_MIN, + .attr = "rated_min", + }, { + .reg = PMBUS_MFR_VOUT_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_sensor_attr voltage_attributes[] = { @@ -1477,7 +1462,7 @@ static const struct pmbus_sensor_attr voltage_attributes[] = { .label = "vin", .func = PMBUS_HAVE_VIN, .sfunc = PMBUS_HAVE_STATUS_INPUT, - .sbase = PB_STATUS_INPUT_BASE, + .sreg = PMBUS_STATUS_INPUT, .gbit = PB_STATUS_VIN_UV, .limit = vin_limit_attrs, .nlimit = ARRAY_SIZE(vin_limit_attrs), @@ -1487,7 +1472,7 @@ static const struct pmbus_sensor_attr voltage_attributes[] = { .label = "vmon", .func = PMBUS_HAVE_VMON, .sfunc = PMBUS_HAVE_STATUS_VMON, - .sbase = PB_STATUS_VMON_BASE, + .sreg = PMBUS_VIRT_STATUS_VMON, .limit = vmon_limit_attrs, .nlimit = ARRAY_SIZE(vmon_limit_attrs), }, { @@ -1502,7 +1487,7 @@ static const struct pmbus_sensor_attr voltage_attributes[] = { .paged = true, .func = PMBUS_HAVE_VOUT, .sfunc = PMBUS_HAVE_STATUS_VOUT, - .sbase = PB_STATUS_VOUT_BASE, + .sreg = PMBUS_STATUS_VOUT, .gbit = PB_STATUS_VOUT_OV, .limit = vout_limit_attrs, .nlimit = ARRAY_SIZE(vout_limit_attrs), @@ -1537,7 +1522,10 @@ static const struct pmbus_limit_attr iin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_IIN_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_IIN_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_limit_attr iout_limit_attrs[] = { @@ -1571,7 +1559,10 @@ static const struct pmbus_limit_attr iout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_IOUT_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_IOUT_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_sensor_attr current_attributes[] = { @@ -1581,7 +1572,7 @@ static const struct pmbus_sensor_attr current_attributes[] = { .label = "iin", .func = PMBUS_HAVE_IIN, .sfunc = PMBUS_HAVE_STATUS_INPUT, - .sbase = PB_STATUS_INPUT_BASE, + .sreg = PMBUS_STATUS_INPUT, .gbit = PB_STATUS_INPUT, .limit = iin_limit_attrs, .nlimit = ARRAY_SIZE(iin_limit_attrs), @@ -1592,7 +1583,7 @@ static const struct pmbus_sensor_attr current_attributes[] = { .paged = true, .func = PMBUS_HAVE_IOUT, .sfunc = PMBUS_HAVE_STATUS_IOUT, - .sbase = PB_STATUS_IOUT_BASE, + .sreg = PMBUS_STATUS_IOUT, .gbit = PB_STATUS_IOUT_OC, .limit = iout_limit_attrs, .nlimit = ARRAY_SIZE(iout_limit_attrs), @@ -1622,7 +1613,10 @@ static const struct pmbus_limit_attr pin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_PIN_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_PIN_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_limit_attr pout_limit_attrs[] = { @@ -1656,7 +1650,10 @@ static const struct pmbus_limit_attr pout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_POUT_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_POUT_MAX, + .attr = "rated_max", + }, }; static const struct pmbus_sensor_attr power_attributes[] = { @@ -1666,7 +1663,7 @@ static const struct pmbus_sensor_attr power_attributes[] = { .label = "pin", .func = PMBUS_HAVE_PIN, .sfunc = PMBUS_HAVE_STATUS_INPUT, - .sbase = PB_STATUS_INPUT_BASE, + .sreg = PMBUS_STATUS_INPUT, .gbit = PB_STATUS_INPUT, .limit = pin_limit_attrs, .nlimit = ARRAY_SIZE(pin_limit_attrs), @@ -1677,7 +1674,7 @@ static const struct pmbus_sensor_attr power_attributes[] = { .paged = true, .func = PMBUS_HAVE_POUT, .sfunc = PMBUS_HAVE_STATUS_IOUT, - .sbase = PB_STATUS_IOUT_BASE, + .sreg = PMBUS_STATUS_IOUT, .limit = pout_limit_attrs, .nlimit = ARRAY_SIZE(pout_limit_attrs), } @@ -1720,7 +1717,10 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = { }, { .reg = PMBUS_VIRT_RESET_TEMP_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_MAX_TEMP_1, + .attr = "rated_max", + }, }; static const struct pmbus_limit_attr temp_limit_attrs2[] = { @@ -1758,7 +1758,10 @@ static const struct pmbus_limit_attr temp_limit_attrs2[] = { }, { .reg = PMBUS_VIRT_RESET_TEMP2_HISTORY, .attr = "reset_history", - } + }, { + .reg = PMBUS_MFR_MAX_TEMP_2, + .attr = "rated_max", + }, }; static const struct pmbus_limit_attr temp_limit_attrs3[] = { @@ -1784,7 +1787,10 @@ static const struct pmbus_limit_attr temp_limit_attrs3[] = { .attr = "crit", .alarm = "crit_alarm", .sbit = PB_TEMP_OT_FAULT, - } + }, { + .reg = PMBUS_MFR_MAX_TEMP_3, + .attr = "rated_max", + }, }; static const struct pmbus_sensor_attr temp_attributes[] = { @@ -1796,7 +1802,7 @@ static const struct pmbus_sensor_attr temp_attributes[] = { .compare = true, .func = PMBUS_HAVE_TEMP, .sfunc = PMBUS_HAVE_STATUS_TEMP, - .sbase = PB_STATUS_TEMP_BASE, + .sreg = PMBUS_STATUS_TEMPERATURE, .gbit = PB_STATUS_TEMPERATURE, .limit = temp_limit_attrs, .nlimit = ARRAY_SIZE(temp_limit_attrs), @@ -1808,7 +1814,7 @@ static const struct pmbus_sensor_attr temp_attributes[] = { .compare = true, .func = PMBUS_HAVE_TEMP2, .sfunc = PMBUS_HAVE_STATUS_TEMP, - .sbase = PB_STATUS_TEMP_BASE, + .sreg = PMBUS_STATUS_TEMPERATURE, .gbit = PB_STATUS_TEMPERATURE, .limit = temp_limit_attrs2, .nlimit = ARRAY_SIZE(temp_limit_attrs2), @@ -1820,7 +1826,7 @@ static const struct pmbus_sensor_attr temp_attributes[] = { .compare = true, .func = PMBUS_HAVE_TEMP3, .sfunc = PMBUS_HAVE_STATUS_TEMP, - .sbase = PB_STATUS_TEMP_BASE, + .sreg = PMBUS_STATUS_TEMPERATURE, .gbit = PB_STATUS_TEMPERATURE, .limit = temp_limit_attrs3, .nlimit = ARRAY_SIZE(temp_limit_attrs3), @@ -1945,19 +1951,19 @@ static int pmbus_add_fan_attributes(struct i2c_client *client, if ((info->func[page] & pmbus_fan_status_flags[f]) && pmbus_check_byte_register(client, page, pmbus_fan_status_registers[f])) { - int base; + int reg; if (f > 1) /* fan 3, 4 */ - base = PB_STATUS_FAN34_BASE + page; + reg = PMBUS_STATUS_FAN_34; else - base = PB_STATUS_FAN_BASE + page; + reg = PMBUS_STATUS_FAN_12; ret = pmbus_add_boolean(data, "fan", - "alarm", index, NULL, NULL, base, + "alarm", index, NULL, NULL, page, reg, PB_FAN_FAN1_WARNING >> (f & 1)); if (ret) return ret; ret = pmbus_add_boolean(data, "fan", - "fault", index, NULL, NULL, base, + "fault", index, NULL, NULL, page, reg, PB_FAN_FAN1_FAULT >> (f & 1)); if (ret) return ret; @@ -2346,6 +2352,42 @@ static int pmbus_debugfs_get_status(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_status, pmbus_debugfs_get_status, NULL, "0x%04llx\n"); +static int pmbus_debugfs_get_pec(void *data, u64 *val) +{ + struct i2c_client *client = data; + + *val = !!(client->flags & I2C_CLIENT_PEC); + + return 0; +} + +static int pmbus_debugfs_set_pec(void *data, u64 val) +{ + int rc; + struct i2c_client *client = data; + + if (!val) { + client->flags &= ~I2C_CLIENT_PEC; + return 0; + } + + if (val != 1) + return -EINVAL; + + rc = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); + if (rc < 0) + return rc; + + if (!(rc & PB_CAPABILITY_ERROR_CHECK)) + return -EOPNOTSUPP; + + client->flags |= I2C_CLIENT_PEC; + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_pec, pmbus_debugfs_get_pec, + pmbus_debugfs_set_pec, "%llu\n"); + static int pmbus_init_debugfs(struct i2c_client *client, struct pmbus_data *data) { @@ -2374,6 +2416,9 @@ static int pmbus_init_debugfs(struct i2c_client *client, if (!entries) return -ENOMEM; + debugfs_create_file("pec", 0664, data->debugfs, client, + &pmbus_debugfs_ops_pec); + for (i = 0; i < data->info->pages; ++i) { /* Check accessibility of status register if it's not page 0 */ if (!i || pmbus_check_status_register(client, i)) { @@ -2488,8 +2533,7 @@ static int pmbus_init_debugfs(struct i2c_client *client, } #endif /* IS_ENABLED(CONFIG_DEBUG_FS) */ -int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, - struct pmbus_driver_info *info) +int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) { struct device *dev = &client->dev; const struct pmbus_platform_data *pdata = dev_get_platdata(dev); @@ -2534,7 +2578,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, ret = pmbus_find_attributes(client, data); if (ret) - goto out_kfree; + return ret; /* * If there are no attributes, something is wrong. @@ -2542,35 +2586,27 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, */ if (!data->num_attributes) { dev_err(dev, "No attributes found\n"); - ret = -ENODEV; - goto out_kfree; + return -ENODEV; } data->groups[0] = &data->group; memcpy(data->groups + 1, info->groups, sizeof(void *) * groups_num); - data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, - data, data->groups); + data->hwmon_dev = devm_hwmon_device_register_with_groups(dev, + client->name, data, data->groups); if (IS_ERR(data->hwmon_dev)) { - ret = PTR_ERR(data->hwmon_dev); dev_err(dev, "Failed to register hwmon device\n"); - goto out_kfree; + return PTR_ERR(data->hwmon_dev); } ret = pmbus_regulator_register(data); if (ret) - goto out_unregister; + return ret; ret = pmbus_init_debugfs(client, data); if (ret) dev_warn(dev, "Failed to register debugfs\n"); return 0; - -out_unregister: - hwmon_device_unregister(data->hwmon_dev); -out_kfree: - kfree(data->group.attrs); - return ret; } EXPORT_SYMBOL_GPL(pmbus_do_probe); @@ -2580,8 +2616,6 @@ int pmbus_do_remove(struct i2c_client *client) debugfs_remove_recursive(data->debugfs); - hwmon_device_unregister(data->hwmon_dev); - kfree(data->group.attrs); return 0; } EXPORT_SYMBOL_GPL(pmbus_do_remove); diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c index 517584cff3de..fa5c5dd29b7a 100644 --- a/drivers/hwmon/pmbus/pxe1610.c +++ b/drivers/hwmon/pmbus/pxe1610.c @@ -78,8 +78,7 @@ static struct pmbus_driver_info pxe1610_info = { .identify = pxe1610_identify, }; -static int pxe1610_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pxe1610_probe(struct i2c_client *client) { struct pmbus_driver_info *info; u8 buf[I2C_SMBUS_BLOCK_MAX]; @@ -115,7 +114,7 @@ static int pxe1610_probe(struct i2c_client *client, if (!info) return -ENOMEM; - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id pxe1610_id[] = { @@ -131,7 +130,7 @@ static struct i2c_driver pxe1610_driver = { .driver = { .name = "pxe1610", }, - .probe = pxe1610_probe, + .probe_new = pxe1610_probe, .remove = pmbus_do_remove, .id_table = pxe1610_id, }; diff --git a/drivers/hwmon/pmbus/tps40422.c b/drivers/hwmon/pmbus/tps40422.c index 2b83dcda964a..edbdfa809d51 100644 --- a/drivers/hwmon/pmbus/tps40422.c +++ b/drivers/hwmon/pmbus/tps40422.c @@ -25,10 +25,9 @@ static struct pmbus_driver_info tps40422_info = { | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, }; -static int tps40422_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tps40422_probe(struct i2c_client *client) { - return pmbus_do_probe(client, id, &tps40422_info); + return pmbus_do_probe(client, &tps40422_info); } static const struct i2c_device_id tps40422_id[] = { @@ -43,7 +42,7 @@ static struct i2c_driver tps40422_driver = { .driver = { .name = "tps40422", }, - .probe = tps40422_probe, + .probe_new = tps40422_probe, .remove = pmbus_do_remove, .id_table = tps40422_id, }; diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index 157c99ffb52b..db2bdf2a1f02 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -34,6 +34,8 @@ enum chips { #define TPS53681_MFR_SPECIFIC_20 0xe4 /* Number of phases, per page */ +static const struct i2c_device_id tps53679_id[]; + static int tps53679_identify_mode(struct i2c_client *client, struct pmbus_driver_info *info) { @@ -183,8 +185,7 @@ static struct pmbus_driver_info tps53679_info = { .pfunc[5] = PMBUS_HAVE_IOUT, }; -static int tps53679_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tps53679_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct pmbus_driver_info *info; @@ -193,7 +194,7 @@ static int tps53679_probe(struct i2c_client *client, if (dev->of_node) chip_id = (enum chips)of_device_get_match_data(dev); else - chip_id = id->driver_data; + chip_id = i2c_match_id(tps53679_id, client)->driver_data; info = devm_kmemdup(dev, &tps53679_info, sizeof(*info), GFP_KERNEL); if (!info) @@ -220,7 +221,7 @@ static int tps53679_probe(struct i2c_client *client, return -ENODEV; } - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id tps53679_id[] = { @@ -249,7 +250,7 @@ static struct i2c_driver tps53679_driver = { .name = "tps53679", .of_match_table = of_match_ptr(tps53679_of_match), }, - .probe = tps53679_probe, + .probe_new = tps53679_probe, .remove = pmbus_do_remove, .id_table = tps53679_id, }; diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index 81f4c4f166cd..f8017993e2b4 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -487,8 +487,7 @@ static int ucd9000_init_debugfs(struct i2c_client *client, } #endif /* CONFIG_DEBUG_FS */ -static int ucd9000_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ucd9000_probe(struct i2c_client *client) { u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; struct ucd9000_data *data; @@ -523,12 +522,12 @@ static int ucd9000_probe(struct i2c_client *client, if (client->dev.of_node) chip = (enum chips)of_device_get_match_data(&client->dev); else - chip = id->driver_data; + chip = mid->driver_data; - if (chip != ucd9000 && chip != mid->driver_data) + if (chip != ucd9000 && strcmp(client->name, mid->name) != 0) dev_notice(&client->dev, "Device mismatch: Configured %s, detected %s\n", - id->name, mid->name); + client->name, mid->name); data = devm_kzalloc(&client->dev, sizeof(struct ucd9000_data), GFP_KERNEL); @@ -603,7 +602,7 @@ static int ucd9000_probe(struct i2c_client *client, ucd9000_probe_gpio(client, mid, data); - ret = pmbus_do_probe(client, mid, info); + ret = pmbus_do_probe(client, info); if (ret) return ret; @@ -621,7 +620,7 @@ static struct i2c_driver ucd9000_driver = { .name = "ucd9000", .of_match_table = of_match_ptr(ucd9000_of_match), }, - .probe = ucd9000_probe, + .probe_new = ucd9000_probe, .remove = pmbus_do_remove, .id_table = ucd9000_id, }; diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c index 7c04745a9709..e111e25e1619 100644 --- a/drivers/hwmon/pmbus/ucd9200.c +++ b/drivers/hwmon/pmbus/ucd9200.c @@ -71,8 +71,7 @@ static const struct of_device_id __maybe_unused ucd9200_of_match[] = { }; MODULE_DEVICE_TABLE(of, ucd9200_of_match); -static int ucd9200_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ucd9200_probe(struct i2c_client *client) { u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; struct pmbus_driver_info *info; @@ -106,12 +105,12 @@ static int ucd9200_probe(struct i2c_client *client, if (client->dev.of_node) chip = (enum chips)of_device_get_match_data(&client->dev); else - chip = id->driver_data; + chip = mid->driver_data; - if (chip != ucd9200 && chip != mid->driver_data) + if (chip != ucd9200 && strcmp(client->name, mid->name) != 0) dev_notice(&client->dev, "Device mismatch: Configured %s, detected %s\n", - id->name, mid->name); + client->name, mid->name); info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info), GFP_KERNEL); @@ -192,7 +191,7 @@ static int ucd9200_probe(struct i2c_client *client, if (mid->driver_data == ucd9240) info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12; - return pmbus_do_probe(client, mid, info); + return pmbus_do_probe(client, info); } /* This is the driver that will be inserted */ @@ -201,7 +200,7 @@ static struct i2c_driver ucd9200_driver = { .name = "ucd9200", .of_match_table = of_match_ptr(ucd9200_of_match), }, - .probe = ucd9200_probe, + .probe_new = ucd9200_probe, .remove = pmbus_do_remove, .id_table = ucd9200_id, }; diff --git a/drivers/hwmon/pmbus/xdpe12284.c b/drivers/hwmon/pmbus/xdpe12284.c index d5103fc9e269..c95ac934fde4 100644 --- a/drivers/hwmon/pmbus/xdpe12284.c +++ b/drivers/hwmon/pmbus/xdpe12284.c @@ -127,8 +127,7 @@ static struct pmbus_driver_info xdpe122_info = { .read_word_data = xdpe122_read_word_data, }; -static int xdpe122_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int xdpe122_probe(struct i2c_client *client) { struct pmbus_driver_info *info; @@ -137,7 +136,7 @@ static int xdpe122_probe(struct i2c_client *client, if (!info) return -ENOMEM; - return pmbus_do_probe(client, id, info); + return pmbus_do_probe(client, info); } static const struct i2c_device_id xdpe122_id[] = { @@ -160,7 +159,7 @@ static struct i2c_driver xdpe122_driver = { .name = "xdpe12284", .of_match_table = of_match_ptr(xdpe122_of_match), }, - .probe = xdpe122_probe, + .probe_new = xdpe122_probe, .remove = pmbus_do_remove, .id_table = xdpe122_id, }; diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index 3a827d0a881d..e8bda340482b 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -301,8 +301,7 @@ static const struct i2c_device_id zl6100_id[] = { }; MODULE_DEVICE_TABLE(i2c, zl6100_id); -static int zl6100_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int zl6100_probe(struct i2c_client *client) { int ret; struct zl6100_data *data; @@ -333,10 +332,10 @@ static int zl6100_probe(struct i2c_client *client, dev_err(&client->dev, "Unsupported device\n"); return -ENODEV; } - if (id->driver_data != mid->driver_data) + if (strcmp(client->name, mid->name) != 0) dev_notice(&client->dev, "Device mismatch: Configured %s, detected %s\n", - id->name, mid->name); + client->name, mid->name); data = devm_kzalloc(&client->dev, sizeof(struct zl6100_data), GFP_KERNEL); @@ -389,14 +388,14 @@ static int zl6100_probe(struct i2c_client *client, info->write_word_data = zl6100_write_word_data; info->write_byte = zl6100_write_byte; - return pmbus_do_probe(client, mid, info); + return pmbus_do_probe(client, info); } static struct i2c_driver zl6100_driver = { .driver = { .name = "zl6100", }, - .probe = zl6100_probe, + .probe_new = zl6100_probe, .remove = pmbus_do_remove, .id_table = zl6100_id, }; |