summaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-04-26 14:59:21 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2021-04-26 14:59:21 -0700
commit47080f2286110c371b9cf75ac7b34a6f2f1cf4ba (patch)
treefdc9cf3da77cffd1add8a9e7c44df988291837c7 /drivers/hwmon
parent55ba0fe059a577fa08f23223991b24564962620f (diff)
parent9049572fb145746725b198a19e27fa2671b80448 (diff)
downloadlinux-47080f2286110c371b9cf75ac7b34a6f2f1cf4ba.tar.bz2
Merge tag 'hwmon-for-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull hwmon updates from Guenter Roeck: "The most notable change is the removal of the amd_energy driver. It was rendered all but unusable by making its attributes privileged-only to work around a security issue. A suggested remedy was rejected by AMD, so the only real solution was to remove the driver. For the future, we'll have to make sure that no privileged-access-only drivers are accepted into the hwmon subsystem in the first place. The hwmon ABI document was updated accordingly. Other changes: PMBus drivers: - Added driver for MAX15301 - Added driver for BluTek BPA-RS600 - Added driver for fsp-3y PSUs and PDUs - Added driver for Infineon IR36021 - Added driver for ST STPDDC60 - Added support for TI TPS53676 to tps53679 driver - Introduced PMBUS symbol namespace. This was made necessary by a suggestion to use its exported functions from outside the hwmon subsystem. - Minor improvements and bug fixes New drivers: - Driver for NZXT Kraken X42/X52/X62/X72 Driver enhancements: - Added support for Intel D5005 to intel-m10-bmc-hwmon driver - Added support for NCT6686D to nct6683 driver Other: - Converted sch5627 and amd9240 drivers to hwmon_device_register_with_info() - Added support for fan drawers capability and present registers to mlxreg-fan driver - Added Dell Latitude E7440 to fan control whitelist in dell-smm driver - Replaced snprintf in show functions with sysfs_emit. Done with coccinelle script for all drivers to preempt endless per-driver submissions of the same change. - Use kobj_to_dev(). Another coccinelle based change to preempt endless per-driver submissions of the same change. - Various minor fixes and improvements" * tag 'hwmon-for-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (38 commits) hwmon: Remove amd_energy driver hwmon: Clarify scope of attribute access hwmon: (pmbus) Introduce PMBUS symbol namespace hwmon: (pmbus) Add pmbus driver for MAX15301 hwmon: (sch5627) Remove unnecessary error path hwmon: (sch5627) Use devres function hwmon: (pmbus/pxe1610) don't bail out when not all pages are active hwmon: Add driver for fsp-3y PSUs and PDUs hwmon: (intel-m10-bmc-hwmon) add sensor support of Intel D5005 card hwmon: (sch5627) Split sch5627_update_device() hwmon: (sch5627) Convert to hwmon_device_register_with_info() hwmon: (nct6683) remove useless function hwmon: (dell-smm) Add Dell Latitude E7440 to fan control whitelist MAINTAINERS: Add keyword pattern for hwmon registration functions hwmon: (mlxreg-fan) Add support for fan drawers capability and present registers hwmon: (pmbus/tps53679) Add support for TI TPS53676 dt-bindings: Add trivial device entry for TPS53676 hwmon: (ftsteutates) Rudimentary typo fixes hwmon: (pmbus) Add driver for BluTek BPA-RS600 dt-bindings: Add vendor prefix and trivial device for BluTek BPA-RS600 ...
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig20
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/adc128d818.c2
-rw-r--r--drivers/hwmon/adm9240.c982
-rw-r--r--drivers/hwmon/amd_energy.c379
-rw-r--r--drivers/hwmon/applesmc.c34
-rw-r--r--drivers/hwmon/corsair-psu.c355
-rw-r--r--drivers/hwmon/dell-smm-hwmon.c8
-rw-r--r--drivers/hwmon/ds1621.c2
-rw-r--r--drivers/hwmon/ftsteutates.c4
-rw-r--r--drivers/hwmon/hwmon.c2
-rw-r--r--drivers/hwmon/ina209.c6
-rw-r--r--drivers/hwmon/ina2xx.c11
-rw-r--r--drivers/hwmon/ina3221.c2
-rw-r--r--drivers/hwmon/intel-m10-bmc-hwmon.c122
-rw-r--r--drivers/hwmon/it87.c12
-rw-r--r--drivers/hwmon/lineage-pem.c8
-rw-r--r--drivers/hwmon/lm63.c2
-rw-r--r--drivers/hwmon/ltc2945.c4
-rw-r--r--drivers/hwmon/ltc2990.c4
-rw-r--r--drivers/hwmon/ltc4151.c2
-rw-r--r--drivers/hwmon/ltc4215.c8
-rw-r--r--drivers/hwmon/ltc4222.c4
-rw-r--r--drivers/hwmon/ltc4260.c4
-rw-r--r--drivers/hwmon/ltc4261.c4
-rw-r--r--drivers/hwmon/max16065.c18
-rw-r--r--drivers/hwmon/max6697.c2
-rw-r--r--drivers/hwmon/mlxreg-fan.c51
-rw-r--r--drivers/hwmon/nct6683.c22
-rw-r--r--drivers/hwmon/nzxt-kraken2.c234
-rw-r--r--drivers/hwmon/occ/common.c69
-rw-r--r--drivers/hwmon/occ/sysfs.c4
-rw-r--r--drivers/hwmon/pmbus/Kconfig51
-rw-r--r--drivers/hwmon/pmbus/Makefile5
-rw-r--r--drivers/hwmon/pmbus/adm1266.c1
-rw-r--r--drivers/hwmon/pmbus/adm1275.c1
-rw-r--r--drivers/hwmon/pmbus/bel-pfe.c1
-rw-r--r--drivers/hwmon/pmbus/bpa-rs600.c173
-rw-r--r--drivers/hwmon/pmbus/fsp-3y.c254
-rw-r--r--drivers/hwmon/pmbus/ibm-cffps.c1
-rw-r--r--drivers/hwmon/pmbus/inspur-ipsps.c29
-rw-r--r--drivers/hwmon/pmbus/ir35221.c1
-rw-r--r--drivers/hwmon/pmbus/ir36021.c80
-rw-r--r--drivers/hwmon/pmbus/ir38064.c1
-rw-r--r--drivers/hwmon/pmbus/irps5401.c1
-rw-r--r--drivers/hwmon/pmbus/isl68137.c1
-rw-r--r--drivers/hwmon/pmbus/lm25066.c1
-rw-r--r--drivers/hwmon/pmbus/ltc2978.c1
-rw-r--r--drivers/hwmon/pmbus/ltc3815.c1
-rw-r--r--drivers/hwmon/pmbus/max15301.c190
-rw-r--r--drivers/hwmon/pmbus/max16064.c1
-rw-r--r--drivers/hwmon/pmbus/max16601.c1
-rw-r--r--drivers/hwmon/pmbus/max20730.c1
-rw-r--r--drivers/hwmon/pmbus/max20751.c1
-rw-r--r--drivers/hwmon/pmbus/max31785.c1
-rw-r--r--drivers/hwmon/pmbus/max34440.c1
-rw-r--r--drivers/hwmon/pmbus/max8688.c1
-rw-r--r--drivers/hwmon/pmbus/mp2975.c1
-rw-r--r--drivers/hwmon/pmbus/pm6764tr.c1
-rw-r--r--drivers/hwmon/pmbus/pmbus.c1
-rw-r--r--drivers/hwmon/pmbus/pmbus.h1
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c63
-rw-r--r--drivers/hwmon/pmbus/pxe1610.c10
-rw-r--r--drivers/hwmon/pmbus/q54sj108a2.c1
-rw-r--r--drivers/hwmon/pmbus/stpddc60.c249
-rw-r--r--drivers/hwmon/pmbus/tps40422.c1
-rw-r--r--drivers/hwmon/pmbus/tps53679.c52
-rw-r--r--drivers/hwmon/pmbus/ucd9000.c1
-rw-r--r--drivers/hwmon/pmbus/ucd9200.c1
-rw-r--r--drivers/hwmon/pmbus/xdpe12284.c1
-rw-r--r--drivers/hwmon/pmbus/zl6100.c1
-rw-r--r--drivers/hwmon/s3c-hwmon.c4
-rw-r--r--drivers/hwmon/sch5627.c521
-rw-r--r--drivers/hwmon/sch5636.c20
-rw-r--r--drivers/hwmon/smm665.c4
-rw-r--r--drivers/hwmon/stts751.c20
-rw-r--r--drivers/hwmon/vexpress-hwmon.c12
-rw-r--r--drivers/hwmon/xgene-hwmon.c14
78 files changed, 2665 insertions, 1496 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 54f04e61fb83..87624902ea80 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -321,16 +321,6 @@ config SENSORS_FAM15H_POWER
This driver can also be built as a module. If so, the module
will be called fam15h_power.
-config SENSORS_AMD_ENERGY
- tristate "AMD RAPL MSR based Energy driver"
- depends on X86
- help
- If you say yes here you get support for core and package energy
- sensors, based on RAPL MSR for AMD family 17h and above CPUs.
-
- This driver can also be built as a module. If so, the module
- will be called as amd_energy.
-
config SENSORS_APPLESMC
tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
depends on INPUT && X86
@@ -1492,6 +1482,16 @@ config SENSORS_NSA320
This driver can also be built as a module. If so, the module
will be called nsa320-hwmon.
+config SENSORS_NZXT_KRAKEN2
+ tristate "NZXT Kraken X42/X51/X62/X72 liquid coolers"
+ depends on USB_HID
+ help
+ If you say yes here you get support for hardware monitoring for the
+ NZXT Kraken X42/X52/X62/X72 all-in-one CPU liquid coolers.
+
+ This driver can also be built as a module. If so, the module
+ will be called nzxt-kraken2.
+
source "drivers/hwmon/occ/Kconfig"
config SENSORS_PCF8591
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index fe38e8a5c979..59e78bc212cf 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -155,6 +155,7 @@ obj-$(CONFIG_SENSORS_NCT7904) += nct7904.o
obj-$(CONFIG_SENSORS_NPCM7XX) += npcm750-pwm-fan.o
obj-$(CONFIG_SENSORS_NSA320) += nsa320-hwmon.o
obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
+obj-$(CONFIG_SENSORS_NZXT_KRAKEN2) += nzxt-kraken2.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c
index 6c9a906631b8..fd938c70293f 100644
--- a/drivers/hwmon/adc128d818.c
+++ b/drivers/hwmon/adc128d818.c
@@ -248,7 +248,7 @@ static ssize_t adc128_alarm_show(struct device *dev,
static umode_t adc128_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct adc128_data *data = dev_get_drvdata(dev);
if (index < ADC128_ATTR_NUM_VOLT) {
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index cc3e0184e720..5677263bcf0d 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -28,6 +28,7 @@
* LM81 extended temp reading not implemented
*/
+#include <linux/bits.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -37,7 +38,6 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
-#include <linux/jiffies.h>
#include <linux/regmap.h>
/* Addresses to scan */
@@ -123,32 +123,18 @@ static inline unsigned int AOUT_FROM_REG(u8 reg)
/* per client data */
struct adm9240_data {
- struct i2c_client *client;
+ struct device *dev;
struct regmap *regmap;
struct mutex update_lock;
- char valid;
- unsigned long last_updated_measure;
- unsigned long last_updated_config;
-
- u8 in[6]; /* ro in0_input */
- u8 in_max[6]; /* rw in0_max */
- u8 in_min[6]; /* rw in0_min */
- u8 fan[2]; /* ro fan1_input */
- u8 fan_min[2]; /* rw fan1_min */
+
u8 fan_div[2]; /* rw fan1_div, read-only accessor */
- s16 temp; /* ro temp1_input, 9-bit sign-extended */
- s8 temp_max[2]; /* rw 0 -> temp_max, 1 -> temp_max_hyst */
- u16 alarms; /* ro alarms */
- u8 aout; /* rw aout_output */
- u8 vid; /* ro vid */
u8 vrm; /* -- vrm set on startup, no accessor */
};
/* write new fan div, callers must hold data->update_lock */
-static int adm9240_write_fan_div(struct adm9240_data *data, int nr,
- u8 fan_div)
+static int adm9240_write_fan_div(struct adm9240_data *data, int channel, u8 fan_div)
{
- unsigned int reg, old, shift = (nr + 2) * 2;
+ unsigned int reg, old, shift = (channel + 2) * 2;
int err;
err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, &reg);
@@ -160,336 +146,13 @@ static int adm9240_write_fan_div(struct adm9240_data *data, int nr,
err = regmap_write(data->regmap, ADM9240_REG_VID_FAN_DIV, reg);
if (err < 0)
return err;
- dev_dbg(&data->client->dev,
- "fan%d clock divider changed from %u to %u\n",
- nr + 1, 1 << old, 1 << fan_div);
-
- return 0;
-}
-
-static int adm9240_update_measure(struct adm9240_data *data)
-{
- unsigned int val;
- u8 regs[2];
- int err;
- int i;
-
- err = regmap_bulk_read(data->regmap, ADM9240_REG_IN(0), &data->in[0], 6);
- if (err < 0)
- return err;
- err = regmap_bulk_read(data->regmap, ADM9240_REG_INT(0), &regs, 2);
- if (err < 0)
- return err;
-
- data->alarms = regs[0] | regs[1] << 8;
-
- /*
- * read temperature: assume temperature changes less than
- * 0.5'C per two measurement cycles thus ignore possible
- * but unlikely aliasing error on lsb reading. --Grant
- */
- err = regmap_read(data->regmap, ADM9240_REG_TEMP, &val);
- if (err < 0)
- return err;
- data->temp = val << 8;
- err = regmap_read(data->regmap, ADM9240_REG_TEMP_CONF, &val);
- if (err < 0)
- return err;
- data->temp |= val;
-
- err = regmap_bulk_read(data->regmap, ADM9240_REG_FAN(0),
- &data->fan[0], 2);
- if (err < 0)
- return err;
-
- for (i = 0; i < 2; i++) { /* read fans */
- /* adjust fan clock divider on overflow */
- if (data->valid && data->fan[i] == 255 &&
- data->fan_div[i] < 3) {
-
- err = adm9240_write_fan_div(data, i,
- ++data->fan_div[i]);
- if (err < 0)
- return err;
-
- /* adjust fan_min if active, but not to 0 */
- if (data->fan_min[i] < 255 &&
- data->fan_min[i] >= 2)
- data->fan_min[i] /= 2;
- }
- }
+ dev_dbg(data->dev,
+ "fan%d clock divider changed from %lu to %lu\n",
+ channel + 1, BIT(old), BIT(fan_div));
return 0;
}
-static int adm9240_update_config(struct adm9240_data *data)
-{
- unsigned int val;
- int i;
- int err;
-
- for (i = 0; i < 6; i++) {
- err = regmap_raw_read(data->regmap, ADM9240_REG_IN_MIN(i),
- &data->in_min[i], 1);
- if (err < 0)
- return err;
- err = regmap_raw_read(data->regmap, ADM9240_REG_IN_MAX(i),
- &data->in_max[i], 1);
- if (err < 0)
- return err;
- }
- err = regmap_bulk_read(data->regmap, ADM9240_REG_FAN_MIN(0),
- &data->fan_min[0], 2);
- if (err < 0)
- return err;
- err = regmap_bulk_read(data->regmap, ADM9240_REG_TEMP_MAX(0),
- &data->temp_max[0], 2);
- if (err < 0)
- return err;
-
- /* read fan divs and 5-bit VID */
- err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, &val);
- if (err < 0)
- return err;
- data->fan_div[0] = (val >> 4) & 3;
- data->fan_div[1] = (val >> 6) & 3;
- data->vid = val & 0x0f;
- err = regmap_read(data->regmap, ADM9240_REG_VID4, &val);
- if (err < 0)
- return err;
- data->vid |= (val & 1) << 4;
- /* read analog out */
- err = regmap_raw_read(data->regmap, ADM9240_REG_ANALOG_OUT,
- &data->aout, 1);
-
- return err;
-}
-
-static struct adm9240_data *adm9240_update_device(struct device *dev)
-{
- struct adm9240_data *data = dev_get_drvdata(dev);
- int err;
-
- mutex_lock(&data->update_lock);
-
- /* minimum measurement cycle: 1.75 seconds */
- if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4))
- || !data->valid) {
- err = adm9240_update_measure(data);
- if (err < 0) {
- data->valid = 0;
- mutex_unlock(&data->update_lock);
- return ERR_PTR(err);
- }
- data->last_updated_measure = jiffies;
- }
-
- /* minimum config reading cycle: 300 seconds */
- if (time_after(jiffies, data->last_updated_config + (HZ * 300))
- || !data->valid) {
- err = adm9240_update_config(data);
- if (err < 0) {
- data->valid = 0;
- mutex_unlock(&data->update_lock);
- return ERR_PTR(err);
- }
- data->last_updated_config = jiffies;
- data->valid = 1;
- }
- mutex_unlock(&data->update_lock);
- return data;
-}
-
-/*** sysfs accessors ***/
-
-/* temperature */
-static ssize_t temp1_input_show(struct device *dev,
- struct device_attribute *dummy, char *buf)
-{
- struct adm9240_data *data = adm9240_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- return sprintf(buf, "%d\n", data->temp / 128 * 500); /* 9-bit value */
-}
-
-static ssize_t max_show(struct device *dev, struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adm9240_data *data = adm9240_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- return sprintf(buf, "%d\n", data->temp_max[attr->index] * 1000);
-}
-
-static ssize_t max_store(struct device *dev, struct device_attribute *devattr,
- const char *buf, size_t count)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adm9240_data *data = dev_get_drvdata(dev);
- long val;
- int err;
-
- err = kstrtol(buf, 10, &val);
- if (err)
- return err;
-
- mutex_lock(&data->update_lock);
- data->temp_max[attr->index] = TEMP_TO_REG(val);
- err = regmap_write(data->regmap, ADM9240_REG_TEMP_MAX(attr->index),
- data->temp_max[attr->index]);
- mutex_unlock(&data->update_lock);
- return err < 0 ? err : count;
-}
-
-static DEVICE_ATTR_RO(temp1_input);
-static SENSOR_DEVICE_ATTR_RW(temp1_max, max, 0);
-static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, max, 1);
-
-/* voltage */
-static ssize_t in_show(struct device *dev, struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adm9240_data *data = adm9240_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- return sprintf(buf, "%d\n", IN_FROM_REG(data->in[attr->index],
- attr->index));
-}
-
-static ssize_t in_min_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adm9240_data *data = adm9240_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[attr->index],
- attr->index));
-}
-
-static ssize_t in_max_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adm9240_data *data = adm9240_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[attr->index],
- attr->index));
-}
-
-static ssize_t in_min_store(struct device *dev,
- struct device_attribute *devattr, const char *buf,
- size_t count)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adm9240_data *data = dev_get_drvdata(dev);
- unsigned long val;
- int err;
-
- err = kstrtoul(buf, 10, &val);
- if (err)
- return err;
-
- mutex_lock(&data->update_lock);
- data->in_min[attr->index] = IN_TO_REG(val, attr->index);
- err = regmap_write(data->regmap, ADM9240_REG_IN_MIN(attr->index),
- data->in_min[attr->index]);
- mutex_unlock(&data->update_lock);
- return err < 0 ? err : count;
-}
-
-static ssize_t in_max_store(struct device *dev,
- struct device_attribute *devattr, const char *buf,
- size_t count)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adm9240_data *data = dev_get_drvdata(dev);
- unsigned long val;
- int err;
-
- err = kstrtoul(buf, 10, &val);
- if (err)
- return err;
-
- mutex_lock(&data->update_lock);
- data->in_max[attr->index] = IN_TO_REG(val, attr->index);
- err = regmap_write(data->regmap, ADM9240_REG_IN_MAX(attr->index),
- data->in_max[attr->index]);
- mutex_unlock(&data->update_lock);
- return err < 0 ? err : count;
-}
-
-static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0);
-static SENSOR_DEVICE_ATTR_RW(in0_min, in_min, 0);
-static SENSOR_DEVICE_ATTR_RW(in0_max, in_max, 0);
-static SENSOR_DEVICE_ATTR_RO(in1_input, in, 1);
-static SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 1);
-static SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 1);
-static SENSOR_DEVICE_ATTR_RO(in2_input, in, 2);
-static SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 2);
-static SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 2);
-static SENSOR_DEVICE_ATTR_RO(in3_input, in, 3);
-static SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 3);
-static SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 3);
-static SENSOR_DEVICE_ATTR_RO(in4_input, in, 4);
-static SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 4);
-static SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 4);
-static SENSOR_DEVICE_ATTR_RO(in5_input, in, 5);
-static SENSOR_DEVICE_ATTR_RW(in5_min, in_min, 5);
-static SENSOR_DEVICE_ATTR_RW(in5_max, in_max, 5);
-
-/* fans */
-static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adm9240_data *data = adm9240_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index],
- 1 << data->fan_div[attr->index]));
-}
-
-static ssize_t fan_min_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adm9240_data *data = adm9240_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[attr->index],
- 1 << data->fan_div[attr->index]));
-}
-
-static ssize_t fan_div_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adm9240_data *data = adm9240_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- return sprintf(buf, "%d\n", 1 << data->fan_div[attr->index]);
-}
-
/*
* set fan speed low limit:
*
@@ -501,38 +164,25 @@ static ssize_t fan_div_show(struct device *dev,
* - otherwise: select fan clock divider to suit fan speed low limit,
* measurement code may adjust registers to ensure fan speed reading
*/
-static ssize_t fan_min_store(struct device *dev,
- struct device_attribute *devattr,
- const char *buf, size_t count)
+static int adm9240_fan_min_write(struct adm9240_data *data, int channel, long val)
{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adm9240_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
- int nr = attr->index;
u8 new_div;
- unsigned long val;
+ u8 fan_min;
int err;
- err = kstrtoul(buf, 10, &val);
- if (err)
- return err;
-
mutex_lock(&data->update_lock);
if (!val) {
- data->fan_min[nr] = 255;
- new_div = data->fan_div[nr];
-
- dev_dbg(&client->dev, "fan%u low limit set disabled\n",
- nr + 1);
+ fan_min = 255;
+ new_div = data->fan_div[channel];
+ dev_dbg(data->dev, "fan%u low limit set disabled\n", channel + 1);
} else if (val < 1350000 / (8 * 254)) {
new_div = 3;
- data->fan_min[nr] = 254;
-
- dev_dbg(&client->dev, "fan%u low limit set minimum %u\n",
- nr + 1, FAN_FROM_REG(254, 1 << new_div));
+ fan_min = 254;
+ dev_dbg(data->dev, "fan%u low limit set minimum %u\n",
+ channel + 1, FAN_FROM_REG(254, BIT(new_div)));
} else {
unsigned int new_min = 1350000 / val;
@@ -544,87 +194,55 @@ static ssize_t fan_min_store(struct device *dev,
if (!new_min) /* keep > 0 */
new_min++;
- data->fan_min[nr] = new_min;
+ fan_min = new_min;
- dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n",
- nr + 1, FAN_FROM_REG(new_min, 1 << new_div));
+ dev_dbg(data->dev, "fan%u low limit set fan speed %u\n",
+ channel + 1, FAN_FROM_REG(new_min, BIT(new_div)));
}
- if (new_div != data->fan_div[nr]) {
- data->fan_div[nr] = new_div;
- adm9240_write_fan_div(data, nr, new_div);
+ if (new_div != data->fan_div[channel]) {
+ data->fan_div[channel] = new_div;
+ adm9240_write_fan_div(data, channel, new_div);
}
- err = regmap_write(data->regmap, ADM9240_REG_FAN_MIN(nr),
- data->fan_min[nr]);
+ err = regmap_write(data->regmap, ADM9240_REG_FAN_MIN(channel), fan_min);
mutex_unlock(&data->update_lock);
- return err < 0 ? err : count;
-}
-
-static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
-static SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0);
-static SENSOR_DEVICE_ATTR_RO(fan1_div, fan_div, 0);
-static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
-static SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1);
-static SENSOR_DEVICE_ATTR_RO(fan2_div, fan_div, 1);
-/* alarms */
-static ssize_t alarms_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct adm9240_data *data = adm9240_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- return sprintf(buf, "%u\n", data->alarms);
+ return err;
}
-static DEVICE_ATTR_RO(alarms);
-static ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- int bitnr = to_sensor_dev_attr(attr)->index;
- struct adm9240_data *data = adm9240_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
-}
-static SENSOR_DEVICE_ATTR_RO(in0_alarm, alarm, 0);
-static SENSOR_DEVICE_ATTR_RO(in1_alarm, alarm, 1);
-static SENSOR_DEVICE_ATTR_RO(in2_alarm, alarm, 2);
-static SENSOR_DEVICE_ATTR_RO(in3_alarm, alarm, 3);
-static SENSOR_DEVICE_ATTR_RO(in4_alarm, alarm, 8);
-static SENSOR_DEVICE_ATTR_RO(in5_alarm, alarm, 9);
-static SENSOR_DEVICE_ATTR_RO(temp1_alarm, alarm, 4);
-static SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 6);
-static SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 7);
-
-/* vid */
static ssize_t cpu0_vid_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct adm9240_data *data = adm9240_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
+ struct adm9240_data *data = dev_get_drvdata(dev);
+ unsigned int regval;
+ int err;
+ u8 vid;
- return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+ err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, &regval);
+ if (err < 0)
+ return err;
+ vid = regval & 0x0f;
+ err = regmap_read(data->regmap, ADM9240_REG_VID4, &regval);
+ if (err < 0)
+ return err;
+ vid |= (regval & 1) << 4;
+ return sprintf(buf, "%d\n", vid_from_reg(vid, data->vrm));
}
static DEVICE_ATTR_RO(cpu0_vid);
-/* analog output */
static ssize_t aout_output_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct adm9240_data *data = adm9240_update_device(dev);
+ struct adm9240_data *data = dev_get_drvdata(dev);
+ unsigned int regval;
+ int err;
- if (IS_ERR(data))
- return PTR_ERR(data);
+ err = regmap_read(data->regmap, ADM9240_REG_ANALOG_OUT, &regval);
+ if (err)
+ return err;
- return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout));
+ return sprintf(buf, "%d\n", AOUT_FROM_REG(regval));
}
static ssize_t aout_output_store(struct device *dev,
@@ -639,76 +257,13 @@ static ssize_t aout_output_store(struct device *dev,
if (err)
return err;
- mutex_lock(&data->update_lock);
- data->aout = AOUT_TO_REG(val);
- err = regmap_write(data->regmap, ADM9240_REG_ANALOG_OUT, data->aout);
- mutex_unlock(&data->update_lock);
+ err = regmap_write(data->regmap, ADM9240_REG_ANALOG_OUT, AOUT_TO_REG(val));
return err < 0 ? err : count;
}
static DEVICE_ATTR_RW(aout_output);
-static ssize_t alarm_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct adm9240_data *data = dev_get_drvdata(dev);
- unsigned long val;
- int err;
-
- if (kstrtoul(buf, 10, &val) || val != 0)
- return -EINVAL;
-
- mutex_lock(&data->update_lock);
- err = regmap_write(data->regmap, ADM9240_REG_CHASSIS_CLEAR, 0x80);
- data->valid = 0; /* Force cache refresh */
- mutex_unlock(&data->update_lock);
- if (err < 0)
- return err;
- dev_dbg(&data->client->dev, "chassis intrusion latch cleared\n");
-
- return count;
-}
-static SENSOR_DEVICE_ATTR_RW(intrusion0_alarm, alarm, 12);
-
static struct attribute *adm9240_attrs[] = {
- &sensor_dev_attr_in0_input.dev_attr.attr,
- &sensor_dev_attr_in0_min.dev_attr.attr,
- &sensor_dev_attr_in0_max.dev_attr.attr,
- &sensor_dev_attr_in0_alarm.dev_attr.attr,
- &sensor_dev_attr_in1_input.dev_attr.attr,
- &sensor_dev_attr_in1_min.dev_attr.attr,
- &sensor_dev_attr_in1_max.dev_attr.attr,
- &sensor_dev_attr_in1_alarm.dev_attr.attr,
- &sensor_dev_attr_in2_input.dev_attr.attr,
- &sensor_dev_attr_in2_min.dev_attr.attr,
- &sensor_dev_attr_in2_max.dev_attr.attr,
- &sensor_dev_attr_in2_alarm.dev_attr.attr,
- &sensor_dev_attr_in3_input.dev_attr.attr,
- &sensor_dev_attr_in3_min.dev_attr.attr,
- &sensor_dev_attr_in3_max.dev_attr.attr,
- &sensor_dev_attr_in3_alarm.dev_attr.attr,
- &sensor_dev_attr_in4_input.dev_attr.attr,
- &sensor_dev_attr_in4_min.dev_attr.attr,
- &sensor_dev_attr_in4_max.dev_attr.attr,
- &sensor_dev_attr_in4_alarm.dev_attr.attr,
- &sensor_dev_attr_in5_input.dev_attr.attr,
- &sensor_dev_attr_in5_min.dev_attr.attr,
- &sensor_dev_attr_in5_max.dev_attr.attr,
- &sensor_dev_attr_in5_alarm.dev_attr.attr,
- &dev_attr_temp1_input.attr,
- &sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
- &sensor_dev_attr_temp1_alarm.dev_attr.attr,
- &sensor_dev_attr_fan1_input.dev_attr.attr,
- &sensor_dev_attr_fan1_div.dev_attr.attr,
- &sensor_dev_attr_fan1_min.dev_attr.attr,
- &sensor_dev_attr_fan1_alarm.dev_attr.attr,
- &sensor_dev_attr_fan2_input.dev_attr.attr,
- &sensor_dev_attr_fan2_div.dev_attr.attr,
- &sensor_dev_attr_fan2_min.dev_attr.attr,
- &sensor_dev_attr_fan2_alarm.dev_attr.attr,
- &dev_attr_alarms.attr,
&dev_attr_aout_output.attr,
- &sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
&dev_attr_cpu0_vid.attr,
NULL
};
@@ -730,26 +285,19 @@ static int adm9240_detect(struct i2c_client *new_client,
return -ENODEV;
/* verify chip: reg address should match i2c address */
- if (i2c_smbus_read_byte_data(new_client, ADM9240_REG_I2C_ADDR)
- != address) {
- dev_err(&adapter->dev, "detect fail: address match, 0x%02x\n",
- address);
+ if (i2c_smbus_read_byte_data(new_client, ADM9240_REG_I2C_ADDR) != address)
return -ENODEV;
- }
/* check known chip manufacturer */
man_id = i2c_smbus_read_byte_data(new_client, ADM9240_REG_MAN_ID);
- if (man_id == 0x23) {
+ if (man_id == 0x23)
name = "adm9240";
- } else if (man_id == 0xda) {
+ else if (man_id == 0xda)
name = "ds1780";
- } else if (man_id == 0x01) {
+ else if (man_id == 0x01)
name = "lm81";
- } else {
- dev_err(&adapter->dev, "detect fail: unknown manuf, 0x%02x\n",
- man_id);
+ else
return -ENODEV;
- }
/* successful detect, print chip info */
die_rev = i2c_smbus_read_byte_data(new_client, ADM9240_REG_DIE_REV);
@@ -757,13 +305,14 @@ static int adm9240_detect(struct i2c_client *new_client,
man_id == 0x23 ? "ADM9240" :
man_id == 0xda ? "DS1780" : "LM81", die_rev);
- strlcpy(info->type, name, I2C_NAME_SIZE);
+ strscpy(info->type, name, I2C_NAME_SIZE);
return 0;
}
-static int adm9240_init_client(struct i2c_client *client, struct adm9240_data *data)
+static int adm9240_init_client(struct adm9240_data *data)
{
+ unsigned int regval;
u8 conf, mode;
int err;
@@ -777,13 +326,13 @@ static int adm9240_init_client(struct i2c_client *client, struct adm9240_data *d
data->vrm = vid_which_vrm(); /* need this to report vid as mV */
- dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10,
- data->vrm % 10);
+ dev_info(data->dev, "Using VRM: %d.%d\n", data->vrm / 10,
+ data->vrm % 10);
if (conf & 1) { /* measurement cycle running: report state */
- dev_info(&client->dev, "status: config 0x%02x mode %u\n",
- conf, mode);
+ dev_info(data->dev, "status: config 0x%02x mode %u\n",
+ conf, mode);
} else { /* cold start: open limits before starting chip */
int i;
@@ -800,13 +349,13 @@ static int adm9240_init_client(struct i2c_client *client, struct adm9240_data *d
}
for (i = 0; i < 2; i++) {
err = regmap_write(data->regmap,
- ADM9240_REG_FAN_MIN(i), 255);
+ ADM9240_REG_FAN_MIN(i), 255);
if (err < 0)
return err;
}
for (i = 0; i < 2; i++) {
err = regmap_write(data->regmap,
- ADM9240_REG_TEMP_MAX(i), 127);
+ ADM9240_REG_TEMP_MAX(i), 127);
if (err < 0)
return err;
}
@@ -816,23 +365,417 @@ static int adm9240_init_client(struct i2c_client *client, struct adm9240_data *d
if (err < 0)
return err;
- dev_info(&client->dev,
+ dev_info(data->dev,
"cold start: config was 0x%02x mode %u\n", conf, mode);
}
+ /* read fan divs */
+ err = regmap_read(data->regmap, ADM9240_REG_VID_FAN_DIV, &regval);
+ if (err < 0)
+ return err;
+ data->fan_div[0] = (regval >> 4) & 3;
+ data->fan_div[1] = (regval >> 6) & 3;
return 0;
}
+static int adm9240_chip_read(struct device *dev, u32 attr, long *val)
+{
+ struct adm9240_data *data = dev_get_drvdata(dev);
+ u8 regs[2];
+ int err;
+
+ switch (attr) {
+ case hwmon_chip_alarms:
+ err = regmap_bulk_read(data->regmap, ADM9240_REG_INT(0), &regs, 2);
+ if (err < 0)
+ return err;
+ *val = regs[0] | regs[1] << 8;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int adm9240_intrusion_read(struct device *dev, u32 attr, long *val)
+{
+ struct adm9240_data *data = dev_get_drvdata(dev);
+ unsigned int regval;
+ int err;
+
+ switch (attr) {
+ case hwmon_intrusion_alarm:
+ err = regmap_read(data->regmap, ADM9240_REG_INT(1), &regval);
+ if (err < 0)
+ return err;
+ *val = !!(regval & BIT(4));
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int adm9240_intrusion_write(struct device *dev, u32 attr, long val)
+{
+ struct adm9240_data *data = dev_get_drvdata(dev);
+ int err;
+
+ switch (attr) {
+ case hwmon_intrusion_alarm:
+ if (val)
+ return -EINVAL;
+ err = regmap_write(data->regmap, ADM9240_REG_CHASSIS_CLEAR, 0x80);
+ if (err < 0)
+ return err;
+ dev_dbg(data->dev, "chassis intrusion latch cleared\n");
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int adm9240_in_read(struct device *dev, u32 attr, int channel, long *val)
+{
+ struct adm9240_data *data = dev_get_drvdata(dev);
+ unsigned int regval;
+ int reg;
+ int err;
+
+ switch (attr) {
+ case hwmon_in_input:
+ reg = ADM9240_REG_IN(channel);
+ break;
+ case hwmon_in_min:
+ reg = ADM9240_REG_IN_MIN(channel);
+ break;
+ case hwmon_in_max:
+ reg = ADM9240_REG_IN_MAX(channel);
+ break;
+ case hwmon_in_alarm:
+ if (channel < 4) {
+ reg = ADM9240_REG_INT(0);
+ } else {
+ reg = ADM9240_REG_INT(1);
+ channel -= 4;
+ }
+ err = regmap_read(data->regmap, reg, &regval);
+ if (err < 0)
+ return err;
+ *val = !!(regval & BIT(channel));
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+ err = regmap_read(data->regmap, reg, &regval);
+ if (err < 0)
+ return err;
+ *val = IN_FROM_REG(regval, channel);
+ return 0;
+}
+
+static int adm9240_in_write(struct device *dev, u32 attr, int channel, long val)
+{
+ struct adm9240_data *data = dev_get_drvdata(dev);
+ int reg;
+
+ switch (attr) {
+ case hwmon_in_min:
+ reg = ADM9240_REG_IN_MIN(channel);
+ break;
+ case hwmon_in_max:
+ reg = ADM9240_REG_IN(channel);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return regmap_write(data->regmap, reg, IN_TO_REG(val, channel));
+}
+
+static int adm9240_fan_read(struct device *dev, u32 attr, int channel, long *val)
+{
+ struct adm9240_data *data = dev_get_drvdata(dev);
+ unsigned int regval;
+ int err;
+
+ switch (attr) {
+ case hwmon_fan_input:
+ err = regmap_read(data->regmap, ADM9240_REG_FAN(channel), &regval);
+ if (err < 0)
+ return err;
+ if (regval == 255 && data->fan_div[channel] < 3) {
+ /* adjust fan clock divider on overflow */
+ err = adm9240_write_fan_div(data, channel,
+ ++data->fan_div[channel]);
+ if (err)
+ return err;
+ }
+ *val = FAN_FROM_REG(regval, BIT(data->fan_div[channel]));
+ break;
+ case hwmon_fan_div:
+ *val = BIT(data->fan_div[channel]);
+ break;
+ case hwmon_fan_min:
+ err = regmap_read(data->regmap, ADM9240_REG_FAN_MIN(channel), &regval);
+ if (err < 0)
+ return err;
+ *val = FAN_FROM_REG(regval, BIT(data->fan_div[channel]));
+ break;
+ case hwmon_fan_alarm:
+ err = regmap_read(data->regmap, ADM9240_REG_INT(0), &regval);
+ if (err < 0)
+ return err;
+ *val = !!(regval & BIT(channel + 6));
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int adm9240_fan_write(struct device *dev, u32 attr, int channel, long val)
+{
+ struct adm9240_data *data = dev_get_drvdata(dev);
+ int err;
+
+ switch (attr) {
+ case hwmon_fan_min:
+ err = adm9240_fan_min_write(data, channel, val);
+ if (err < 0)
+ return err;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int adm9240_temp_read(struct device *dev, u32 attr, int channel, long *val)
+{
+ struct adm9240_data *data = dev_get_drvdata(dev);
+ unsigned int regval;
+ int err, temp;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ err = regmap_read(data->regmap, ADM9240_REG_TEMP, &regval);
+ if (err < 0)
+ return err;
+ temp = regval << 1;
+ err = regmap_read(data->regmap, ADM9240_REG_TEMP_CONF, &regval);
+ if (err < 0)
+ return err;
+ temp |= regval >> 7;
+ *val = sign_extend32(temp, 8) * 500;
+ break;
+ case hwmon_temp_max:
+ err = regmap_read(data->regmap, ADM9240_REG_TEMP_MAX(0), &regval);
+ if (err < 0)
+ return err;
+ *val = (s8)regval * 1000;
+ break;
+ case hwmon_temp_max_hyst:
+ err = regmap_read(data->regmap, ADM9240_REG_TEMP_MAX(1), &regval);
+ if (err < 0)
+ return err;
+ *val = (s8)regval * 1000;
+ break;
+ case hwmon_temp_alarm:
+ err = regmap_read(data->regmap, ADM9240_REG_INT(0), &regval);
+ if (err < 0)
+ return err;
+ *val = !!(regval & BIT(4));
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int adm9240_temp_write(struct device *dev, u32 attr, int channel, long val)
+{
+ struct adm9240_data *data = dev_get_drvdata(dev);
+ int reg;
+
+ switch (attr) {
+ case hwmon_temp_max:
+ reg = ADM9240_REG_TEMP_MAX(0);
+ break;
+ case hwmon_temp_max_hyst:
+ reg = ADM9240_REG_TEMP_MAX(1);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return regmap_write(data->regmap, reg, TEMP_TO_REG(val));
+}
+
+static int adm9240_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+ int channel, long *val)
+{
+ switch (type) {
+ case hwmon_chip:
+ return adm9240_chip_read(dev, attr, val);
+ case hwmon_intrusion:
+ return adm9240_intrusion_read(dev, attr, val);
+ case hwmon_in:
+ return adm9240_in_read(dev, attr, channel, val);
+ case hwmon_fan:
+ return adm9240_fan_read(dev, attr, channel, val);
+ case hwmon_temp:
+ return adm9240_temp_read(dev, attr, channel, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int adm9240_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+ int channel, long val)
+{
+ switch (type) {
+ case hwmon_intrusion:
+ return adm9240_intrusion_write(dev, attr, val);
+ case hwmon_in:
+ return adm9240_in_write(dev, attr, channel, val);
+ case hwmon_fan:
+ return adm9240_fan_write(dev, attr, channel, val);
+ case hwmon_temp:
+ return adm9240_temp_write(dev, attr, channel, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static umode_t adm9240_is_visible(const void *_data, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ umode_t mode = 0;
+
+ switch (type) {
+ case hwmon_chip:
+ switch (attr) {
+ case hwmon_chip_alarms:
+ mode = 0444;
+ break;
+ default:
+ break;
+ }
+ break;
+ case hwmon_intrusion:
+ switch (attr) {
+ case hwmon_intrusion_alarm:
+ mode = 0644;
+ break;
+ default:
+ break;
+ }
+ break;
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp:
+ case hwmon_temp_alarm:
+ mode = 0444;
+ break;
+ case hwmon_temp_max:
+ case hwmon_temp_max_hyst:
+ mode = 0644;
+ break;
+ default:
+ break;
+ }
+ break;
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_input:
+ case hwmon_fan_div:
+ case hwmon_fan_alarm:
+ mode = 0444;
+ break;
+ case hwmon_fan_min:
+ mode = 0644;
+ break;
+ default:
+ break;
+ }
+ break;
+ case hwmon_in:
+ switch (attr) {
+ case hwmon_in_input:
+ case hwmon_in_alarm:
+ mode = 0444;
+ break;
+ case hwmon_in_min:
+ case hwmon_in_max:
+ mode = 0644;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return mode;
+}
+
+static const struct hwmon_ops adm9240_hwmon_ops = {
+ .is_visible = adm9240_is_visible,
+ .read = adm9240_read,
+ .write = adm9240_write,
+};
+
+static const struct hwmon_channel_info *adm9240_info[] = {
+ HWMON_CHANNEL_INFO(chip, HWMON_C_ALARMS),
+ HWMON_CHANNEL_INFO(intrusion, HWMON_INTRUSION_ALARM),
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | HWMON_T_ALARM),
+ HWMON_CHANNEL_INFO(in,
+ HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM,
+ HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM,
+ HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM,
+ HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM,
+ HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM,
+ HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM),
+ HWMON_CHANNEL_INFO(fan,
+ HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_DIV | HWMON_F_ALARM,
+ HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_DIV | HWMON_F_ALARM),
+ NULL
+};
+
+static const struct hwmon_chip_info adm9240_chip_info = {
+ .ops = &adm9240_hwmon_ops,
+ .info = adm9240_info,
+};
+
+static bool adm9240_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ADM9240_REG_IN(0) ... ADM9240_REG_IN(5):
+ case ADM9240_REG_FAN(0) ... ADM9240_REG_FAN(1):
+ case ADM9240_REG_INT(0) ... ADM9240_REG_INT(1):
+ case ADM9240_REG_TEMP:
+ case ADM9240_REG_TEMP_CONF:
+ case ADM9240_REG_VID_FAN_DIV:
+ case ADM9240_REG_VID4:
+ case ADM9240_REG_ANALOG_OUT:
+ return true;
+ default:
+ return false;
+ }
+}
+
static const struct regmap_config adm9240_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.use_single_read = true,
.use_single_write = true,
+ .volatile_reg = adm9240_volatile_reg,
};
-static int adm9240_probe(struct i2c_client *new_client)
+static int adm9240_probe(struct i2c_client *client)
{
- struct device *dev = &new_client->dev;
+ struct device *dev = &client->dev;
struct device *hwmon_dev;
struct adm9240_data *data;
int err;
@@ -841,20 +784,19 @@ static int adm9240_probe(struct i2c_client *new_client)
if (!data)
return -ENOMEM;
- data->client = new_client;
+ data->dev = dev;
mutex_init(&data->update_lock);
- data->regmap = devm_regmap_init_i2c(new_client, &adm9240_regmap_config);
+ data->regmap = devm_regmap_init_i2c(client, &adm9240_regmap_config);
if (IS_ERR(data->regmap))
return PTR_ERR(data->regmap);
- err = adm9240_init_client(new_client, data);
+ err = adm9240_init_client(data);
if (err < 0)
return err;
- hwmon_dev = devm_hwmon_device_register_with_groups(dev,
- new_client->name,
- data,
- adm9240_groups);
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data,
+ &adm9240_chip_info,
+ adm9240_groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
diff --git a/drivers/hwmon/amd_energy.c b/drivers/hwmon/amd_energy.c
deleted file mode 100644
index a86cc8d6d93d..000000000000
--- a/drivers/hwmon/amd_energy.c
+++ /dev/null
@@ -1,379 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-/*
- * Copyright (C) 2020 Advanced Micro Devices, Inc.
- */
-#include <asm/cpu_device_id.h>
-
-#include <linux/bits.h>
-#include <linux/cpu.h>
-#include <linux/cpumask.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/hwmon.h>
-#include <linux/kernel.h>
-#include <linux/kthread.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/processor.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/topology.h>
-#include <linux/types.h>
-
-#define DRVNAME "amd_energy"
-
-#define ENERGY_PWR_UNIT_MSR 0xC0010299
-#define ENERGY_CORE_MSR 0xC001029A
-#define ENERGY_PKG_MSR 0xC001029B
-
-#define AMD_ENERGY_UNIT_MASK 0x01F00
-#define AMD_ENERGY_MASK 0xFFFFFFFF
-
-struct sensor_accumulator {
- u64 energy_ctr;
- u64 prev_value;
-};
-
-struct amd_energy_data {
- struct hwmon_channel_info energy_info;
- const struct hwmon_channel_info *info[2];
- struct hwmon_chip_info chip;
- struct task_struct *wrap_accumulate;
- /* Lock around the accumulator */
- struct mutex lock;
- /* An accumulator for each core and socket */
- struct sensor_accumulator *accums;
- unsigned int timeout_ms;
- /* Energy Status Units */
- int energy_units;
- int nr_cpus;
- int nr_socks;
- int core_id;
- char (*label)[10];
-};
-
-static int amd_energy_read_labels(struct device *dev,
- enum hwmon_sensor_types type,
- u32 attr, int channel,
- const char **str)
-{
- struct amd_energy_data *data = dev_get_drvdata(dev);
-
- *str = data->label[channel];
- return 0;
-}
-
-static void get_energy_units(struct amd_energy_data *data)
-{
- u64 rapl_units;
-
- rdmsrl_safe(ENERGY_PWR_UNIT_MSR, &rapl_units);
- data->energy_units = (rapl_units & AMD_ENERGY_UNIT_MASK) >> 8;
-}
-
-static void accumulate_delta(struct amd_energy_data *data,
- int channel, int cpu, u32 reg)
-{
- struct sensor_accumulator *accum;
- u64 input;
-
- mutex_lock(&data->lock);
- rdmsrl_safe_on_cpu(cpu, reg, &input);
- input &= AMD_ENERGY_MASK;
-
- accum = &data->accums[channel];
- if (input >= accum->prev_value)
- accum->energy_ctr +=
- input - accum->prev_value;
- else
- accum->energy_ctr += UINT_MAX -
- accum->prev_value + input;
-
- accum->prev_value = input;
- mutex_unlock(&data->lock);
-}
-
-static void read_accumulate(struct amd_energy_data *data)
-{
- int sock, scpu, cpu;
-
- for (sock = 0; sock < data->nr_socks; sock++) {
- scpu = cpumask_first_and(cpu_online_mask,
- cpumask_of_node(sock));
-
- accumulate_delta(data, data->nr_cpus + sock,
- scpu, ENERGY_PKG_MSR);
- }
-
- if (data->core_id >= data->nr_cpus)
- data->core_id = 0;
-
- cpu = data->core_id;
- if (cpu_online(cpu))
- accumulate_delta(data, cpu, cpu, ENERGY_CORE_MSR);
-
- data->core_id++;
-}
-
-static void amd_add_delta(struct amd_energy_data *data, int ch,
- int cpu, long *val, u32 reg)
-{
- struct sensor_accumulator *accum;
- u64 input;
-
- mutex_lock(&data->lock);
- rdmsrl_safe_on_cpu(cpu, reg, &input);
- input &= AMD_ENERGY_MASK;
-
- accum = &data->accums[ch];
- if (input >= accum->prev_value)
- input += accum->energy_ctr -
- accum->prev_value;
- else
- input += UINT_MAX - accum->prev_value +
- accum->energy_ctr;
-
- /* Energy consumed = (1/(2^ESU) * RAW * 1000000UL) μJoules */
- *val = div64_ul(input * 1000000UL, BIT(data->energy_units));
-
- mutex_unlock(&data->lock);
-}
-
-static int amd_energy_read(struct device *dev,
- enum hwmon_sensor_types type,
- u32 attr, int channel, long *val)
-{
- struct amd_energy_data *data = dev_get_drvdata(dev);
- u32 reg;
- int cpu;
-
- if (channel >= data->nr_cpus) {
- cpu = cpumask_first_and(cpu_online_mask,
- cpumask_of_node
- (channel - data->nr_cpus));
- reg = ENERGY_PKG_MSR;
- } else {
- cpu = channel;
- if (!cpu_online(cpu))
- return -ENODEV;
-
- reg = ENERGY_CORE_MSR;
- }
- amd_add_delta(data, channel, cpu, val, reg);
-
- return 0;
-}
-
-static umode_t amd_energy_is_visible(const void *_data,
- enum hwmon_sensor_types type,
- u32 attr, int channel)
-{
- return 0440;
-}
-
-static int energy_accumulator(void *p)
-{
- struct amd_energy_data *data = (struct amd_energy_data *)p;
- unsigned int timeout = data->timeout_ms;
-
- while (!kthread_should_stop()) {
- /*
- * Ignoring the conditions such as
- * cpu being offline or rdmsr failure
- */
- read_accumulate(data);
-
- set_current_state(TASK_INTERRUPTIBLE);
- if (kthread_should_stop())
- break;
-
- schedule_timeout(msecs_to_jiffies(timeout));
- }
- return 0;
-}
-
-static const struct hwmon_ops amd_energy_ops = {
- .is_visible = amd_energy_is_visible,
- .read = amd_energy_read,
- .read_string = amd_energy_read_labels,
-};
-
-static int amd_create_sensor(struct device *dev,
- struct amd_energy_data *data,
- enum hwmon_sensor_types type, u32 config)
-{
- struct hwmon_channel_info *info = &data->energy_info;
- struct sensor_accumulator *accums;
- int i, num_siblings, cpus, sockets;
- u32 *s_config;
- char (*label_l)[10];
-
- /* Identify the number of siblings per core */
- num_siblings = ((cpuid_ebx(0x8000001e) >> 8) & 0xff) + 1;
-
- sockets = num_possible_nodes();
-
- /*
- * Energy counter register is accessed at core level.
- * Hence, filterout the siblings.
- */
- cpus = num_present_cpus() / num_siblings;
-
- s_config = devm_kcalloc(dev, cpus + sockets + 1,
- sizeof(u32), GFP_KERNEL);
- if (!s_config)
- return -ENOMEM;
-
- accums = devm_kcalloc(dev, cpus + sockets,
- sizeof(struct sensor_accumulator),
- GFP_KERNEL);
- if (!accums)
- return -ENOMEM;
-
- label_l = devm_kcalloc(dev, cpus + sockets,
- sizeof(*label_l), GFP_KERNEL);
- if (!label_l)
- return -ENOMEM;
-
- info->type = type;
- info->config = s_config;
-
- data->nr_cpus = cpus;
- data->nr_socks = sockets;
- data->accums = accums;
- data->label = label_l;
-
- for (i = 0; i < cpus + sockets; i++) {
- s_config[i] = config;
- if (i < cpus)
- scnprintf(label_l[i], 10, "Ecore%03u", i);
- else
- scnprintf(label_l[i], 10, "Esocket%u", (i - cpus));
- }
-
- s_config[i] = 0;
- return 0;
-}
-
-static int amd_energy_probe(struct platform_device *pdev)
-{
- struct device *hwmon_dev;
- struct amd_energy_data *data;
- struct device *dev = &pdev->dev;
- int ret;
-
- data = devm_kzalloc(dev,
- sizeof(struct amd_energy_data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- data->chip.ops = &amd_energy_ops;
- data->chip.info = data->info;
-
- dev_set_drvdata(dev, data);
- /* Populate per-core energy reporting */
- data->info[0] = &data->energy_info;
- ret = amd_create_sensor(dev, data, hwmon_energy,
- HWMON_E_INPUT | HWMON_E_LABEL);
- if (ret)
- return ret;
-
- mutex_init(&data->lock);
- get_energy_units(data);
-
- hwmon_dev = devm_hwmon_device_register_with_info(dev, DRVNAME,
- data,
- &data->chip,
- NULL);
- if (IS_ERR(hwmon_dev))
- return PTR_ERR(hwmon_dev);
-
- /*
- * On a system with peak wattage of 250W
- * timeout = 2 ^ 32 / 2 ^ energy_units / 250 secs
- */
- data->timeout_ms = 1000 *
- BIT(min(28, 31 - data->energy_units)) / 250;
-
- data->wrap_accumulate = kthread_run(energy_accumulator, data,
- "%s", dev_name(hwmon_dev));
- return PTR_ERR_OR_ZERO(data->wrap_accumulate);
-}
-
-static int amd_energy_remove(struct platform_device *pdev)
-{
- struct amd_energy_data *data = dev_get_drvdata(&pdev->dev);
-
- if (data && data->wrap_accumulate)
- kthread_stop(data->wrap_accumulate);
-
- return 0;
-}
-
-static const struct platform_device_id amd_energy_ids[] = {
- { .name = DRVNAME, },
- {}
-};
-MODULE_DEVICE_TABLE(platform, amd_energy_ids);
-
-static struct platform_driver amd_energy_driver = {
- .probe = amd_energy_probe,
- .remove = amd_energy_remove,
- .id_table = amd_energy_ids,
- .driver = {
- .name = DRVNAME,
- },
-};
-
-static struct platform_device *amd_energy_platdev;
-
-static const struct x86_cpu_id cpu_ids[] __initconst = {
- X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x17, 0x31, NULL),
- X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x19, 0x01, NULL),
- X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x19, 0x30, NULL),
- {}
-};
-MODULE_DEVICE_TABLE(x86cpu, cpu_ids);
-
-static int __init amd_energy_init(void)
-{
- int ret;
-
- if (!x86_match_cpu(cpu_ids))
- return -ENODEV;
-
- ret = platform_driver_register(&amd_energy_driver);
- if (ret)
- return ret;
-
- amd_energy_platdev = platform_device_alloc(DRVNAME, 0);
- if (!amd_energy_platdev) {
- platform_driver_unregister(&amd_energy_driver);
- return -ENOMEM;
- }
-
- ret = platform_device_add(amd_energy_platdev);
- if (ret) {
- platform_device_put(amd_energy_platdev);
- platform_driver_unregister(&amd_energy_driver);
- return ret;
- }
-
- return ret;
-}
-
-static void __exit amd_energy_exit(void)
-{
- platform_device_unregister(amd_energy_platdev);
- platform_driver_unregister(&amd_energy_driver);
-}
-
-module_init(amd_energy_init);
-module_exit(amd_energy_exit);
-
-MODULE_DESCRIPTION("Driver for AMD Energy reporting from RAPL MSR via HWMON interface");
-MODULE_AUTHOR("Naveen Krishna Chatradhi <nchatrad@amd.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 28b137eedf2e..c31759794a29 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -741,7 +741,7 @@ static void applesmc_idev_poll(struct input_dev *idev)
static ssize_t applesmc_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "applesmc\n");
+ return sysfs_emit(buf, "applesmc\n");
}
static ssize_t applesmc_position_show(struct device *dev,
@@ -763,8 +763,8 @@ static ssize_t applesmc_position_show(struct device *dev,
out:
if (ret)
return ret;
- else
- return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
+
+ return sysfs_emit(buf, "(%d,%d,%d)\n", x, y, z);
}
static ssize_t applesmc_light_show(struct device *dev,
@@ -804,8 +804,8 @@ static ssize_t applesmc_light_show(struct device *dev,
out:
if (ret)
return ret;
- else
- return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
+
+ return sysfs_emit(sysfsbuf, "(%d,%d)\n", left, right);
}
/* Displays sensor key as label */
@@ -814,7 +814,7 @@ static ssize_t applesmc_show_sensor_label(struct device *dev,
{
const char *key = smcreg.index[to_index(devattr)];
- return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
+ return sysfs_emit(sysfsbuf, "%s\n", key);
}
/* Displays degree Celsius * 1000 */
@@ -832,7 +832,7 @@ static ssize_t applesmc_show_temperature(struct device *dev,
temp = 250 * (value >> 6);
- return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", temp);
+ return sysfs_emit(sysfsbuf, "%d\n", temp);
}
static ssize_t applesmc_show_fan_speed(struct device *dev,
@@ -851,7 +851,7 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
return ret;
speed = ((buffer[0] << 8 | buffer[1]) >> 2);
- return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
+ return sysfs_emit(sysfsbuf, "%u\n", speed);
}
static ssize_t applesmc_store_fan_speed(struct device *dev,
@@ -891,7 +891,7 @@ static ssize_t applesmc_show_fan_manual(struct device *dev,
return ret;
manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
- return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
+ return sysfs_emit(sysfsbuf, "%d\n", manual);
}
static ssize_t applesmc_store_fan_manual(struct device *dev,
@@ -943,14 +943,14 @@ static ssize_t applesmc_show_fan_position(struct device *dev,
if (ret)
return ret;
- else
- return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
+
+ return sysfs_emit(sysfsbuf, "%s\n", buffer + 4);
}
static ssize_t applesmc_calibrate_show(struct device *dev,
struct device_attribute *attr, char *sysfsbuf)
{
- return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
+ return sysfs_emit(sysfsbuf, "(%d,%d)\n", rest_x, rest_y);
}
static ssize_t applesmc_calibrate_store(struct device *dev,
@@ -992,7 +992,7 @@ static ssize_t applesmc_key_count_show(struct device *dev,
count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
((u32)buffer[2]<<8) + buffer[3];
- return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
+ return sysfs_emit(sysfsbuf, "%d\n", count);
}
static ssize_t applesmc_key_at_index_read_show(struct device *dev,
@@ -1020,7 +1020,7 @@ static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
if (IS_ERR(entry))
return PTR_ERR(entry);
- return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", entry->len);
+ return sysfs_emit(sysfsbuf, "%d\n", entry->len);
}
static ssize_t applesmc_key_at_index_type_show(struct device *dev,
@@ -1032,7 +1032,7 @@ static ssize_t applesmc_key_at_index_type_show(struct device *dev,
if (IS_ERR(entry))
return PTR_ERR(entry);
- return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->type);
+ return sysfs_emit(sysfsbuf, "%s\n", entry->type);
}
static ssize_t applesmc_key_at_index_name_show(struct device *dev,
@@ -1044,13 +1044,13 @@ static ssize_t applesmc_key_at_index_name_show(struct device *dev,
if (IS_ERR(entry))
return PTR_ERR(entry);
- return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->key);
+ return sysfs_emit(sysfsbuf, "%s\n", entry->key);
}
static ssize_t applesmc_key_at_index_show(struct device *dev,
struct device_attribute *attr, char *sysfsbuf)
{
- return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
+ return sysfs_emit(sysfsbuf, "%d\n", key_at_index);
}
static ssize_t applesmc_key_at_index_store(struct device *dev,
diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c
index 99494056f4bd..3a5807e4a2ef 100644
--- a/drivers/hwmon/corsair-psu.c
+++ b/drivers/hwmon/corsair-psu.c
@@ -53,11 +53,17 @@
#define CMD_TIMEOUT_MS 250
#define SECONDS_PER_HOUR (60 * 60)
#define SECONDS_PER_DAY (SECONDS_PER_HOUR * 24)
+#define RAIL_COUNT 3 /* 3v3 + 5v + 12v */
+#define TEMP_COUNT 2
#define PSU_CMD_SELECT_RAIL 0x00 /* expects length 2 */
-#define PSU_CMD_IN_VOLTS 0x88 /* the rest of the commands expect length 3 */
+#define PSU_CMD_RAIL_VOLTS_HCRIT 0x40 /* the rest of the commands expect length 3 */
+#define PSU_CMD_RAIL_VOLTS_LCRIT 0x44
+#define PSU_CMD_RAIL_AMPS_HCRIT 0x46
+#define PSU_CMD_TEMP_HCRIT 0x4F
+#define PSU_CMD_IN_VOLTS 0x88
#define PSU_CMD_IN_AMPS 0x89
-#define PSU_CMD_RAIL_OUT_VOLTS 0x8B
+#define PSU_CMD_RAIL_VOLTS 0x8B
#define PSU_CMD_RAIL_AMPS 0x8C
#define PSU_CMD_TEMP0 0x8D
#define PSU_CMD_TEMP1 0x8E
@@ -116,30 +122,25 @@ struct corsairpsu_data {
u8 *cmd_buffer;
char vendor[REPLY_SIZE];
char product[REPLY_SIZE];
+ long temp_crit[TEMP_COUNT];
+ long in_crit[RAIL_COUNT];
+ long in_lcrit[RAIL_COUNT];
+ long curr_crit[RAIL_COUNT];
+ u8 temp_crit_support;
+ u8 in_crit_support;
+ u8 in_lcrit_support;
+ u8 curr_crit_support;
+ bool in_curr_cmd_support; /* not all commands are supported on every PSU */
};
/* some values are SMBus LINEAR11 data which need a conversion */
-static int corsairpsu_linear11_to_int(const int val)
+static int corsairpsu_linear11_to_int(const u16 val, const int scale)
{
- int exp = (val & 0xFFFF) >> 0x0B;
- int mant = val & 0x7FF;
- int i;
-
- if (exp > 0x0F)
- exp -= 0x20;
- if (mant > 0x3FF)
- mant -= 0x800;
- if ((mant & 0x01) == 1)
- ++mant;
- if (exp < 0) {
- for (i = 0; i < -exp; ++i)
- mant /= 2;
- } else {
- for (i = 0; i < exp; ++i)
- mant *= 2;
- }
+ const int exp = ((s16)val) >> 11;
+ const int mant = (((s16)(val & 0x7ff)) << 5) >> 5;
+ const int result = mant * scale;
- return mant;
+ return (exp >= 0) ? (result << exp) : (result >> -exp);
}
static int corsairpsu_usb_cmd(struct corsairpsu_data *priv, u8 p0, u8 p1, u8 p2, void *data)
@@ -207,7 +208,10 @@ static int corsairpsu_request(struct corsairpsu_data *priv, u8 cmd, u8 rail, voi
mutex_lock(&priv->lock);
switch (cmd) {
- case PSU_CMD_RAIL_OUT_VOLTS:
+ case PSU_CMD_RAIL_VOLTS_HCRIT:
+ case PSU_CMD_RAIL_VOLTS_LCRIT:
+ case PSU_CMD_RAIL_AMPS_HCRIT:
+ case PSU_CMD_RAIL_VOLTS:
case PSU_CMD_RAIL_AMPS:
case PSU_CMD_RAIL_WATTS:
ret = corsairpsu_usb_cmd(priv, 2, PSU_CMD_SELECT_RAIL, rail, NULL);
@@ -243,20 +247,24 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l
*/
tmp = ((long)data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
switch (cmd) {
+ case PSU_CMD_RAIL_VOLTS_HCRIT:
+ case PSU_CMD_RAIL_VOLTS_LCRIT:
+ case PSU_CMD_RAIL_AMPS_HCRIT:
+ case PSU_CMD_TEMP_HCRIT:
case PSU_CMD_IN_VOLTS:
case PSU_CMD_IN_AMPS:
- case PSU_CMD_RAIL_OUT_VOLTS:
+ case PSU_CMD_RAIL_VOLTS:
case PSU_CMD_RAIL_AMPS:
case PSU_CMD_TEMP0:
case PSU_CMD_TEMP1:
- *val = corsairpsu_linear11_to_int(tmp & 0xFFFF) * 1000;
+ *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000);
break;
case PSU_CMD_FAN:
- *val = corsairpsu_linear11_to_int(tmp & 0xFFFF);
+ *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1);
break;
case PSU_CMD_RAIL_WATTS:
case PSU_CMD_TOTAL_WATTS:
- *val = corsairpsu_linear11_to_int(tmp & 0xFFFF) * 1000000;
+ *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000000);
break;
case PSU_CMD_TOTAL_UPTIME:
case PSU_CMD_UPTIME:
@@ -270,75 +278,265 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l
return ret;
}
-static umode_t corsairpsu_hwmon_ops_is_visible(const void *data, enum hwmon_sensor_types type,
- u32 attr, int channel)
+static void corsairpsu_get_criticals(struct corsairpsu_data *priv)
{
- if (type == hwmon_temp && (attr == hwmon_temp_input || attr == hwmon_temp_label))
- return 0444;
- else if (type == hwmon_fan && (attr == hwmon_fan_input || attr == hwmon_fan_label))
- return 0444;
- else if (type == hwmon_power && (attr == hwmon_power_input || attr == hwmon_power_label))
- return 0444;
- else if (type == hwmon_in && (attr == hwmon_in_input || attr == hwmon_in_label))
+ long tmp;
+ int rail;
+
+ for (rail = 0; rail < TEMP_COUNT; ++rail) {
+ if (!corsairpsu_get_value(priv, PSU_CMD_TEMP_HCRIT, rail, &tmp)) {
+ priv->temp_crit_support |= BIT(rail);
+ priv->temp_crit[rail] = tmp;
+ }
+ }
+
+ for (rail = 0; rail < RAIL_COUNT; ++rail) {
+ if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS_HCRIT, rail, &tmp)) {
+ priv->in_crit_support |= BIT(rail);
+ priv->in_crit[rail] = tmp;
+ }
+
+ if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS_LCRIT, rail, &tmp)) {
+ priv->in_lcrit_support |= BIT(rail);
+ priv->in_lcrit[rail] = tmp;
+ }
+
+ if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_AMPS_HCRIT, rail, &tmp)) {
+ priv->curr_crit_support |= BIT(rail);
+ priv->curr_crit[rail] = tmp;
+ }
+ }
+}
+
+static void corsairpsu_check_cmd_support(struct corsairpsu_data *priv)
+{
+ long tmp;
+
+ priv->in_curr_cmd_support = !corsairpsu_get_value(priv, PSU_CMD_IN_AMPS, 0, &tmp);
+}
+
+static umode_t corsairpsu_hwmon_temp_is_visible(const struct corsairpsu_data *priv, u32 attr,
+ int channel)
+{
+ umode_t res = 0444;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ case hwmon_temp_label:
+ case hwmon_temp_crit:
+ if (channel > 0 && !(priv->temp_crit_support & BIT(channel - 1)))
+ res = 0;
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+static umode_t corsairpsu_hwmon_fan_is_visible(const struct corsairpsu_data *priv, u32 attr,
+ int channel)
+{
+ switch (attr) {
+ case hwmon_fan_input:
+ case hwmon_fan_label:
return 0444;
- else if (type == hwmon_curr && (attr == hwmon_curr_input || attr == hwmon_curr_label))
+ default:
+ return 0;
+ }
+}
+
+static umode_t corsairpsu_hwmon_power_is_visible(const struct corsairpsu_data *priv, u32 attr,
+ int channel)
+{
+ switch (attr) {
+ case hwmon_power_input:
+ case hwmon_power_label:
return 0444;
+ default:
+ return 0;
+ };
+}
- return 0;
+static umode_t corsairpsu_hwmon_in_is_visible(const struct corsairpsu_data *priv, u32 attr,
+ int channel)
+{
+ umode_t res = 0444;
+
+ switch (attr) {
+ case hwmon_in_input:
+ case hwmon_in_label:
+ case hwmon_in_crit:
+ if (channel > 0 && !(priv->in_crit_support & BIT(channel - 1)))
+ res = 0;
+ break;
+ case hwmon_in_lcrit:
+ if (channel > 0 && !(priv->in_lcrit_support & BIT(channel - 1)))
+ res = 0;
+ break;
+ default:
+ break;
+ };
+
+ return res;
}
-static int corsairpsu_hwmon_ops_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
- int channel, long *val)
+static umode_t corsairpsu_hwmon_curr_is_visible(const struct corsairpsu_data *priv, u32 attr,
+ int channel)
{
- struct corsairpsu_data *priv = dev_get_drvdata(dev);
- int ret;
+ umode_t res = 0444;
+
+ switch (attr) {
+ case hwmon_curr_input:
+ if (channel == 0 && !priv->in_curr_cmd_support)
+ res = 0;
+ break;
+ case hwmon_curr_label:
+ case hwmon_curr_crit:
+ if (channel > 0 && !(priv->curr_crit_support & BIT(channel - 1)))
+ res = 0;
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+static umode_t corsairpsu_hwmon_ops_is_visible(const void *data, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct corsairpsu_data *priv = data;
+
+ switch (type) {
+ case hwmon_temp:
+ return corsairpsu_hwmon_temp_is_visible(priv, attr, channel);
+ case hwmon_fan:
+ return corsairpsu_hwmon_fan_is_visible(priv, attr, channel);
+ case hwmon_power:
+ return corsairpsu_hwmon_power_is_visible(priv, attr, channel);
+ case hwmon_in:
+ return corsairpsu_hwmon_in_is_visible(priv, attr, channel);
+ case hwmon_curr:
+ return corsairpsu_hwmon_curr_is_visible(priv, attr, channel);
+ default:
+ return 0;
+ }
+}
+
+static int corsairpsu_hwmon_temp_read(struct corsairpsu_data *priv, u32 attr, int channel,
+ long *val)
+{
+ int err = -EOPNOTSUPP;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ return corsairpsu_get_value(priv, channel ? PSU_CMD_TEMP1 : PSU_CMD_TEMP0,
+ channel, val);
+ case hwmon_temp_crit:
+ *val = priv->temp_crit[channel];
+ err = 0;
+ break;
+ default:
+ break;
+ }
- if (type == hwmon_temp && attr == hwmon_temp_input && channel < 2) {
- ret = corsairpsu_get_value(priv, channel ? PSU_CMD_TEMP1 : PSU_CMD_TEMP0, channel,
- val);
- } else if (type == hwmon_fan && attr == hwmon_fan_input) {
- ret = corsairpsu_get_value(priv, PSU_CMD_FAN, 0, val);
- } else if (type == hwmon_power && attr == hwmon_power_input) {
+ return err;
+}
+
+static int corsairpsu_hwmon_power_read(struct corsairpsu_data *priv, u32 attr, int channel,
+ long *val)
+{
+ if (attr == hwmon_power_input) {
switch (channel) {
case 0:
- ret = corsairpsu_get_value(priv, PSU_CMD_TOTAL_WATTS, 0, val);
- break;
+ return corsairpsu_get_value(priv, PSU_CMD_TOTAL_WATTS, 0, val);
case 1 ... 3:
- ret = corsairpsu_get_value(priv, PSU_CMD_RAIL_WATTS, channel - 1, val);
- break;
+ return corsairpsu_get_value(priv, PSU_CMD_RAIL_WATTS, channel - 1, val);
default:
- return -EOPNOTSUPP;
+ break;
}
- } else if (type == hwmon_in && attr == hwmon_in_input) {
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int corsairpsu_hwmon_in_read(struct corsairpsu_data *priv, u32 attr, int channel, long *val)
+{
+ int err = -EOPNOTSUPP;
+
+ switch (attr) {
+ case hwmon_in_input:
switch (channel) {
case 0:
- ret = corsairpsu_get_value(priv, PSU_CMD_IN_VOLTS, 0, val);
- break;
+ return corsairpsu_get_value(priv, PSU_CMD_IN_VOLTS, 0, val);
case 1 ... 3:
- ret = corsairpsu_get_value(priv, PSU_CMD_RAIL_OUT_VOLTS, channel - 1, val);
- break;
+ return corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS, channel - 1, val);
default:
- return -EOPNOTSUPP;
+ break;
}
- } else if (type == hwmon_curr && attr == hwmon_curr_input) {
+ break;
+ case hwmon_in_crit:
+ *val = priv->in_crit[channel - 1];
+ err = 0;
+ break;
+ case hwmon_in_lcrit:
+ *val = priv->in_lcrit[channel - 1];
+ err = 0;
+ break;
+ }
+
+ return err;
+}
+
+static int corsairpsu_hwmon_curr_read(struct corsairpsu_data *priv, u32 attr, int channel,
+ long *val)
+{
+ int err = -EOPNOTSUPP;
+
+ switch (attr) {
+ case hwmon_curr_input:
switch (channel) {
case 0:
- ret = corsairpsu_get_value(priv, PSU_CMD_IN_AMPS, 0, val);
- break;
+ return corsairpsu_get_value(priv, PSU_CMD_IN_AMPS, 0, val);
case 1 ... 3:
- ret = corsairpsu_get_value(priv, PSU_CMD_RAIL_AMPS, channel - 1, val);
- break;
+ return corsairpsu_get_value(priv, PSU_CMD_RAIL_AMPS, channel - 1, val);
default:
- return -EOPNOTSUPP;
+ break;
}
- } else {
- return -EOPNOTSUPP;
+ break;
+ case hwmon_curr_crit:
+ *val = priv->curr_crit[channel - 1];
+ err = 0;
+ break;
+ default:
+ break;
}
- if (ret < 0)
- return ret;
+ return err;
+}
- return 0;
+static int corsairpsu_hwmon_ops_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+ int channel, long *val)
+{
+ struct corsairpsu_data *priv = dev_get_drvdata(dev);
+
+ switch (type) {
+ case hwmon_temp:
+ return corsairpsu_hwmon_temp_read(priv, attr, channel, val);
+ case hwmon_fan:
+ if (attr == hwmon_fan_input)
+ return corsairpsu_get_value(priv, PSU_CMD_FAN, 0, val);
+ return -EOPNOTSUPP;
+ case hwmon_power:
+ return corsairpsu_hwmon_power_read(priv, attr, channel, val);
+ case hwmon_in:
+ return corsairpsu_hwmon_in_read(priv, attr, channel, val);
+ case hwmon_curr:
+ return corsairpsu_hwmon_curr_read(priv, attr, channel, val);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static int corsairpsu_hwmon_ops_read_string(struct device *dev, enum hwmon_sensor_types type,
@@ -374,8 +572,8 @@ static const struct hwmon_channel_info *corsairpsu_info[] = {
HWMON_CHANNEL_INFO(chip,
HWMON_C_REGISTER_TZ),
HWMON_CHANNEL_INFO(temp,
- HWMON_T_INPUT | HWMON_T_LABEL,
- HWMON_T_INPUT | HWMON_T_LABEL),
+ HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT,
+ HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT),
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_LABEL),
HWMON_CHANNEL_INFO(power,
@@ -385,14 +583,14 @@ static const struct hwmon_channel_info *corsairpsu_info[] = {
HWMON_P_INPUT | HWMON_P_LABEL),
HWMON_CHANNEL_INFO(in,
HWMON_I_INPUT | HWMON_I_LABEL,
- HWMON_I_INPUT | HWMON_I_LABEL,
- HWMON_I_INPUT | HWMON_I_LABEL,
- HWMON_I_INPUT | HWMON_I_LABEL),
+ HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_LCRIT | HWMON_I_CRIT,
+ HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_LCRIT | HWMON_I_CRIT,
+ HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_LCRIT | HWMON_I_CRIT),
HWMON_CHANNEL_INFO(curr,
HWMON_C_INPUT | HWMON_C_LABEL,
- HWMON_C_INPUT | HWMON_C_LABEL,
- HWMON_C_INPUT | HWMON_C_LABEL,
- HWMON_C_INPUT | HWMON_C_LABEL),
+ HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_CRIT,
+ HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_CRIT,
+ HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_CRIT),
NULL
};
@@ -527,6 +725,9 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id
goto fail_and_stop;
}
+ corsairpsu_get_criticals(priv);
+ corsairpsu_check_cmd_support(priv);
+
priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsairpsu", priv,
&corsairpsu_chip_info, 0);
diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
index 73b9db9e3aab..2970892bed82 100644
--- a/drivers/hwmon/dell-smm-hwmon.c
+++ b/drivers/hwmon/dell-smm-hwmon.c
@@ -1210,6 +1210,14 @@ static struct dmi_system_id i8k_whitelist_fan_control[] __initdata = {
},
.driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
},
+ {
+ .ident = "Dell Latitude E7440",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Latitude E7440"),
+ },
+ .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
+ },
{ }
};
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index e1d742bfc74c..bf1c4b7ecb40 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -326,7 +326,7 @@ static struct attribute *ds1621_attributes[] = {
static umode_t ds1621_attribute_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct ds1621_data *data = dev_get_drvdata(dev);
if (attr == &dev_attr_update_interval.attr)
diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c
index ef88a156efc2..ceffc76a0c51 100644
--- a/drivers/hwmon/ftsteutates.c
+++ b/drivers/hwmon/ftsteutates.c
@@ -509,7 +509,7 @@ error:
/* SysFS structs */
/*****************************************************************************/
-/* Temprature sensors */
+/* Temperature sensors */
static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_value, 0);
static SENSOR_DEVICE_ATTR_RO(temp2_input, temp_value, 1);
static SENSOR_DEVICE_ATTR_RO(temp3_input, temp_value, 2);
@@ -713,7 +713,7 @@ static int fts_detect(struct i2c_client *client,
{
int val;
- /* detection works with revsion greater or equal to 0x2b */
+ /* detection works with revision greater or equal to 0x2b */
val = i2c_smbus_read_byte_data(client, FTS_DEVICE_REVISION_REG);
if (val < 0x2b)
return -ENODEV;
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index 6c684058bfdf..fd47ab4e6892 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -79,7 +79,7 @@ static struct attribute *hwmon_dev_attrs[] = {
static umode_t hwmon_dev_name_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
if (to_hwmon_device(dev)->name == NULL)
return 0;
diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c
index f4c7b5f76359..fc3007c3e85c 100644
--- a/drivers/hwmon/ina209.c
+++ b/drivers/hwmon/ina209.c
@@ -259,7 +259,7 @@ static ssize_t ina209_interval_show(struct device *dev,
{
struct ina209_data *data = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%d\n", data->update_interval);
+ return sysfs_emit(buf, "%d\n", data->update_interval);
}
/*
@@ -343,7 +343,7 @@ static ssize_t ina209_value_show(struct device *dev,
return PTR_ERR(data);
val = ina209_from_reg(attr->index, data->regs[attr->index]);
- return snprintf(buf, PAGE_SIZE, "%ld\n", val);
+ return sysfs_emit(buf, "%ld\n", val);
}
static ssize_t ina209_alarm_show(struct device *dev,
@@ -363,7 +363,7 @@ static ssize_t ina209_alarm_show(struct device *dev,
* All alarms are in the INA209_STATUS register. To avoid a long
* switch statement, the mask is passed in attr->index
*/
- return snprintf(buf, PAGE_SIZE, "%u\n", !!(status & mask));
+ return sysfs_emit(buf, "%u\n", !!(status & mask));
}
/* Shunt voltage, history, limits, alarms */
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index ca97f9e931bc..00fc70305a89 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -310,8 +310,7 @@ static ssize_t ina2xx_value_show(struct device *dev,
if (err < 0)
return err;
- return snprintf(buf, PAGE_SIZE, "%d\n",
- ina2xx_get_value(data, attr->index, regval));
+ return sysfs_emit(buf, "%d\n", ina2xx_get_value(data, attr->index, regval));
}
static int ina226_reg_to_alert(struct ina2xx_data *data, u8 bit, u16 regval)
@@ -386,7 +385,7 @@ static ssize_t ina226_alert_show(struct device *dev,
val = ina226_reg_to_alert(data, attr->index, regval);
}
- ret = snprintf(buf, PAGE_SIZE, "%d\n", val);
+ ret = sysfs_emit(buf, "%d\n", val);
abort:
mutex_unlock(&data->config_lock);
return ret;
@@ -450,7 +449,7 @@ static ssize_t ina226_alarm_show(struct device *dev,
alarm = (regval & BIT(attr->index)) &&
(regval & INA226_ALERT_FUNCTION_FLAG);
- return snprintf(buf, PAGE_SIZE, "%d\n", alarm);
+ return sysfs_emit(buf, "%d\n", alarm);
}
/*
@@ -481,7 +480,7 @@ static ssize_t ina2xx_shunt_show(struct device *dev,
{
struct ina2xx_data *data = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%li\n", data->rshunt);
+ return sysfs_emit(buf, "%li\n", data->rshunt);
}
static ssize_t ina2xx_shunt_store(struct device *dev,
@@ -537,7 +536,7 @@ static ssize_t ina226_interval_show(struct device *dev,
if (status)
return status;
- return snprintf(buf, PAGE_SIZE, "%d\n", ina226_reg_to_interval(regval));
+ return sysfs_emit(buf, "%d\n", ina226_reg_to_interval(regval));
}
/* shunt voltage */
diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c
index d80bd3efcd6d..c602583d19f3 100644
--- a/drivers/hwmon/ina3221.c
+++ b/drivers/hwmon/ina3221.c
@@ -698,7 +698,7 @@ static ssize_t ina3221_shunt_show(struct device *dev,
unsigned int channel = sd_attr->index;
struct ina3221_input *input = &ina->inputs[channel];
- return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor);
+ return sysfs_emit(buf, "%d\n", input->shunt_resistor);
}
static ssize_t ina3221_shunt_store(struct device *dev,
diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c
index 17d5e6b91c8a..bd7ed2ed3a1e 100644
--- a/drivers/hwmon/intel-m10-bmc-hwmon.c
+++ b/drivers/hwmon/intel-m10-bmc-hwmon.c
@@ -99,6 +99,50 @@ static const struct hwmon_channel_info *n3000bmc_hinfo[] = {
NULL
};
+static const struct m10bmc_sdata d5005bmc_temp_tbl[] = {
+ { 0x100, 0x104, 0x108, 0x10c, 0x0, 500, "Board Inlet Air Temperature" },
+ { 0x110, 0x114, 0x118, 0x0, 0x0, 500, "FPGA Core Temperature" },
+ { 0x11c, 0x120, 0x124, 0x128, 0x0, 500, "Board Exhaust Air Temperature" },
+ { 0x12c, 0x130, 0x134, 0x0, 0x0, 500, "FPGA Transceiver Temperature" },
+ { 0x138, 0x13c, 0x140, 0x144, 0x0, 500, "RDIMM0 Temperature" },
+ { 0x148, 0x14c, 0x150, 0x154, 0x0, 500, "RDIMM1 Temperature" },
+ { 0x158, 0x15c, 0x160, 0x164, 0x0, 500, "RDIMM2 Temperature" },
+ { 0x168, 0x16c, 0x170, 0x174, 0x0, 500, "RDIMM3 Temperature" },
+ { 0x178, 0x17c, 0x180, 0x0, 0x0, 500, "QSFP0 Temperature" },
+ { 0x188, 0x18c, 0x190, 0x0, 0x0, 500, "QSFP1 Temperature" },
+ { 0x1a0, 0x1a4, 0x1a8, 0x0, 0x0, 500, "3.3v Temperature" },
+ { 0x1bc, 0x1c0, 0x1c4, 0x0, 0x0, 500, "VCCERAM Temperature" },
+ { 0x1d8, 0x1dc, 0x1e0, 0x0, 0x0, 500, "VCCR Temperature" },
+ { 0x1f4, 0x1f8, 0x1fc, 0x0, 0x0, 500, "VCCT Temperature" },
+ { 0x210, 0x214, 0x218, 0x0, 0x0, 500, "1.8v Temperature" },
+ { 0x22c, 0x230, 0x234, 0x0, 0x0, 500, "12v Backplane Temperature" },
+ { 0x248, 0x24c, 0x250, 0x0, 0x0, 500, "12v AUX Temperature" },
+};
+
+static const struct m10bmc_sdata d5005bmc_in_tbl[] = {
+ { 0x184, 0x0, 0x0, 0x0, 0x0, 1, "QSFP0 Supply Voltage" },
+ { 0x194, 0x0, 0x0, 0x0, 0x0, 1, "QSFP1 Supply Voltage" },
+ { 0x198, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage" },
+ { 0x1ac, 0x1b0, 0x1b4, 0x0, 0x0, 1, "3.3v Voltage" },
+ { 0x1c8, 0x1cc, 0x1d0, 0x0, 0x0, 1, "VCCERAM Voltage" },
+ { 0x1e4, 0x1e8, 0x1ec, 0x0, 0x0, 1, "VCCR Voltage" },
+ { 0x200, 0x204, 0x208, 0x0, 0x0, 1, "VCCT Voltage" },
+ { 0x21c, 0x220, 0x224, 0x0, 0x0, 1, "1.8v Voltage" },
+ { 0x238, 0x0, 0x0, 0x0, 0x23c, 1, "12v Backplane Voltage" },
+ { 0x254, 0x0, 0x0, 0x0, 0x258, 1, "12v AUX Voltage" },
+};
+
+static const struct m10bmc_sdata d5005bmc_curr_tbl[] = {
+ { 0x19c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Current" },
+ { 0x1b8, 0x0, 0x0, 0x0, 0x0, 1, "3.3v Current" },
+ { 0x1d4, 0x0, 0x0, 0x0, 0x0, 1, "VCCERAM Current" },
+ { 0x1f0, 0x0, 0x0, 0x0, 0x0, 1, "VCCR Current" },
+ { 0x20c, 0x0, 0x0, 0x0, 0x0, 1, "VCCT Current" },
+ { 0x228, 0x0, 0x0, 0x0, 0x0, 1, "1.8v Current" },
+ { 0x240, 0x244, 0x0, 0x0, 0x0, 1, "12v Backplane Current" },
+ { 0x25c, 0x260, 0x0, 0x0, 0x0, 1, "12v AUX Current" },
+};
+
static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata = {
.tables = {
[hwmon_temp] = n3000bmc_temp_tbl,
@@ -110,6 +154,80 @@ static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata = {
.hinfo = n3000bmc_hinfo,
};
+static const struct hwmon_channel_info *d5005bmc_hinfo[] = {
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
+ HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_LABEL),
+ HWMON_CHANNEL_INFO(in,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
+ HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
+ HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
+ HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
+ HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
+ HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_LABEL),
+ HWMON_CHANNEL_INFO(curr,
+ HWMON_C_INPUT | HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_LABEL,
+ HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_LABEL),
+ NULL
+};
+
+static const struct m10bmc_hwmon_board_data d5005bmc_hwmon_bdata = {
+ .tables = {
+ [hwmon_temp] = d5005bmc_temp_tbl,
+ [hwmon_in] = d5005bmc_in_tbl,
+ [hwmon_curr] = d5005bmc_curr_tbl,
+ },
+
+ .hinfo = d5005bmc_hinfo,
+};
+
static umode_t
m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
u32 attr, int channel)
@@ -316,6 +434,10 @@ static const struct platform_device_id intel_m10bmc_hwmon_ids[] = {
.name = "n3000bmc-hwmon",
.driver_data = (unsigned long)&n3000bmc_hwmon_bdata,
},
+ {
+ .name = "d5005bmc-hwmon",
+ .driver_data = (unsigned long)&d5005bmc_hwmon_bdata,
+ },
{ }
};
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index fac9b5c68a6a..1f93134afcb9 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -1981,7 +1981,7 @@ static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 3);
static umode_t it87_in_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 5; /* voltage index */
int a = index % 5; /* attribute index */
@@ -2065,7 +2065,7 @@ static const struct attribute_group it87_group_in = {
static umode_t it87_temp_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 7; /* temperature index */
int a = index % 7; /* attribute index */
@@ -2126,7 +2126,7 @@ static const struct attribute_group it87_group_temp = {
static umode_t it87_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
if ((index == 2 || index == 3) && !data->has_vid)
@@ -2158,7 +2158,7 @@ static const struct attribute_group it87_group = {
static umode_t it87_fan_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 5; /* fan index */
int a = index % 5; /* attribute index */
@@ -2229,7 +2229,7 @@ static const struct attribute_group it87_group_fan = {
static umode_t it87_pwm_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 4; /* pwm index */
int a = index % 4; /* attribute index */
@@ -2290,7 +2290,7 @@ static const struct attribute_group it87_group_pwm = {
static umode_t it87_auto_pwm_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 11; /* pwm index */
int a = index % 11; /* attribute index */
diff --git a/drivers/hwmon/lineage-pem.c b/drivers/hwmon/lineage-pem.c
index c83eb2fd80eb..1109fffa76fb 100644
--- a/drivers/hwmon/lineage-pem.c
+++ b/drivers/hwmon/lineage-pem.c
@@ -280,7 +280,7 @@ static ssize_t pem_bool_show(struct device *dev, struct device_attribute *da,
return PTR_ERR(data);
status = data->data_string[attr->nr] & attr->index;
- return snprintf(buf, PAGE_SIZE, "%d\n", !!status);
+ return sysfs_emit(buf, "%d\n", !!status);
}
static ssize_t pem_data_show(struct device *dev, struct device_attribute *da,
@@ -296,7 +296,7 @@ static ssize_t pem_data_show(struct device *dev, struct device_attribute *da,
value = pem_get_data(data->data_string, sizeof(data->data_string),
attr->index);
- return snprintf(buf, PAGE_SIZE, "%ld\n", value);
+ return sysfs_emit(buf, "%ld\n", value);
}
static ssize_t pem_input_show(struct device *dev, struct device_attribute *da,
@@ -312,7 +312,7 @@ static ssize_t pem_input_show(struct device *dev, struct device_attribute *da,
value = pem_get_input(data->input_string, sizeof(data->input_string),
attr->index);
- return snprintf(buf, PAGE_SIZE, "%ld\n", value);
+ return sysfs_emit(buf, "%ld\n", value);
}
static ssize_t pem_fan_show(struct device *dev, struct device_attribute *da,
@@ -328,7 +328,7 @@ static ssize_t pem_fan_show(struct device *dev, struct device_attribute *da,
value = pem_get_fan(data->fan_speed, sizeof(data->fan_speed),
attr->index);
- return snprintf(buf, PAGE_SIZE, "%ld\n", value);
+ return sysfs_emit(buf, "%ld\n", value);
}
/* Voltages */
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 50f67265c71d..c8f93c5d1ccc 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -931,7 +931,7 @@ static const struct attribute_group lm63_group_extra_lut = {
static umode_t lm63_attribute_mode(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct lm63_data *data = dev_get_drvdata(dev);
if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr
diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c
index ba9c868a8641..9adebb59f604 100644
--- a/drivers/hwmon/ltc2945.c
+++ b/drivers/hwmon/ltc2945.c
@@ -226,7 +226,7 @@ static ssize_t ltc2945_value_show(struct device *dev,
value = ltc2945_reg_to_val(dev, attr->index);
if (value < 0)
return value;
- return snprintf(buf, PAGE_SIZE, "%lld\n", value);
+ return sysfs_emit(buf, "%lld\n", value);
}
static ssize_t ltc2945_value_store(struct device *dev,
@@ -333,7 +333,7 @@ static ssize_t ltc2945_bool_show(struct device *dev,
if (fault) /* Clear reported faults in chip register */
regmap_update_bits(regmap, LTC2945_FAULT, attr->index, 0);
- return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+ return sysfs_emit(buf, "%d\n", !!fault);
}
/* Input voltages */
diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c
index 78b191b26bb2..689f788b8563 100644
--- a/drivers/hwmon/ltc2990.c
+++ b/drivers/hwmon/ltc2990.c
@@ -147,13 +147,13 @@ static ssize_t ltc2990_value_show(struct device *dev,
if (unlikely(ret < 0))
return ret;
- return snprintf(buf, PAGE_SIZE, "%d\n", value);
+ return sysfs_emit(buf, "%d\n", value);
}
static umode_t ltc2990_attrs_visible(struct kobject *kobj,
struct attribute *a, int n)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct ltc2990_data *data = dev_get_drvdata(dev);
struct device_attribute *da =
container_of(a, struct device_attribute, attr);
diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c
index 321f54e237bd..13b85367a21f 100644
--- a/drivers/hwmon/ltc4151.c
+++ b/drivers/hwmon/ltc4151.c
@@ -128,7 +128,7 @@ static ssize_t ltc4151_value_show(struct device *dev,
return PTR_ERR(data);
value = ltc4151_get_value(data, attr->index);
- return snprintf(buf, PAGE_SIZE, "%d\n", value);
+ return sysfs_emit(buf, "%d\n", value);
}
/*
diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c
index 7cef3cb2962b..1d18c212054f 100644
--- a/drivers/hwmon/ltc4215.c
+++ b/drivers/hwmon/ltc4215.c
@@ -139,7 +139,7 @@ static ssize_t ltc4215_voltage_show(struct device *dev,
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
const int voltage = ltc4215_get_voltage(dev, attr->index);
- return snprintf(buf, PAGE_SIZE, "%d\n", voltage);
+ return sysfs_emit(buf, "%d\n", voltage);
}
static ssize_t ltc4215_current_show(struct device *dev,
@@ -147,7 +147,7 @@ static ssize_t ltc4215_current_show(struct device *dev,
{
const unsigned int curr = ltc4215_get_current(dev);
- return snprintf(buf, PAGE_SIZE, "%u\n", curr);
+ return sysfs_emit(buf, "%u\n", curr);
}
static ssize_t ltc4215_power_show(struct device *dev,
@@ -159,7 +159,7 @@ static ssize_t ltc4215_power_show(struct device *dev,
/* current in mA * voltage in mV == power in uW */
const unsigned int power = abs(output_voltage * curr);
- return snprintf(buf, PAGE_SIZE, "%u\n", power);
+ return sysfs_emit(buf, "%u\n", power);
}
static ssize_t ltc4215_alarm_show(struct device *dev,
@@ -170,7 +170,7 @@ static ssize_t ltc4215_alarm_show(struct device *dev,
const u8 reg = data->regs[LTC4215_STATUS];
const u32 mask = attr->index;
- return snprintf(buf, PAGE_SIZE, "%u\n", !!(reg & mask));
+ return sysfs_emit(buf, "%u\n", !!(reg & mask));
}
/*
diff --git a/drivers/hwmon/ltc4222.c b/drivers/hwmon/ltc4222.c
index 3efce6d1cb88..d2027ca5c925 100644
--- a/drivers/hwmon/ltc4222.c
+++ b/drivers/hwmon/ltc4222.c
@@ -94,7 +94,7 @@ static ssize_t ltc4222_value_show(struct device *dev,
value = ltc4222_get_value(dev, attr->index);
if (value < 0)
return value;
- return snprintf(buf, PAGE_SIZE, "%d\n", value);
+ return sysfs_emit(buf, "%d\n", value);
}
static ssize_t ltc4222_bool_show(struct device *dev,
@@ -112,7 +112,7 @@ static ssize_t ltc4222_bool_show(struct device *dev,
if (fault) /* Clear reported faults in chip register */
regmap_update_bits(regmap, attr->nr, attr->index, 0);
- return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+ return sysfs_emit(buf, "%d\n", !!fault);
}
/* Voltages */
diff --git a/drivers/hwmon/ltc4260.c b/drivers/hwmon/ltc4260.c
index d0beb43abf3f..75e89cec381e 100644
--- a/drivers/hwmon/ltc4260.c
+++ b/drivers/hwmon/ltc4260.c
@@ -79,7 +79,7 @@ static ssize_t ltc4260_value_show(struct device *dev,
value = ltc4260_get_value(dev, attr->index);
if (value < 0)
return value;
- return snprintf(buf, PAGE_SIZE, "%d\n", value);
+ return sysfs_emit(buf, "%d\n", value);
}
static ssize_t ltc4260_bool_show(struct device *dev,
@@ -98,7 +98,7 @@ static ssize_t ltc4260_bool_show(struct device *dev,
if (fault) /* Clear reported faults in chip register */
regmap_update_bits(regmap, LTC4260_FAULT, attr->index, 0);
- return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
+ return sysfs_emit(buf, "%d\n", !!fault);
}
/* Voltages */
diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c
index 1dab84b52df5..b81e9c3d297b 100644
--- a/drivers/hwmon/ltc4261.c
+++ b/drivers/hwmon/ltc4261.c
@@ -130,7 +130,7 @@ static ssize_t ltc4261_value_show(struct device *dev,
return PTR_ERR(data);
value = ltc4261_get_value(data, attr->index);
- return snprintf(buf, PAGE_SIZE, "%d\n", value);
+ return sysfs_emit(buf, "%d\n", value);
}
static ssize_t ltc4261_bool_show(struct device *dev,
@@ -147,7 +147,7 @@ static ssize_t ltc4261_bool_show(struct device *dev,
if (fault) /* Clear reported faults in chip register */
i2c_smbus_write_byte_data(data->client, LTC4261_FAULT, ~fault);
- return snprintf(buf, PAGE_SIZE, "%d\n", fault ? 1 : 0);
+ return sysfs_emit(buf, "%d\n", fault ? 1 : 0);
}
/*
diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c
index a26226e7bc37..ae3a6a7bdaa2 100644
--- a/drivers/hwmon/max16065.c
+++ b/drivers/hwmon/max16065.c
@@ -187,7 +187,7 @@ static ssize_t max16065_alarm_show(struct device *dev,
i2c_smbus_write_byte_data(data->client,
MAX16065_FAULT(attr2->nr), val);
- return snprintf(buf, PAGE_SIZE, "%d\n", !!val);
+ return sysfs_emit(buf, "%d\n", !!val);
}
static ssize_t max16065_input_show(struct device *dev,
@@ -200,8 +200,8 @@ static ssize_t max16065_input_show(struct device *dev,
if (unlikely(adc < 0))
return adc;
- return snprintf(buf, PAGE_SIZE, "%d\n",
- ADC_TO_MV(adc, data->range[attr->index]));
+ return sysfs_emit(buf, "%d\n",
+ ADC_TO_MV(adc, data->range[attr->index]));
}
static ssize_t max16065_current_show(struct device *dev,
@@ -212,8 +212,8 @@ static ssize_t max16065_current_show(struct device *dev,
if (unlikely(data->curr_sense < 0))
return data->curr_sense;
- return snprintf(buf, PAGE_SIZE, "%d\n",
- ADC_TO_CURR(data->curr_sense, data->curr_gain));
+ return sysfs_emit(buf, "%d\n",
+ ADC_TO_CURR(data->curr_sense, data->curr_gain));
}
static ssize_t max16065_limit_store(struct device *dev,
@@ -249,8 +249,8 @@ static ssize_t max16065_limit_show(struct device *dev,
struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(da);
struct max16065_data *data = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%d\n",
- data->limit[attr2->nr][attr2->index]);
+ return sysfs_emit(buf, "%d\n",
+ data->limit[attr2->nr][attr2->index]);
}
/* Construct a sensor_device_attribute structure for each register */
@@ -454,7 +454,7 @@ static struct attribute *max16065_max_attributes[] = {
static umode_t max16065_basic_is_visible(struct kobject *kobj,
struct attribute *a, int n)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct max16065_data *data = dev_get_drvdata(dev);
int index = n / 4;
@@ -466,7 +466,7 @@ static umode_t max16065_basic_is_visible(struct kobject *kobj,
static umode_t max16065_secondary_is_visible(struct kobject *kobj,
struct attribute *a, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct max16065_data *data = dev_get_drvdata(dev);
if (index >= data->num_adc)
diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c
index fc3241101178..2895cea54193 100644
--- a/drivers/hwmon/max6697.c
+++ b/drivers/hwmon/max6697.c
@@ -460,7 +460,7 @@ static DEVICE_ATTR(dummy, 0, NULL, NULL);
static umode_t max6697_is_visible(struct kobject *kobj, struct attribute *attr,
int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct max6697_data *data = dev_get_drvdata(dev);
const struct max6697_chip_data *chip = data->chip;
int channel = index / 7; /* channel number */
diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c
index ed8d59d4eecb..116681fde33d 100644
--- a/drivers/hwmon/mlxreg-fan.c
+++ b/drivers/hwmon/mlxreg-fan.c
@@ -67,11 +67,13 @@
* @connected: indicates if tachometer is connected;
* @reg: register offset;
* @mask: fault mask;
+ * @prsnt: present register offset;
*/
struct mlxreg_fan_tacho {
bool connected;
u32 reg;
u32 mask;
+ u32 prsnt;
};
/*
@@ -92,6 +94,7 @@ struct mlxreg_fan_pwm {
* @regmap: register map of parent device;
* @tacho: tachometer data;
* @pwm: PWM data;
+ * @tachos_per_drwr - number of tachometers per drawer;
* @samples: minimum allowed samples per pulse;
* @divider: divider value for tachometer RPM calculation;
* @cooling: cooling device levels;
@@ -103,6 +106,7 @@ struct mlxreg_fan {
struct mlxreg_core_platform_data *pdata;
struct mlxreg_fan_tacho tacho[MLXREG_FAN_MAX_TACHO];
struct mlxreg_fan_pwm pwm;
+ int tachos_per_drwr;
int samples;
int divider;
u8 cooling_levels[MLXREG_FAN_MAX_STATE + 1];
@@ -123,6 +127,26 @@ mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
tacho = &fan->tacho[channel];
switch (attr) {
case hwmon_fan_input:
+ /*
+ * Check FAN presence: FAN related bit in presence register is one,
+ * if FAN is physically connected, zero - otherwise.
+ */
+ if (tacho->prsnt && fan->tachos_per_drwr) {
+ err = regmap_read(fan->regmap, tacho->prsnt, &regval);
+ if (err)
+ return err;
+
+ /*
+ * Map channel to presence bit - drawer can be equipped with
+ * one or few FANs, while presence is indicated per drawer.
+ */
+ if (BIT(channel / fan->tachos_per_drwr) & regval) {
+ /* FAN is not connected - return zero for FAN speed. */
+ *val = 0;
+ return 0;
+ }
+ }
+
err = regmap_read(fan->regmap, tacho->reg, &regval);
if (err)
return err;
@@ -389,8 +413,8 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
struct mlxreg_core_platform_data *pdata)
{
struct mlxreg_core_data *data = pdata->data;
+ int tacho_num = 0, tacho_avail = 0, i;
bool configured = false;
- int tacho_num = 0, i;
int err;
fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF;
@@ -415,7 +439,9 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
fan->tacho[tacho_num].reg = data->reg;
fan->tacho[tacho_num].mask = data->mask;
+ fan->tacho[tacho_num].prsnt = data->reg_prsnt;
fan->tacho[tacho_num++].connected = true;
+ tacho_avail++;
} else if (strnstr(data->label, "pwm", sizeof(data->label))) {
if (fan->pwm.connected) {
dev_err(fan->dev, "duplicate pwm entry: %s\n",
@@ -453,6 +479,29 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
}
}
+ if (pdata->capability) {
+ int drwr_avail;
+ u32 regval;
+
+ /* Obtain the number of FAN drawers, supported by system. */
+ err = regmap_read(fan->regmap, pdata->capability, &regval);
+ if (err) {
+ dev_err(fan->dev, "Failed to query capability register 0x%08x\n",
+ pdata->capability);
+ return err;
+ }
+
+ drwr_avail = hweight32(regval);
+ if (!tacho_avail || !drwr_avail || tacho_avail < drwr_avail) {
+ dev_err(fan->dev, "Configuration is invalid: drawers num %d tachos num %d\n",
+ drwr_avail, tacho_avail);
+ return -EINVAL;
+ }
+
+ /* Set the number of tachometers per one drawer. */
+ fan->tachos_per_drwr = tacho_avail / drwr_avail;
+ }
+
/* Init cooling levels per PWM state. */
for (i = 0; i < MLXREG_FAN_SPEED_MIN_LEVEL; i++)
fan->cooling_levels[i] = MLXREG_FAN_SPEED_MIN_LEVEL;
diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c
index a23047a3bfe2..35f8635dc7f3 100644
--- a/drivers/hwmon/nct6683.c
+++ b/drivers/hwmon/nct6683.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* nct6683 - Driver for the hardware monitoring functionality of
- * Nuvoton NCT6683D/NCT6687D eSIO
+ * Nuvoton NCT6683D/NCT6686D/NCT6687D eSIO
*
* Copyright (C) 2013 Guenter Roeck <linux@roeck-us.net>
*
@@ -12,6 +12,7 @@
*
* Chip #vin #fan #pwm #temp chip ID
* nct6683d 21(1) 16 8 32(1) 0xc730
+ * nct6686d 21(1) 16 8 32(1) 0xd440
* nct6687d 21(1) 16 8 32(1) 0xd590
*
* Notes:
@@ -33,7 +34,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-enum kinds { nct6683, nct6687 };
+enum kinds { nct6683, nct6686, nct6687 };
static bool force;
module_param(force, bool, 0);
@@ -41,11 +42,13 @@ MODULE_PARM_DESC(force, "Set to one to enable support for unknown vendors");
static const char * const nct6683_device_names[] = {
"nct6683",
+ "nct6686",
"nct6687",
};
static const char * const nct6683_chip_names[] = {
"NCT6683D",
+ "NCT6686D",
"NCT6687D",
};
@@ -66,6 +69,7 @@ static const char * const nct6683_chip_names[] = {
#define SIO_NCT6681_ID 0xb270 /* for later */
#define SIO_NCT6683_ID 0xc730
+#define SIO_NCT6686_ID 0xd440
#define SIO_NCT6687_ID 0xd590
#define SIO_ID_MASK 0xFFF0
@@ -488,17 +492,6 @@ static inline long in_from_reg(u16 reg, u8 src)
return reg * scale;
}
-static inline u16 in_to_reg(u32 val, u8 src)
-{
- int scale = 16;
-
- if (src == MON_SRC_VCC || src == MON_SRC_VSB || src == MON_SRC_AVSB ||
- src == MON_SRC_VBAT)
- scale <<= 1;
-
- return clamp_val(DIV_ROUND_CLOSEST(val, scale), 0, 127);
-}
-
static u16 nct6683_read(struct nct6683_data *data, u16 reg)
{
int res;
@@ -1362,6 +1355,9 @@ static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data)
case SIO_NCT6683_ID:
sio_data->kind = nct6683;
break;
+ case SIO_NCT6686_ID:
+ sio_data->kind = nct6686;
+ break;
case SIO_NCT6687_ID:
sio_data->kind = nct6687;
break;
diff --git a/drivers/hwmon/nzxt-kraken2.c b/drivers/hwmon/nzxt-kraken2.c
new file mode 100644
index 000000000000..89f7ea4f42d4
--- /dev/null
+++ b/drivers/hwmon/nzxt-kraken2.c
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * nzxt-kraken2.c - hwmon driver for NZXT Kraken X42/X52/X62/X72 coolers
+ *
+ * The device asynchronously sends HID reports (with id 0x04) twice a second to
+ * communicate current fan speed, pump speed and coolant temperature. The
+ * device does not respond to Get_Report requests for this status report.
+ *
+ * Copyright 2019-2021 Jonas Malaco <jonas@protocubo.io>
+ */
+
+#include <asm/unaligned.h>
+#include <linux/hid.h>
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+
+#define STATUS_REPORT_ID 0x04
+#define STATUS_VALIDITY 2 /* seconds; equivalent to 4 missed updates */
+
+static const char *const kraken2_temp_label[] = {
+ "Coolant",
+};
+
+static const char *const kraken2_fan_label[] = {
+ "Fan",
+ "Pump",
+};
+
+struct kraken2_priv_data {
+ struct hid_device *hid_dev;
+ struct device *hwmon_dev;
+ s32 temp_input[1];
+ u16 fan_input[2];
+ unsigned long updated; /* jiffies */
+};
+
+static umode_t kraken2_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ return 0444;
+}
+
+static int kraken2_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct kraken2_priv_data *priv = dev_get_drvdata(dev);
+
+ if (time_after(jiffies, priv->updated + STATUS_VALIDITY * HZ))
+ return -ENODATA;
+
+ switch (type) {
+ case hwmon_temp:
+ *val = priv->temp_input[channel];
+ break;
+ case hwmon_fan:
+ *val = priv->fan_input[channel];
+ break;
+ default:
+ return -EOPNOTSUPP; /* unreachable */
+ }
+
+ return 0;
+}
+
+static int kraken2_read_string(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ switch (type) {
+ case hwmon_temp:
+ *str = kraken2_temp_label[channel];
+ break;
+ case hwmon_fan:
+ *str = kraken2_fan_label[channel];
+ break;
+ default:
+ return -EOPNOTSUPP; /* unreachable */
+ }
+ return 0;
+}
+
+static const struct hwmon_ops kraken2_hwmon_ops = {
+ .is_visible = kraken2_is_visible,
+ .read = kraken2_read,
+ .read_string = kraken2_read_string,
+};
+
+static const struct hwmon_channel_info *kraken2_info[] = {
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_INPUT | HWMON_T_LABEL),
+ HWMON_CHANNEL_INFO(fan,
+ HWMON_F_INPUT | HWMON_F_LABEL,
+ HWMON_F_INPUT | HWMON_F_LABEL),
+ NULL
+};
+
+static const struct hwmon_chip_info kraken2_chip_info = {
+ .ops = &kraken2_hwmon_ops,
+ .info = kraken2_info,
+};
+
+static int kraken2_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data, int size)
+{
+ struct kraken2_priv_data *priv;
+
+ if (size < 7 || report->id != STATUS_REPORT_ID)
+ return 0;
+
+ priv = hid_get_drvdata(hdev);
+
+ /*
+ * The fractional byte of the coolant temperature has been observed to
+ * be in the interval [1,9], but some of these steps are also
+ * consistently skipped for certain integer parts.
+ *
+ * For the lack of a better idea, assume that the resolution is 0.1°C,
+ * and that the missing steps are artifacts of how the firmware
+ * processes the raw sensor data.
+ */
+ priv->temp_input[0] = data[1] * 1000 + data[2] * 100;
+
+ priv->fan_input[0] = get_unaligned_be16(data + 3);
+ priv->fan_input[1] = get_unaligned_be16(data + 5);
+
+ priv->updated = jiffies;
+
+ return 0;
+}
+
+static int kraken2_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ struct kraken2_priv_data *priv;
+ int ret;
+
+ priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->hid_dev = hdev;
+ hid_set_drvdata(hdev, priv);
+
+ /*
+ * Initialize ->updated to STATUS_VALIDITY seconds in the past, making
+ * the initial empty data invalid for kraken2_read without the need for
+ * a special case there.
+ */
+ priv->updated = jiffies - STATUS_VALIDITY * HZ;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "hid parse failed with %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * Enable hidraw so existing user-space tools can continue to work.
+ */
+ ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+ if (ret) {
+ hid_err(hdev, "hid hw start failed with %d\n", ret);
+ goto fail_and_stop;
+ }
+
+ ret = hid_hw_open(hdev);
+ if (ret) {
+ hid_err(hdev, "hid hw open failed with %d\n", ret);
+ goto fail_and_close;
+ }
+
+ priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "kraken2",
+ priv, &kraken2_chip_info,
+ NULL);
+ if (IS_ERR(priv->hwmon_dev)) {
+ ret = PTR_ERR(priv->hwmon_dev);
+ hid_err(hdev, "hwmon registration failed with %d\n", ret);
+ goto fail_and_close;
+ }
+
+ return 0;
+
+fail_and_close:
+ hid_hw_close(hdev);
+fail_and_stop:
+ hid_hw_stop(hdev);
+ return ret;
+}
+
+static void kraken2_remove(struct hid_device *hdev)
+{
+ struct kraken2_priv_data *priv = hid_get_drvdata(hdev);
+
+ hwmon_device_unregister(priv->hwmon_dev);
+
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
+}
+
+static const struct hid_device_id kraken2_table[] = {
+ { HID_USB_DEVICE(0x1e71, 0x170e) }, /* NZXT Kraken X42/X52/X62/X72 */
+ { }
+};
+
+MODULE_DEVICE_TABLE(hid, kraken2_table);
+
+static struct hid_driver kraken2_driver = {
+ .name = "nzxt-kraken2",
+ .id_table = kraken2_table,
+ .probe = kraken2_probe,
+ .remove = kraken2_remove,
+ .raw_event = kraken2_raw_event,
+};
+
+static int __init kraken2_init(void)
+{
+ return hid_register_driver(&kraken2_driver);
+}
+
+static void __exit kraken2_exit(void)
+{
+ hid_unregister_driver(&kraken2_driver);
+}
+
+/*
+ * When compiled into the kernel, initialize after the hid bus.
+ */
+late_initcall(kraken2_init);
+module_exit(kraken2_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonas Malaco <jonas@protocubo.io>");
+MODULE_DESCRIPTION("Hwmon driver for NZXT Kraken X42/X52/X62/X72 coolers");
diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c
index 7a5e539b567b..f1ac153d0b56 100644
--- a/drivers/hwmon/occ/common.c
+++ b/drivers/hwmon/occ/common.c
@@ -261,7 +261,7 @@ static ssize_t occ_show_temp_1(struct device *dev,
return -EINVAL;
}
- return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static ssize_t occ_show_temp_2(struct device *dev,
@@ -312,7 +312,7 @@ static ssize_t occ_show_temp_2(struct device *dev,
return -EINVAL;
}
- return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static ssize_t occ_show_temp_10(struct device *dev,
@@ -366,7 +366,7 @@ static ssize_t occ_show_temp_10(struct device *dev,
return -EINVAL;
}
- return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static ssize_t occ_show_freq_1(struct device *dev,
@@ -396,7 +396,7 @@ static ssize_t occ_show_freq_1(struct device *dev,
return -EINVAL;
}
- return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static ssize_t occ_show_freq_2(struct device *dev,
@@ -426,7 +426,7 @@ static ssize_t occ_show_freq_2(struct device *dev,
return -EINVAL;
}
- return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static ssize_t occ_show_power_1(struct device *dev,
@@ -465,7 +465,7 @@ static ssize_t occ_show_power_1(struct device *dev,
return -EINVAL;
}
- return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
+ return sysfs_emit(buf, "%llu\n", val);
}
static u64 occ_get_powr_avg(u64 *accum, u32 *samples)
@@ -494,9 +494,9 @@ static ssize_t occ_show_power_2(struct device *dev,
switch (sattr->nr) {
case 0:
- return snprintf(buf, PAGE_SIZE - 1, "%u_%u_%u\n",
- get_unaligned_be32(&power->sensor_id),
- power->function_id, power->apss_channel);
+ return sysfs_emit(buf, "%u_%u_%u\n",
+ get_unaligned_be32(&power->sensor_id),
+ power->function_id, power->apss_channel);
case 1:
val = occ_get_powr_avg(&power->accumulator,
&power->update_tag);
@@ -512,7 +512,7 @@ static ssize_t occ_show_power_2(struct device *dev,
return -EINVAL;
}
- return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
+ return sysfs_emit(buf, "%llu\n", val);
}
static ssize_t occ_show_power_a0(struct device *dev,
@@ -533,8 +533,8 @@ static ssize_t occ_show_power_a0(struct device *dev,
switch (sattr->nr) {
case 0:
- return snprintf(buf, PAGE_SIZE - 1, "%u_system\n",
- get_unaligned_be32(&power->sensor_id));
+ return sysfs_emit(buf, "%u_system\n",
+ get_unaligned_be32(&power->sensor_id));
case 1:
val = occ_get_powr_avg(&power->system.accumulator,
&power->system.update_tag);
@@ -547,8 +547,8 @@ static ssize_t occ_show_power_a0(struct device *dev,
val = get_unaligned_be16(&power->system.value) * 1000000ULL;
break;
case 4:
- return snprintf(buf, PAGE_SIZE - 1, "%u_proc\n",
- get_unaligned_be32(&power->sensor_id));
+ return sysfs_emit(buf, "%u_proc\n",
+ get_unaligned_be32(&power->sensor_id));
case 5:
val = occ_get_powr_avg(&power->proc.accumulator,
&power->proc.update_tag);
@@ -561,8 +561,8 @@ static ssize_t occ_show_power_a0(struct device *dev,
val = get_unaligned_be16(&power->proc.value) * 1000000ULL;
break;
case 8:
- return snprintf(buf, PAGE_SIZE - 1, "%u_vdd\n",
- get_unaligned_be32(&power->sensor_id));
+ return sysfs_emit(buf, "%u_vdd\n",
+ get_unaligned_be32(&power->sensor_id));
case 9:
val = occ_get_powr_avg(&power->vdd.accumulator,
&power->vdd.update_tag);
@@ -575,8 +575,8 @@ static ssize_t occ_show_power_a0(struct device *dev,
val = get_unaligned_be16(&power->vdd.value) * 1000000ULL;
break;
case 12:
- return snprintf(buf, PAGE_SIZE - 1, "%u_vdn\n",
- get_unaligned_be32(&power->sensor_id));
+ return sysfs_emit(buf, "%u_vdn\n",
+ get_unaligned_be32(&power->sensor_id));
case 13:
val = occ_get_powr_avg(&power->vdn.accumulator,
&power->vdn.update_tag);
@@ -592,7 +592,7 @@ static ssize_t occ_show_power_a0(struct device *dev,
return -EINVAL;
}
- return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
+ return sysfs_emit(buf, "%llu\n", val);
}
static ssize_t occ_show_caps_1_2(struct device *dev,
@@ -613,7 +613,7 @@ static ssize_t occ_show_caps_1_2(struct device *dev,
switch (sattr->nr) {
case 0:
- return snprintf(buf, PAGE_SIZE - 1, "system\n");
+ return sysfs_emit(buf, "system\n");
case 1:
val = get_unaligned_be16(&caps->cap) * 1000000ULL;
break;
@@ -642,7 +642,7 @@ static ssize_t occ_show_caps_1_2(struct device *dev,
return -EINVAL;
}
- return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
+ return sysfs_emit(buf, "%llu\n", val);
}
static ssize_t occ_show_caps_3(struct device *dev,
@@ -663,7 +663,7 @@ static ssize_t occ_show_caps_3(struct device *dev,
switch (sattr->nr) {
case 0:
- return snprintf(buf, PAGE_SIZE - 1, "system\n");
+ return sysfs_emit(buf, "system\n");
case 1:
val = get_unaligned_be16(&caps->cap) * 1000000ULL;
break;
@@ -689,7 +689,7 @@ static ssize_t occ_show_caps_3(struct device *dev,
return -EINVAL;
}
- return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
+ return sysfs_emit(buf, "%llu\n", val);
}
static ssize_t occ_store_caps_user(struct device *dev,
@@ -732,21 +732,22 @@ static ssize_t occ_show_extended(struct device *dev,
switch (sattr->nr) {
case 0:
- if (extn->flags & EXTN_FLAG_SENSOR_ID)
- rc = snprintf(buf, PAGE_SIZE - 1, "%u",
- get_unaligned_be32(&extn->sensor_id));
- else
- rc = snprintf(buf, PAGE_SIZE - 1, "%02x%02x%02x%02x\n",
- extn->name[0], extn->name[1],
- extn->name[2], extn->name[3]);
+ if (extn->flags & EXTN_FLAG_SENSOR_ID) {
+ rc = sysfs_emit(buf, "%u",
+ get_unaligned_be32(&extn->sensor_id));
+ } else {
+ rc = sysfs_emit(buf, "%02x%02x%02x%02x\n",
+ extn->name[0], extn->name[1],
+ extn->name[2], extn->name[3]);
+ }
break;
case 1:
- rc = snprintf(buf, PAGE_SIZE - 1, "%02x\n", extn->flags);
+ rc = sysfs_emit(buf, "%02x\n", extn->flags);
break;
case 2:
- rc = snprintf(buf, PAGE_SIZE - 1, "%02x%02x%02x%02x%02x%02x\n",
- extn->data[0], extn->data[1], extn->data[2],
- extn->data[3], extn->data[4], extn->data[5]);
+ rc = sysfs_emit(buf, "%02x%02x%02x%02x%02x%02x\n",
+ extn->data[0], extn->data[1], extn->data[2],
+ extn->data[3], extn->data[4], extn->data[5]);
break;
default:
return -EINVAL;
diff --git a/drivers/hwmon/occ/sysfs.c b/drivers/hwmon/occ/sysfs.c
index c73be0747e66..03b16abef67f 100644
--- a/drivers/hwmon/occ/sysfs.c
+++ b/drivers/hwmon/occ/sysfs.c
@@ -67,7 +67,7 @@ static ssize_t occ_sysfs_show(struct device *dev,
return -EINVAL;
}
- return snprintf(buf, PAGE_SIZE - 1, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
static ssize_t occ_error_show(struct device *dev,
@@ -77,7 +77,7 @@ static ssize_t occ_error_show(struct device *dev,
occ_update_response(occ);
- return snprintf(buf, PAGE_SIZE - 1, "%d\n", occ->error);
+ return sysfs_emit(buf, "%d\n", occ->error);
}
static SENSOR_DEVICE_ATTR(occ_master, 0444, occ_sysfs_show, NULL, 0);
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 32d2fc850621..37a5c39784fa 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -56,6 +56,25 @@ config SENSORS_BEL_PFE
This driver can also be built as a module. If so, the module will
be called bel-pfe.
+config SENSORS_BPA_RS600
+ tristate "BluTek BPA-RS600 Power Supplies"
+ help
+ If you say yes here you get hardware monitoring support for BluTek
+ BPA-RS600 Power Supplies.
+
+ This driver can also be built as a module. If so, the module will
+ be called bpa-rs600.
+
+config SENSORS_FSP_3Y
+ tristate "FSP/3Y-Power power supplies"
+ help
+ If you say yes here you get hardware monitoring support for
+ FSP/3Y-Power hot-swap power supplies.
+ Supported models: YH-5151E, YM-2151E
+
+ This driver can also be built as a module. If so, the module will
+ be called fsp-3y.
+
config SENSORS_IBM_CFFPS
tristate "IBM Common Form Factor Power Supply"
depends on LEDS_CLASS
@@ -84,6 +103,15 @@ config SENSORS_IR35221
This driver can also be built as a module. If so, the module will
be called ir35221.
+config SENSORS_IR36021
+ tristate "Infineon IR36021"
+ help
+ If you say yes here you get hardware monitoring support for Infineon
+ IR36021.
+
+ This driver can also be built as a module. If so, the module will
+ be called ir36021.
+
config SENSORS_IR38064
tristate "Infineon IR38064"
help
@@ -148,6 +176,15 @@ config SENSORS_LTC3815
This driver can also be built as a module. If so, the module will
be called ltc3815.
+config SENSORS_MAX15301
+ tristate "Maxim MAX15301"
+ help
+ If you say yes here you get hardware monitoring support for Maxim
+ MAX15301, as well as for Flex BMR461.
+
+ This driver can also be built as a module. If so, the module will
+ be called max15301.
+
config SENSORS_MAX16064
tristate "Maxim MAX16064"
help
@@ -247,6 +284,16 @@ config SENSORS_Q54SJ108A2
This driver can also be built as a module. If so, the module will
be called q54sj108a2.
+config SENSORS_STPDDC60
+ tristate "ST STPDDC60"
+ help
+ If you say yes here you get hardware monitoring support for ST
+ STPDDC60 Universal Digital Multicell Controller, as well as for
+ Flex BMR481.
+
+ This driver can also be built as a module. If so, the module will
+ be called stpddc60.
+
config SENSORS_TPS40422
tristate "TI TPS40422"
help
@@ -257,10 +304,10 @@ config SENSORS_TPS40422
be called tps40422.
config SENSORS_TPS53679
- tristate "TI TPS53647, TPS53667, TPS53679, TPS53681, TPS53688"
+ tristate "TI TPS53647, TPS53667, TPS53676, TPS53679, TPS53681, TPS53688"
help
If you say yes here you get hardware monitoring support for TI
- TPS53647, TPS53667, TPS53679, TPS53681, and TPS53688.
+ TPS53647, TPS53667, TPS53676, TPS53679, TPS53681, and TPS53688.
This driver can also be built as a module. If so, the module will
be called tps53679.
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
index 6a4ba0fdc1db..f8dcc27cd56a 100644
--- a/drivers/hwmon/pmbus/Makefile
+++ b/drivers/hwmon/pmbus/Makefile
@@ -8,15 +8,19 @@ 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_BPA_RS600) += bpa-rs600.o
+obj-$(CONFIG_SENSORS_FSP_3Y) += fsp-3y.o
obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o
obj-$(CONFIG_SENSORS_INSPUR_IPSPS) += inspur-ipsps.o
obj-$(CONFIG_SENSORS_IR35221) += ir35221.o
+obj-$(CONFIG_SENSORS_IR36021) += ir36021.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
+obj-$(CONFIG_SENSORS_MAX15301) += max15301.o
obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
obj-$(CONFIG_SENSORS_MAX16601) += max16601.o
obj-$(CONFIG_SENSORS_MAX20730) += max20730.o
@@ -28,6 +32,7 @@ obj-$(CONFIG_SENSORS_MP2975) += mp2975.o
obj-$(CONFIG_SENSORS_PM6764TR) += pm6764tr.o
obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o
obj-$(CONFIG_SENSORS_Q54SJ108A2) += q54sj108a2.o
+obj-$(CONFIG_SENSORS_STPDDC60) += stpddc60.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/adm1266.c b/drivers/hwmon/pmbus/adm1266.c
index 4d2e4ddcfbfd..ec5f932fc6f0 100644
--- a/drivers/hwmon/pmbus/adm1266.c
+++ b/drivers/hwmon/pmbus/adm1266.c
@@ -510,3 +510,4 @@ 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");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c
index 38a6515b0763..980a3850b2f3 100644
--- a/drivers/hwmon/pmbus/adm1275.c
+++ b/drivers/hwmon/pmbus/adm1275.c
@@ -805,3 +805,4 @@ module_i2c_driver(adm1275_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/bel-pfe.c b/drivers/hwmon/pmbus/bel-pfe.c
index aed7542d7ce5..4100eefb7ac3 100644
--- a/drivers/hwmon/pmbus/bel-pfe.c
+++ b/drivers/hwmon/pmbus/bel-pfe.c
@@ -129,3 +129,4 @@ module_i2c_driver(pfe_pmbus_driver);
MODULE_AUTHOR("Tao Ren <rentao.bupt@gmail.com>");
MODULE_DESCRIPTION("PMBus driver for BEL PFE Family Power Supplies");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/bpa-rs600.c b/drivers/hwmon/pmbus/bpa-rs600.c
new file mode 100644
index 000000000000..f6558ee9dec3
--- /dev/null
+++ b/drivers/hwmon/pmbus/bpa-rs600.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Hardware monitoring driver for BluTek BPA-RS600 Power Supplies
+ *
+ * Copyright 2021 Allied Telesis Labs
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pmbus.h>
+#include "pmbus.h"
+
+#define BPARS600_MFR_VIN_MIN 0xa0
+#define BPARS600_MFR_VIN_MAX 0xa1
+#define BPARS600_MFR_IIN_MAX 0xa2
+#define BPARS600_MFR_PIN_MAX 0xa3
+#define BPARS600_MFR_VOUT_MIN 0xa4
+#define BPARS600_MFR_VOUT_MAX 0xa5
+#define BPARS600_MFR_IOUT_MAX 0xa6
+#define BPARS600_MFR_POUT_MAX 0xa7
+
+static int bpa_rs600_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ int ret;
+
+ if (page > 0)
+ return -ENXIO;
+
+ switch (reg) {
+ case PMBUS_FAN_CONFIG_12:
+ /*
+ * Two fans are reported in PMBUS_FAN_CONFIG_12 but there is
+ * only one fan in the module. Mask out the FAN2 bits.
+ */
+ ret = pmbus_read_byte_data(client, 0, PMBUS_FAN_CONFIG_12);
+ if (ret >= 0)
+ ret &= ~(PB_FAN_2_INSTALLED | PB_FAN_2_PULSE_MASK);
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+
+ return ret;
+}
+
+static int bpa_rs600_read_word_data(struct i2c_client *client, int page, int phase, int reg)
+{
+ int ret;
+
+ if (page > 0)
+ return -ENXIO;
+
+ switch (reg) {
+ case PMBUS_VIN_UV_WARN_LIMIT:
+ ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_VIN_MIN);
+ break;
+ case PMBUS_VIN_OV_WARN_LIMIT:
+ ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_VIN_MAX);
+ break;
+ case PMBUS_VOUT_UV_WARN_LIMIT:
+ ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_VOUT_MIN);
+ break;
+ case PMBUS_VOUT_OV_WARN_LIMIT:
+ ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_VOUT_MAX);
+ break;
+ case PMBUS_IIN_OC_WARN_LIMIT:
+ ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_IIN_MAX);
+ break;
+ case PMBUS_IOUT_OC_WARN_LIMIT:
+ ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_IOUT_MAX);
+ break;
+ case PMBUS_PIN_OP_WARN_LIMIT:
+ ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_PIN_MAX);
+ break;
+ case PMBUS_POUT_OP_WARN_LIMIT:
+ ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_POUT_MAX);
+ break;
+ case PMBUS_VIN_UV_FAULT_LIMIT:
+ case PMBUS_VIN_OV_FAULT_LIMIT:
+ case PMBUS_VOUT_UV_FAULT_LIMIT:
+ case PMBUS_VOUT_OV_FAULT_LIMIT:
+ /* These commands return data but it is invalid/un-documented */
+ ret = -ENXIO;
+ break;
+ default:
+ if (reg >= PMBUS_VIRT_BASE)
+ ret = -ENXIO;
+ else
+ ret = -ENODATA;
+ break;
+ }
+
+ return ret;
+}
+
+static struct pmbus_driver_info bpa_rs600_info = {
+ .pages = 1,
+ .format[PSC_VOLTAGE_IN] = linear,
+ .format[PSC_VOLTAGE_OUT] = linear,
+ .format[PSC_CURRENT_IN] = linear,
+ .format[PSC_CURRENT_OUT] = linear,
+ .format[PSC_POWER] = linear,
+ .format[PSC_TEMPERATURE] = linear,
+ .format[PSC_FAN] = 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_TEMP2 |
+ PMBUS_HAVE_FAN12 |
+ PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
+ PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |
+ PMBUS_HAVE_STATUS_FAN12,
+ .read_byte_data = bpa_rs600_read_byte_data,
+ .read_word_data = bpa_rs600_read_word_data,
+};
+
+static int bpa_rs600_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
+ 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;
+
+ ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read Manufacturer Model\n");
+ return ret;
+ }
+
+ if (strncmp(buf, "BPA-RS600", 8)) {
+ buf[ret] = '\0';
+ dev_err(dev, "Unsupported Manufacturer Model '%s'\n", buf);
+ return -ENODEV;
+ }
+
+ return pmbus_do_probe(client, &bpa_rs600_info);
+}
+
+static const struct i2c_device_id bpa_rs600_id[] = {
+ { "bpars600", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, bpa_rs600_id);
+
+static const struct of_device_id __maybe_unused bpa_rs600_of_match[] = {
+ { .compatible = "blutek,bpa-rs600" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bpa_rs600_of_match);
+
+static struct i2c_driver bpa_rs600_driver = {
+ .driver = {
+ .name = "bpa-rs600",
+ .of_match_table = of_match_ptr(bpa_rs600_of_match),
+ },
+ .probe_new = bpa_rs600_probe,
+ .id_table = bpa_rs600_id,
+};
+
+module_i2c_driver(bpa_rs600_driver);
+
+MODULE_AUTHOR("Chris Packham");
+MODULE_DESCRIPTION("PMBus driver for BluTek BPA-RS600");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/fsp-3y.c b/drivers/hwmon/pmbus/fsp-3y.c
new file mode 100644
index 000000000000..b177987286ae
--- /dev/null
+++ b/drivers/hwmon/pmbus/fsp-3y.c
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Hardware monitoring driver for FSP 3Y-Power PSUs
+ *
+ * Copyright (c) 2021 Václav Kubernát, CESNET
+ *
+ * This driver is mostly reverse engineered with the help of a tool called pmbus_peek written by
+ * David Brownell (and later adopted by Jan Kundrát). The device has some sort of a timing issue
+ * when switching pages, details are explained in the code. The driver support is limited. It
+ * exposes only the values, that have been tested to work correctly. Unsupported values either
+ * aren't supported by the devices or their encondings are unknown.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "pmbus.h"
+
+#define YM2151_PAGE_12V_LOG 0x00
+#define YM2151_PAGE_12V_REAL 0x00
+#define YM2151_PAGE_5VSB_LOG 0x01
+#define YM2151_PAGE_5VSB_REAL 0x20
+#define YH5151E_PAGE_12V_LOG 0x00
+#define YH5151E_PAGE_12V_REAL 0x00
+#define YH5151E_PAGE_5V_LOG 0x01
+#define YH5151E_PAGE_5V_REAL 0x10
+#define YH5151E_PAGE_3V3_LOG 0x02
+#define YH5151E_PAGE_3V3_REAL 0x11
+
+enum chips {
+ ym2151e,
+ yh5151e
+};
+
+struct fsp3y_data {
+ struct pmbus_driver_info info;
+ int chip;
+ int page;
+};
+
+#define to_fsp3y_data(x) container_of(x, struct fsp3y_data, info)
+
+static int page_log_to_page_real(int page_log, enum chips chip)
+{
+ switch (chip) {
+ case ym2151e:
+ switch (page_log) {
+ case YM2151_PAGE_12V_LOG:
+ return YM2151_PAGE_12V_REAL;
+ case YM2151_PAGE_5VSB_LOG:
+ return YM2151_PAGE_5VSB_REAL;
+ }
+ return -EINVAL;
+ case yh5151e:
+ switch (page_log) {
+ case YH5151E_PAGE_12V_LOG:
+ return YH5151E_PAGE_12V_REAL;
+ case YH5151E_PAGE_5V_LOG:
+ return YH5151E_PAGE_5V_LOG;
+ case YH5151E_PAGE_3V3_LOG:
+ return YH5151E_PAGE_3V3_REAL;
+ }
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
+static int set_page(struct i2c_client *client, int page_log)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct fsp3y_data *data = to_fsp3y_data(info);
+ int rv;
+ int page_real;
+
+ if (page_log < 0)
+ return 0;
+
+ page_real = page_log_to_page_real(page_log, data->chip);
+ if (page_real < 0)
+ return page_real;
+
+ if (data->page != page_real) {
+ rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page_real);
+ if (rv < 0)
+ return rv;
+
+ data->page = page_real;
+
+ /*
+ * Testing showed that the device has a timing issue. After
+ * setting a page, it takes a while, before the device actually
+ * gives the correct values from the correct page. 20 ms was
+ * tested to be enough to not give wrong values (15 ms wasn't
+ * enough).
+ */
+ usleep_range(20000, 30000);
+ }
+
+ return 0;
+}
+
+static int fsp3y_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ int rv;
+
+ rv = set_page(client, page);
+ if (rv < 0)
+ return rv;
+
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int fsp3y_read_word_data(struct i2c_client *client, int page, int phase, int reg)
+{
+ int rv;
+
+ /*
+ * This masks commands which weren't tested to work correctly. Some of
+ * the masked commands return 0xFFFF. These would probably get tagged as
+ * invalid by pmbus_core. Other ones do return values which might be
+ * useful (that is, they are not 0xFFFF), but their encoding is unknown,
+ * and so they are unsupported.
+ */
+ switch (reg) {
+ case PMBUS_READ_FAN_SPEED_1:
+ case PMBUS_READ_IIN:
+ case PMBUS_READ_IOUT:
+ case PMBUS_READ_PIN:
+ case PMBUS_READ_POUT:
+ case PMBUS_READ_TEMPERATURE_1:
+ case PMBUS_READ_TEMPERATURE_2:
+ case PMBUS_READ_TEMPERATURE_3:
+ case PMBUS_READ_VIN:
+ case PMBUS_READ_VOUT:
+ case PMBUS_STATUS_WORD:
+ break;
+ default:
+ return -ENXIO;
+ }
+
+ rv = set_page(client, page);
+ if (rv < 0)
+ return rv;
+
+ return i2c_smbus_read_word_data(client, reg);
+}
+
+static struct pmbus_driver_info fsp3y_info[] = {
+ [ym2151e] = {
+ .pages = 2,
+ .func[YM2151_PAGE_12V_LOG] =
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+ PMBUS_HAVE_PIN | PMBUS_HAVE_POUT |
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
+ PMBUS_HAVE_VIN | PMBUS_HAVE_IIN |
+ PMBUS_HAVE_FAN12,
+ .func[YM2151_PAGE_5VSB_LOG] =
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT,
+ PMBUS_HAVE_IIN,
+ .read_word_data = fsp3y_read_word_data,
+ .read_byte_data = fsp3y_read_byte_data,
+ },
+ [yh5151e] = {
+ .pages = 3,
+ .func[YH5151E_PAGE_12V_LOG] =
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+ PMBUS_HAVE_POUT |
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3,
+ .func[YH5151E_PAGE_5V_LOG] =
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+ PMBUS_HAVE_POUT,
+ .func[YH5151E_PAGE_3V3_LOG] =
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+ PMBUS_HAVE_POUT,
+ .read_word_data = fsp3y_read_word_data,
+ .read_byte_data = fsp3y_read_byte_data,
+ }
+};
+
+static int fsp3y_detect(struct i2c_client *client)
+{
+ int rv;
+ u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
+
+ rv = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
+ if (rv < 0)
+ return rv;
+
+ buf[rv] = '\0';
+
+ if (rv == 8) {
+ if (!strcmp(buf, "YM-2151E"))
+ return ym2151e;
+ else if (!strcmp(buf, "YH-5151E"))
+ return yh5151e;
+ }
+
+ dev_err(&client->dev, "Unsupported model %.*s\n", rv, buf);
+ return -ENODEV;
+}
+
+static const struct i2c_device_id fsp3y_id[] = {
+ {"ym2151e", ym2151e},
+ {"yh5151e", yh5151e},
+ { }
+};
+
+static int fsp3y_probe(struct i2c_client *client)
+{
+ struct fsp3y_data *data;
+ const struct i2c_device_id *id;
+ int rv;
+
+ data = devm_kzalloc(&client->dev, sizeof(struct fsp3y_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->chip = fsp3y_detect(client);
+ if (data->chip < 0)
+ return data->chip;
+
+ id = i2c_match_id(fsp3y_id, client);
+ if (data->chip != id->driver_data)
+ dev_warn(&client->dev, "Device mismatch: Configured %s (%d), detected %d\n",
+ id->name, (int)id->driver_data, data->chip);
+
+ rv = i2c_smbus_read_byte_data(client, PMBUS_PAGE);
+ if (rv < 0)
+ return rv;
+ data->page = rv;
+
+ data->info = fsp3y_info[data->chip];
+
+ return pmbus_do_probe(client, &data->info);
+}
+
+MODULE_DEVICE_TABLE(i2c, fsp3y_id);
+
+static struct i2c_driver fsp3y_driver = {
+ .driver = {
+ .name = "fsp3y",
+ },
+ .probe_new = fsp3y_probe,
+ .id_table = fsp3y_id
+};
+
+module_i2c_driver(fsp3y_driver);
+
+MODULE_AUTHOR("Václav Kubernát");
+MODULE_DESCRIPTION("PMBus driver for FSP/3Y-Power power supplies");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c
index ffde5aaa5036..5668d8305b78 100644
--- a/drivers/hwmon/pmbus/ibm-cffps.c
+++ b/drivers/hwmon/pmbus/ibm-cffps.c
@@ -625,3 +625,4 @@ module_i2c_driver(ibm_cffps_driver);
MODULE_AUTHOR("Eddie James");
MODULE_DESCRIPTION("PMBus driver for IBM Common Form Factor power supplies");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/inspur-ipsps.c b/drivers/hwmon/pmbus/inspur-ipsps.c
index 88c5865c4d6f..0f614e8d95f6 100644
--- a/drivers/hwmon/pmbus/inspur-ipsps.c
+++ b/drivers/hwmon/pmbus/inspur-ipsps.c
@@ -70,7 +70,7 @@ static ssize_t ipsps_string_show(struct device *dev,
p = memscan(data, '#', rc);
*p = '\0';
- return snprintf(buf, PAGE_SIZE, "%s\n", data);
+ return sysfs_emit(buf, "%s\n", data);
}
static ssize_t ipsps_fw_version_show(struct device *dev,
@@ -91,9 +91,9 @@ static ssize_t ipsps_fw_version_show(struct device *dev,
if (rc != 6)
return -EPROTO;
- return snprintf(buf, PAGE_SIZE, "%u.%02u%u-%u.%02u\n",
- data[1], data[2]/* < 100 */, data[3]/*< 10*/,
- data[4], data[5]/* < 100 */);
+ return sysfs_emit(buf, "%u.%02u%u-%u.%02u\n",
+ data[1], data[2]/* < 100 */, data[3]/*< 10*/,
+ data[4], data[5]/* < 100 */);
}
static ssize_t ipsps_mode_show(struct device *dev,
@@ -111,19 +111,19 @@ static ssize_t ipsps_mode_show(struct device *dev,
switch (rc) {
case MODE_ACTIVE:
- return snprintf(buf, PAGE_SIZE, "[%s] %s %s\n",
- MODE_ACTIVE_STRING,
- MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
+ return sysfs_emit(buf, "[%s] %s %s\n",
+ MODE_ACTIVE_STRING,
+ MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
case MODE_STANDBY:
- return snprintf(buf, PAGE_SIZE, "%s [%s] %s\n",
- MODE_ACTIVE_STRING,
- MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
+ return sysfs_emit(buf, "%s [%s] %s\n",
+ MODE_ACTIVE_STRING,
+ MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
case MODE_REDUNDANCY:
- return snprintf(buf, PAGE_SIZE, "%s %s [%s]\n",
- MODE_ACTIVE_STRING,
- MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
+ return sysfs_emit(buf, "%s %s [%s]\n",
+ MODE_ACTIVE_STRING,
+ MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
default:
- return snprintf(buf, PAGE_SIZE, "unspecified\n");
+ return sysfs_emit(buf, "unspecified\n");
}
}
@@ -224,3 +224,4 @@ module_i2c_driver(ipsps_driver);
MODULE_AUTHOR("John Wang");
MODULE_DESCRIPTION("PMBus driver for Inspur Power System power supplies");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/ir35221.c b/drivers/hwmon/pmbus/ir35221.c
index 3aebeb1443fd..a6cf98e49666 100644
--- a/drivers/hwmon/pmbus/ir35221.c
+++ b/drivers/hwmon/pmbus/ir35221.c
@@ -145,3 +145,4 @@ module_i2c_driver(ir35221_driver);
MODULE_AUTHOR("Samuel Mendoza-Jonas <sam@mendozajonas.com");
MODULE_DESCRIPTION("PMBus driver for IR35221");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/ir36021.c b/drivers/hwmon/pmbus/ir36021.c
new file mode 100644
index 000000000000..4dca4767f571
--- /dev/null
+++ b/drivers/hwmon/pmbus/ir36021.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Hardware monitoring driver for Infineon IR36021
+ *
+ * Copyright (c) 2021 Allied Telesis
+ */
+#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 ir36021_info = {
+ .pages = 1,
+ .format[PSC_VOLTAGE_IN] = linear,
+ .format[PSC_VOLTAGE_OUT] = linear,
+ .format[PSC_CURRENT_IN] = linear,
+ .format[PSC_CURRENT_OUT] = linear,
+ .format[PSC_POWER] = linear,
+ .format[PSC_TEMPERATURE] = 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_TEMP2
+ | PMBUS_HAVE_STATUS_TEMP,
+};
+
+static int ir36021_probe(struct i2c_client *client)
+{
+ 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;
+
+ ret = i2c_smbus_read_i2c_block_data(client, PMBUS_MFR_MODEL, 2, buf);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read PMBUS_MFR_MODEL\n");
+ return ret;
+ }
+ if (ret != 2 || buf[0] != 0x01 || buf[1] != 0x2d) {
+ dev_err(&client->dev, "MFR_MODEL unrecognised\n");
+ return -ENODEV;
+ }
+
+ return pmbus_do_probe(client, &ir36021_info);
+}
+
+static const struct i2c_device_id ir36021_id[] = {
+ { "ir36021", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, ir36021_id);
+
+static const struct of_device_id __maybe_unused ir36021_of_id[] = {
+ { .compatible = "infineon,ir36021" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ir36021_of_id);
+
+static struct i2c_driver ir36021_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "ir36021",
+ .of_match_table = of_match_ptr(ir36021_of_id),
+ },
+ .probe_new = ir36021_probe,
+ .id_table = ir36021_id,
+};
+
+module_i2c_driver(ir36021_driver);
+
+MODULE_AUTHOR("Chris Packham <chris.packham@alliedtelesis.co.nz>");
+MODULE_DESCRIPTION("PMBus driver for Infineon IR36021");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/ir38064.c b/drivers/hwmon/pmbus/ir38064.c
index 46f17c4b4873..1fb7f1248639 100644
--- a/drivers/hwmon/pmbus/ir38064.c
+++ b/drivers/hwmon/pmbus/ir38064.c
@@ -61,3 +61,4 @@ module_i2c_driver(ir38064_driver);
MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>");
MODULE_DESCRIPTION("PMBus driver for Infineon IR38064");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/irps5401.c b/drivers/hwmon/pmbus/irps5401.c
index 93ef6d64a33a..de3449e4d77a 100644
--- a/drivers/hwmon/pmbus/irps5401.c
+++ b/drivers/hwmon/pmbus/irps5401.c
@@ -63,3 +63,4 @@ module_i2c_driver(irps5401_driver);
MODULE_AUTHOR("Robert Hancock");
MODULE_DESCRIPTION("PMBus driver for Infineon IRPS5401");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c
index 2bee930d3900..40597a9e799f 100644
--- a/drivers/hwmon/pmbus/isl68137.c
+++ b/drivers/hwmon/pmbus/isl68137.c
@@ -332,3 +332,4 @@ module_i2c_driver(isl68137_driver);
MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>");
MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
index e9a66fd9e144..d209e0afc2ca 100644
--- a/drivers/hwmon/pmbus/lm25066.c
+++ b/drivers/hwmon/pmbus/lm25066.c
@@ -511,3 +511,4 @@ module_i2c_driver(lm25066_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for LM25066 and compatible chips");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
index 7e53fa95b92d..0127273883f0 100644
--- a/drivers/hwmon/pmbus/ltc2978.c
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -883,3 +883,4 @@ module_i2c_driver(ltc2978_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for LTC2978 and compatible chips");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/ltc3815.c b/drivers/hwmon/pmbus/ltc3815.c
index e45e14d26c9a..8e13a7ddcb42 100644
--- a/drivers/hwmon/pmbus/ltc3815.c
+++ b/drivers/hwmon/pmbus/ltc3815.c
@@ -208,3 +208,4 @@ module_i2c_driver(ltc3815_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for LTC3815");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/max15301.c b/drivers/hwmon/pmbus/max15301.c
new file mode 100644
index 000000000000..0b6f88428ea8
--- /dev/null
+++ b/drivers/hwmon/pmbus/max15301.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Hardware monitoring driver for Maxim MAX15301
+ *
+ * Copyright (c) 2021 Flextronics International Sweden AB
+ *
+ * Even though the specification does not specifically mention it,
+ * extensive empirical testing has revealed that auto-detection of
+ * limit-registers will fail in a random fashion unless the delay
+ * parameter is set to above about 80us. The default delay is set
+ * to 100us to include some safety margin.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/ktime.h>
+#include <linux/delay.h>
+#include <linux/pmbus.h>
+#include "pmbus.h"
+
+static const struct i2c_device_id max15301_id[] = {
+ {"bmr461", 0},
+ {"max15301", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, max15301_id);
+
+struct max15301_data {
+ int id;
+ ktime_t access; /* Chip access time */
+ int delay; /* Delay between chip accesses in us */
+ struct pmbus_driver_info info;
+};
+
+#define to_max15301_data(x) container_of(x, struct max15301_data, info)
+
+#define MAX15301_WAIT_TIME 100 /* us */
+
+static ushort delay = MAX15301_WAIT_TIME;
+module_param(delay, ushort, 0644);
+MODULE_PARM_DESC(delay, "Delay between chip accesses in us");
+
+static struct max15301_data max15301_data = {
+ .info = {
+ .pages = 1,
+ .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
+ | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2
+ | PMBUS_HAVE_STATUS_TEMP
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+ }
+};
+
+/* This chip needs a delay between accesses */
+static inline void max15301_wait(const struct max15301_data *data)
+{
+ if (data->delay) {
+ s64 delta = ktime_us_delta(ktime_get(), data->access);
+
+ if (delta < data->delay)
+ udelay(data->delay - delta);
+ }
+}
+
+static int max15301_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 max15301_data *data = to_max15301_data(info);
+ int ret;
+
+ if (page > 0)
+ return -ENXIO;
+
+ if (reg >= PMBUS_VIRT_BASE)
+ return -ENXIO;
+
+ max15301_wait(data);
+ ret = pmbus_read_word_data(client, page, phase, reg);
+ data->access = ktime_get();
+
+ return ret;
+}
+
+static int max15301_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct max15301_data *data = to_max15301_data(info);
+ int ret;
+
+ if (page > 0)
+ return -ENXIO;
+
+ max15301_wait(data);
+ ret = pmbus_read_byte_data(client, page, reg);
+ data->access = ktime_get();
+
+ return ret;
+}
+
+static int max15301_write_word_data(struct i2c_client *client, int page, int reg,
+ u16 word)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct max15301_data *data = to_max15301_data(info);
+ int ret;
+
+ if (page > 0)
+ return -ENXIO;
+
+ if (reg >= PMBUS_VIRT_BASE)
+ return -ENXIO;
+
+ max15301_wait(data);
+ ret = pmbus_write_word_data(client, page, reg, word);
+ data->access = ktime_get();
+
+ return ret;
+}
+
+static int max15301_write_byte(struct i2c_client *client, int page, u8 value)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct max15301_data *data = to_max15301_data(info);
+ int ret;
+
+ if (page > 0)
+ return -ENXIO;
+
+ max15301_wait(data);
+ ret = pmbus_write_byte(client, page, value);
+ data->access = ktime_get();
+
+ return ret;
+}
+
+static int max15301_probe(struct i2c_client *client)
+{
+ int status;
+ u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
+ const struct i2c_device_id *mid;
+ struct pmbus_driver_info *info = &max15301_data.info;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA
+ | I2C_FUNC_SMBUS_BLOCK_DATA))
+ return -ENODEV;
+
+ status = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, device_id);
+ if (status < 0) {
+ dev_err(&client->dev, "Failed to read Device Id\n");
+ return status;
+ }
+ for (mid = max15301_id; mid->name[0]; mid++) {
+ if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
+ break;
+ }
+ if (!mid->name[0]) {
+ dev_err(&client->dev, "Unsupported device\n");
+ return -ENODEV;
+ }
+
+ max15301_data.delay = delay;
+
+ info->read_byte_data = max15301_read_byte_data;
+ info->read_word_data = max15301_read_word_data;
+ info->write_byte = max15301_write_byte;
+ info->write_word_data = max15301_write_word_data;
+
+ return pmbus_do_probe(client, info);
+}
+
+static struct i2c_driver max15301_driver = {
+ .driver = {
+ .name = "max15301",
+ },
+ .probe_new = max15301_probe,
+ .id_table = max15301_id,
+};
+
+module_i2c_driver(max15301_driver);
+
+MODULE_AUTHOR("Erik Rosen <erik.rosen@metormote.com>");
+MODULE_DESCRIPTION("PMBus driver for Maxim MAX15301");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c
index d79add99083e..94f869039071 100644
--- a/drivers/hwmon/pmbus/max16064.c
+++ b/drivers/hwmon/pmbus/max16064.c
@@ -111,3 +111,4 @@ module_i2c_driver(max16064_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX16064");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/max16601.c b/drivers/hwmon/pmbus/max16601.c
index 0d1204c2dd54..5a226a564776 100644
--- a/drivers/hwmon/pmbus/max16601.c
+++ b/drivers/hwmon/pmbus/max16601.c
@@ -359,3 +359,4 @@ module_i2c_driver(max16601_driver);
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX16601");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/max20730.c b/drivers/hwmon/pmbus/max20730.c
index 9dd3dd79bc18..ba39f03c6374 100644
--- a/drivers/hwmon/pmbus/max20730.c
+++ b/drivers/hwmon/pmbus/max20730.c
@@ -785,3 +785,4 @@ module_i2c_driver(max20730_driver);
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX20710 / MAX20730 / MAX20734 / MAX20743");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c
index 9d42f82fdd99..2272dc8c2e38 100644
--- a/drivers/hwmon/pmbus/max20751.c
+++ b/drivers/hwmon/pmbus/max20751.c
@@ -51,3 +51,4 @@ module_i2c_driver(max20751_driver);
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX20751");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c
index 17489abc49d5..95d79a64b483 100644
--- a/drivers/hwmon/pmbus/max31785.c
+++ b/drivers/hwmon/pmbus/max31785.c
@@ -403,3 +403,4 @@ module_i2c_driver(max31785_driver);
MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
MODULE_DESCRIPTION("PMBus driver for the Maxim MAX31785");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c
index dad66b3c0116..ea7609058a12 100644
--- a/drivers/hwmon/pmbus/max34440.c
+++ b/drivers/hwmon/pmbus/max34440.c
@@ -529,3 +529,4 @@ module_i2c_driver(max34440_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c
index 329dc851fc59..5e66c28c0b71 100644
--- a/drivers/hwmon/pmbus/max8688.c
+++ b/drivers/hwmon/pmbus/max8688.c
@@ -191,3 +191,4 @@ module_i2c_driver(max8688_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX8688");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c
index 60fbdb371332..eb94bd5f4e2a 100644
--- a/drivers/hwmon/pmbus/mp2975.c
+++ b/drivers/hwmon/pmbus/mp2975.c
@@ -766,3 +766,4 @@ module_i2c_driver(mp2975_driver);
MODULE_AUTHOR("Vadim Pasternak <vadimp@nvidia.com>");
MODULE_DESCRIPTION("PMBus driver for MPS MP2975 device");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/pm6764tr.c b/drivers/hwmon/pmbus/pm6764tr.c
index d97cb6d6c87f..e0bbc8a30d21 100644
--- a/drivers/hwmon/pmbus/pm6764tr.c
+++ b/drivers/hwmon/pmbus/pm6764tr.c
@@ -73,3 +73,4 @@ module_i2c_driver(pm6764tr_driver);
MODULE_AUTHOR("Charles Hsu");
MODULE_DESCRIPTION("PMBus driver for ST PM6764TR");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c
index a1b4260e75b2..618c377664c4 100644
--- a/drivers/hwmon/pmbus/pmbus.c
+++ b/drivers/hwmon/pmbus/pmbus.c
@@ -246,3 +246,4 @@ module_i2c_driver(pmbus_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("Generic PMBus driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index 4c30ec89f5bf..3968924f8533 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -475,6 +475,7 @@ extern const struct regulator_ops pmbus_regulator_ops;
/* Function declarations */
void pmbus_clear_cache(struct i2c_client *client);
+void pmbus_set_update(struct i2c_client *client, u8 reg, bool update);
int pmbus_set_page(struct i2c_client *client, int page, int phase);
int pmbus_read_word_data(struct i2c_client *client, int page, int phase,
u8 reg);
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index aadea85fe630..bbd745178147 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -139,7 +139,18 @@ void pmbus_clear_cache(struct i2c_client *client)
for (sensor = data->sensors; sensor; sensor = sensor->next)
sensor->data = -ENODATA;
}
-EXPORT_SYMBOL_GPL(pmbus_clear_cache);
+EXPORT_SYMBOL_NS_GPL(pmbus_clear_cache, PMBUS);
+
+void pmbus_set_update(struct i2c_client *client, u8 reg, bool update)
+{
+ struct pmbus_data *data = i2c_get_clientdata(client);
+ struct pmbus_sensor *sensor;
+
+ for (sensor = data->sensors; sensor; sensor = sensor->next)
+ if (sensor->reg == reg)
+ sensor->update = update;
+}
+EXPORT_SYMBOL_NS_GPL(pmbus_set_update, PMBUS);
int pmbus_set_page(struct i2c_client *client, int page, int phase)
{
@@ -175,7 +186,7 @@ int pmbus_set_page(struct i2c_client *client, int page, int phase)
return 0;
}
-EXPORT_SYMBOL_GPL(pmbus_set_page);
+EXPORT_SYMBOL_NS_GPL(pmbus_set_page, PMBUS);
int pmbus_write_byte(struct i2c_client *client, int page, u8 value)
{
@@ -187,7 +198,7 @@ int pmbus_write_byte(struct i2c_client *client, int page, u8 value)
return i2c_smbus_write_byte(client, value);
}
-EXPORT_SYMBOL_GPL(pmbus_write_byte);
+EXPORT_SYMBOL_NS_GPL(pmbus_write_byte, PMBUS);
/*
* _pmbus_write_byte() is similar to pmbus_write_byte(), but checks if
@@ -218,7 +229,7 @@ int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg,
return i2c_smbus_write_word_data(client, reg, word);
}
-EXPORT_SYMBOL_GPL(pmbus_write_word_data);
+EXPORT_SYMBOL_NS_GPL(pmbus_write_word_data, PMBUS);
static int pmbus_write_virt_reg(struct i2c_client *client, int page, int reg,
@@ -288,7 +299,7 @@ int pmbus_update_fan(struct i2c_client *client, int page, int id,
return _pmbus_write_word_data(client, page,
pmbus_fan_command_registers[id], command);
}
-EXPORT_SYMBOL_GPL(pmbus_update_fan);
+EXPORT_SYMBOL_NS_GPL(pmbus_update_fan, PMBUS);
int pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg)
{
@@ -300,7 +311,7 @@ int pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg)
return i2c_smbus_read_word_data(client, reg);
}
-EXPORT_SYMBOL_GPL(pmbus_read_word_data);
+EXPORT_SYMBOL_NS_GPL(pmbus_read_word_data, PMBUS);
static int pmbus_read_virt_reg(struct i2c_client *client, int page, int reg)
{
@@ -359,7 +370,7 @@ int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg)
return i2c_smbus_read_byte_data(client, reg);
}
-EXPORT_SYMBOL_GPL(pmbus_read_byte_data);
+EXPORT_SYMBOL_NS_GPL(pmbus_read_byte_data, PMBUS);
int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value)
{
@@ -371,7 +382,7 @@ int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value)
return i2c_smbus_write_byte_data(client, reg, value);
}
-EXPORT_SYMBOL_GPL(pmbus_write_byte_data);
+EXPORT_SYMBOL_NS_GPL(pmbus_write_byte_data, PMBUS);
int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,
u8 mask, u8 value)
@@ -390,7 +401,7 @@ int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,
return rv;
}
-EXPORT_SYMBOL_GPL(pmbus_update_byte_data);
+EXPORT_SYMBOL_NS_GPL(pmbus_update_byte_data, PMBUS);
/*
* _pmbus_read_byte_data() is similar to pmbus_read_byte_data(), but checks if
@@ -463,14 +474,14 @@ int pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id,
{
return pmbus_get_fan_rate(client, page, id, mode, false);
}
-EXPORT_SYMBOL_GPL(pmbus_get_fan_rate_device);
+EXPORT_SYMBOL_NS_GPL(pmbus_get_fan_rate_device, PMBUS);
int pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id,
enum pmbus_fan_mode mode)
{
return pmbus_get_fan_rate(client, page, id, mode, true);
}
-EXPORT_SYMBOL_GPL(pmbus_get_fan_rate_cached);
+EXPORT_SYMBOL_NS_GPL(pmbus_get_fan_rate_cached, PMBUS);
static void pmbus_clear_fault_page(struct i2c_client *client, int page)
{
@@ -485,7 +496,7 @@ void pmbus_clear_faults(struct i2c_client *client)
for (i = 0; i < data->info->pages; i++)
pmbus_clear_fault_page(client, i);
}
-EXPORT_SYMBOL_GPL(pmbus_clear_faults);
+EXPORT_SYMBOL_NS_GPL(pmbus_clear_faults, PMBUS);
static int pmbus_check_status_cml(struct i2c_client *client)
{
@@ -537,13 +548,13 @@ bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg)
{
return pmbus_check_register(client, _pmbus_read_byte_data, page, reg);
}
-EXPORT_SYMBOL_GPL(pmbus_check_byte_register);
+EXPORT_SYMBOL_NS_GPL(pmbus_check_byte_register, PMBUS);
bool pmbus_check_word_register(struct i2c_client *client, int page, int reg)
{
return pmbus_check_register(client, __pmbus_read_word_data, page, reg);
}
-EXPORT_SYMBOL_GPL(pmbus_check_word_register);
+EXPORT_SYMBOL_NS_GPL(pmbus_check_word_register, PMBUS);
const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client)
{
@@ -551,7 +562,7 @@ const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client)
return data->info;
}
-EXPORT_SYMBOL_GPL(pmbus_get_driver_info);
+EXPORT_SYMBOL_NS_GPL(pmbus_get_driver_info, PMBUS);
static int pmbus_get_status(struct i2c_client *client, int page, int reg)
{
@@ -932,7 +943,7 @@ static ssize_t pmbus_show_boolean(struct device *dev,
val = pmbus_get_boolean(client, boolean, attr->index);
if (val < 0)
return val;
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
static ssize_t pmbus_show_sensor(struct device *dev,
@@ -948,7 +959,7 @@ static ssize_t pmbus_show_sensor(struct device *dev,
if (sensor->data < 0)
ret = sensor->data;
else
- ret = snprintf(buf, PAGE_SIZE, "%lld\n", pmbus_reg2data(data, sensor));
+ ret = sysfs_emit(buf, "%lld\n", pmbus_reg2data(data, sensor));
mutex_unlock(&data->update_lock);
return ret;
}
@@ -984,7 +995,7 @@ static ssize_t pmbus_show_label(struct device *dev,
{
struct pmbus_label *label = to_pmbus_label(da);
- return snprintf(buf, PAGE_SIZE, "%s\n", label->label);
+ return sysfs_emit(buf, "%s\n", label->label);
}
static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr)
@@ -2024,7 +2035,7 @@ static ssize_t pmbus_show_samples(struct device *dev,
if (val < 0)
return val;
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
static ssize_t pmbus_set_samples(struct device *dev,
@@ -2288,7 +2299,7 @@ const struct regulator_ops pmbus_regulator_ops = {
.disable = pmbus_regulator_disable,
.is_enabled = pmbus_regulator_is_enabled,
};
-EXPORT_SYMBOL_GPL(pmbus_regulator_ops);
+EXPORT_SYMBOL_NS_GPL(pmbus_regulator_ops, PMBUS);
static int pmbus_regulator_register(struct pmbus_data *data)
{
@@ -2557,6 +2568,7 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info)
struct pmbus_data *data;
size_t groups_num = 0;
int ret;
+ char *name;
if (!info)
return -ENODEV;
@@ -2606,10 +2618,15 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info)
return -ENODEV;
}
+ name = devm_kstrdup(dev, client->name, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+ strreplace(name, '-', '_');
+
data->groups[0] = &data->group;
memcpy(data->groups + 1, info->groups, sizeof(void *) * groups_num);
data->hwmon_dev = devm_hwmon_device_register_with_groups(dev,
- client->name, data, data->groups);
+ name, data, data->groups);
if (IS_ERR(data->hwmon_dev)) {
dev_err(dev, "Failed to register hwmon device\n");
return PTR_ERR(data->hwmon_dev);
@@ -2625,7 +2642,7 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info)
return 0;
}
-EXPORT_SYMBOL_GPL(pmbus_do_probe);
+EXPORT_SYMBOL_NS_GPL(pmbus_do_probe, PMBUS);
struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client)
{
@@ -2633,7 +2650,7 @@ struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client)
return data->debugfs;
}
-EXPORT_SYMBOL_GPL(pmbus_get_debugfs_dir);
+EXPORT_SYMBOL_NS_GPL(pmbus_get_debugfs_dir, PMBUS);
static int __init pmbus_core_init(void)
{
diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c
index da27ce34ee3f..52bee5de2988 100644
--- a/drivers/hwmon/pmbus/pxe1610.c
+++ b/drivers/hwmon/pmbus/pxe1610.c
@@ -41,6 +41,15 @@ static int pxe1610_identify(struct i2c_client *client,
info->vrm_version[i] = vr13;
break;
default:
+ /*
+ * If prior pages are available limit operation
+ * to them
+ */
+ if (i != 0) {
+ info->pages = i;
+ return 0;
+ }
+
return -ENODEV;
}
}
@@ -139,3 +148,4 @@ 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");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/q54sj108a2.c b/drivers/hwmon/pmbus/q54sj108a2.c
index aec512766c31..b6e8b20466f1 100644
--- a/drivers/hwmon/pmbus/q54sj108a2.c
+++ b/drivers/hwmon/pmbus/q54sj108a2.c
@@ -420,3 +420,4 @@ module_i2c_driver(q54sj108a2_driver);
MODULE_AUTHOR("Xiao.Ma <xiao.mx.ma@deltaww.com>");
MODULE_DESCRIPTION("PMBus driver for Delta Q54SJ108A2 series modules");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/stpddc60.c b/drivers/hwmon/pmbus/stpddc60.c
new file mode 100644
index 000000000000..357b9d9d896b
--- /dev/null
+++ b/drivers/hwmon/pmbus/stpddc60.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Hardware monitoring driver for the STPDDC60 controller
+ *
+ * Copyright (c) 2021 Flextronics International Sweden AB.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/pmbus.h>
+#include "pmbus.h"
+
+#define STPDDC60_MFR_READ_VOUT 0xd2
+#define STPDDC60_MFR_OV_LIMIT_OFFSET 0xe5
+#define STPDDC60_MFR_UV_LIMIT_OFFSET 0xe6
+
+static const struct i2c_device_id stpddc60_id[] = {
+ {"stpddc60", 0},
+ {"bmr481", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, stpddc60_id);
+
+static struct pmbus_driver_info stpddc60_info = {
+ .pages = 1,
+ .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
+ | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+ | PMBUS_HAVE_POUT,
+};
+
+/*
+ * Calculate the closest absolute offset between commanded vout value
+ * and limit value in steps of 50mv in the range 0 (50mv) to 7 (400mv).
+ * Return 0 if the upper limit is lower than vout or if the lower limit
+ * is higher than vout.
+ */
+static u8 stpddc60_get_offset(int vout, u16 limit, bool over)
+{
+ int offset;
+ long v, l;
+
+ v = 250 + (vout - 1) * 5; /* Convert VID to mv */
+ l = (limit * 1000L) >> 8; /* Convert LINEAR to mv */
+
+ if (over == (l < v))
+ return 0;
+
+ offset = DIV_ROUND_CLOSEST(abs(l - v), 50);
+
+ if (offset > 0)
+ offset--;
+
+ return clamp_val(offset, 0, 7);
+}
+
+/*
+ * Adjust the linear format word to use the given fixed exponent.
+ */
+static u16 stpddc60_adjust_linear(u16 word, s16 fixed)
+{
+ s16 e, m, d;
+
+ e = ((s16)word) >> 11;
+ m = ((s16)((word & 0x7ff) << 5)) >> 5;
+ d = e - fixed;
+
+ if (d >= 0)
+ m <<= d;
+ else
+ m >>= -d;
+
+ return clamp_val(m, 0, 0x3ff) | ((fixed << 11) & 0xf800);
+}
+
+/*
+ * The VOUT_COMMAND register uses the VID format but the vout alarm limit
+ * registers use the LINEAR format so we override VOUT_MODE here to force
+ * LINEAR format for all registers.
+ */
+static int stpddc60_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ int ret;
+
+ if (page > 0)
+ return -ENXIO;
+
+ switch (reg) {
+ case PMBUS_VOUT_MODE:
+ ret = 0x18;
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * The vout related registers return values in LINEAR11 format when LINEAR16
+ * is expected. Clear the top 5 bits to set the exponent part to zero to
+ * convert the value to LINEAR16 format.
+ */
+static int stpddc60_read_word_data(struct i2c_client *client, int page,
+ int phase, int reg)
+{
+ int ret;
+
+ if (page > 0)
+ return -ENXIO;
+
+ switch (reg) {
+ case PMBUS_READ_VOUT:
+ ret = pmbus_read_word_data(client, page, phase,
+ STPDDC60_MFR_READ_VOUT);
+ if (ret < 0)
+ return ret;
+ ret &= 0x7ff;
+ break;
+ case PMBUS_VOUT_OV_FAULT_LIMIT:
+ case PMBUS_VOUT_UV_FAULT_LIMIT:
+ ret = pmbus_read_word_data(client, page, phase, reg);
+ if (ret < 0)
+ return ret;
+ ret &= 0x7ff;
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * The vout under- and over-voltage limits are set as an offset relative to
+ * the commanded vout voltage. The vin, iout, pout and temp limits must use
+ * the same fixed exponent the chip uses to encode the data when read.
+ */
+static int stpddc60_write_word_data(struct i2c_client *client, int page,
+ int reg, u16 word)
+{
+ int ret;
+ u8 offset;
+
+ if (page > 0)
+ return -ENXIO;
+
+ switch (reg) {
+ case PMBUS_VOUT_OV_FAULT_LIMIT:
+ ret = pmbus_read_word_data(client, page, 0xff,
+ PMBUS_VOUT_COMMAND);
+ if (ret < 0)
+ return ret;
+ offset = stpddc60_get_offset(ret, word, true);
+ ret = pmbus_write_byte_data(client, page,
+ STPDDC60_MFR_OV_LIMIT_OFFSET,
+ offset);
+ break;
+ case PMBUS_VOUT_UV_FAULT_LIMIT:
+ ret = pmbus_read_word_data(client, page, 0xff,
+ PMBUS_VOUT_COMMAND);
+ if (ret < 0)
+ return ret;
+ offset = stpddc60_get_offset(ret, word, false);
+ ret = pmbus_write_byte_data(client, page,
+ STPDDC60_MFR_UV_LIMIT_OFFSET,
+ offset);
+ break;
+ case PMBUS_VIN_OV_FAULT_LIMIT:
+ case PMBUS_VIN_UV_FAULT_LIMIT:
+ case PMBUS_OT_FAULT_LIMIT:
+ case PMBUS_OT_WARN_LIMIT:
+ case PMBUS_IOUT_OC_FAULT_LIMIT:
+ case PMBUS_IOUT_OC_WARN_LIMIT:
+ case PMBUS_POUT_OP_FAULT_LIMIT:
+ ret = pmbus_read_word_data(client, page, 0xff, reg);
+ if (ret < 0)
+ return ret;
+ word = stpddc60_adjust_linear(word, ret >> 11);
+ ret = pmbus_write_word_data(client, page, reg, word);
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+
+ return ret;
+}
+
+static int stpddc60_probe(struct i2c_client *client)
+{
+ int status;
+ u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
+ const struct i2c_device_id *mid;
+ struct pmbus_driver_info *info = &stpddc60_info;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA
+ | I2C_FUNC_SMBUS_BLOCK_DATA))
+ return -ENODEV;
+
+ status = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, device_id);
+ if (status < 0) {
+ dev_err(&client->dev, "Failed to read Manufacturer Model\n");
+ return status;
+ }
+ for (mid = stpddc60_id; mid->name[0]; mid++) {
+ if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
+ break;
+ }
+ if (!mid->name[0]) {
+ dev_err(&client->dev, "Unsupported device\n");
+ return -ENODEV;
+ }
+
+ info->read_byte_data = stpddc60_read_byte_data;
+ info->read_word_data = stpddc60_read_word_data;
+ info->write_word_data = stpddc60_write_word_data;
+
+ status = pmbus_do_probe(client, info);
+ if (status < 0)
+ return status;
+
+ pmbus_set_update(client, PMBUS_VOUT_OV_FAULT_LIMIT, true);
+ pmbus_set_update(client, PMBUS_VOUT_UV_FAULT_LIMIT, true);
+
+ return 0;
+}
+
+static struct i2c_driver stpddc60_driver = {
+ .driver = {
+ .name = "stpddc60",
+ },
+ .probe_new = stpddc60_probe,
+ .id_table = stpddc60_id,
+};
+
+module_i2c_driver(stpddc60_driver);
+
+MODULE_AUTHOR("Erik Rosen <erik.rosen@metormote.com>");
+MODULE_DESCRIPTION("PMBus driver for ST STPDDC60");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/tps40422.c b/drivers/hwmon/pmbus/tps40422.c
index f7f00ab6f46c..31bb83c0ef3e 100644
--- a/drivers/hwmon/pmbus/tps40422.c
+++ b/drivers/hwmon/pmbus/tps40422.c
@@ -51,3 +51,4 @@ module_i2c_driver(tps40422_driver);
MODULE_AUTHOR("Zhu Laiwen <richard.zhu@nsn.com>");
MODULE_DESCRIPTION("PMBus driver for TI TPS40422");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c
index ba838fa311c3..81b9d813655a 100644
--- a/drivers/hwmon/pmbus/tps53679.c
+++ b/drivers/hwmon/pmbus/tps53679.c
@@ -16,11 +16,14 @@
#include "pmbus.h"
enum chips {
- tps53647, tps53667, tps53679, tps53681, tps53688
+ tps53647, tps53667, tps53676, tps53679, tps53681, tps53688
};
#define TPS53647_PAGE_NUM 1
+#define TPS53676_USER_DATA_03 0xb3
+#define TPS53676_MAX_PHASES 7
+
#define TPS53679_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */
#define TPS53679_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */
#define TPS53679_PROT_VR13_10MV 0x04 /* VR13.0 mode, 10-mV DAC */
@@ -143,6 +146,45 @@ static int tps53681_identify(struct i2c_client *client,
TPS53681_DEVICE_ID);
}
+static int tps53676_identify(struct i2c_client *client,
+ struct pmbus_driver_info *info)
+{
+ u8 buf[I2C_SMBUS_BLOCK_MAX];
+ int phases_a = 0, phases_b = 0;
+ int i, ret;
+
+ ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf);
+ if (ret < 0)
+ return ret;
+ if (strncmp("TI\x53\x67\x60", buf, 5)) {
+ dev_err(&client->dev, "Unexpected device ID: %s\n", buf);
+ return -ENODEV;
+ }
+
+ ret = i2c_smbus_read_block_data(client, TPS53676_USER_DATA_03, buf);
+ if (ret < 0)
+ return ret;
+ if (ret != 24)
+ return -EIO;
+ for (i = 0; i < 2 * TPS53676_MAX_PHASES; i += 2) {
+ if (buf[i + 1] & 0x80) {
+ if (buf[i] & 0x08)
+ phases_b++;
+ else
+ phases_a++;
+ }
+ }
+
+ info->format[PSC_VOLTAGE_OUT] = linear;
+ info->pages = 1;
+ info->phases[0] = phases_a;
+ if (phases_b > 0) {
+ info->pages = 2;
+ info->phases[1] = phases_b;
+ }
+ return 0;
+}
+
static int tps53681_read_word_data(struct i2c_client *client, int page,
int phase, int reg)
{
@@ -183,6 +225,7 @@ static struct pmbus_driver_info tps53679_info = {
.pfunc[3] = PMBUS_HAVE_IOUT,
.pfunc[4] = PMBUS_HAVE_IOUT,
.pfunc[5] = PMBUS_HAVE_IOUT,
+ .pfunc[6] = PMBUS_HAVE_IOUT,
};
static int tps53679_probe(struct i2c_client *client)
@@ -206,6 +249,9 @@ static int tps53679_probe(struct i2c_client *client)
info->pages = TPS53647_PAGE_NUM;
info->identify = tps53679_identify;
break;
+ case tps53676:
+ info->identify = tps53676_identify;
+ break;
case tps53679:
case tps53688:
info->pages = TPS53679_PAGE_NUM;
@@ -225,8 +271,10 @@ static int tps53679_probe(struct i2c_client *client)
}
static const struct i2c_device_id tps53679_id[] = {
+ {"bmr474", tps53676},
{"tps53647", tps53647},
{"tps53667", tps53667},
+ {"tps53676", tps53676},
{"tps53679", tps53679},
{"tps53681", tps53681},
{"tps53688", tps53688},
@@ -238,6 +286,7 @@ MODULE_DEVICE_TABLE(i2c, tps53679_id);
static const struct of_device_id __maybe_unused tps53679_of_match[] = {
{.compatible = "ti,tps53647", .data = (void *)tps53647},
{.compatible = "ti,tps53667", .data = (void *)tps53667},
+ {.compatible = "ti,tps53676", .data = (void *)tps53676},
{.compatible = "ti,tps53679", .data = (void *)tps53679},
{.compatible = "ti,tps53681", .data = (void *)tps53681},
{.compatible = "ti,tps53688", .data = (void *)tps53688},
@@ -259,3 +308,4 @@ module_i2c_driver(tps53679_driver);
MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
MODULE_DESCRIPTION("PMBus driver for Texas Instruments TPS53679");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c
index a15e6fe3e425..75fc770c9e40 100644
--- a/drivers/hwmon/pmbus/ucd9000.c
+++ b/drivers/hwmon/pmbus/ucd9000.c
@@ -629,3 +629,4 @@ module_i2c_driver(ucd9000_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c
index 47cc7ca9d329..6bc3273e31e7 100644
--- a/drivers/hwmon/pmbus/ucd9200.c
+++ b/drivers/hwmon/pmbus/ucd9200.c
@@ -209,3 +209,4 @@ module_i2c_driver(ucd9200_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for TI UCD922x, UCD924x");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/xdpe12284.c b/drivers/hwmon/pmbus/xdpe12284.c
index f8bc0f41cd5f..b07da06a40c9 100644
--- a/drivers/hwmon/pmbus/xdpe12284.c
+++ b/drivers/hwmon/pmbus/xdpe12284.c
@@ -168,3 +168,4 @@ module_i2c_driver(xdpe122_driver);
MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
MODULE_DESCRIPTION("PMBus driver for Infineon XDPE122 family");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c
index 69120ca7aaa8..b7d4eacdc3ef 100644
--- a/drivers/hwmon/pmbus/zl6100.c
+++ b/drivers/hwmon/pmbus/zl6100.c
@@ -404,3 +404,4 @@ module_i2c_driver(zl6100_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PMBUS);
diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c
index f2703c5460d0..70ae665db477 100644
--- a/drivers/hwmon/s3c-hwmon.c
+++ b/drivers/hwmon/s3c-hwmon.c
@@ -166,7 +166,7 @@ static ssize_t s3c_hwmon_ch_show(struct device *dev,
ret *= cfg->mult;
ret = DIV_ROUND_CLOSEST(ret, cfg->div);
- return snprintf(buf, PAGE_SIZE, "%d\n", ret);
+ return sysfs_emit(buf, "%d\n", ret);
}
/**
@@ -187,7 +187,7 @@ static ssize_t s3c_hwmon_label_show(struct device *dev,
cfg = pdata->in[sen_attr->index];
- return snprintf(buf, PAGE_SIZE, "%s\n", cfg->name);
+ return sysfs_emit(buf, "%s\n", cfg->name);
}
/**
diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c
index 039644263101..4324a5dbc968 100644
--- a/drivers/hwmon/sch5627.c
+++ b/drivers/hwmon/sch5627.c
@@ -12,7 +12,6 @@
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include "sch56xx-common.h"
@@ -65,7 +64,6 @@ static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
struct sch5627_data {
unsigned short addr;
- struct device *hwmon_dev;
struct sch56xx_watchdog_data *watchdog;
u8 control;
u8 temp_max[SCH5627_NO_TEMPS];
@@ -74,66 +72,96 @@ struct sch5627_data {
struct mutex update_lock;
unsigned long last_battery; /* In jiffies */
- char valid; /* !=0 if following fields are valid */
- unsigned long last_updated; /* In jiffies */
+ char temp_valid; /* !=0 if following fields are valid */
+ char fan_valid;
+ char in_valid;
+ unsigned long temp_last_updated; /* In jiffies */
+ unsigned long fan_last_updated;
+ unsigned long in_last_updated;
u16 temp[SCH5627_NO_TEMPS];
u16 fan[SCH5627_NO_FANS];
u16 in[SCH5627_NO_IN];
};
-static struct sch5627_data *sch5627_update_device(struct device *dev)
+static int sch5627_update_temp(struct sch5627_data *data)
{
- struct sch5627_data *data = dev_get_drvdata(dev);
- struct sch5627_data *ret = data;
+ int ret = 0;
int i, val;
mutex_lock(&data->update_lock);
- /* Trigger a Vbat voltage measurement every 5 minutes */
- if (time_after(jiffies, data->last_battery + 300 * HZ)) {
- sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL,
- data->control | 0x10);
- data->last_battery = jiffies;
- }
-
/* Cache the values for 1 second */
- if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ if (time_after(jiffies, data->temp_last_updated + HZ) || !data->temp_valid) {
for (i = 0; i < SCH5627_NO_TEMPS; i++) {
- val = sch56xx_read_virtual_reg12(data->addr,
- SCH5627_REG_TEMP_MSB[i],
- SCH5627_REG_TEMP_LSN[i],
- SCH5627_REG_TEMP_HIGH_NIBBLE[i]);
+ val = sch56xx_read_virtual_reg12(data->addr, SCH5627_REG_TEMP_MSB[i],
+ SCH5627_REG_TEMP_LSN[i],
+ SCH5627_REG_TEMP_HIGH_NIBBLE[i]);
if (unlikely(val < 0)) {
- ret = ERR_PTR(val);
+ ret = val;
goto abort;
}
data->temp[i] = val;
}
+ data->temp_last_updated = jiffies;
+ data->temp_valid = 1;
+ }
+abort:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+static int sch5627_update_fan(struct sch5627_data *data)
+{
+ int ret = 0;
+ int i, val;
+
+ mutex_lock(&data->update_lock);
+
+ /* Cache the values for 1 second */
+ if (time_after(jiffies, data->fan_last_updated + HZ) || !data->fan_valid) {
for (i = 0; i < SCH5627_NO_FANS; i++) {
- val = sch56xx_read_virtual_reg16(data->addr,
- SCH5627_REG_FAN[i]);
+ val = sch56xx_read_virtual_reg16(data->addr, SCH5627_REG_FAN[i]);
if (unlikely(val < 0)) {
- ret = ERR_PTR(val);
+ ret = val;
goto abort;
}
data->fan[i] = val;
}
+ data->fan_last_updated = jiffies;
+ data->fan_valid = 1;
+ }
+abort:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static int sch5627_update_in(struct sch5627_data *data)
+{
+ int ret = 0;
+ int i, val;
+
+ mutex_lock(&data->update_lock);
+ /* Trigger a Vbat voltage measurement every 5 minutes */
+ if (time_after(jiffies, data->last_battery + 300 * HZ)) {
+ sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL, data->control | 0x10);
+ data->last_battery = jiffies;
+ }
+
+ /* Cache the values for 1 second */
+ if (time_after(jiffies, data->in_last_updated + HZ) || !data->in_valid) {
for (i = 0; i < SCH5627_NO_IN; i++) {
- val = sch56xx_read_virtual_reg12(data->addr,
- SCH5627_REG_IN_MSB[i],
- SCH5627_REG_IN_LSN[i],
- SCH5627_REG_IN_HIGH_NIBBLE[i]);
+ val = sch56xx_read_virtual_reg12(data->addr, SCH5627_REG_IN_MSB[i],
+ SCH5627_REG_IN_LSN[i],
+ SCH5627_REG_IN_HIGH_NIBBLE[i]);
if (unlikely(val < 0)) {
- ret = ERR_PTR(val);
+ ret = val;
goto abort;
}
data->in[i] = val;
}
-
- data->last_updated = jiffies;
- data->valid = 1;
+ data->in_last_updated = jiffies;
+ data->in_valid = 1;
}
abort:
mutex_unlock(&data->update_lock);
@@ -192,249 +220,141 @@ static int reg_to_rpm(u16 reg)
return 5400540 / reg;
}
-static ssize_t name_show(struct device *dev, struct device_attribute *devattr,
- char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%s\n", DEVNAME);
-}
-
-static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct sch5627_data *data = sch5627_update_device(dev);
- int val;
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- val = reg_to_temp(data->temp[attr->index]);
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
-}
-
-static ssize_t temp_fault_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct sch5627_data *data = sch5627_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", data->temp[attr->index] == 0);
-}
-
-static ssize_t temp_max_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct sch5627_data *data = dev_get_drvdata(dev);
- int val;
-
- val = reg_to_temp_limit(data->temp_max[attr->index]);
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
-}
-
-static ssize_t temp_crit_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct sch5627_data *data = dev_get_drvdata(dev);
- int val;
-
- val = reg_to_temp_limit(data->temp_crit[attr->index]);
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
-}
-
-static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct sch5627_data *data = sch5627_update_device(dev);
- int val;
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- val = reg_to_rpm(data->fan[attr->index]);
- if (val < 0)
- return val;
-
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
-}
-
-static ssize_t fan_fault_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
+static umode_t sch5627_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,
+ int channel)
{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct sch5627_data *data = sch5627_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- data->fan[attr->index] == 0xffff);
+ return 0444;
}
-static ssize_t fan_min_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
+static int sch5627_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
+ long *val)
{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct sch5627_data *data = dev_get_drvdata(dev);
- int val = reg_to_rpm(data->fan_min[attr->index]);
- if (val < 0)
- return val;
-
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
-}
-
-static ssize_t in_show(struct device *dev, struct device_attribute *devattr,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct sch5627_data *data = sch5627_update_device(dev);
- int val;
-
- if (IS_ERR(data))
- return PTR_ERR(data);
+ int ret;
+
+ switch (type) {
+ case hwmon_temp:
+ ret = sch5627_update_temp(data);
+ if (ret < 0)
+ return ret;
+ switch (attr) {
+ case hwmon_temp_input:
+ *val = reg_to_temp(data->temp[channel]);
+ return 0;
+ case hwmon_temp_max:
+ *val = reg_to_temp_limit(data->temp_max[channel]);
+ return 0;
+ case hwmon_temp_crit:
+ *val = reg_to_temp_limit(data->temp_crit[channel]);
+ return 0;
+ case hwmon_temp_fault:
+ *val = (data->temp[channel] == 0);
+ return 0;
+ default:
+ break;
+ }
+ break;
+ case hwmon_fan:
+ ret = sch5627_update_fan(data);
+ if (ret < 0)
+ return ret;
+ switch (attr) {
+ case hwmon_fan_input:
+ ret = reg_to_rpm(data->fan[channel]);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return 0;
+ case hwmon_fan_min:
+ ret = reg_to_rpm(data->fan_min[channel]);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return 0;
+ case hwmon_fan_fault:
+ *val = (data->fan[channel] == 0xffff);
+ return 0;
+ default:
+ break;
+ }
+ break;
+ case hwmon_in:
+ ret = sch5627_update_in(data);
+ if (ret < 0)
+ return ret;
+ switch (attr) {
+ case hwmon_in_input:
+ *val = DIV_ROUND_CLOSEST(data->in[channel] * SCH5627_REG_IN_FACTOR[channel],
+ 10000);
+ return 0;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
- val = DIV_ROUND_CLOSEST(
- data->in[attr->index] * SCH5627_REG_IN_FACTOR[attr->index],
- 10000);
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
+ return -EOPNOTSUPP;
}
-static ssize_t in_label_show(struct device *dev,
- struct device_attribute *devattr, char *buf)
+static int sch5627_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+ int channel, const char **str)
{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ switch (type) {
+ case hwmon_in:
+ switch (attr) {
+ case hwmon_in_label:
+ *str = SCH5627_IN_LABELS[channel];
+ return 0;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
- return snprintf(buf, PAGE_SIZE, "%s\n",
- SCH5627_IN_LABELS[attr->index]);
+ return -EOPNOTSUPP;
}
-static DEVICE_ATTR_RO(name);
-static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
-static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
-static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);
-static SENSOR_DEVICE_ATTR_RO(temp4_input, temp, 3);
-static SENSOR_DEVICE_ATTR_RO(temp5_input, temp, 4);
-static SENSOR_DEVICE_ATTR_RO(temp6_input, temp, 5);
-static SENSOR_DEVICE_ATTR_RO(temp7_input, temp, 6);
-static SENSOR_DEVICE_ATTR_RO(temp8_input, temp, 7);
-static SENSOR_DEVICE_ATTR_RO(temp1_fault, temp_fault, 0);
-static SENSOR_DEVICE_ATTR_RO(temp2_fault, temp_fault, 1);
-static SENSOR_DEVICE_ATTR_RO(temp3_fault, temp_fault, 2);
-static SENSOR_DEVICE_ATTR_RO(temp4_fault, temp_fault, 3);
-static SENSOR_DEVICE_ATTR_RO(temp5_fault, temp_fault, 4);
-static SENSOR_DEVICE_ATTR_RO(temp6_fault, temp_fault, 5);
-static SENSOR_DEVICE_ATTR_RO(temp7_fault, temp_fault, 6);
-static SENSOR_DEVICE_ATTR_RO(temp8_fault, temp_fault, 7);
-static SENSOR_DEVICE_ATTR_RO(temp1_max, temp_max, 0);
-static SENSOR_DEVICE_ATTR_RO(temp2_max, temp_max, 1);
-static SENSOR_DEVICE_ATTR_RO(temp3_max, temp_max, 2);
-static SENSOR_DEVICE_ATTR_RO(temp4_max, temp_max, 3);
-static SENSOR_DEVICE_ATTR_RO(temp5_max, temp_max, 4);
-static SENSOR_DEVICE_ATTR_RO(temp6_max, temp_max, 5);
-static SENSOR_DEVICE_ATTR_RO(temp7_max, temp_max, 6);
-static SENSOR_DEVICE_ATTR_RO(temp8_max, temp_max, 7);
-static SENSOR_DEVICE_ATTR_RO(temp1_crit, temp_crit, 0);
-static SENSOR_DEVICE_ATTR_RO(temp2_crit, temp_crit, 1);
-static SENSOR_DEVICE_ATTR_RO(temp3_crit, temp_crit, 2);
-static SENSOR_DEVICE_ATTR_RO(temp4_crit, temp_crit, 3);
-static SENSOR_DEVICE_ATTR_RO(temp5_crit, temp_crit, 4);
-static SENSOR_DEVICE_ATTR_RO(temp6_crit, temp_crit, 5);
-static SENSOR_DEVICE_ATTR_RO(temp7_crit, temp_crit, 6);
-static SENSOR_DEVICE_ATTR_RO(temp8_crit, temp_crit, 7);
-
-static SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
-static SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
-static SENSOR_DEVICE_ATTR_RO(fan3_input, fan, 2);
-static SENSOR_DEVICE_ATTR_RO(fan4_input, fan, 3);
-static SENSOR_DEVICE_ATTR_RO(fan1_fault, fan_fault, 0);
-static SENSOR_DEVICE_ATTR_RO(fan2_fault, fan_fault, 1);
-static SENSOR_DEVICE_ATTR_RO(fan3_fault, fan_fault, 2);
-static SENSOR_DEVICE_ATTR_RO(fan4_fault, fan_fault, 3);
-static SENSOR_DEVICE_ATTR_RO(fan1_min, fan_min, 0);
-static SENSOR_DEVICE_ATTR_RO(fan2_min, fan_min, 1);
-static SENSOR_DEVICE_ATTR_RO(fan3_min, fan_min, 2);
-static SENSOR_DEVICE_ATTR_RO(fan4_min, fan_min, 3);
-
-static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0);
-static SENSOR_DEVICE_ATTR_RO(in1_input, in, 1);
-static SENSOR_DEVICE_ATTR_RO(in2_input, in, 2);
-static SENSOR_DEVICE_ATTR_RO(in3_input, in, 3);
-static SENSOR_DEVICE_ATTR_RO(in4_input, in, 4);
-static SENSOR_DEVICE_ATTR_RO(in0_label, in_label, 0);
-static SENSOR_DEVICE_ATTR_RO(in1_label, in_label, 1);
-static SENSOR_DEVICE_ATTR_RO(in2_label, in_label, 2);
-static SENSOR_DEVICE_ATTR_RO(in3_label, in_label, 3);
-
-static struct attribute *sch5627_attributes[] = {
- &dev_attr_name.attr,
-
- &sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp2_input.dev_attr.attr,
- &sensor_dev_attr_temp3_input.dev_attr.attr,
- &sensor_dev_attr_temp4_input.dev_attr.attr,
- &sensor_dev_attr_temp5_input.dev_attr.attr,
- &sensor_dev_attr_temp6_input.dev_attr.attr,
- &sensor_dev_attr_temp7_input.dev_attr.attr,
- &sensor_dev_attr_temp8_input.dev_attr.attr,
- &sensor_dev_attr_temp1_fault.dev_attr.attr,
- &sensor_dev_attr_temp2_fault.dev_attr.attr,
- &sensor_dev_attr_temp3_fault.dev_attr.attr,
- &sensor_dev_attr_temp4_fault.dev_attr.attr,
- &sensor_dev_attr_temp5_fault.dev_attr.attr,
- &sensor_dev_attr_temp6_fault.dev_attr.attr,
- &sensor_dev_attr_temp7_fault.dev_attr.attr,
- &sensor_dev_attr_temp8_fault.dev_attr.attr,
- &sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp2_max.dev_attr.attr,
- &sensor_dev_attr_temp3_max.dev_attr.attr,
- &sensor_dev_attr_temp4_max.dev_attr.attr,
- &sensor_dev_attr_temp5_max.dev_attr.attr,
- &sensor_dev_attr_temp6_max.dev_attr.attr,
- &sensor_dev_attr_temp7_max.dev_attr.attr,
- &sensor_dev_attr_temp8_max.dev_attr.attr,
- &sensor_dev_attr_temp1_crit.dev_attr.attr,
- &sensor_dev_attr_temp2_crit.dev_attr.attr,
- &sensor_dev_attr_temp3_crit.dev_attr.attr,
- &sensor_dev_attr_temp4_crit.dev_attr.attr,
- &sensor_dev_attr_temp5_crit.dev_attr.attr,
- &sensor_dev_attr_temp6_crit.dev_attr.attr,
- &sensor_dev_attr_temp7_crit.dev_attr.attr,
- &sensor_dev_attr_temp8_crit.dev_attr.attr,
-
- &sensor_dev_attr_fan1_input.dev_attr.attr,
- &sensor_dev_attr_fan2_input.dev_attr.attr,
- &sensor_dev_attr_fan3_input.dev_attr.attr,
- &sensor_dev_attr_fan4_input.dev_attr.attr,
- &sensor_dev_attr_fan1_fault.dev_attr.attr,
- &sensor_dev_attr_fan2_fault.dev_attr.attr,
- &sensor_dev_attr_fan3_fault.dev_attr.attr,
- &sensor_dev_attr_fan4_fault.dev_attr.attr,
- &sensor_dev_attr_fan1_min.dev_attr.attr,
- &sensor_dev_attr_fan2_min.dev_attr.attr,
- &sensor_dev_attr_fan3_min.dev_attr.attr,
- &sensor_dev_attr_fan4_min.dev_attr.attr,
-
- &sensor_dev_attr_in0_input.dev_attr.attr,
- &sensor_dev_attr_in1_input.dev_attr.attr,
- &sensor_dev_attr_in2_input.dev_attr.attr,
- &sensor_dev_attr_in3_input.dev_attr.attr,
- &sensor_dev_attr_in4_input.dev_attr.attr,
- &sensor_dev_attr_in0_label.dev_attr.attr,
- &sensor_dev_attr_in1_label.dev_attr.attr,
- &sensor_dev_attr_in2_label.dev_attr.attr,
- &sensor_dev_attr_in3_label.dev_attr.attr,
- /* No in4_label as in4 is a generic input pin */
+static const struct hwmon_ops sch5627_ops = {
+ .is_visible = sch5627_is_visible,
+ .read = sch5627_read,
+ .read_string = sch5627_read_string,
+};
+static const struct hwmon_channel_info *sch5627_info[] = {
+ HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT
+ ),
+ HWMON_CHANNEL_INFO(fan,
+ HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
+ HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT
+ ),
+ HWMON_CHANNEL_INFO(in,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT
+ ),
NULL
};
-static const struct attribute_group sch5627_group = {
- .attrs = sch5627_attributes,
+static const struct hwmon_chip_info sch5627_chip_info = {
+ .ops = &sch5627_ops,
+ .info = sch5627_info,
};
static int sch5627_remove(struct platform_device *pdev)
@@ -444,17 +364,13 @@ static int sch5627_remove(struct platform_device *pdev)
if (data->watchdog)
sch56xx_watchdog_unregister(data->watchdog);
- if (data->hwmon_dev)
- hwmon_device_unregister(data->hwmon_dev);
-
- sysfs_remove_group(&pdev->dev.kobj, &sch5627_group);
-
return 0;
}
static int sch5627_probe(struct platform_device *pdev)
{
struct sch5627_data *data;
+ struct device *hwmon_dev;
int err, build_code, build_id, hwmon_rev, val;
data = devm_kzalloc(&pdev->dev, sizeof(struct sch5627_data),
@@ -467,72 +383,58 @@ static int sch5627_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_HWMON_ID);
- if (val < 0) {
- err = val;
- goto error;
- }
+ if (val < 0)
+ return val;
+
if (val != SCH5627_HWMON_ID) {
pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "hwmon",
val, SCH5627_HWMON_ID);
- err = -ENODEV;
- goto error;
+ return -ENODEV;
}
val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_COMPANY_ID);
- if (val < 0) {
- err = val;
- goto error;
- }
+ if (val < 0)
+ return val;
+
if (val != SCH5627_COMPANY_ID) {
pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "company",
val, SCH5627_COMPANY_ID);
- err = -ENODEV;
- goto error;
+ return -ENODEV;
}
val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_PRIMARY_ID);
- if (val < 0) {
- err = val;
- goto error;
- }
+ if (val < 0)
+ return val;
+
if (val != SCH5627_PRIMARY_ID) {
pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "primary",
val, SCH5627_PRIMARY_ID);
- err = -ENODEV;
- goto error;
+ return -ENODEV;
}
build_code = sch56xx_read_virtual_reg(data->addr,
SCH5627_REG_BUILD_CODE);
- if (build_code < 0) {
- err = build_code;
- goto error;
- }
+ if (build_code < 0)
+ return build_code;
build_id = sch56xx_read_virtual_reg16(data->addr,
SCH5627_REG_BUILD_ID);
- if (build_id < 0) {
- err = build_id;
- goto error;
- }
+ if (build_id < 0)
+ return build_id;
hwmon_rev = sch56xx_read_virtual_reg(data->addr,
SCH5627_REG_HWMON_REV);
- if (hwmon_rev < 0) {
- err = hwmon_rev;
- goto error;
- }
+ if (hwmon_rev < 0)
+ return hwmon_rev;
val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_CTRL);
- if (val < 0) {
- err = val;
- goto error;
- }
+ if (val < 0)
+ return val;
+
data->control = val;
if (!(data->control & 0x01)) {
pr_err("hardware monitoring not enabled\n");
- err = -ENODEV;
- goto error;
+ return -ENODEV;
}
/* Trigger a Vbat voltage measurement, so that we get a valid reading
the first time we read Vbat */
@@ -546,23 +448,16 @@ static int sch5627_probe(struct platform_device *pdev)
*/
err = sch5627_read_limits(data);
if (err)
- goto error;
+ return err;
pr_info("found %s chip at %#hx\n", DEVNAME, data->addr);
pr_info("firmware build: code 0x%02X, id 0x%04X, hwmon: rev 0x%02X\n",
build_code, build_id, hwmon_rev);
- /* Register sysfs interface files */
- err = sysfs_create_group(&pdev->dev.kobj, &sch5627_group);
- if (err)
- goto error;
-
- data->hwmon_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->hwmon_dev)) {
- err = PTR_ERR(data->hwmon_dev);
- data->hwmon_dev = NULL;
- goto error;
- }
+ hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, DEVNAME, data,
+ &sch5627_chip_info, NULL);
+ if (IS_ERR(hwmon_dev))
+ return PTR_ERR(hwmon_dev);
/* Note failing to register the watchdog is not a fatal error */
data->watchdog = sch56xx_watchdog_register(&pdev->dev, data->addr,
@@ -570,10 +465,6 @@ static int sch5627_probe(struct platform_device *pdev)
&data->update_lock, 1);
return 0;
-
-error:
- sch5627_remove(pdev);
- return err;
}
static struct platform_driver sch5627_driver = {
diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c
index 200bb2bfc986..5683a38740f6 100644
--- a/drivers/hwmon/sch5636.c
+++ b/drivers/hwmon/sch5636.c
@@ -160,7 +160,7 @@ static int reg_to_rpm(u16 reg)
static ssize_t name_show(struct device *dev, struct device_attribute *devattr,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%s\n", DEVNAME);
+ return sysfs_emit(buf, "%s\n", DEVNAME);
}
static ssize_t in_value_show(struct device *dev,
@@ -176,7 +176,7 @@ static ssize_t in_value_show(struct device *dev,
val = DIV_ROUND_CLOSEST(
data->in[attr->index] * SCH5636_REG_IN_FACTORS[attr->index],
255);
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
static ssize_t in_label_show(struct device *dev,
@@ -184,8 +184,8 @@ static ssize_t in_label_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- return snprintf(buf, PAGE_SIZE, "%s\n",
- SCH5636_IN_LABELS[attr->index]);
+ return sysfs_emit(buf, "%s\n",
+ SCH5636_IN_LABELS[attr->index]);
}
static ssize_t temp_value_show(struct device *dev,
@@ -199,7 +199,7 @@ static ssize_t temp_value_show(struct device *dev,
return PTR_ERR(data);
val = (data->temp_val[attr->index] - 64) * 1000;
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
static ssize_t temp_fault_show(struct device *dev,
@@ -213,7 +213,7 @@ static ssize_t temp_fault_show(struct device *dev,
return PTR_ERR(data);
val = (data->temp_ctrl[attr->index] & SCH5636_TEMP_WORKING) ? 0 : 1;
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
static ssize_t temp_alarm_show(struct device *dev,
@@ -227,7 +227,7 @@ static ssize_t temp_alarm_show(struct device *dev,
return PTR_ERR(data);
val = (data->temp_ctrl[attr->index] & SCH5636_TEMP_ALARM) ? 1 : 0;
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
static ssize_t fan_value_show(struct device *dev,
@@ -244,7 +244,7 @@ static ssize_t fan_value_show(struct device *dev,
if (val < 0)
return val;
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
static ssize_t fan_fault_show(struct device *dev,
@@ -258,7 +258,7 @@ static ssize_t fan_fault_show(struct device *dev,
return PTR_ERR(data);
val = (data->fan_ctrl[attr->index] & SCH5636_FAN_NOT_PRESENT) ? 1 : 0;
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
static ssize_t fan_alarm_show(struct device *dev,
@@ -272,7 +272,7 @@ static ssize_t fan_alarm_show(struct device *dev,
return PTR_ERR(data);
val = (data->fan_ctrl[attr->index] & SCH5636_FAN_ALARM) ? 1 : 0;
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
static struct sensor_device_attribute sch5636_attr[] = {
diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c
index b6cbe9810a1b..62906d9c4b86 100644
--- a/drivers/hwmon/smm665.c
+++ b/drivers/hwmon/smm665.c
@@ -351,7 +351,7 @@ static ssize_t smm665_show_crit_alarm(struct device *dev,
if (data->faults & (1 << attr->index))
val = 1;
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
static ssize_t smm665_show_input(struct device *dev,
@@ -366,7 +366,7 @@ static ssize_t smm665_show_input(struct device *dev,
return PTR_ERR(data);
val = smm665_convert(data->adc[adc], adc);
- return snprintf(buf, PAGE_SIZE, "%d\n", val);
+ return sysfs_emit(buf, "%d\n", val);
}
#define SMM665_SHOW(what) \
diff --git a/drivers/hwmon/stts751.c b/drivers/hwmon/stts751.c
index 6928be6dbe4e..0ed28408aa07 100644
--- a/drivers/hwmon/stts751.c
+++ b/drivers/hwmon/stts751.c
@@ -387,7 +387,7 @@ static ssize_t max_alarm_show(struct device *dev,
if (ret < 0)
return ret;
- return snprintf(buf, PAGE_SIZE, "%d\n", priv->max_alert);
+ return sysfs_emit(buf, "%d\n", priv->max_alert);
}
static ssize_t min_alarm_show(struct device *dev,
@@ -404,7 +404,7 @@ static ssize_t min_alarm_show(struct device *dev,
if (ret < 0)
return ret;
- return snprintf(buf, PAGE_SIZE, "%d\n", priv->min_alert);
+ return sysfs_emit(buf, "%d\n", priv->min_alert);
}
static ssize_t input_show(struct device *dev, struct device_attribute *attr,
@@ -419,7 +419,7 @@ static ssize_t input_show(struct device *dev, struct device_attribute *attr,
if (ret < 0)
return ret;
- return snprintf(buf, PAGE_SIZE, "%d\n", priv->temp);
+ return sysfs_emit(buf, "%d\n", priv->temp);
}
static ssize_t therm_show(struct device *dev, struct device_attribute *attr,
@@ -427,7 +427,7 @@ static ssize_t therm_show(struct device *dev, struct device_attribute *attr,
{
struct stts751_priv *priv = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%d\n", priv->therm);
+ return sysfs_emit(buf, "%d\n", priv->therm);
}
static ssize_t therm_store(struct device *dev, struct device_attribute *attr,
@@ -469,7 +469,7 @@ static ssize_t hyst_show(struct device *dev, struct device_attribute *attr,
{
struct stts751_priv *priv = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%d\n", priv->hyst);
+ return sysfs_emit(buf, "%d\n", priv->hyst);
}
static ssize_t hyst_store(struct device *dev, struct device_attribute *attr,
@@ -509,7 +509,7 @@ static ssize_t therm_trip_show(struct device *dev,
if (ret < 0)
return ret;
- return snprintf(buf, PAGE_SIZE, "%d\n", priv->therm_trip);
+ return sysfs_emit(buf, "%d\n", priv->therm_trip);
}
static ssize_t max_show(struct device *dev, struct device_attribute *attr,
@@ -517,7 +517,7 @@ static ssize_t max_show(struct device *dev, struct device_attribute *attr,
{
struct stts751_priv *priv = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%d\n", priv->event_max);
+ return sysfs_emit(buf, "%d\n", priv->event_max);
}
static ssize_t max_store(struct device *dev, struct device_attribute *attr,
@@ -551,7 +551,7 @@ static ssize_t min_show(struct device *dev, struct device_attribute *attr,
{
struct stts751_priv *priv = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%d\n", priv->event_min);
+ return sysfs_emit(buf, "%d\n", priv->event_min);
}
static ssize_t min_store(struct device *dev, struct device_attribute *attr,
@@ -585,8 +585,8 @@ static ssize_t interval_show(struct device *dev,
{
struct stts751_priv *priv = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%d\n",
- stts751_intervals[priv->interval]);
+ return sysfs_emit(buf, "%d\n",
+ stts751_intervals[priv->interval]);
}
static ssize_t interval_store(struct device *dev,
diff --git a/drivers/hwmon/vexpress-hwmon.c b/drivers/hwmon/vexpress-hwmon.c
index e7109657129a..44d798be3d59 100644
--- a/drivers/hwmon/vexpress-hwmon.c
+++ b/drivers/hwmon/vexpress-hwmon.c
@@ -27,7 +27,7 @@ static ssize_t vexpress_hwmon_label_show(struct device *dev,
{
const char *label = of_get_property(dev->of_node, "label", NULL);
- return snprintf(buffer, PAGE_SIZE, "%s\n", label);
+ return sysfs_emit(buffer, "%s\n", label);
}
static ssize_t vexpress_hwmon_u32_show(struct device *dev,
@@ -41,8 +41,8 @@ static ssize_t vexpress_hwmon_u32_show(struct device *dev,
if (err)
return err;
- return snprintf(buffer, PAGE_SIZE, "%u\n", value /
- to_sensor_dev_attr(dev_attr)->index);
+ return sysfs_emit(buffer, "%u\n", value /
+ to_sensor_dev_attr(dev_attr)->index);
}
static ssize_t vexpress_hwmon_u64_show(struct device *dev,
@@ -60,9 +60,9 @@ static ssize_t vexpress_hwmon_u64_show(struct device *dev,
if (err)
return err;
- return snprintf(buffer, PAGE_SIZE, "%llu\n",
- div_u64(((u64)value_hi << 32) | value_lo,
- to_sensor_dev_attr(dev_attr)->index));
+ return sysfs_emit(buffer, "%llu\n",
+ div_u64(((u64)value_hi << 32) | value_lo,
+ to_sensor_dev_attr(dev_attr)->index));
}
static umode_t vexpress_hwmon_attr_is_visible(struct kobject *kobj,
diff --git a/drivers/hwmon/xgene-hwmon.c b/drivers/hwmon/xgene-hwmon.c
index 1489e83cb0c4..382ef0395d8e 100644
--- a/drivers/hwmon/xgene-hwmon.c
+++ b/drivers/hwmon/xgene-hwmon.c
@@ -329,14 +329,14 @@ static ssize_t temp1_input_show(struct device *dev,
temp = sign_extend32(val, TEMP_NEGATIVE_BIT);
- return snprintf(buf, PAGE_SIZE, "%d\n", CELSIUS_TO_mCELSIUS(temp));
+ return sysfs_emit(buf, "%d\n", CELSIUS_TO_mCELSIUS(temp));
}
static ssize_t temp1_label_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, "SoC Temperature\n");
+ return sysfs_emit(buf, "SoC Temperature\n");
}
static ssize_t temp1_critical_alarm_show(struct device *dev,
@@ -345,21 +345,21 @@ static ssize_t temp1_critical_alarm_show(struct device *dev,
{
struct xgene_hwmon_dev *ctx = dev_get_drvdata(dev);
- return snprintf(buf, PAGE_SIZE, "%d\n", ctx->temp_critical_alarm);
+ return sysfs_emit(buf, "%d\n", ctx->temp_critical_alarm);
}
static ssize_t power1_label_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, "CPU power\n");
+ return sysfs_emit(buf, "CPU power\n");
}
static ssize_t power2_label_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, "IO power\n");
+ return sysfs_emit(buf, "IO power\n");
}
static ssize_t power1_input_show(struct device *dev,
@@ -374,7 +374,7 @@ static ssize_t power1_input_show(struct device *dev,
if (rc < 0)
return rc;
- return snprintf(buf, PAGE_SIZE, "%u\n", mWATT_TO_uWATT(val));
+ return sysfs_emit(buf, "%u\n", mWATT_TO_uWATT(val));
}
static ssize_t power2_input_show(struct device *dev,
@@ -389,7 +389,7 @@ static ssize_t power2_input_show(struct device *dev,
if (rc < 0)
return rc;
- return snprintf(buf, PAGE_SIZE, "%u\n", mWATT_TO_uWATT(val));
+ return sysfs_emit(buf, "%u\n", mWATT_TO_uWATT(val));
}
static DEVICE_ATTR_RO(temp1_label);