diff options
Diffstat (limited to 'drivers/hwmon/pmbus')
25 files changed, 799 insertions, 228 deletions
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 629cb45f8557..b6588483fae1 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # PMBus chip drivers configuration # @@ -54,6 +55,33 @@ config SENSORS_IR35221 This driver can also be built as a module. If so, the module will be called ir35521. +config SENSORS_IR38064 + tristate "Infineon IR38064" + help + If you say yes here you get hardware monitoring support for Infineon + IR38064. + + This driver can also be built as a module. If so, the module will + be called ir38064. + +config SENSORS_IRPS5401 + tristate "Infineon IRPS5401" + help + If you say yes here you get hardware monitoring support for the + Infineon IRPS5401 controller. + + This driver can also be built as a module. If so, the module will + be called irps5401. + +config SENSORS_ISL68137 + tristate "Intersil ISL68137" + help + If you say yes here you get hardware monitoring support for Intersil + ISL68137. + + This driver can also be built as a module. If so, the module will + be called isl68137. + config SENSORS_LM25066 tristate "National Semiconductor LM25066 and compatibles" help @@ -135,6 +163,15 @@ config SENSORS_MAX8688 This driver can also be built as a module. If so, the module will be called max8688. +config SENSORS_PXE1610 + tristate "Infineon PXE1610" + help + If you say yes here you get hardware monitoring support for Infineon + PXE1610. + + This driver can also be built as a module. If so, the module will + be called pxe1610. + config SENSORS_TPS40422 tristate "TI TPS40422" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index ea0e39518c21..c950ea9a5d00 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -8,6 +8,9 @@ obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o obj-$(CONFIG_SENSORS_IR35221) += ir35221.o +obj-$(CONFIG_SENSORS_IR38064) += ir38064.o +obj-$(CONFIG_SENSORS_IRPS5401) += irps5401.o +obj-$(CONFIG_SENSORS_ISL68137) += isl68137.o obj-$(CONFIG_SENSORS_LM25066) += lm25066.o obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o @@ -16,6 +19,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_PXE1610) += pxe1610.o obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index f569372c9204..5caa37fbfc18 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -1,19 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller * and Digital Power Monitor * * Copyright (c) 2011 Ericsson AB. * Copyright (c) 2018 Guenter Roeck - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/kernel.h> @@ -23,6 +14,8 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/bitops.h> +#include <linux/bitfield.h> +#include <linux/log2.h> #include "pmbus.h" enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 }; @@ -78,6 +71,18 @@ enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 }; #define ADM1075_VAUX_OV_WARN BIT(7) #define ADM1075_VAUX_UV_WARN BIT(6) +#define ADM1275_VI_AVG_SHIFT 0 +#define ADM1275_VI_AVG_MASK GENMASK(ADM1275_VI_AVG_SHIFT + 2, \ + ADM1275_VI_AVG_SHIFT) +#define ADM1275_SAMPLES_AVG_MAX 128 + +#define ADM1278_PWR_AVG_SHIFT 11 +#define ADM1278_PWR_AVG_MASK GENMASK(ADM1278_PWR_AVG_SHIFT + 2, \ + ADM1278_PWR_AVG_SHIFT) +#define ADM1278_VI_AVG_SHIFT 8 +#define ADM1278_VI_AVG_MASK GENMASK(ADM1278_VI_AVG_SHIFT + 2, \ + ADM1278_VI_AVG_SHIFT) + struct adm1275_data { int id; bool have_oc_fault; @@ -89,6 +94,7 @@ struct adm1275_data { bool have_pin_min; bool have_pin_max; bool have_temp_max; + bool have_power_sampling; struct pmbus_driver_info info; }; @@ -164,6 +170,62 @@ static const struct coefficients adm1293_coefficients[] = { [18] = { 7658, 0, -3 }, /* power, 21V, irange200 */ }; +static int adm1275_read_pmon_config(const struct adm1275_data *data, + struct i2c_client *client, bool is_power) +{ + int shift, ret; + u16 mask; + + /* + * The PMON configuration register is a 16-bit register only on chips + * supporting power average sampling. On other chips it is an 8-bit + * register. + */ + if (data->have_power_sampling) { + ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); + mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK; + shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT; + } else { + ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); + mask = ADM1275_VI_AVG_MASK; + shift = ADM1275_VI_AVG_SHIFT; + } + if (ret < 0) + return ret; + + return (ret & mask) >> shift; +} + +static int adm1275_write_pmon_config(const struct adm1275_data *data, + struct i2c_client *client, + bool is_power, u16 word) +{ + int shift, ret; + u16 mask; + + if (data->have_power_sampling) { + ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); + mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK; + shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT; + } else { + ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); + mask = ADM1275_VI_AVG_MASK; + shift = ADM1275_VI_AVG_SHIFT; + } + if (ret < 0) + return ret; + + word = (ret & ~mask) | ((word << shift) & mask); + if (data->have_power_sampling) + ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, + word); + else + ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG, + word); + + return ret; +} + static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); @@ -242,6 +304,21 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) if (!data->have_temp_max) return -ENXIO; break; + case PMBUS_VIRT_POWER_SAMPLES: + if (!data->have_power_sampling) + return -ENXIO; + ret = adm1275_read_pmon_config(data, client, true); + if (ret < 0) + break; + ret = BIT(ret); + break; + case PMBUS_VIRT_IN_SAMPLES: + case PMBUS_VIRT_CURR_SAMPLES: + ret = adm1275_read_pmon_config(data, client, false); + if (ret < 0) + break; + ret = BIT(ret); + break; default: ret = -ENODATA; break; @@ -286,6 +363,19 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, case PMBUS_VIRT_RESET_TEMP_HISTORY: ret = pmbus_write_word_data(client, 0, ADM1278_PEAK_TEMP, 0); break; + case PMBUS_VIRT_POWER_SAMPLES: + if (!data->have_power_sampling) + return -ENXIO; + word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX); + ret = adm1275_write_pmon_config(data, client, true, + ilog2(word)); + break; + case PMBUS_VIRT_IN_SAMPLES: + case PMBUS_VIRT_CURR_SAMPLES: + word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX); + ret = adm1275_write_pmon_config(data, client, false, + ilog2(word)); + break; default: ret = -ENODATA; break; @@ -439,7 +529,8 @@ static int adm1275_probe(struct i2c_client *client, info->format[PSC_CURRENT_OUT] = direct; info->format[PSC_POWER] = direct; info->format[PSC_TEMPERATURE] = direct; - info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; + info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_SAMPLES; info->read_word_data = adm1275_read_word_data; info->read_byte_data = adm1275_read_byte_data; @@ -480,6 +571,7 @@ static int adm1275_probe(struct i2c_client *client, data->have_vout = true; data->have_pin_max = true; data->have_temp_max = true; + data->have_power_sampling = true; coefficients = adm1272_coefficients; vindex = (config & ADM1275_VRANGE) ? 1 : 0; @@ -565,6 +657,7 @@ static int adm1275_probe(struct i2c_client *client, data->have_vout = true; data->have_pin_max = true; data->have_temp_max = true; + data->have_power_sampling = true; coefficients = adm1278_coefficients; vindex = 0; @@ -600,6 +693,7 @@ static int adm1275_probe(struct i2c_client *client, data->have_pin_min = true; data->have_pin_max = true; data->have_mfr_vaux_status = true; + data->have_power_sampling = true; coefficients = adm1293_coefficients; diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index 93d9a9ea112b..ee2ee9e3ffd7 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -1,10 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright 2017 IBM Corp. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #include <linux/bitops.h> diff --git a/drivers/hwmon/pmbus/ir35221.c b/drivers/hwmon/pmbus/ir35221.c index 977315b0fd90..0d878bcd6d26 100644 --- a/drivers/hwmon/pmbus/ir35221.c +++ b/drivers/hwmon/pmbus/ir35221.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for IR35221 * * Copyright (C) IBM Corporation 2017. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/err.h> diff --git a/drivers/hwmon/pmbus/ir38064.c b/drivers/hwmon/pmbus/ir38064.c new file mode 100644 index 000000000000..1820f5077f66 --- /dev/null +++ b/drivers/hwmon/pmbus/ir38064.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hardware monitoring driver for Infineon IR38064 + * + * Copyright (c) 2017 Google Inc + * + * VOUT_MODE is not supported by the device. The driver fakes VOUT linear16 + * mode with exponent value -8 as direct mode with m=256/b=0/R=0. + * + * The device supports VOUT_PEAK, IOUT_PEAK, and TEMPERATURE_PEAK, however + * this driver does not currently support them. + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include "pmbus.h" + +static struct pmbus_driver_info ir38064_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .format[PSC_TEMPERATURE] = linear, + .m[PSC_VOLTAGE_OUT] = 256, + .b[PSC_VOLTAGE_OUT] = 0, + .R[PSC_VOLTAGE_OUT] = 0, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_POUT, +}; + +static int ir38064_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return pmbus_do_probe(client, id, &ir38064_info); +} + +static const struct i2c_device_id ir38064_id[] = { + {"ir38064", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ir38064_id); + +/* This is the driver that will be inserted */ +static struct i2c_driver ir38064_driver = { + .driver = { + .name = "ir38064", + }, + .probe = ir38064_probe, + .remove = pmbus_do_remove, + .id_table = ir38064_id, +}; + +module_i2c_driver(ir38064_driver); + +MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>"); +MODULE_DESCRIPTION("PMBus driver for Infineon IR38064"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/pmbus/irps5401.c b/drivers/hwmon/pmbus/irps5401.c new file mode 100644 index 000000000000..d37daa001fb3 --- /dev/null +++ b/drivers/hwmon/pmbus/irps5401.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hardware monitoring driver for the Infineon IRPS5401M PMIC. + * + * Copyright (c) 2019 SED Systems, a division of Calian Ltd. + * + * The device supports VOUT_PEAK, IOUT_PEAK, and TEMPERATURE_PEAK, however + * this driver does not currently support them. + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include "pmbus.h" + +#define IRPS5401_SW_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | \ + PMBUS_HAVE_STATUS_INPUT | \ + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \ + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \ + PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | \ + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP) + +#define IRPS5401_LDO_FUNC (PMBUS_HAVE_VIN | \ + PMBUS_HAVE_STATUS_INPUT | \ + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \ + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \ + PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | \ + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP) + +static struct pmbus_driver_info irps5401_info = { + .pages = 5, + .func[0] = IRPS5401_SW_FUNC, + .func[1] = IRPS5401_SW_FUNC, + .func[2] = IRPS5401_SW_FUNC, + .func[3] = IRPS5401_SW_FUNC, + .func[4] = IRPS5401_LDO_FUNC, +}; + +static int irps5401_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return pmbus_do_probe(client, id, &irps5401_info); +} + +static const struct i2c_device_id irps5401_id[] = { + {"irps5401", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, irps5401_id); + +static struct i2c_driver irps5401_driver = { + .driver = { + .name = "irps5401", + }, + .probe = irps5401_probe, + .remove = pmbus_do_remove, + .id_table = irps5401_id, +}; + +module_i2c_driver(irps5401_driver); + +MODULE_AUTHOR("Robert Hancock"); +MODULE_DESCRIPTION("PMBus driver for Infineon IRPS5401"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c new file mode 100644 index 000000000000..515596c92fe1 --- /dev/null +++ b/drivers/hwmon/pmbus/isl68137.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hardware monitoring driver for Intersil ISL68137 + * + * Copyright (c) 2017 Google Inc + * + */ + +#include <linux/err.h> +#include <linux/hwmon-sysfs.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include "pmbus.h" + +#define ISL68137_VOUT_AVS 0x30 + +static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, + int page, + char *buf) +{ + int val = pmbus_read_byte_data(client, page, PMBUS_OPERATION); + + return sprintf(buf, "%d\n", + (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS ? 1 : 0); +} + +static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client, + int page, + const char *buf, size_t count) +{ + int rc, op_val; + bool result; + + rc = kstrtobool(buf, &result); + if (rc) + return rc; + + op_val = result ? ISL68137_VOUT_AVS : 0; + + /* + * Writes to VOUT setpoint over AVSBus will persist after the VRM is + * switched to PMBus control. Switching back to AVSBus control + * restores this persisted setpoint rather than re-initializing to + * PMBus VOUT_COMMAND. Writing VOUT_COMMAND first over PMBus before + * enabling AVS control is the workaround. + */ + if (op_val == ISL68137_VOUT_AVS) { + rc = pmbus_read_word_data(client, page, PMBUS_VOUT_COMMAND); + if (rc < 0) + return rc; + + rc = pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND, + rc); + if (rc < 0) + return rc; + } + + rc = pmbus_update_byte_data(client, page, PMBUS_OPERATION, + ISL68137_VOUT_AVS, op_val); + + return (rc < 0) ? rc : count; +} + +static ssize_t isl68137_avs_enable_show(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + return isl68137_avs_enable_show_page(client, attr->index, buf); +} + +static ssize_t isl68137_avs_enable_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + return isl68137_avs_enable_store_page(client, attr->index, buf, count); +} + +static SENSOR_DEVICE_ATTR_RW(avs0_enable, isl68137_avs_enable, 0); +static SENSOR_DEVICE_ATTR_RW(avs1_enable, isl68137_avs_enable, 1); + +static struct attribute *enable_attrs[] = { + &sensor_dev_attr_avs0_enable.dev_attr.attr, + &sensor_dev_attr_avs1_enable.dev_attr.attr, + NULL, +}; + +static const struct attribute_group enable_group = { + .attrs = enable_attrs, +}; + +static const struct attribute_group *attribute_groups[] = { + &enable_group, + NULL, +}; + +static struct pmbus_driver_info isl68137_info = { + .pages = 2, + .format[PSC_VOLTAGE_IN] = direct, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_CURRENT_IN] = direct, + .format[PSC_CURRENT_OUT] = direct, + .format[PSC_POWER] = direct, + .format[PSC_TEMPERATURE] = direct, + .m[PSC_VOLTAGE_IN] = 1, + .b[PSC_VOLTAGE_IN] = 0, + .R[PSC_VOLTAGE_IN] = 3, + .m[PSC_VOLTAGE_OUT] = 1, + .b[PSC_VOLTAGE_OUT] = 0, + .R[PSC_VOLTAGE_OUT] = 3, + .m[PSC_CURRENT_IN] = 1, + .b[PSC_CURRENT_IN] = 0, + .R[PSC_CURRENT_IN] = 2, + .m[PSC_CURRENT_OUT] = 1, + .b[PSC_CURRENT_OUT] = 0, + .R[PSC_CURRENT_OUT] = 1, + .m[PSC_POWER] = 1, + .b[PSC_POWER] = 0, + .R[PSC_POWER] = 0, + .m[PSC_TEMPERATURE] = 1, + .b[PSC_TEMPERATURE] = 0, + .R[PSC_TEMPERATURE] = 0, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN + | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 + | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, + .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, + .groups = attribute_groups, +}; + +static int isl68137_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return pmbus_do_probe(client, id, &isl68137_info); +} + +static const struct i2c_device_id isl68137_id[] = { + {"isl68137", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, isl68137_id); + +/* This is the driver that will be inserted */ +static struct i2c_driver isl68137_driver = { + .driver = { + .name = "isl68137", + }, + .probe = isl68137_probe, + .remove = pmbus_do_remove, + .id_table = isl68137_id, +}; + +module_i2c_driver(isl68137_driver); + +MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>"); +MODULE_DESCRIPTION("PMBus driver for Intersil ISL68137"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index 53db78753a0d..05fce86f1f81 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for LM25056 / LM25066 / LM5064 / LM5066 * * Copyright (c) 2011 Ericsson AB. * Copyright (c) 2013 Guenter Roeck - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/bitops.h> @@ -26,6 +13,7 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/log2.h> #include "pmbus.h" enum chips { lm25056, lm25066, lm5064, lm5066, lm5066i }; @@ -39,12 +27,15 @@ enum chips { lm25056, lm25066, lm5064, lm5066, lm5066i }; #define LM25066_CLEAR_PIN_PEAK 0xd6 #define LM25066_DEVICE_SETUP 0xd9 #define LM25066_READ_AVG_VIN 0xdc +#define LM25066_SAMPLES_FOR_AVG 0xdb #define LM25066_READ_AVG_VOUT 0xdd #define LM25066_READ_AVG_IIN 0xde #define LM25066_READ_AVG_PIN 0xdf #define LM25066_DEV_SETUP_CL BIT(4) /* Current limit */ +#define LM25066_SAMPLES_FOR_AVG_MAX 4096 + /* LM25056 only */ #define LM25056_VAUX_OV_WARN_LIMIT 0xe3 @@ -284,6 +275,12 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg) case PMBUS_VIRT_RESET_PIN_HISTORY: ret = 0; break; + case PMBUS_VIRT_SAMPLES: + ret = pmbus_read_byte_data(client, 0, LM25066_SAMPLES_FOR_AVG); + if (ret < 0) + break; + ret = 1 << ret; + break; default: ret = -ENODATA; break; @@ -398,6 +395,11 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg, case PMBUS_VIRT_RESET_PIN_HISTORY: ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK); break; + case PMBUS_VIRT_SAMPLES: + word = clamp_val(word, 1, LM25066_SAMPLES_FOR_AVG_MAX); + ret = pmbus_write_byte_data(client, 0, LM25066_SAMPLES_FOR_AVG, + ilog2(word)); + break; default: ret = -ENODATA; break; @@ -438,7 +440,7 @@ static int lm25066_probe(struct i2c_client *client, info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VMON | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT - | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_SAMPLES; if (data->id == lm25056) { info->func[0] |= PMBUS_HAVE_STATUS_VMON; diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 29c0b7219aaa..f01f4887fb2e 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for LTC2978 and compatible chips. * @@ -5,16 +6,6 @@ * Copyright (c) 2013, 2014, 2015 Guenter Roeck * Copyright (c) 2015 Linear Technology * Copyright (c) 2018 Analog Devices Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/delay.h> diff --git a/drivers/hwmon/pmbus/ltc3815.c b/drivers/hwmon/pmbus/ltc3815.c index bb32e6276622..b83a18a58364 100644 --- a/drivers/hwmon/pmbus/ltc3815.c +++ b/drivers/hwmon/pmbus/ltc3815.c @@ -1,18 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for LTC3815 * * Copyright (c) 2015 Linear Technology * Copyright (c) 2015 Guenter Roeck - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/err.h> diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c index fa237a3c3291..b3e7b8d2e69d 100644 --- a/drivers/hwmon/pmbus/max16064.c +++ b/drivers/hwmon/pmbus/max16064.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for Maxim MAX16064 * * Copyright (c) 2011 Ericsson AB. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c index ab74aeae8cf2..ee5f0cdbde06 100644 --- a/drivers/hwmon/pmbus/max20751.c +++ b/drivers/hwmon/pmbus/max20751.c @@ -1,17 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for Maxim MAX20751 * * Copyright (c) 2015 Guenter Roeck - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/kernel.h> diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c index c9dc8799b5e1..69d9029ea410 100644 --- a/drivers/hwmon/pmbus/max31785.c +++ b/drivers/hwmon/pmbus/max31785.c @@ -1,10 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2017 IBM Corp. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #include <linux/kernel.h> diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index 47576c460010..5c63a6600729 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for Maxim MAX34440/MAX34441 * * Copyright (c) 2011 Ericsson AB. * Copyright (c) 2012 Guenter Roeck - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/bitops.h> diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index e951f9b87abb..bc5f4cb6450e 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for Maxim MAX8688 * * Copyright (c) 2011 Ericsson AB. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/bitops.h> diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index f05eaa50535e..c0bc43d01018 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for PMBus devices * * Copyright (c) 2010, 2011 Ericsson AB. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 1d24397d36ec..d198af3a92b6 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -1,22 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * pmbus.h - Common defines and structures for PMBus devices * * Copyright (c) 2010, 2011 Ericsson AB. * Copyright (c) 2012 Guenter Roeck - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef PMBUS_H @@ -217,6 +204,20 @@ enum pmbus_regs { PMBUS_VIRT_PWM_ENABLE_2, PMBUS_VIRT_PWM_ENABLE_3, PMBUS_VIRT_PWM_ENABLE_4, + + /* Samples for average + * + * Drivers wanting to expose functionality for changing the number of + * samples used for average values should implement support in + * {read,write}_word_data callback for either PMBUS_VIRT_SAMPLES if it + * applies to all types of measurements, or any number of specific + * PMBUS_VIRT_*_SAMPLES registers to allow for individual control. + */ + PMBUS_VIRT_SAMPLES, + PMBUS_VIRT_IN_SAMPLES, + PMBUS_VIRT_CURR_SAMPLES, + PMBUS_VIRT_POWER_SAMPLES, + PMBUS_VIRT_TEMP_SAMPLES, }; /* @@ -371,6 +372,7 @@ enum pmbus_sensor_classes { #define PMBUS_HAVE_STATUS_VMON BIT(19) #define PMBUS_HAVE_PWM12 BIT(20) #define PMBUS_HAVE_PWM34 BIT(21) +#define PMBUS_HAVE_SAMPLES BIT(22) #define PMBUS_PAGE_VIRTUAL BIT(31) @@ -417,6 +419,9 @@ struct pmbus_driver_info { /* Regulator functionality, if supported by this chip driver. */ int num_regulators; const struct regulator_desc *reg_desc; + + /* custom attributes */ + const struct attribute_group **groups; }; /* Regulator ops */ diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 2e2b5851139c..8470097907bc 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for PMBus devices * * Copyright (c) 2010, 2011 Ericsson AB. * Copyright (c) 2012 Guenter Roeck - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/debugfs.h> @@ -103,7 +90,7 @@ struct pmbus_data { int max_attributes; int num_attributes; struct attribute_group group; - const struct attribute_group *groups[2]; + const struct attribute_group **groups; struct dentry *debugfs; /* debugfs device directory */ struct pmbus_sensor *sensors; @@ -1073,7 +1060,7 @@ static int pmbus_add_boolean(struct pmbus_data *data, name, seq, type); boolean->s1 = s1; boolean->s2 = s2; - pmbus_attr_init(a, boolean->name, S_IRUGO, pmbus_show_boolean, NULL, + pmbus_attr_init(a, boolean->name, 0444, pmbus_show_boolean, NULL, (reg << 16) | mask); return pmbus_add_attribute(data, &a->dev_attr.attr); @@ -1107,7 +1094,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, sensor->update = update; sensor->convert = convert; pmbus_dev_attr_init(a, sensor->name, - readonly ? S_IRUGO : S_IRUGO | S_IWUSR, + readonly ? 0444 : 0644, pmbus_show_sensor, pmbus_set_sensor); if (pmbus_add_attribute(data, &a->attr)) @@ -1139,7 +1126,7 @@ static int pmbus_add_label(struct pmbus_data *data, snprintf(label->label, sizeof(label->label), "%s%d", lstring, index); - pmbus_dev_attr_init(a, label->name, S_IRUGO, pmbus_show_label, NULL); + pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL); return pmbus_add_attribute(data, &a->attr); } @@ -1230,7 +1217,8 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client, const struct pmbus_driver_info *info, const char *name, int index, int page, - const struct pmbus_sensor_attr *attr) + const struct pmbus_sensor_attr *attr, + bool paged) { struct pmbus_sensor *base; bool upper = !!(attr->gbit & 0xff00); /* need to check STATUS_WORD */ @@ -1238,7 +1226,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client, if (attr->label) { ret = pmbus_add_label(data, name, index, attr->label, - attr->paged ? page + 1 : 0); + paged ? page + 1 : 0); if (ret) return ret; } @@ -1271,6 +1259,30 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client, return 0; } +static bool pmbus_sensor_is_paged(const struct pmbus_driver_info *info, + const struct pmbus_sensor_attr *attr) +{ + int p; + + if (attr->paged) + return true; + + /* + * Some attributes may be present on more than one page despite + * not being marked with the paged attribute. If that is the case, + * then treat the sensor as being paged and add the page suffix to the + * attribute name. + * We don't just add the paged attribute to all such attributes, in + * order to maintain the un-suffixed labels in the case where the + * attribute is only on page 0. + */ + for (p = 1; p < info->pages; p++) { + if (info->func[p] & attr->func) + return true; + } + return false; +} + static int pmbus_add_sensor_attrs(struct i2c_client *client, struct pmbus_data *data, const char *name, @@ -1284,14 +1296,15 @@ static int pmbus_add_sensor_attrs(struct i2c_client *client, index = 1; for (i = 0; i < nattrs; i++) { int page, pages; + bool paged = pmbus_sensor_is_paged(info, attrs); - pages = attrs->paged ? info->pages : 1; + pages = paged ? info->pages : 1; for (page = 0; page < pages; page++) { if (!(info->func[page] & attrs->func)) continue; ret = pmbus_add_sensor_attrs_one(client, data, info, name, index, page, - attrs); + attrs, paged); if (ret) return ret; index++; @@ -1901,6 +1914,115 @@ static int pmbus_add_fan_attributes(struct i2c_client *client, return 0; } +struct pmbus_samples_attr { + int reg; + char *name; +}; + +struct pmbus_samples_reg { + int page; + struct pmbus_samples_attr *attr; + struct device_attribute dev_attr; +}; + +static struct pmbus_samples_attr pmbus_samples_registers[] = { + { + .reg = PMBUS_VIRT_SAMPLES, + .name = "samples", + }, { + .reg = PMBUS_VIRT_IN_SAMPLES, + .name = "in_samples", + }, { + .reg = PMBUS_VIRT_CURR_SAMPLES, + .name = "curr_samples", + }, { + .reg = PMBUS_VIRT_POWER_SAMPLES, + .name = "power_samples", + }, { + .reg = PMBUS_VIRT_TEMP_SAMPLES, + .name = "temp_samples", + } +}; + +#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, dev_attr) + +static ssize_t pmbus_show_samples(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int val; + struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_samples_reg *reg = to_samples_reg(devattr); + + val = _pmbus_read_word_data(client, reg->page, reg->attr->reg); + if (val < 0) + return val; + + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t pmbus_set_samples(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + int ret; + long val; + struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_samples_reg *reg = to_samples_reg(devattr); + struct pmbus_data *data = i2c_get_clientdata(client); + + if (kstrtol(buf, 0, &val) < 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + ret = _pmbus_write_word_data(client, reg->page, reg->attr->reg, val); + mutex_unlock(&data->update_lock); + + return ret ? : count; +} + +static int pmbus_add_samples_attr(struct pmbus_data *data, int page, + struct pmbus_samples_attr *attr) +{ + struct pmbus_samples_reg *reg; + + reg = devm_kzalloc(data->dev, sizeof(*reg), GFP_KERNEL); + if (!reg) + return -ENOMEM; + + reg->attr = attr; + reg->page = page; + + pmbus_dev_attr_init(®->dev_attr, attr->name, 0644, + pmbus_show_samples, pmbus_set_samples); + + return pmbus_add_attribute(data, ®->dev_attr.attr); +} + +static int pmbus_add_samples_attributes(struct i2c_client *client, + struct pmbus_data *data) +{ + const struct pmbus_driver_info *info = data->info; + int s; + + if (!(info->func[0] & PMBUS_HAVE_SAMPLES)) + return 0; + + for (s = 0; s < ARRAY_SIZE(pmbus_samples_registers); s++) { + struct pmbus_samples_attr *attr; + int ret; + + attr = &pmbus_samples_registers[s]; + if (!pmbus_check_word_register(client, 0, attr->reg)) + continue; + + ret = pmbus_add_samples_attr(data, 0, attr); + if (ret) + return ret; + } + + return 0; +} + static int pmbus_find_attributes(struct i2c_client *client, struct pmbus_data *data) { @@ -1932,6 +2054,10 @@ static int pmbus_find_attributes(struct i2c_client *client, /* Fans */ ret = pmbus_add_fan_attributes(client, data); + if (ret) + return ret; + + ret = pmbus_add_samples_attributes(client, data); return ret; } @@ -2305,6 +2431,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, struct device *dev = &client->dev; const struct pmbus_platform_data *pdata = dev_get_platdata(dev); struct pmbus_data *data; + size_t groups_num = 0; int ret; if (!info) @@ -2319,6 +2446,15 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, if (!data) return -ENOMEM; + if (info->groups) + while (info->groups[groups_num]) + groups_num++; + + data->groups = devm_kcalloc(dev, groups_num + 2, sizeof(void *), + GFP_KERNEL); + if (!data->groups) + return -ENOMEM; + i2c_set_clientdata(client, data); mutex_init(&data->update_lock); data->dev = dev; @@ -2346,6 +2482,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, } 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); if (IS_ERR(data->hwmon_dev)) { diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c new file mode 100644 index 000000000000..ebe3f023f840 --- /dev/null +++ b/drivers/hwmon/pmbus/pxe1610.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hardware monitoring driver for Infineon PXE1610 + * + * Copyright (c) 2019 Facebook Inc + * + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include "pmbus.h" + +#define PXE1610_NUM_PAGES 3 + +/* Identify chip parameters. */ +static int pxe1610_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) { + u8 vout_mode; + int ret; + + /* Read the register with VOUT scaling value.*/ + ret = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); + if (ret < 0) + return ret; + + vout_mode = ret & GENMASK(4, 0); + + switch (vout_mode) { + case 1: + info->vrm_version = vr12; + break; + case 2: + info->vrm_version = vr13; + break; + default: + return -ENODEV; + } + } + + return 0; +} + +static struct pmbus_driver_info pxe1610_info = { + .pages = PXE1610_NUM_PAGES, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = vid, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_POWER] = linear, + .func[0] = PMBUS_HAVE_VIN + | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN + | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN + | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP + | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP, + .func[1] = PMBUS_HAVE_VIN + | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN + | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN + | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP + | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP, + .func[2] = PMBUS_HAVE_VIN + | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN + | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN + | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP + | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP, + .identify = pxe1610_identify, +}; + +static int pxe1610_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pmbus_driver_info *info; + u8 buf[I2C_SMBUS_BLOCK_MAX]; + int ret; + + if (!i2c_check_functionality( + client->adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA + | I2C_FUNC_SMBUS_READ_WORD_DATA + | I2C_FUNC_SMBUS_READ_BLOCK_DATA)) + return -ENODEV; + + /* + * By default this device doesn't boot to page 0, so set page 0 + * to access all pmbus registers. + */ + i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); + + /* Read Manufacturer id */ + ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf); + if (ret < 0) { + dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n"); + return ret; + } + if (ret != 2 || strncmp(buf, "XP", 2)) { + dev_err(&client->dev, "MFR_ID unrecognized\n"); + return -ENODEV; + } + + info = devm_kmemdup(&client->dev, &pxe1610_info, + sizeof(struct pmbus_driver_info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + return pmbus_do_probe(client, id, info); +} + +static const struct i2c_device_id pxe1610_id[] = { + {"pxe1610", 0}, + {"pxe1110", 0}, + {"pxm1310", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, pxe1610_id); + +static struct i2c_driver pxe1610_driver = { + .driver = { + .name = "pxe1610", + }, + .probe = pxe1610_probe, + .remove = pmbus_do_remove, + .id_table = pxe1610_id, +}; + +module_i2c_driver(pxe1610_driver); + +MODULE_AUTHOR("Vijay Khemka <vijaykhemka@fb.com>"); +MODULE_DESCRIPTION("PMBus driver for Infineon PXE1610, PXE1110 and PXM1310"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/pmbus/tps40422.c b/drivers/hwmon/pmbus/tps40422.c index 32803825d47e..2b83dcda964a 100644 --- a/drivers/hwmon/pmbus/tps40422.c +++ b/drivers/hwmon/pmbus/tps40422.c @@ -1,17 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for TI TPS40422 * * Copyright (c) 2014 Nokia Solutions and Networks. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/kernel.h> diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index 2bc352c5357f..86bb3aca09ed 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -1,18 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for Texas Instruments TPS53679 * * Copyright (c) 2017 Mellanox Technologies. All rights reserved. * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/err.h> @@ -97,7 +88,7 @@ static const struct i2c_device_id tps53679_id[] = { MODULE_DEVICE_TABLE(i2c, tps53679_id); -static const struct of_device_id tps53679_of_match[] = { +static const struct of_device_id __maybe_unused tps53679_of_match[] = { {.compatible = "ti,tps53679"}, {} }; diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index ae93885fccd8..c846759bc1c0 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for UCD90xxx Sequencer and System Health * Controller series * * Copyright (C) 2011 Ericsson AB. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/debugfs.h> @@ -151,7 +138,7 @@ static const struct i2c_device_id ucd9000_id[] = { }; MODULE_DEVICE_TABLE(i2c, ucd9000_id); -static const struct of_device_id ucd9000_of_match[] = { +static const struct of_device_id __maybe_unused ucd9000_of_match[] = { { .compatible = "ti,ucd9000", .data = (void *)ucd9000 diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c index 3ed94585837a..7c04745a9709 100644 --- a/drivers/hwmon/pmbus/ucd9200.c +++ b/drivers/hwmon/pmbus/ucd9200.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for ucd9200 series Digital PWM System Controllers * * Copyright (C) 2011 Ericsson AB. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> @@ -47,7 +34,7 @@ static const struct i2c_device_id ucd9200_id[] = { }; MODULE_DEVICE_TABLE(i2c, ucd9200_id); -static const struct of_device_id ucd9200_of_match[] = { +static const struct of_device_id __maybe_unused ucd9200_of_match[] = { { .compatible = "ti,cd9200", .data = (void *)ucd9200 diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index 771802d7e20d..190b898e404a 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for ZL6100 and compatibles * * Copyright (c) 2011 Ericsson AB. * Copyright (c) 2012 Guenter Roeck - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/bitops.h> |