Commit 4d03390b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hwmon-for-v6.2-rc1' of...

Merge tag 'hwmon-for-v6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon updates from Guenter Roeck:
 "New drivers:

   - Driver for OneXPlayer mini AMD sensors

   - Ampere's Altra smpro-hwmon driver

  New chip and attribute support in existing drivers:

   - nct6775: Support for ASUS CROSSHAIR VIII/TUF/ProArt B550M

   - pmbus/ltc2978: Support for LTC7132

   - aquacomputer_d5next: Support for temperature sensor offsets and
     flow sensor pulses

   - coretemp: Support for dynamic ttarget and tjmax

  Improvements:

   - Use devm_regulator_get_enable() where appropriate

   - Use sysfs_emit() instead of scnprintf()

   - Remove some useless #include <linux/hwmon-vid.h>

   - Include <linux/kstrtox.h> when appropriate

   - Use simple i2c probe

   - it87: Check for a valid chip before using force_id, and new new
     module parameter to ignore ACPI resource conflicts

   - jc42: Use regmap, and restore min/max/critical temperatures on
     resume

   - Add reporting power good and status to PMBus based regulators

  Last minute fixes:

   - emc2305: Fix probing of emc2301/2/3, and fix setting pwm values
     manually if THERMAL is enabled

  And various other minor fixes and improvements"

* tag 'hwmon-for-v6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (37 commits)
  hwmon: (emc2305) fix pwm never being able to set lower
  hwmon: (emc2305) fix unable to probe emc2301/2/3
  hwmon: (dell-smm) Move error message to make probing silent
  hwmon: use sysfs_emit() to instead of scnprintf()
  hwmon: (oxp-sensors) Fix pwm reading
  hwmon: (aquacomputer_d5next) Add support for Quadro flow sensor pulses
  hwmon: (pmbus/core) Implement regulator get_status
  hwmon: (oxp-sensors) Add AOK ZOE and Mini PRO
  hwmon: (gsc-hwmon) Switch to flexible array to simplify code
  hwmon: (pmbus) Add power good support
  hwmon: (nct6775) add ASUS CROSSHAIR VIII/TUF/ProArt B550M
  hwmon: (coretemp) Add support for dynamic ttarget
  hwmon: (coretemp) Add support for dynamic tjmax
  hwmon: (coretemp) rearrange tjmax handing code
  hwmon: Remove some useless #include <linux/hwmon-vid.h>
  hwmon: (coretemp) Remove obsolete temp_data->valid
  hwmon: add OneXPlayer mini AMD sensors driver
  hwmon: (aquacomputer_d5next) Clear up macros and comments
  hwmon: (it87) Add DMI table for future extensions
  hwmon: Include <linux/kstrtox.h> when appropriate
  ...
parents 361c89a0 364ffd25
......@@ -39,7 +39,7 @@ current.
The Quadro exposes four physical and sixteen virtual temperature sensors, a flow
sensor and four PWM controllable fans, along with their speed (in RPM), power,
voltage and current.
voltage and current. Flow sensor pulses are also available.
The Farbwerk and Farbwerk 360 expose four temperature sensors. Additionally,
sixteen virtual temperature sensors of the Farbwerk 360 are exposed.
......@@ -62,7 +62,9 @@ Sysfs entries
================ ==============================================================
temp[1-20]_input Physical/virtual temperature sensors (in millidegrees Celsius)
temp[1-4]_offset Temperature sensor correction offset (in millidegrees Celsius)
fan[1-8]_input Pump/fan speed (in RPM) / Flow speed (in dL/h)
fan5_pulses Quadro flow sensor pulses
power[1-8]_input Pump/fan power (in micro Watts)
in[0-7]_input Pump/fan voltage (in milli Volts)
curr[1-8]_input Pump/fan current (in milli Amperes)
......
......@@ -160,6 +160,7 @@ Hardware Monitoring Kernel Drivers
nzxt-kraken2
nzxt-smart2
occ
oxp-sensors
pc87360
pc87427
pcf8591
......@@ -187,6 +188,7 @@ Hardware Monitoring Kernel Drivers
sis5595
sl28cpld
smm665
smpro-hwmon
smsc47b397
smsc47m192
smsc47m1
......
.. SPDX-License-Identifier: GPL-2.0-or-later
Kernel driver oxp-sensors
=========================
Author:
- Joaquín Ignacio Aramendía <samsagax@gmail.com>
Description:
------------
One X Player devices from One Netbook provide fan readings and fan control
through its Embedded Controller.
Currently only supports AMD boards from the One X Player and AOK ZOE lineup.
Intel boards could be supported if we could figure out the EC registers and
values to write to since the EC layout and model is different.
Supported devices
-----------------
Currently the driver supports the following handhelds:
- AOK ZOE A1
- OneXPlayer AMD
- OneXPlayer mini AMD
- OneXPlayer mini AMD PRO
Sysfs entries
-------------
The following attributes are supported:
fan1_input
Read Only. Reads current fan RMP.
pwm1_enable
Read Write. Enable manual fan control. Write "1" to set to manual, write "0"
to let the EC control de fan speed. Read this attribute to see current status.
pwm1
Read Write. Read this attribute to see current duty cycle in the range [0-255].
When pwm1_enable is set to "1" (manual) write any value in the range [0-255]
to set fan speed.
.. SPDX-License-Identifier: GPL-2.0-only
Kernel driver Ampere(R)'s Altra(R) SMpro hwmon
==============================================
Supported chips:
* Ampere(R) Altra(R)
Prefix: ``smpro``
Reference: `Altra SoC BMC Interface Specification`
Author: Thu Nguyen <thu@os.amperecomputing.com>
Description
-----------
The smpro-hwmon driver supports hardware monitoring for Ampere(R) Altra(R)
SoCs based on the SMpro co-processor (SMpro). The following sensor metrics
are supported by the driver:
* temperature
* voltage
* current
* power
The interface provides the registers to query the various sensors and
their values which are then exported to userspace by this driver.
Usage Notes
-----------
The driver creates at least two sysfs files for each sensor.
* ``<sensor_type><idx>_label`` reports the sensor label.
* ``<sensor_type><idx>_input`` returns the sensor value.
The sysfs files are allocated in the SMpro rootfs folder, with one root
directory for each instance.
When the SoC is turned off, the driver will fail to read registers and
return ``-ENXIO``.
Sysfs entries
-------------
The following sysfs files are supported:
* Ampere(R) Altra(R):
============ ============= ====== ===============================================
Name Unit Perm Description
============ ============= ====== ===============================================
temp1_input millicelsius RO SoC temperature
temp2_input millicelsius RO Max temperature reported among SoC VRDs
temp2_crit millicelsius RO SoC VRD HOT Threshold temperature
temp3_input millicelsius RO Max temperature reported among DIMM VRDs
temp4_input millicelsius RO Max temperature reported among Core VRDs
temp5_input millicelsius RO Temperature of DIMM0 on CH0
temp5_crit millicelsius RO MEM HOT Threshold for all DIMMs
temp6_input millicelsius RO Temperature of DIMM0 on CH1
temp6_crit millicelsius RO MEM HOT Threshold for all DIMMs
temp7_input millicelsius RO Temperature of DIMM0 on CH2
temp7_crit millicelsius RO MEM HOT Threshold for all DIMMs
temp8_input millicelsius RO Temperature of DIMM0 on CH3
temp8_crit millicelsius RO MEM HOT Threshold for all DIMMs
temp9_input millicelsius RO Temperature of DIMM0 on CH4
temp9_crit millicelsius RO MEM HOT Threshold for all DIMMs
temp10_input millicelsius RO Temperature of DIMM0 on CH5
temp10_crit millicelsius RO MEM HOT Threshold for all DIMMs
temp11_input millicelsius RO Temperature of DIMM0 on CH6
temp11_crit millicelsius RO MEM HOT Threshold for all DIMMs
temp12_input millicelsius RO Temperature of DIMM0 on CH7
temp12_crit millicelsius RO MEM HOT Threshold for all DIMMs
temp13_input millicelsius RO Max temperature reported among RCA VRDs
in0_input millivolts RO Core voltage
in1_input millivolts RO SoC voltage
in2_input millivolts RO DIMM VRD1 voltage
in3_input millivolts RO DIMM VRD2 voltage
in4_input millivolts RO RCA VRD voltage
cur1_input milliamperes RO Core VRD current
cur2_input milliamperes RO SoC VRD current
cur3_input milliamperes RO DIMM VRD1 current
cur4_input milliamperes RO DIMM VRD2 current
cur5_input milliamperes RO RCA VRD current
power1_input microwatts RO Core VRD power
power2_input microwatts RO SoC VRD power
power3_input microwatts RO DIMM VRD1 power
power4_input microwatts RO DIMM VRD2 power
power5_input microwatts RO RCA VRD power
============ ============= ====== ===============================================
Example::
# cat in0_input
830
# cat temp1_input
37000
# cat curr1_input
9000
# cat power5_input
19500000
......@@ -15452,6 +15452,12 @@ S: Maintained
F: drivers/mtd/nand/onenand/
F: include/linux/mtd/onenand*.h
ONEXPLAYER FAN DRIVER
M: Joaquín Ignacio Aramendía <samsagax@gmail.com>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: drivers/hwmon/oxp-sensors.c
ONION OMEGA2+ BOARD
M: Harvey Hunt <harveyhuntnexus@gmail.com>
L: linux-mips@vger.kernel.org
......
......@@ -67,6 +67,14 @@ config SENSORS_ABITUGURU3
This driver can also be built as a module. If so, the module
will be called abituguru3.
config SENSORS_SMPRO
tristate "Ampere's Altra SMpro hardware monitoring driver"
depends on MFD_SMPRO
help
If you say yes here you get support for the thermal, voltage,
current and power sensors of Ampere's Altra processor family SoC
with SMpro co-processor.
config SENSORS_AD7314
tristate "Analog Devices AD7314 and compatibles"
depends on SPI
......@@ -799,6 +807,7 @@ config SENSORS_IT87
config SENSORS_JC42
tristate "JEDEC JC42.4 compliant memory module temperature sensors"
depends on I2C
select REGMAP_I2C
help
If you say yes here, you get support for JEDEC JC42.4 compliant
temperature sensors, which are used on many DDR3 memory modules for
......@@ -1607,6 +1616,17 @@ config SENSORS_NZXT_SMART2
source "drivers/hwmon/occ/Kconfig"
config SENSORS_OXP
tristate "OneXPlayer EC fan control"
depends on ACPI
depends on X86
help
If you say yes here you get support for fan readings and control over
OneXPlayer handheld devices. Only OneXPlayer mini AMD handheld variant
boards are supported.
Can also be built as a module. In that case it will be called oxp-sensors.
config SENSORS_PCF8591
tristate "Philips PCF8591 ADC/DAC"
depends on I2C
......
......@@ -167,6 +167,7 @@ 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_NZXT_SMART2) += nzxt-smart2.o
obj-$(CONFIG_SENSORS_OXP) += oxp-sensors.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
......@@ -187,6 +188,7 @@ obj-$(CONFIG_SENSORS_SHT4x) += sht4x.o
obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o
obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
obj-$(CONFIG_SENSORS_SMM665) += smm665.o
obj-$(CONFIG_SENSORS_SMPRO) += smpro-hwmon.o
obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
......
......@@ -26,14 +26,12 @@
/**
* struct adm1177_state - driver instance specific data
* @client: pointer to i2c client
* @reg: regulator info for the power supply of the device
* @r_sense_uohm: current sense resistor value
* @alert_threshold_ua: current limit for shutdown
* @vrange_high: internal voltage divider
*/
struct adm1177_state {
struct i2c_client *client;
struct regulator *reg;
u32 r_sense_uohm;
u32 alert_threshold_ua;
bool vrange_high;
......@@ -189,13 +187,6 @@ static const struct hwmon_chip_info adm1177_chip_info = {
.info = adm1177_info,
};
static void adm1177_remove(void *data)
{
struct adm1177_state *st = data;
regulator_disable(st->reg);
}
static int adm1177_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
......@@ -210,22 +201,10 @@ static int adm1177_probe(struct i2c_client *client)
st->client = client;
st->reg = devm_regulator_get_optional(&client->dev, "vref");
if (IS_ERR(st->reg)) {
if (PTR_ERR(st->reg) == -EPROBE_DEFER)
ret = devm_regulator_get_enable_optional(&client->dev, "vref");
if (ret == -EPROBE_DEFER)
return -EPROBE_DEFER;
st->reg = NULL;
} else {
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = devm_add_action_or_reset(&client->dev, adm1177_remove,
st);
if (ret)
return ret;
}
if (device_property_read_u32(dev, "shunt-resistor-micro-ohms",
&st->r_sense_uohm))
st->r_sense_uohm = 0;
......
......@@ -289,8 +289,7 @@ static const struct hwmon_chip_info aht10_chip_info = {
.info = aht10_info,
};
static int aht10_probe(struct i2c_client *client,
const struct i2c_device_id *aht10_id)
static int aht10_probe(struct i2c_client *client)
{
struct device *device = &client->dev;
struct device *hwmon_dev;
......@@ -336,7 +335,7 @@ static struct i2c_driver aht10_driver = {
.driver = {
.name = "aht10",
},
.probe = aht10_probe,
.probe_new = aht10_probe,
.id_table = aht10_id,
};
......
This diff is collapsed.
......@@ -16,6 +16,7 @@
#include <linux/hwmon.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/kstrtox.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
......
......@@ -55,6 +55,8 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
/*
* Per-Core Temperature Data
* @tjmax: The static tjmax value when tjmax cannot be retrieved from
* IA32_TEMPERATURE_TARGET MSR.
* @last_updated: The time when the current temperature value was updated
* earlier (in jiffies).
* @cpu_core_id: The CPU Core from which temperature values should be read
......@@ -64,11 +66,9 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
* @attr_size: Total number of pre-core attrs displayed in the sysfs.
* @is_pkg_data: If this is 1, the temp_data holds pkgtemp data.
* Otherwise, temp_data holds coretemp data.
* @valid: If this is 1, the current temperature is valid.
*/
struct temp_data {
int temp;
int ttarget;
int tjmax;
unsigned long last_updated;
unsigned int cpu;
......@@ -76,7 +76,6 @@ struct temp_data {
u32 status_reg;
int attr_size;
bool is_pkg_data;
bool valid;
struct sensor_device_attribute sd_attrs[TOTAL_ATTRS];
char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH];
struct attribute *attrs[TOTAL_ATTRS + 1];
......@@ -95,85 +94,6 @@ struct platform_data {
struct device_attribute name_attr;
};
/* Keep track of how many zone pointers we allocated in init() */
static int max_zones __read_mostly;
/* Array of zone pointers. Serialized by cpu hotplug lock */
static struct platform_device **zone_devices;
static ssize_t show_label(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct platform_data *pdata = dev_get_drvdata(dev);
struct temp_data *tdata = pdata->core_data[attr->index];
if (tdata->is_pkg_data)
return sprintf(buf, "Package id %u\n", pdata->pkg_id);
return sprintf(buf, "Core %u\n", tdata->cpu_core_id);
}
static ssize_t show_crit_alarm(struct device *dev,
struct device_attribute *devattr, char *buf)
{
u32 eax, edx;
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct platform_data *pdata = dev_get_drvdata(dev);
struct temp_data *tdata = pdata->core_data[attr->index];
mutex_lock(&tdata->update_lock);
rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
mutex_unlock(&tdata->update_lock);
return sprintf(buf, "%d\n", (eax >> 5) & 1);
}
static ssize_t show_tjmax(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct platform_data *pdata = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tjmax);
}
static ssize_t show_ttarget(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct platform_data *pdata = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget);
}
static ssize_t show_temp(struct device *dev,
struct device_attribute *devattr, char *buf)
{
u32 eax, edx;
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct platform_data *pdata = dev_get_drvdata(dev);
struct temp_data *tdata = pdata->core_data[attr->index];
mutex_lock(&tdata->update_lock);
/* Check whether the time interval has elapsed */
if (!tdata->valid || time_after(jiffies, tdata->last_updated + HZ)) {
rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
/*
* Ignore the valid bit. In all observed cases the register
* value is either low or zero if the valid bit is 0.
* Return it instead of reporting an error which doesn't
* really help at all.
*/
tdata->temp = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000;
tdata->valid = true;
tdata->last_updated = jiffies;
}
mutex_unlock(&tdata->update_lock);
return sprintf(buf, "%d\n", tdata->temp);
}
struct tjmax_pci {
unsigned int device;
int tjmax;
......@@ -340,20 +260,25 @@ static bool cpu_has_tjmax(struct cpuinfo_x86 *c)
model != 0x36;
}
static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
static int get_tjmax(struct temp_data *tdata, struct device *dev)
{
struct cpuinfo_x86 *c = &cpu_data(tdata->cpu);
int err;
u32 eax, edx;
u32 val;
/* use static tjmax once it is set */
if (tdata->tjmax)
return tdata->tjmax;
/*
* A new feature of current Intel(R) processors, the
* IA32_TEMPERATURE_TARGET contains the TjMax value
*/
err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
err = rdmsr_safe_on_cpu(tdata->cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
if (err) {
if (cpu_has_tjmax(c))
dev_warn(dev, "Unable to read TjMax from CPU %u\n", id);
dev_warn(dev, "Unable to read TjMax from CPU %u\n", tdata->cpu);
} else {
val = (eax >> 16) & 0xff;
/*
......@@ -369,14 +294,133 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
if (force_tjmax) {
dev_notice(dev, "TjMax forced to %d degrees C by user\n",
force_tjmax);
return force_tjmax * 1000;
}
tdata->tjmax = force_tjmax * 1000;
} else {
/*
* An assumption is made for early CPUs and unreadable MSR.
* NOTE: the calculated value may not be correct.
*/
return adjust_tjmax(c, id, dev);
tdata->tjmax = adjust_tjmax(c, tdata->cpu, dev);
}
return tdata->tjmax;
}
static int get_ttarget(struct temp_data *tdata, struct device *dev)
{
u32 eax, edx;
int tjmax, ttarget_offset, ret;
/*
* ttarget is valid only if tjmax can be retrieved from
* MSR_IA32_TEMPERATURE_TARGET
*/
if (tdata->tjmax)
return -ENODEV;
ret = rdmsr_safe_on_cpu(tdata->cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
if (ret)
return ret;
tjmax = (eax >> 16) & 0xff;
/* Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET. */
ttarget_offset = (eax >> 8) & 0xff;
return (tjmax - ttarget_offset) * 1000;
}
/* Keep track of how many zone pointers we allocated in init() */
static int max_zones __read_mostly;
/* Array of zone pointers. Serialized by cpu hotplug lock */
static struct platform_device **zone_devices;
static ssize_t show_label(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct platform_data *pdata = dev_get_drvdata(dev);
struct temp_data *tdata = pdata->core_data[attr->index];
if (tdata->is_pkg_data)
return sprintf(buf, "Package id %u\n", pdata->pkg_id);
return sprintf(buf, "Core %u\n", tdata->cpu_core_id);
}
static ssize_t show_crit_alarm(struct device *dev,
struct device_attribute *devattr, char *buf)
{
u32 eax, edx;
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct platform_data *pdata = dev_get_drvdata(dev);
struct temp_data *tdata = pdata->core_data[attr->index];
mutex_lock(&tdata->update_lock);
rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
mutex_unlock(&tdata->update_lock);
return sprintf(buf, "%d\n", (eax >> 5) & 1);
}
static ssize_t show_tjmax(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct platform_data *pdata = dev_get_drvdata(dev);
struct temp_data *tdata = pdata->core_data[attr->index];
int tjmax;
mutex_lock(&tdata->update_lock);
tjmax = get_tjmax(tdata, dev);
mutex_unlock(&tdata->update_lock);
return sprintf(buf, "%d\n", tjmax);
}
static ssize_t show_ttarget(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct platform_data *pdata = dev_get_drvdata(dev);
struct temp_data *tdata = pdata->core_data[attr->index];
int ttarget;
mutex_lock(&tdata->update_lock);
ttarget = get_ttarget(tdata, dev);
mutex_unlock(&tdata->update_lock);
if (ttarget < 0)
return ttarget;
return sprintf(buf, "%d\n", ttarget);
}
static ssize_t show_temp(struct device *dev,
struct device_attribute *devattr, char *buf)
{
u32 eax, edx;
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct platform_data *pdata = dev_get_drvdata(dev);
struct temp_data *tdata = pdata->core_data[attr->index];
int tjmax;
mutex_lock(&tdata->update_lock);
tjmax = get_tjmax(tdata, dev);
/* Check whether the time interval has elapsed */
if (time_after(jiffies, tdata->last_updated + HZ)) {
rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
/*
* Ignore the valid bit. In all observed cases the register
* value is either low or zero if the valid bit is 0.
* Return it instead of reporting an error which doesn't
* really help at all.
*/
tdata->temp = tjmax - ((eax >> 16) & 0x7f) * 1000;
tdata->last_updated = jiffies;
}
mutex_unlock(&tdata->update_lock);
return sprintf(buf, "%d\n", tdata->temp);
}
static int create_core_attrs(struct temp_data *tdata, struct device *dev,
......@@ -490,23 +534,17 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
if (err)
goto exit_free;
/* We can access status register. Get Critical Temperature */
tdata->tjmax = get_tjmax(c, cpu, &pdev->dev);
/* Make sure tdata->tjmax is a valid indicator for dynamic/static tjmax */
get_tjmax(tdata, &pdev->dev);
/*
* Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET.
* The target temperature is available on older CPUs but not in this
* register. Atoms don't have the register at all.
* The target temperature is available on older CPUs but not in the
* MSR_IA32_TEMPERATURE_TARGET register. Atoms don't have the register
* at all.
*/
if (c->x86_model > 0xe && c->x86_model != 0x1c) {
err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET,
&eax, &edx);
if (!err) {
tdata->ttarget
= tdata->tjmax - ((eax >> 8) & 0xff) * 1000;
if (c->x86_model > 0xe && c->x86_model != 0x1c)
if (get_ttarget(tdata, &pdev->dev) >= 0)
tdata->attr_size++;
}
}
pdata->core_data[attr_no] = tdata;
......
......@@ -1447,9 +1447,10 @@ static int __init i8k_init(void)
*/
if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) &&
i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) {
pr_err("unable to get SMM Dell signature\n");
if (!force)
return -ENODEV;
pr_err("Unable to get Dell SMM signature\n");
}
dell_smm_device = platform_create_bundle(&dell_smm_driver, dell_smm_probe, NULL, 0, NULL,
......
......@@ -269,7 +269,7 @@ static ssize_t update_interval_show(struct device *dev,
struct device_attribute *da, char *buf)
{
struct ds1621_data *data = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%hu\n", data->update_interval);
return sysfs_emit(buf, "%hu\n", data->update_interval);
}
static ssize_t update_interval_store(struct device *dev,
......
......@@ -16,7 +16,6 @@ static const unsigned short
emc2305_normal_i2c[] = { 0x27, 0x2c, 0x2d, 0x2e, 0x2f, 0x4c, 0x4d, I2C_CLIENT_END };
#define EMC2305_REG_DRIVE_FAIL_STATUS 0x27
#define EMC2305_REG_DEVICE 0xfd
#define EMC2305_REG_VENDOR 0xfe
#define EMC2305_FAN_MAX 0xff
#define EMC2305_FAN_MIN 0x00
......@@ -172,22 +171,12 @@ static int emc2305_get_max_state(struct thermal_cooling_device *cdev, unsigned l
return 0;
}
static int emc2305_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
static int __emc2305_set_cur_state(struct emc2305_data *data, int cdev_idx, unsigned long state)
{
int cdev_idx, ret;
struct emc2305_data *data = cdev->devdata;
int ret;
struct i2c_client *client = data->client;
u8 val, i;
if (state > data->max_state)
return -EINVAL;
cdev_idx = emc2305_get_cdev_idx(cdev);
if (cdev_idx < 0)
return cdev_idx;
/* Save thermal state. */
data->cdev_data[cdev_idx].last_thermal_state = state;
state = max_t(unsigned long, state, data->cdev_data[cdev_idx].last_hwmon_state);
val = EMC2305_PWM_STATE2DUTY(state, data->max_state, EMC2305_FAN_MAX);
......@@ -212,6 +201,27 @@ static int emc2305_set_cur_state(struct thermal_cooling_device *cdev, unsigned l
return 0;
}
static int emc2305_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
{
int cdev_idx, ret;
struct emc2305_data *data = cdev->devdata;
if (state > data->max_state)
return -EINVAL;
cdev_idx = emc2305_get_cdev_idx(cdev);
if (cdev_idx < 0)
return cdev_idx;
/* Save thermal state. */
data->cdev_data[cdev_idx].last_thermal_state = state;
ret = __emc2305_set_cur_state(data, cdev_idx, state);
if (ret < 0)
return ret;
return 0;
}
static const struct thermal_cooling_device_ops emc2305_cooling_ops = {
.get_max_state = emc2305_get_max_state,
.get_cur_state = emc2305_get_cur_state,
......@@ -402,7 +412,7 @@ emc2305_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int ch
*/
if (data->cdev_data[cdev_idx].last_hwmon_state >=
data->cdev_data[cdev_idx].last_thermal_state)
return emc2305_set_cur_state(data->cdev_data[cdev_idx].cdev,
return __emc2305_set_cur_state(data, cdev_idx,
data->cdev_data[cdev_idx].last_hwmon_state);
return 0;
}
......@@ -518,13 +528,13 @@ static int emc2305_identify(struct device *dev)
return 0;
}
static int emc2305_probe(struct i2c_client *client, const struct i2c_device_id *id)
static int emc2305_probe(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
struct device *dev = &client->dev;
struct emc2305_data *data;
struct emc2305_platform_data *pdata;
int vendor, device;
int vendor;
int ret;
int i;
......@@ -535,10 +545,6 @@ static int emc2305_probe(struct i2c_client *client, const struct i2c_device_id *
if (vendor != EMC2305_VENDOR)
return -ENODEV;
device = i2c_smbus_read_byte_data(client, EMC2305_REG_DEVICE);
if (device != EMC2305_DEVICE)
return -ENODEV;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
......@@ -607,7 +613,7 @@ static struct i2c_driver emc2305_driver = {
.driver = {
.name = "emc2305",
},
.probe = emc2305_probe,
.probe_new = emc2305_probe,
.remove = emc2305_remove,
.id_table = emc2305_ids,
.address_list = emc2305_normal_i2c,
......
......@@ -1083,9 +1083,9 @@ static int fschmd_detect(struct i2c_client *client,
static int fschmd_probe(struct i2c_client *client)
{
struct fschmd_data *data;
const char * const names[7] = { "Poseidon", "Hermes", "Scylla",
static const char * const names[7] = { "Poseidon", "Hermes", "Scylla",
"Heracles", "Heimdall", "Hades", "Syleus" };
const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
static const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
int i, err;
enum chips kind = i2c_match_id(fschmd_id, client)->driver_data;
......
......@@ -14,6 +14,7 @@
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/kstrtox.h>
#include <linux/mutex.h>
#include <linux/hwmon.h>
#include <linux/gpio/consumer.h>
......
......@@ -257,13 +257,10 @@ gsc_hwmon_get_devtree_pdata(struct device *dev)
if (nchannels == 0)
return ERR_PTR(-ENODEV);
pdata = devm_kzalloc(dev,
sizeof(*pdata) + nchannels * sizeof(*ch),
pdata = devm_kzalloc(dev, struct_size(pdata, channels, nchannels),
GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
ch = (struct gsc_hwmon_channel *)(pdata + 1);
pdata->channels = ch;
pdata->nchannels = nchannels;
/* fan controller base address */
......@@ -277,6 +274,7 @@ gsc_hwmon_get_devtree_pdata(struct device *dev)
of_node_put(fan);
ch = pdata->channels;
/* allocate structures for channels and count instances of each type */
device_for_each_child_node(dev, child) {
if (fwnode_property_read_string(child, "label", &ch->name)) {
......
......@@ -15,6 +15,7 @@
#include <linux/gfp.h>
#include <linux/hwmon.h>
#include <linux/idr.h>
#include <linux/kstrtox.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/pci.h>
......
......@@ -69,6 +69,10 @@ static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
static bool ignore_resource_conflict;
module_param(ignore_resource_conflict, bool, 0);
MODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict");
static struct platform_device *it87_pdev[2];
#define REG_2E 0x2e /* The register to read/write */
......@@ -563,6 +567,14 @@ struct it87_data {
s8 auto_temp[NUM_AUTO_PWM][5]; /* [nr][0] is point1_temp_hyst */
};
/* Board specific settings from DMI matching */
struct it87_dmi_data {
u8 skip_pwm; /* pwm channels to skip for this board */
};
/* Global for results from DMI matching, if needed */
static struct it87_dmi_data *dmi_data;
static int adc_lsb(const struct it87_data *data, int nr)
{
int lsb;
......@@ -2389,7 +2401,6 @@ static int __init it87_find(int sioaddr, unsigned short *address,
{
int err;
u16 chip_type;
const char *board_vendor, *board_name;
const struct it87_devices *config;
err = superio_enter(sioaddr);
......@@ -2397,7 +2408,13 @@ static int __init it87_find(int sioaddr, unsigned short *address,
return err;
err = -ENODEV;
chip_type = force_id ? force_id : superio_inw(sioaddr, DEVID);
chip_type = superio_inw(sioaddr, DEVID);
/* check first for a valid chip before forcing chip id */
if (chip_type == 0xffff)
goto exit;
if (force_id)
chip_type = force_id;
switch (chip_type) {
case IT8705F_DEVID:
......@@ -2802,24 +2819,9 @@ static int __init it87_find(int sioaddr, unsigned short *address,
if (sio_data->beep_pin)
pr_info("Beeping is supported\n");
/* Disable specific features based on DMI strings */
board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
board_name = dmi_get_system_info(DMI_BOARD_NAME);
if (board_vendor && board_name) {
if (strcmp(board_vendor, "nVIDIA") == 0 &&
strcmp(board_name, "FN68PT") == 0) {
/*
* On the Shuttle SN68PT, FAN_CTL2 is apparently not
* connected to a fan, but to something else. One user
* has reported instant system power-off when changing
* the PWM2 duty cycle, so we disable it.
* I use the board name string as the trigger in case
* the same board is ever used in other systems.
*/
pr_info("Disabling pwm2 due to hardware constraints\n");
sio_data->skip_pwm = BIT(1);
}
}
/* Set values based on DMI matches */
if (dmi_data)
sio_data->skip_pwm |= dmi_data->skip_pwm;
exit:
superio_exit(sioaddr);
......@@ -3261,8 +3263,10 @@ static int __init it87_device_add(int index, unsigned short address,
int err;
err = acpi_check_resource_conflict(&res);
if (err)
if (err) {
if (!ignore_resource_conflict)
return err;
}
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev)
......@@ -3295,6 +3299,46 @@ static int __init it87_device_add(int index, unsigned short address,
return err;
}
/* callback function for DMI */
static int it87_dmi_cb(const struct dmi_system_id *dmi_entry)
{
dmi_data = dmi_entry->driver_data;
if (dmi_data && dmi_data->skip_pwm)
pr_info("Disabling pwm2 due to hardware constraints\n");
return 1;
}
/*
* On the Shuttle SN68PT, FAN_CTL2 is apparently not
* connected to a fan, but to something else. One user
* has reported instant system power-off when changing
* the PWM2 duty cycle, so we disable it.
* I use the board name string as the trigger in case
* the same board is ever used in other systems.
*/
static struct it87_dmi_data nvidia_fn68pt = {
.skip_pwm = BIT(1),
};
#define IT87_DMI_MATCH_VND(vendor, name, cb, data) \
{ \
.callback = cb, \
.matches = { \
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, vendor), \
DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \
}, \
.driver_data = data, \
}
static const struct dmi_system_id it87_dmi_table[] __initconst = {
IT87_DMI_MATCH_VND("nVIDIA", "FN68PT", it87_dmi_cb, &nvidia_fn68pt),
{ }
};
MODULE_DEVICE_TABLE(dmi, it87_dmi_table);
static int __init sm_it87_init(void)
{
int sioaddr[2] = { REG_2E, REG_4E };
......@@ -3307,6 +3351,8 @@ static int __init sm_it87_init(void)
if (err)
return err;
dmi_check_system(it87_dmi_table);
for (i = 0; i < ARRAY_SIZE(sioaddr); i++) {
memset(&sio_data, 0, sizeof(struct it87_sio_data));
isa_address[i] = 0;
......
This diff is collapsed.
......@@ -92,7 +92,7 @@ static ssize_t temp_show(struct device *dev, struct device_attribute *da,
/* use integer division instead of equivalent right shift to
guarantee arithmetic shift and preserve the sign */
temp = (((s16) err) * 250) / 32;
return scnprintf(buf, PAGE_SIZE, "%d\n", temp);
return sysfs_emit(buf, "%d\n", temp);
}
static ssize_t convrate_store(struct device *dev, struct device_attribute *da,
......@@ -137,7 +137,7 @@ static ssize_t convrate_show(struct device *dev, struct device_attribute *da,
int res;
res = (data->ctrl & LM73_CTRL_RES_MASK) >> LM73_CTRL_RES_SHIFT;
return scnprintf(buf, PAGE_SIZE, "%hu\n", lm73_convrates[res]);
return sysfs_emit(buf, "%hu\n", lm73_convrates[res]);
}
static ssize_t maxmin_alarm_show(struct device *dev,
......@@ -154,7 +154,7 @@ static ssize_t maxmin_alarm_show(struct device *dev,
data->ctrl = ctrl;
mutex_unlock(&data->lock);
return scnprintf(buf, PAGE_SIZE, "%d\n", (ctrl >> attr->index) & 1);
return sysfs_emit(buf, "%d\n", (ctrl >> attr->index) & 1);
abort:
mutex_unlock(&data->lock);
......
......@@ -103,6 +103,7 @@
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/hwmon.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
......@@ -2663,11 +2664,6 @@ static void lm90_remove_pec(void *dev)
device_remove_file(dev, &dev_attr_pec);
}
static void lm90_regulator_disable(void *regulator)
{
regulator_disable(regulator);
}
static int lm90_probe_channel_from_dt(struct i2c_client *client,
struct device_node *child,
struct lm90_data *data)
......@@ -2749,24 +2745,13 @@ static int lm90_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct i2c_adapter *adapter = client->adapter;
struct hwmon_channel_info *info;
struct regulator *regulator;
struct device *hwmon_dev;
struct lm90_data *data;
int err;
regulator = devm_regulator_get(dev, "vcc");
if (IS_ERR(regulator))
return PTR_ERR(regulator);
err = regulator_enable(regulator);
if (err < 0) {
dev_err(dev, "Failed to enable regulator: %d\n", err);
return err;
}
err = devm_add_action_or_reset(dev, lm90_regulator_disable, regulator);
err = devm_regulator_get_enable(dev, "vcc");
if (err)
return err;
return dev_err_probe(dev, err, "Failed to enable regulator\n");
data = devm_kzalloc(dev, sizeof(struct lm90_data), GFP_KERNEL);
if (!data)
......
......@@ -881,7 +881,7 @@ static int ltc2992_parse_dt(struct ltc2992_state *st)
return 0;
}
static int ltc2992_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
static int ltc2992_i2c_probe(struct i2c_client *client)
{
struct device *hwmon_dev;
struct ltc2992_state *st;
......@@ -927,7 +927,7 @@ static struct i2c_driver ltc2992_i2c_driver = {
.name = "ltc2992",
.of_match_table = ltc2992_of_match,
},
.probe = ltc2992_i2c_probe,
.probe_new = ltc2992_i2c_probe,
.id_table = ltc2992_i2c_id,
};
......
......@@ -303,8 +303,7 @@ static const struct hwmon_chip_info max127_chip_info = {
.info = max127_info,
};
static int max127_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int max127_probe(struct i2c_client *client)
{
int i;
struct device *hwmon_dev;
......@@ -340,7 +339,7 @@ static struct i2c_driver max127_driver = {
.driver = {
.name = "max127",
},
.probe = max127_probe,
.probe_new = max127_probe,
.id_table = max127_id,
};
......
......@@ -11,6 +11,7 @@
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/hwmon.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
......
......@@ -1043,7 +1043,9 @@ static struct platform_device *pdev[2];
static const char * const asus_wmi_boards[] = {
"PRO H410T",
"ProArt B550-CREATOR",
"ProArt X570-CREATOR WIFI",
"ProArt Z490-CREATOR 10G",
"Pro B550M-C",
"Pro WS X570-ACE",
"PRIME B360-PLUS",
......@@ -1055,8 +1057,10 @@ static const char * const asus_wmi_boards[] = {
"PRIME X570-P",
"PRIME X570-PRO",
"ROG CROSSHAIR VIII DARK HERO",
"ROG CROSSHAIR VIII EXTREME",
"ROG CROSSHAIR VIII FORMULA",
"ROG CROSSHAIR VIII HERO",
"ROG CROSSHAIR VIII HERO (WI-FI)",
"ROG CROSSHAIR VIII IMPACT",
"ROG STRIX B550-A GAMING",
"ROG STRIX B550-E GAMING",
......@@ -1080,8 +1084,11 @@ static const char * const asus_wmi_boards[] = {
"ROG STRIX Z490-G GAMING (WI-FI)",
"ROG STRIX Z490-H GAMING",
"ROG STRIX Z490-I GAMING",
"TUF GAMING B550M-E",
"TUF GAMING B550M-E (WI-FI)",
"TUF GAMING B550M-PLUS",
"TUF GAMING B550M-PLUS (WI-FI)",
"TUF GAMING B550M-PLUS WIFI II",
"TUF GAMING B550-PLUS",
"TUF GAMING B550-PLUS WIFI II",
"TUF GAMING B550-PRO",
......
......@@ -6,7 +6,6 @@
config SENSORS_OCC_P8_I2C
tristate "POWER8 OCC through I2C"
depends on I2C
depends on ARM || ARM64 || COMPILE_TEST
select SENSORS_OCC
help
This option enables support for monitoring sensors provided by the
......@@ -21,7 +20,6 @@ config SENSORS_OCC_P8_I2C
config SENSORS_OCC_P9_SBE
tristate "POWER9 OCC through SBE"
depends on FSI_OCC
depends on ARM || ARM64 || COMPILE_TEST
select SENSORS_OCC
help
This option enables support for monitoring sensors provided by the
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Platform driver for OXP Handhelds that expose fan reading and control
* via hwmon sysfs.
*
* Old boards have the same DMI strings and they are told appart by the
* boot cpu vendor (Intel/AMD). Currently only AMD boards are supported
* but the code is made to be simple to add other handheld boards in the
* future.
* Fan control is provided via pwm interface in the range [0-255].
* Old AMD boards use [0-100] as range in the EC, the written value is
* scaled to accommodate for that. Newer boards like the mini PRO and
* AOK ZOE are not scaled but have the same EC layout.
*
* Copyright (C) 2022 Joaquín I. Aramendía <samsagax@gmail.com>
*/
#include <linux/acpi.h>
#include <linux/dev_printk.h>
#include <linux/dmi.h>
#include <linux/hwmon.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/processor.h>
/* Handle ACPI lock mechanism */
static u32 oxp_mutex;
#define ACPI_LOCK_DELAY_MS 500
static bool lock_global_acpi_lock(void)
{
return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS, &oxp_mutex));
}
static bool unlock_global_acpi_lock(void)
{
return ACPI_SUCCESS(acpi_release_global_lock(oxp_mutex));
}
enum oxp_board {
aok_zoe_a1 = 1,
oxp_mini_amd,
oxp_mini_amd_pro,
};
static enum oxp_board board;
#define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */
#define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */
#define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */
static const struct dmi_system_id dmi_table[] = {
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"),
},
.driver_data = (void *) &(enum oxp_board) {aok_zoe_a1},
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"),
},
.driver_data = (void *) &(enum oxp_board) {oxp_mini_amd},
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"),
},
.driver_data = (void *) &(enum oxp_board) {oxp_mini_amd_pro},
},
{},
};
/* Helper functions to handle EC read/write */
static int read_from_ec(u8 reg, int size, long *val)
{
int i;
int ret;
u8 buffer;
if (!lock_global_acpi_lock())
return -EBUSY;
*val = 0;
for (i = 0; i < size; i++) {
ret = ec_read(reg + i, &buffer);
if (ret)
return ret;
*val <<= i * 8;
*val += buffer;
}
if (!unlock_global_acpi_lock())
return -EBUSY;
return 0;
}
static int write_to_ec(const struct device *dev, u8 reg, u8 value)
{
int ret;
if (!lock_global_acpi_lock())
return -EBUSY;
ret = ec_write(reg, value);
if (!unlock_global_acpi_lock())
return -EBUSY;
return ret;
}
static int oxp_pwm_enable(const struct device *dev)
{
return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x01);
}
static int oxp_pwm_disable(const struct device *dev)
{
return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x00);
}
/* Callbacks for hwmon interface */
static umode_t oxp_ec_hwmon_is_visible(const void *drvdata,
enum hwmon_sensor_types type, u32 attr, int channel)
{
switch (type) {
case hwmon_fan:
return 0444;
case hwmon_pwm:
return 0644;
default:
return 0;
}
}
static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
int ret;
switch (type) {
case hwmon_fan:
switch (attr) {
case hwmon_fan_input:
return read_from_ec(OXP_SENSOR_FAN_REG, 2, val);
default:
break;
}
break;
case hwmon_pwm:
switch (attr) {
case hwmon_pwm_input:
ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
if (ret)
return ret;
if (board == oxp_mini_amd)
*val = (*val * 255) / 100;
return 0;
case hwmon_pwm_enable:
return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val);
default:
break;
}
break;
default:
break;
}
return -EOPNOTSUPP;
}
static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{
switch (type) {
case hwmon_pwm:
switch (attr) {
case hwmon_pwm_enable:
if (val == 1)
return oxp_pwm_enable(dev);
else if (val == 0)
return oxp_pwm_disable(dev);
return -EINVAL;
case hwmon_pwm_input:
if (val < 0 || val > 255)
return -EINVAL;
if (board == oxp_mini_amd)
val = (val * 100) / 255;
return write_to_ec(dev, OXP_SENSOR_PWM_REG, val);
default:
break;
}
break;
default:
break;
}
return -EOPNOTSUPP;
}
/* Known sensors in the OXP EC controllers */
static const struct hwmon_channel_info *oxp_platform_sensors[] = {
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT),
HWMON_CHANNEL_INFO(pwm,
HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
NULL,
};
static const struct hwmon_ops oxp_ec_hwmon_ops = {
.is_visible = oxp_ec_hwmon_is_visible,
.read = oxp_platform_read,
.write = oxp_platform_write,
};
static const struct hwmon_chip_info oxp_ec_chip_info = {
.ops = &oxp_ec_hwmon_ops,
.info = oxp_platform_sensors,
};
/* Initialization logic */
static int oxp_platform_probe(struct platform_device *pdev)
{
const struct dmi_system_id *dmi_entry;
struct device *dev = &pdev->dev;
struct device *hwdev;
/*
* Have to check for AMD processor here because DMI strings are the
* same between Intel and AMD boards, the only way to tell them appart
* is the CPU.
* Intel boards seem to have different EC registers and values to
* read/write.
*/
dmi_entry = dmi_first_match(dmi_table);
if (!dmi_entry || boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
return -ENODEV;
board = *((enum oxp_board *) dmi_entry->driver_data);
hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL,
&oxp_ec_chip_info, NULL);
return PTR_ERR_OR_ZERO(hwdev);
}
static struct platform_driver oxp_platform_driver = {
.driver = {
.name = "oxp-platform",
},
.probe = oxp_platform_probe,
};
static struct platform_device *oxp_platform_device;
static int __init oxp_platform_init(void)
{
oxp_platform_device =
platform_create_bundle(&oxp_platform_driver,
oxp_platform_probe, NULL, 0, NULL, 0);
return PTR_ERR_OR_ZERO(oxp_platform_device);
}
static void __exit oxp_platform_exit(void)
{
platform_device_unregister(oxp_platform_device);
platform_driver_unregister(&oxp_platform_driver);
}
MODULE_DEVICE_TABLE(dmi, dmi_table);
module_init(oxp_platform_init);
module_exit(oxp_platform_exit);
MODULE_AUTHOR("Joaquín Ignacio Aramendía <samsagax@gmail.com>");
MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices");
MODULE_LICENSE("GPL");
......@@ -14,6 +14,7 @@
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/kstrtox.h>
/* Insmod parameters */
......
......@@ -23,7 +23,7 @@ enum chips {
/* Managers */
ltc2972, ltc2974, ltc2975, ltc2977, ltc2978, ltc2979, ltc2980,
/* Controllers */
ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7880,
ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7132, ltc7880,
/* Modules */
ltm2987, ltm4664, ltm4675, ltm4676, ltm4677, ltm4678, ltm4680, ltm4686,
ltm4700,
......@@ -45,15 +45,14 @@ enum chips {
#define LTC2974_MFR_IOUT_PEAK 0xd7
#define LTC2974_MFR_IOUT_MIN 0xd8
/* LTC3880, LTC3882, LTC3883, LTC3887, LTM4675, and LTM4676 */
/* LTC3880, LTC3882, LTC3883, LTC3887, LTM4675, LTM4676, LTC7132 */
#define LTC3880_MFR_IOUT_PEAK 0xd7
#define LTC3880_MFR_CLEAR_PEAKS 0xe3
#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4
/* LTC3883, LTC3884, LTC3886, LTC3889 and LTC7880 only */
/* LTC3883, LTC3884, LTC3886, LTC3889, LTC7132, LTC7880 */
#define LTC3883_MFR_IIN_PEAK 0xe1
/* LTC2975 only */
#define LTC2975_MFR_IIN_PEAK 0xc4
#define LTC2975_MFR_IIN_MIN 0xc5
......@@ -79,10 +78,11 @@ enum chips {
#define LTC3884_ID 0x4C00
#define LTC3886_ID 0x4600
#define LTC3887_ID 0x4700
#define LTM2987_ID_A 0x8010 /* A/B for two die IDs */
#define LTM2987_ID_B 0x8020
#define LTC3889_ID 0x4900
#define LTC7132_ID 0x4CE0
#define LTC7880_ID 0x49E0
#define LTM2987_ID_A 0x8010 /* A/B for two die IDs */
#define LTM2987_ID_B 0x8020
#define LTM4664_ID 0x4120
#define LTM4675_ID 0x47a0
#define LTM4676_ID_REV1 0x4400
......@@ -547,6 +547,7 @@ static const struct i2c_device_id ltc2978_id[] = {
{"ltc3886", ltc3886},
{"ltc3887", ltc3887},
{"ltc3889", ltc3889},
{"ltc7132", ltc7132},
{"ltc7880", ltc7880},
{"ltm2987", ltm2987},
{"ltm4664", ltm4664},
......@@ -651,6 +652,8 @@ static int ltc2978_get_id(struct i2c_client *client)
return ltc3887;
else if (chip_id == LTC3889_ID)
return ltc3889;
else if (chip_id == LTC7132_ID)
return ltc7132;
else if (chip_id == LTC7880_ID)
return ltc7880;
else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B)
......@@ -831,6 +834,7 @@ static int ltc2978_probe(struct i2c_client *client)
case ltc3884:
case ltc3886:
case ltc3889:
case ltc7132:
case ltc7880:
case ltm4664:
case ltm4678:
......@@ -902,6 +906,7 @@ static const struct of_device_id ltc2978_of_match[] = {
{ .compatible = "lltc,ltc3886" },
{ .compatible = "lltc,ltc3887" },
{ .compatible = "lltc,ltc3889" },
{ .compatible = "lltc,ltc7132" },
{ .compatible = "lltc,ltc7880" },
{ .compatible = "lltc,ltm2987" },
{ .compatible = "lltc,ltm4664" },
......
......@@ -2827,9 +2827,13 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
if (status < 0)
return status;
if (pmbus_regulator_is_enabled(rdev) && (status & PB_STATUS_OFF))
if (pmbus_regulator_is_enabled(rdev)) {
if (status & PB_STATUS_OFF)
*flags |= REGULATOR_ERROR_FAIL;
if (status & PB_STATUS_POWER_GOOD_N)
*flags |= REGULATOR_ERROR_REGULATION_OUT;
}
/*
* Unlike most other status bits, PB_STATUS_{IOUT_OC,VOUT_OV} are
* defined strictly as fault indicators (not warnings).
......@@ -2851,6 +2855,49 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned
return 0;
}
static int pmbus_regulator_get_status(struct regulator_dev *rdev)
{
struct device *dev = rdev_get_dev(rdev);
struct i2c_client *client = to_i2c_client(dev->parent);
struct pmbus_data *data = i2c_get_clientdata(client);
u8 page = rdev_get_id(rdev);
int status, ret;
mutex_lock(&data->update_lock);
status = pmbus_get_status(client, page, PMBUS_STATUS_WORD);
if (status < 0) {
ret = status;
goto unlock;
}
if (status & PB_STATUS_OFF) {
ret = REGULATOR_STATUS_OFF;
goto unlock;
}
/* If regulator is ON & reports power good then return ON */
if (!(status & PB_STATUS_POWER_GOOD_N)) {
ret = REGULATOR_STATUS_ON;
goto unlock;
}
ret = pmbus_regulator_get_error_flags(rdev, &status);
if (ret)
goto unlock;
if (status & (REGULATOR_ERROR_UNDER_VOLTAGE | REGULATOR_ERROR_OVER_CURRENT |
REGULATOR_ERROR_REGULATION_OUT | REGULATOR_ERROR_FAIL | REGULATOR_ERROR_OVER_TEMP)) {
ret = REGULATOR_STATUS_ERROR;
goto unlock;
}
ret = REGULATOR_STATUS_UNDEFINED;
unlock:
mutex_unlock(&data->update_lock);
return ret;
}
static int pmbus_regulator_get_low_margin(struct i2c_client *client, int page)
{
struct pmbus_data *data = i2c_get_clientdata(client);
......@@ -2991,6 +3038,7 @@ const struct regulator_ops pmbus_regulator_ops = {
.disable = pmbus_regulator_disable,
.is_enabled = pmbus_regulator_is_enabled,
.get_error_flags = pmbus_regulator_get_error_flags,
.get_status = pmbus_regulator_get_status,
.get_voltage = pmbus_regulator_get_voltage,
.set_voltage = pmbus_regulator_set_voltage,
.list_voltage = pmbus_regulator_list_voltage,
......
......@@ -8,6 +8,7 @@
#include <linux/debugfs.h>
#include <linux/i2c.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include "pmbus.h"
......
......@@ -297,8 +297,7 @@ static int sbrmi_get_max_pwr_limit(struct sbrmi_data *data)
return ret;
}
static int sbrmi_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int sbrmi_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct device *hwmon_dev;
......@@ -348,7 +347,7 @@ static struct i2c_driver sbrmi_driver = {
.name = "sbrmi",
.of_match_table = of_match_ptr(sbrmi_of_match),
},
.probe = sbrmi_probe,
.probe_new = sbrmi_probe,
.id_table = sbrmi_id,
};
......
......@@ -199,8 +199,7 @@ static const struct hwmon_chip_info sbtsi_chip_info = {
.info = sbtsi_info,
};
static int sbtsi_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int sbtsi_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct device *hwmon_dev;
......@@ -239,7 +238,7 @@ static struct i2c_driver sbtsi_driver = {
.name = "sbtsi",
.of_match_table = of_match_ptr(sbtsi_of_match),
},
.probe = sbtsi_probe,
.probe_new = sbtsi_probe,
.id_table = sbtsi_id,
};
......
......@@ -320,7 +320,7 @@ static ssize_t temp1_limit_show(struct device *dev,
u8 index = to_sensor_dev_attr(attr)->index;
int temperature_limit = data->temperature_limits[index];
return scnprintf(buf, PAGE_SIZE, "%d\n", temperature_limit);
return sysfs_emit(buf, "%d\n", temperature_limit);
}
static ssize_t humidity1_limit_show(struct device *dev,
......@@ -331,7 +331,7 @@ static ssize_t humidity1_limit_show(struct device *dev,
u8 index = to_sensor_dev_attr(attr)->index;
u32 humidity_limit = data->humidity_limits[index];
return scnprintf(buf, PAGE_SIZE, "%u\n", humidity_limit);
return sysfs_emit(buf, "%u\n", humidity_limit);
}
/*
......@@ -483,7 +483,7 @@ static ssize_t temp1_alarm_show(struct device *dev,
if (ret)
return ret;
return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x04));
return sysfs_emit(buf, "%d\n", !!(buffer[0] & 0x04));
}
static ssize_t humidity1_alarm_show(struct device *dev,
......@@ -498,7 +498,7 @@ static ssize_t humidity1_alarm_show(struct device *dev,
if (ret)
return ret;
return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x08));
return sysfs_emit(buf, "%d\n", !!(buffer[0] & 0x08));
}
static ssize_t heater_enable_show(struct device *dev,
......@@ -513,7 +513,7 @@ static ssize_t heater_enable_show(struct device *dev,
if (ret)
return ret;
return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x20));
return sysfs_emit(buf, "%d\n", !!(buffer[0] & 0x20));
}
static ssize_t heater_enable_store(struct device *dev,
......@@ -550,7 +550,7 @@ static ssize_t update_interval_show(struct device *dev,
{
struct sht3x_data *data = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%u\n",
return sysfs_emit(buf, "%u\n",
mode_to_update_interval[data->mode]);
}
......
......@@ -232,8 +232,7 @@ static const struct hwmon_chip_info sht4x_chip_info = {
.info = sht4x_info,
};
static int sht4x_probe(struct i2c_client *client,
const struct i2c_device_id *sht4x_id)
static int sht4x_probe(struct i2c_client *client)
{
struct device *device = &client->dev;
struct device *hwmon_dev;
......@@ -292,7 +291,7 @@ static struct i2c_driver sht4x_driver = {
.name = "sht4x",
.of_match_table = sht4x_of_match,
},
.probe = sht4x_probe,
.probe_new = sht4x_probe,
.id_table = sht4x_id,
};
......
This diff is collapsed.
......@@ -22,7 +22,6 @@
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/acpi.h>
......
......@@ -16,7 +16,6 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-vid.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
......
......@@ -8,6 +8,7 @@
#define _LINUX_HWMON_SYSFS_H
#include <linux/device.h>
#include <linux/kstrtox.h>
struct sensor_device_attribute{
struct device_attribute dev_attr;
......
......@@ -29,18 +29,17 @@ struct gsc_hwmon_channel {
/**
* struct gsc_hwmon_platform_data - platform data for gsc_hwmon driver
* @channels: pointer to array of gsc_hwmon_channel structures
* describing channels
* @nchannels: number of elements in @channels array
* @vreference: voltage reference (mV)
* @resolution: ADC bit resolution
* @fan_base: register base for FAN controller
* @channels: array of gsc_hwmon_channel structures describing channels
*/
struct gsc_hwmon_platform_data {
const struct gsc_hwmon_channel *channels;
int nchannels;
unsigned int resolution;
unsigned int vreference;
unsigned int fan_base;
struct gsc_hwmon_channel channels[];
};
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment