hwmon updates for v6.6

- New drivers
 
   * Driver for Renesas HS3001
 
 - Chip support added to existing drivers
 
   * pmbus/mp2975 driver now supports MP2971 and MP2973
 
 - Functional improvements
 
   * Additional voltage and temperature sensor support for
     NCT6798/NCT6799 in nt6755 driver
 
   * it87 driver now detects AMDTSI sensor type
 
   * dimmtemp now supports more than 32 DIMMs
 
 - Driver removals
 
   * sm665 driver removed as unsupportable and long since obsolete
 
 - Minor fixes, cleanups, and simplifications in several drivers
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmTsyv4ACgkQyx8mb86f
 mYHlOQ//QgyjtXm3+3e0AzxvFIrp+HZz2QfOEuXOpA9RFZGnpmBhIspeRa88CWYE
 uHMhdMXY8HQxD3nEDbk4MfClJYQmOaZPHUi/3fVu9K0aHaxXSUDlljSGMeEJ5D8U
 taaxl3FjDRvPvf1jLfU95qrV4V0/z10da+gA/ryItkooyvZbZSoi33RgIWRL0KH4
 yFsNYY8xWxnBe0gkoQoTVBFs/wbFRrNOrV698qpAYnPuXHh/lCR3T9rQ78C2xnmg
 urg4b1UCilrrEz30IuatHGwqvaDWXVZXpp3LGCeabLytQg4bSsrdPEyVM66fBLtI
 RvsX7KyhdcVojsshQ27vJte3gGdywgW4OxfIFjmreFSc+A9pjYjwbTc2ZPrrn+jm
 fvDMoSB5Ac5hgWgN1hvh8ioget9CHL7whydFJnDPGjnxOLZoZjIN4ssitydpPQ7Q
 wZfont4/R8Tj0RFapp0VHYMtry7fwWCQnrQ6Cb+IskjXDOclEyYjOCJt71bTTl2Q
 mGH3BoY4R8pE3EcKKMXTiwIIINiBDe4CBV2eQe5hnVIgXQ+Y/XbJZoLjCtiGCoCk
 ySh0eP0MO0En2fkc6LFeiy37r9PEscbagmhTufiGha3q26xIkJountqGpYVDWgZB
 zILIW1UOECKVQ2kFuVps3oBQbOKzwzReo4Nm+XjhWtHxT/1HpyM=
 =dpys
 -----END PGP SIGNATURE-----

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

Pull hwmon updates from Guenter Roeck:
 "New drivers:

   - Renesas HS3001

  Chip support added to existing drivers:

   - pmbus/mp2975 driver now supports MP2971 and MP2973

  Functional improvements:

   - Additional voltage and temperature sensor support for
     NCT6798/NCT6799 in nt6755 driver

   - it87 driver now detects AMDTSI sensor type

   - dimmtemp now supports more than 32 DIMMs

  Driver removals:

   - sm665 driver removed as unsupportable and long since obsolete

  .. and minor fixes, cleanups, and simplifications in several drivers"

* tag 'hwmon-for-v6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (57 commits)
  hwmon: (tmp513) Simplify probe()
  hwmon: (tmp513) Fix the channel number in tmp51x_is_visible()
  hwmon: (mlxreg-fan) Extend number of supported fans
  hwmon: (sis5595) Do PCI error checks on own line
  hwmon: (vt8231) Do PCI error checks on own line
  hwmon: (via686a) Do PCI error checks on own line
  hwmon: pmbus: Fix -EIO seen on pli1209
  hwmon: pmbus: Drop unnecessary clear fault page
  hwmon: pmbus: Reduce clear fault page invocations
  hwmon: (nsa320-hwmon) Remove redundant of_match_ptr()
  hwmon: (pmbus/ucd9200) fix Wvoid-pointer-to-enum-cast warning
  hwmon: (pmbus/ucd9000) fix Wvoid-pointer-to-enum-cast warning
  hwmon: (pmbus/tps53679) fix Wvoid-pointer-to-enum-cast warning
  hwmon: (pmbus/ibm-cffps) fix Wvoid-pointer-to-enum-cast warning
  hwmon: (tmp513) fix Wvoid-pointer-to-enum-cast warning
  hwmon: (max6697) fix Wvoid-pointer-to-enum-cast warning
  hwmon: (max20730) fix Wvoid-pointer-to-enum-cast warning
  hwmon: (lm90) fix Wvoid-pointer-to-enum-cast warning
  hwmon: (lm85) fix Wvoid-pointer-to-enum-cast warning
  hwmon: (lm75) fix Wvoid-pointer-to-enum-cast warning
  ...
This commit is contained in:
Linus Torvalds 2023-08-29 10:02:35 -07:00
commit 41e97d7acf
70 changed files with 1452 additions and 1498 deletions

View file

@ -119,6 +119,10 @@ properties:
- fsl,mpr121
# Monolithic Power Systems Inc. multi-phase controller mp2888
- mps,mp2888
# Monolithic Power Systems Inc. multi-phase controller mp2971
- mps,mp2971
# Monolithic Power Systems Inc. multi-phase controller mp2973
- mps,mp2973
# Monolithic Power Systems Inc. multi-phase controller mp2975
- mps,mp2975
# Honeywell Humidicon HIH-6130 humidity/temperature sensor
@ -315,6 +319,8 @@ properties:
- plx,pex8648
# Pulsedlight LIDAR range-finding sensor
- pulsedlight,lidar-lite-v2
# Renesas HS3001 Temperature and Relative Humidity Sensors
- renesas,hs3001
# Renesas ISL29501 time-of-flight sensor
- renesas,isl29501
# Rohm DH2228FV

View file

@ -0,0 +1,37 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
Kernel driver HS3001
====================
Supported chips:
* Renesas HS3001, HS3002, HS3003, HS3004
Prefix: 'hs3001'
Addresses scanned: -
Datasheet: https://www.renesas.com/us/en/document/dst/hs300x-datasheet?r=417401
Author:
- Andre Werner <andre.werner@systec-electronic.com>
Description
-----------
This driver implements support for the Renesas HS3001 chips, a humidity
and temperature family. Temperature is measured in degrees celsius, relative
humidity is expressed as a percentage. In the sysfs interface, all values are
scaled by 1000, i.e. the value for 31.5 degrees celsius is 31500.
The device communicates with the I2C protocol. Sensors have the I2C
address 0x44 by default.
sysfs-Interface
---------------
=================== =================
temp1_input: temperature input
humidity1_input: humidity input
=================== =================

View file

@ -78,6 +78,7 @@ Hardware Monitoring Kernel Drivers
gxp-fan-ctrl
hih6130
hp-wmi-sensors
hs3001
ibmaem
ibm-cffps
ibmpowernv
@ -195,7 +196,6 @@ Hardware Monitoring Kernel Drivers
shtc1
sis5595
sl28cpld
smm665
smpro-hwmon
smsc47b397
smsc47m192

View file

@ -80,7 +80,13 @@ Supported chips:
Datasheet: Available from Nuvoton upon request
* Nuvoton NCT6796D-S/NCT6799D-R
Prefix: 'nct6799'
Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from Nuvoton upon request
Authors:
@ -277,4 +283,7 @@ will not reflect a usable value. It often reports unreasonably high
temperatures, and in some cases the reported temperature declines if the actual
temperature increases (similar to the raw PECI temperature value - see PECI
specification for details). CPUTIN should therefore be ignored on ASUS
boards. The CPU temperature on ASUS boards is reported from PECI 0.
boards. The CPU temperature on ASUS boards is reported from PECI 0 or TSI 0.
NCT6796D-S and NCT6799D-R chips are very similar and their chip_id indicates
they are different versions. This driver treats them the same way.

View file

@ -163,7 +163,7 @@ Emerson DS1200 power modules might look as follows::
.driver = {
.name = "ds1200",
},
.probe_new = ds1200_probe,
.probe = ds1200_probe,
.id_table = ds1200_id,
};

View file

@ -1,187 +0,0 @@
Kernel driver smm665
====================
Supported chips:
* Summit Microelectronics SMM465
Prefix: 'smm465'
Addresses scanned: -
Datasheet:
http://www.summitmicro.com/prod_select/summary/SMM465/SMM465DS.pdf
* Summit Microelectronics SMM665, SMM665B
Prefix: 'smm665'
Addresses scanned: -
Datasheet:
http://www.summitmicro.com/prod_select/summary/SMM665/SMM665B_2089_20.pdf
* Summit Microelectronics SMM665C
Prefix: 'smm665c'
Addresses scanned: -
Datasheet:
http://www.summitmicro.com/prod_select/summary/SMM665C/SMM665C_2125.pdf
* Summit Microelectronics SMM764
Prefix: 'smm764'
Addresses scanned: -
Datasheet:
http://www.summitmicro.com/prod_select/summary/SMM764/SMM764_2098.pdf
* Summit Microelectronics SMM766, SMM766B
Prefix: 'smm766'
Addresses scanned: -
Datasheets:
http://www.summitmicro.com/prod_select/summary/SMM766/SMM766_2086.pdf
http://www.summitmicro.com/prod_select/summary/SMM766B/SMM766B_2122.pdf
Author: Guenter Roeck <linux@roeck-us.net>
Module Parameters
-----------------
* vref: int
Default: 1250 (mV)
Reference voltage on VREF_ADC pin in mV. It should not be necessary to set
this parameter unless a non-default reference voltage is used.
Description
-----------
[From datasheet] The SMM665 is an Active DC Output power supply Controller
that monitors, margins and cascade sequences power. The part monitors six
power supply channels as well as VDD, 12V input, two general-purpose analog
inputs and an internal temperature sensor using a 10-bit ADC.
Each monitored channel has its own high and low limits, plus a critical
limit.
Support for SMM465, SMM764, and SMM766 has been implemented but is untested.
Usage Notes
-----------
This driver does not probe for devices, since there is no register which
can be safely used to identify the chip. You will have to instantiate
the devices explicitly. When instantiating the device, you have to specify
its configuration register address.
Example: the following will load the driver for an SMM665 at address 0x57
on I2C bus #1::
$ modprobe smm665
$ echo smm665 0x57 > /sys/bus/i2c/devices/i2c-1/new_device
Sysfs entries
-------------
This driver uses the values in the datasheet to convert ADC register values
into the values specified in the sysfs-interface document. All attributes are
read only.
Min, max, lcrit, and crit values are used by the chip to trigger external signals
and/or other activity. Triggered signals can include HEALTHY, RST, Power Off,
or Fault depending on the chip configuration. The driver reports values as lcrit
or crit if exceeding the limits triggers RST, Power Off, or Fault, and as min or
max otherwise. For details please see the SMM665 datasheet.
For SMM465 and SMM764, values for Channel E and F are reported but undefined.
======================= =======================================================
in1_input 12V input voltage (mV)
in2_input 3.3V (VDD) input voltage (mV)
in3_input Channel A voltage (mV)
in4_input Channel B voltage (mV)
in5_input Channel C voltage (mV)
in6_input Channel D voltage (mV)
in7_input Channel E voltage (mV)
in8_input Channel F voltage (mV)
in9_input AIN1 voltage (mV)
in10_input AIN2 voltage (mV)
in1_min 12v input minimum voltage (mV)
in2_min 3.3V (VDD) input minimum voltage (mV)
in3_min Channel A minimum voltage (mV)
in4_min Channel B minimum voltage (mV)
in5_min Channel C minimum voltage (mV)
in6_min Channel D minimum voltage (mV)
in7_min Channel E minimum voltage (mV)
in8_min Channel F minimum voltage (mV)
in9_min AIN1 minimum voltage (mV)
in10_min AIN2 minimum voltage (mV)
in1_max 12v input maximum voltage (mV)
in2_max 3.3V (VDD) input maximum voltage (mV)
in3_max Channel A maximum voltage (mV)
in4_max Channel B maximum voltage (mV)
in5_max Channel C maximum voltage (mV)
in6_max Channel D maximum voltage (mV)
in7_max Channel E maximum voltage (mV)
in8_max Channel F maximum voltage (mV)
in9_max AIN1 maximum voltage (mV)
in10_max AIN2 maximum voltage (mV)
in1_lcrit 12v input critical minimum voltage (mV)
in2_lcrit 3.3V (VDD) input critical minimum voltage (mV)
in3_lcrit Channel A critical minimum voltage (mV)
in4_lcrit Channel B critical minimum voltage (mV)
in5_lcrit Channel C critical minimum voltage (mV)
in6_lcrit Channel D critical minimum voltage (mV)
in7_lcrit Channel E critical minimum voltage (mV)
in8_lcrit Channel F critical minimum voltage (mV)
in9_lcrit AIN1 critical minimum voltage (mV)
in10_lcrit AIN2 critical minimum voltage (mV)
in1_crit 12v input critical maximum voltage (mV)
in2_crit 3.3V (VDD) input critical maximum voltage (mV)
in3_crit Channel A critical maximum voltage (mV)
in4_crit Channel B critical maximum voltage (mV)
in5_crit Channel C critical maximum voltage (mV)
in6_crit Channel D critical maximum voltage (mV)
in7_crit Channel E critical maximum voltage (mV)
in8_crit Channel F critical maximum voltage (mV)
in9_crit AIN1 critical maximum voltage (mV)
in10_crit AIN2 critical maximum voltage (mV)
in1_crit_alarm 12v input critical alarm
in2_crit_alarm 3.3V (VDD) input critical alarm
in3_crit_alarm Channel A critical alarm
in4_crit_alarm Channel B critical alarm
in5_crit_alarm Channel C critical alarm
in6_crit_alarm Channel D critical alarm
in7_crit_alarm Channel E critical alarm
in8_crit_alarm Channel F critical alarm
in9_crit_alarm AIN1 critical alarm
in10_crit_alarm AIN2 critical alarm
temp1_input Chip temperature
temp1_min Minimum chip temperature
temp1_max Maximum chip temperature
temp1_crit Critical chip temperature
temp1_crit_alarm Temperature critical alarm
======================= =======================================================

View file

@ -9509,6 +9509,12 @@ S: Maintained
W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
F: fs/hpfs/
HS3001 Hardware Temperature and Humidity Sensor
M: Andre Werner <andre.werner@systec-electronic.com>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: drivers/hwmon/hs3001.c
HSI SUBSYSTEM
M: Sebastian Reichel <sre@kernel.org>
S: Maintained
@ -19625,13 +19631,6 @@ M: Nicolas Pitre <nico@fluxnic.net>
S: Odd Fixes
F: drivers/net/ethernet/smsc/smc91x.*
SMM665 HARDWARE MONITOR DRIVER
M: Guenter Roeck <linux@roeck-us.net>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/hwmon/smm665.rst
F: drivers/hwmon/smm665.c
SMSC EMC2103 HARDWARE MONITOR DRIVER
M: Steve Glendinning <steve.glendinning@shawell.net>
L: linux-hwmon@vger.kernel.org

View file

@ -734,6 +734,16 @@ config SENSORS_HIH6130
This driver can also be built as a module. If so, the module
will be called hih6130.
config SENSORS_HS3001
tristate "Renesas HS3001 humidity and temperature sensors"
depends on I2C
help
If you say yes here you get support for the Renesas HS3001,
to HS3004 humidity and temperature sensors.
This driver can also be built as a module. If so, the module
will be called hs3001.
config SENSORS_IBMAEM
tristate "IBM Active Energy Manager temperature/power sensors and control"
select IPMI_SI
@ -1951,20 +1961,6 @@ config SENSORS_SFCTEMP
This driver can also be built as a module. If so, the module
will be called sfctemp.
config SENSORS_SMM665
tristate "Summit Microelectronics SMM665"
depends on I2C
help
If you say yes here you get support for the hardware monitoring
features of the Summit Microelectronics SMM665/SMM665B Six-Channel
Active DC Output Controller / Monitor.
Other supported chips are SMM465, SMM665C, SMM764, and SMM766.
Support for those chips is untested.
This driver can also be built as a module. If so, the module will
be called smm665.
config SENSORS_ADC128D818
tristate "Texas Instruments ADC128D818"
depends on I2C

View file

@ -86,6 +86,7 @@ obj-$(CONFIG_SENSORS_GSC) += gsc-hwmon.o
obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
obj-$(CONFIG_SENSORS_GXP_FAN_CTRL) += gxp-fan-ctrl.o
obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o
obj-$(CONFIG_SENSORS_HS3001) += hs3001.o
obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5500) += i5500_temp.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
@ -191,7 +192,6 @@ obj-$(CONFIG_SENSORS_SHT3x) += sht3x.o
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

View file

@ -16,7 +16,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/delay.h>
#include <linux/slab.h>
@ -253,7 +253,7 @@ static int ad7418_probe(struct i2c_client *client)
mutex_init(&data->lock);
data->client = client;
if (dev->of_node)
data->type = (enum chips)of_device_get_match_data(dev);
data->type = (uintptr_t)of_device_get_match_data(dev);
else
data->type = i2c_match_id(ad7418_id, client)->driver_data;

View file

@ -18,7 +18,7 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_data/ads7828.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@ -139,8 +139,7 @@ static int ads7828_probe(struct i2c_client *client)
}
if (client->dev.of_node)
chip = (enum ads7828_chips)
of_device_get_match_data(&client->dev);
chip = (uintptr_t)of_device_get_match_data(&client->dev);
else
chip = i2c_match_id(ads7828_device_ids, client)->driver_data;

View file

@ -10,7 +10,6 @@
*/
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
@ -1653,7 +1652,7 @@ static int adt7475_probe(struct i2c_client *client)
i2c_set_clientdata(client, data);
if (client->dev.of_node)
chip = (enum chips)of_device_get_match_data(&client->dev);
chip = (uintptr_t)of_device_get_match_data(&client->dev);
else
chip = id->driver_data;

View file

@ -11,7 +11,8 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#define CTRL 0x0
#define PD BIT(0)

View file

@ -12,8 +12,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>

View file

@ -340,7 +340,7 @@ static const struct ec_board_info board_info_crosshair_x670e_hero = {
.sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
SENSOR_TEMP_MB | SENSOR_TEMP_VRM |
SENSOR_SET_TEMP_WATER,
.mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX,
.mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
.family = family_amd_600_series,
};

View file

@ -891,15 +891,8 @@ static struct pvt_hwmon *pvt_create_data(struct platform_device *pdev)
static int pvt_request_regs(struct pvt_hwmon *pvt)
{
struct platform_device *pdev = to_platform_device(pvt->dev);
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(pvt->dev, "Couldn't find PVT memresource\n");
return -EINVAL;
}
pvt->regs = devm_ioremap_resource(pvt->dev, res);
pvt->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(pvt->regs))
return PTR_ERR(pvt->regs);

View file

@ -39,7 +39,6 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_data/g762.h>
#define DRVNAME "g762"

View file

@ -6,7 +6,7 @@
#include <linux/hwmon.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#define OFS_FAN_INST 0 /* Is 0 because plreg base will be set at INST */

View file

@ -435,25 +435,11 @@ static union acpi_object *hp_wmi_get_wobj(const char *guid, u8 instance)
/* hp_wmi_wobj_instance_count - find count of WMI object instances */
static u8 hp_wmi_wobj_instance_count(const char *guid)
{
u8 hi = HP_WMI_MAX_INSTANCES;
union acpi_object *wobj;
u8 lo = 0;
u8 mid;
int count;
while (lo < hi) {
mid = (lo + hi) / 2;
count = wmi_instance_count(guid);
wobj = hp_wmi_get_wobj(guid, mid);
if (!wobj) {
hi = mid;
continue;
}
lo = mid + 1;
kfree(wobj);
}
return lo;
return clamp(count, 0, (int)HP_WMI_MAX_INSTANCES);
}
static int check_wobj(const union acpi_object *wobj,
@ -1927,7 +1913,7 @@ static bool add_event_handler(struct hp_wmi_sensors *state)
static int hp_wmi_sensors_init(struct hp_wmi_sensors *state)
{
struct hp_wmi_info *connected[HP_WMI_MAX_INSTANCES];
struct hp_wmi_platform_events *pevents;
struct hp_wmi_platform_events *pevents = NULL;
struct device *dev = &state->wdev->dev;
struct hp_wmi_info *info;
struct device *hwdev;

242
drivers/hwmon/hs3001.c Normal file
View file

@ -0,0 +1,242 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* This is a non-complete driver implementation for the
* HS3001 humidity and temperature sensor and compatibles. It does not include
* the configuration possibilities, where it needs to be set to 'programming mode'
* during power-up.
*
*
* Copyright (C) 2023 SYS TEC electronic AG
* Author: Andre Werner <andre.werner@systec-electronic.com>
*/
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/types.h>
/* Measurement times */
#define HS3001_WAKEUP_TIME 100 /* us */
#define HS3001_8BIT_RESOLUTION 550 /* us */
#define HS3001_10BIT_RESOLUTION 1310 /* us */
#define HS3001_12BIT_RESOLUTION 4500 /* us */
#define HS3001_14BIT_RESOLUTION 16900 /* us */
#define HS3001_RESPONSE_LENGTH 4
#define HS3001_FIXPOINT_ARITH 1000U
#define HS3001_MASK_HUMIDITY_0X3FFF GENMASK(13, 0)
#define HS3001_MASK_STATUS_0XC0 GENMASK(7, 6)
/* Definitions for Status Bits of A/D Data */
#define HS3001_DATA_VALID 0x00 /* Valid Data */
#define HS3001_DATA_STALE 0x01 /* Stale Data */
struct hs3001_data {
struct i2c_client *client;
struct mutex i2c_lock; /* lock for sending i2c commands */
u32 wait_time; /* in us */
int temperature; /* in milli degree */
u32 humidity; /* in milli % */
};
static int hs3001_extract_temperature(u16 raw)
{
/* fixpoint arithmetic 1 digit */
u32 temp = (raw >> 2) * HS3001_FIXPOINT_ARITH * 165;
temp /= (1 << 14) - 1;
return (int)temp - 40 * HS3001_FIXPOINT_ARITH;
}
static u32 hs3001_extract_humidity(u16 raw)
{
u32 hum = (raw & HS3001_MASK_HUMIDITY_0X3FFF) * HS3001_FIXPOINT_ARITH * 100;
return hum /= (1 << 14) - 1;
}
static int hs3001_data_fetch_command(struct i2c_client *client,
struct hs3001_data *data)
{
int ret;
u8 buf[HS3001_RESPONSE_LENGTH];
u8 hs3001_status;
ret = i2c_master_recv(client, buf, HS3001_RESPONSE_LENGTH);
if (ret != HS3001_RESPONSE_LENGTH) {
ret = ret < 0 ? ret : -EIO;
dev_dbg(&client->dev,
"Error in i2c communication. Error code: %d.\n", ret);
return ret;
}
hs3001_status = FIELD_GET(HS3001_MASK_STATUS_0XC0, buf[0]);
if (hs3001_status == HS3001_DATA_STALE) {
dev_dbg(&client->dev, "Sensor busy.\n");
return -EBUSY;
}
if (hs3001_status != HS3001_DATA_VALID) {
dev_dbg(&client->dev, "Data invalid.\n");
return -EIO;
}
data->humidity =
hs3001_extract_humidity(be16_to_cpup((__be16 *)&buf[0]));
data->temperature =
hs3001_extract_temperature(be16_to_cpup((__be16 *)&buf[2]));
return 0;
}
static umode_t hs3001_is_visible(const void *data, enum hwmon_sensor_types type,
u32 attr, int channel)
{
/* Both, humidity and temperature can only be read. */
return 0444;
}
static int hs3001_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct hs3001_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
int ret;
mutex_lock(&data->i2c_lock);
ret = i2c_master_send(client, NULL, 0);
if (ret < 0) {
mutex_unlock(&data->i2c_lock);
return ret;
}
/*
* Sensor needs some time to process measurement depending on
* resolution (ref. datasheet)
*/
fsleep(data->wait_time);
ret = hs3001_data_fetch_command(client, data);
mutex_unlock(&data->i2c_lock);
if (ret < 0)
return ret;
switch (type) {
case hwmon_temp:
switch (attr) {
case hwmon_temp_input:
*val = data->temperature;
break;
default:
return -EINVAL;
}
break;
case hwmon_humidity:
switch (attr) {
case hwmon_humidity_input:
*val = data->humidity;
break;
default:
return -EINVAL;
}
break;
default:
return -EINVAL;
}
return 0;
}
static const struct hwmon_channel_info *hs3001_info[] = {
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT),
NULL
};
static const struct hwmon_ops hs3001_hwmon_ops = {
.is_visible = hs3001_is_visible,
.read = hs3001_read,
};
static const struct hwmon_chip_info hs3001_chip_info = {
.ops = &hs3001_hwmon_ops,
.info = hs3001_info,
};
/* device ID table */
static const struct i2c_device_id hs3001_ids[] = {
{ "hs3001", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, hs3001_ids);
static const struct of_device_id hs3001_of_match[] = {
{.compatible = "renesas,hs3001"},
{ },
};
MODULE_DEVICE_TABLE(of, hs3001_of_match);
static int hs3001_probe(struct i2c_client *client)
{
struct hs3001_data *data;
struct device *hwmon_dev;
struct device *dev = &client->dev;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -EOPNOTSUPP;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->client = client;
/*
* Measurement time = wake-up time + measurement time temperature
* + measurement time humidity. This is currently static, because
* enabling programming mode is not supported, yet.
*/
data->wait_time = (HS3001_WAKEUP_TIME + HS3001_14BIT_RESOLUTION +
HS3001_14BIT_RESOLUTION);
mutex_init(&data->i2c_lock);
hwmon_dev = devm_hwmon_device_register_with_info(dev,
client->name,
data,
&hs3001_chip_info,
NULL);
if (IS_ERR(hwmon_dev))
return dev_err_probe(dev, PTR_ERR(hwmon_dev),
"Unable to register hwmon device.\n");
return 0;
}
static struct i2c_driver hs3001_i2c_driver = {
.driver = {
.name = "hs3001",
.of_match_table = hs3001_of_match,
},
.probe = hs3001_probe,
.id_table = hs3001_ids,
};
module_i2c_driver(hs3001_i2c_driver);
MODULE_AUTHOR("Andre Werner <andre.werner@systec-electronic.com>");
MODULE_DESCRIPTION("HS3001 humidity and temperature sensor base driver");
MODULE_LICENSE("GPL");

View file

@ -31,7 +31,6 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/delay.h>
#include <linux/util_macros.h>
@ -625,7 +624,7 @@ static int ina2xx_probe(struct i2c_client *client)
enum ina2xx_ids chip;
if (client->dev.of_node)
chip = (enum ina2xx_ids)of_device_get_match_data(&client->dev);
chip = (uintptr_t)of_device_get_match_data(&client->dev);
else
chip = i2c_match_id(ina2xx_id, client)->driver_data;

View file

@ -221,6 +221,10 @@ static bool fix_pwm_polarity;
* Super-I/O configuration space.
*/
#define IT87_REG_VID 0x0a
/* Interface Selection register on other chips */
#define IT87_REG_IFSEL 0x0a
/*
* The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b
* for fan divisors. Later IT8712F revisions must use 16-bit tachometer
@ -1159,28 +1163,66 @@ static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0);
static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0);
static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0);
static int get_temp_type(struct it87_data *data, int index)
{
/*
* 2 is deprecated;
* 3 = thermal diode;
* 4 = thermistor;
* 5 = AMDTSI;
* 6 = Intel PECI;
* 0 = disabled
*/
u8 reg, extra;
int ttype, type = 0;
/* Detect PECI vs. AMDTSI */
ttype = 6;
if ((has_temp_peci(data, index)) || data->type == it8721 ||
data->type == it8720) {
extra = it87_read_value(data, IT87_REG_IFSEL);
if ((extra & 0x70) == 0x40)
ttype = 5;
}
reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
/* Per chip special detection */
switch (data->type) {
case it8622:
if (!(reg & 0xc0) && index == 3)
type = ttype;
break;
default:
break;
}
if (type || index >= 3)
return type;
extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
if ((has_temp_peci(data, index) && (reg >> 6 == index + 1)) ||
(has_temp_old_peci(data, index) && (extra & 0x80)))
type = ttype; /* Intel PECI or AMDTSI */
else if (reg & BIT(index))
type = 3; /* thermal diode */
else if (reg & BIT(index + 3))
type = 4; /* thermistor */
return type;
}
static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct it87_data *data = it87_update_device(dev);
u8 reg, extra;
if (IS_ERR(data))
return PTR_ERR(data);
reg = data->sensor; /* In case value is updated while used */
extra = data->extra;
if ((has_temp_peci(data, nr) && (reg >> 6 == nr + 1)) ||
(has_temp_old_peci(data, nr) && (extra & 0x80)))
return sprintf(buf, "6\n"); /* Intel PECI */
if (reg & (1 << nr))
return sprintf(buf, "3\n"); /* thermal diode */
if (reg & (8 << nr))
return sprintf(buf, "4\n"); /* thermistor */
return sprintf(buf, "0\n"); /* disabled */
return sprintf(buf, "%d\n", get_temp_type(data, sensor_attr->index));
}
static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
@ -2313,6 +2355,12 @@ static umode_t it87_temp_is_visible(struct kobject *kobj,
if (!(data->has_temp & BIT(i)))
return 0;
if (a == 3) {
if (get_temp_type(data, i) == 0)
return 0;
return attr->mode;
}
if (a == 5 && !has_temp_offset(data))
return 0;

View file

@ -334,24 +334,6 @@ static struct regmap *lan966x_init_regmap(struct platform_device *pdev,
return devm_regmap_init_mmio(&pdev->dev, base, &regmap_config);
}
static void lan966x_clk_disable(void *data)
{
struct lan966x_hwmon *hwmon = data;
clk_disable_unprepare(hwmon->clk);
}
static int lan966x_clk_enable(struct device *dev, struct lan966x_hwmon *hwmon)
{
int ret;
ret = clk_prepare_enable(hwmon->clk);
if (ret)
return ret;
return devm_add_action_or_reset(dev, lan966x_clk_disable, hwmon);
}
static int lan966x_hwmon_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -363,15 +345,11 @@ static int lan966x_hwmon_probe(struct platform_device *pdev)
if (!hwmon)
return -ENOMEM;
hwmon->clk = devm_clk_get(dev, NULL);
hwmon->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(hwmon->clk))
return dev_err_probe(dev, PTR_ERR(hwmon->clk),
"failed to get clock\n");
ret = lan966x_clk_enable(dev, hwmon);
if (ret)
return dev_err_probe(dev, ret, "failed to enable clock\n");
hwmon->clk_rate = clk_get_rate(hwmon->clk);
hwmon->regmap_pvt = lan966x_init_regmap(pdev, "pvt");

View file

@ -33,7 +33,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/sysfs.h>
#include <linux/types.h>
@ -1105,7 +1105,7 @@ static int lm63_probe(struct i2c_client *client)
/* Set the device type */
if (client->dev.of_node)
data->kind = (enum chips)of_device_get_match_data(&client->dev);
data->kind = (uintptr_t)of_device_get_match_data(&client->dev);
else
data->kind = i2c_match_id(lm63_id, client)->driver_data;
if (data->kind == lm64)

View file

@ -13,7 +13,6 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/util_macros.h>
@ -579,7 +578,7 @@ static int lm75_probe(struct i2c_client *client)
enum lm75_type kind;
if (client->dev.of_node)
kind = (enum lm75_type)of_device_get_match_data(&client->dev);
kind = (uintptr_t)of_device_get_match_data(&client->dev);
else
kind = i2c_match_id(lm75_ids, client)->driver_data;

View file

@ -12,7 +12,7 @@
*/
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
@ -1559,7 +1559,7 @@ static int lm85_probe(struct i2c_client *client)
data->client = client;
if (client->dev.of_node)
data->type = (enum chips)of_device_get_match_data(&client->dev);
data->type = (uintptr_t)of_device_get_match_data(&client->dev);
else
data->type = i2c_match_id(lm85_id, client)->driver_data;
mutex_init(&data->update_lock);

View file

@ -106,7 +106,7 @@
#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
@ -2765,7 +2765,7 @@ static int lm90_probe(struct i2c_client *client)
/* Set the device type */
if (client->dev.of_node)
data->kind = (enum chips)of_device_get_match_data(&client->dev);
data->kind = (uintptr_t)of_device_get_match_data(&client->dev);
else
data->kind = i2c_match_id(lm90_id, client)->driver_data;

View file

@ -16,7 +16,6 @@
#include <linux/mfd/lochnagar2_regs.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>

View file

@ -9,8 +9,9 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/init.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <lantiq_soc.h>

View file

@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/hwmon.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/slab.h>

View file

@ -12,7 +12,7 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/regmap.h>
#define MAX6621_DRV_NAME "max6621"

View file

@ -618,11 +618,17 @@ MODULE_DEVICE_TABLE(i2c, max6639_id);
static DEFINE_SIMPLE_DEV_PM_OPS(max6639_pm_ops, max6639_suspend, max6639_resume);
static const struct of_device_id max6639_of_match[] = {
{ .compatible = "maxim,max6639", },
{ },
};
static struct i2c_driver max6639_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "max6639",
.pm = pm_sleep_ptr(&max6639_pm_ops),
.of_match_table = max6639_of_match,
},
.probe = max6639_probe,
.id_table = max6639_id,

View file

@ -15,7 +15,6 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_data/max6697.h>
@ -703,7 +702,7 @@ static int max6697_probe(struct i2c_client *client)
return -ENOMEM;
if (client->dev.of_node)
data->type = (enum chips)of_device_get_match_data(&client->dev);
data->type = (uintptr_t)of_device_get_match_data(&client->dev);
else
data->type = i2c_match_id(max6697_id, client)->driver_data;
data->chip = &max6697_chip_data[data->type];

View file

@ -20,7 +20,6 @@
#include <linux/err.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_device.h>
/* Vdd / reference voltage in millivolt */
#define MCP3021_VDD_REF_MAX 5500

View file

@ -12,7 +12,7 @@
#include <linux/regmap.h>
#include <linux/thermal.h>
#define MLXREG_FAN_MAX_TACHO 14
#define MLXREG_FAN_MAX_TACHO 24
#define MLXREG_FAN_MAX_PWM 4
#define MLXREG_FAN_PWM_NOT_CONNECTED 0xff
#define MLXREG_FAN_MAX_STATE 10
@ -300,6 +300,16 @@ static const struct hwmon_channel_info * const mlxreg_fan_hwmon_info[] = {
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT),
HWMON_CHANNEL_INFO(pwm,
HWMON_PWM_INPUT,

View file

@ -33,7 +33,8 @@
* (0xd451)
* nct6798d 14 7 7 2+6 0xd428 0xc1 0x5ca3
* (0xd429)
* nct6799d 14 7 7 2+6 0xd802 0xc1 0x5ca3
* nct6796d-s 18 7 7 6+2 0xd801 0xc1 0x5ca3
* nct6799d-r 18 7 7 6+2 0xd802 0xc1 0x5ca3
*
* #temp lists the number of monitored temperature sources (first value) plus
* the number of directly connectable temperature sensors (second value).
@ -79,14 +80,17 @@ static const char * const nct6775_device_names[] = {
/* Common and NCT6775 specific data */
/* Voltage min/max registers for nr=7..14 are in bank 5 */
/*
* Voltage min/max registers for nr=7..14 are in bank 5
* min/max: 15-17 for NCT6799 only
*/
static const u16 NCT6775_REG_IN_MAX[] = {
0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
0x55c, 0x55e, 0x560, 0x562 };
0x55c, 0x55e, 0x560, 0x562, 0x564, 0x570, 0x572 };
static const u16 NCT6775_REG_IN_MIN[] = {
0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
0x55d, 0x55f, 0x561, 0x563 };
0x55d, 0x55f, 0x561, 0x563, 0x565, 0x571, 0x573 };
static const u16 NCT6775_REG_IN[] = {
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
};
@ -97,31 +101,23 @@ static const u16 NCT6775_REG_IN[] = {
static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
static const s8 NCT6775_ALARM_BITS[] = {
0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
-1, /* unused */
6, 7, 11, -1, -1, /* fan1..fan5 */
-1, -1, -1, /* unused */
4, 5, 13, -1, -1, -1, /* temp1..temp6 */
12, -1 }; /* intrusion0, intrusion1 */
static const s8 NCT6775_ALARM_BITS[NUM_ALARM_BITS] = {
0, 1, 2, 3, 8, 21, 20, 16, 17, -1, -1, -1, /* in0-in11 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
6, 7, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
4, 5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
12, -1, /* intr0-intr1 */
};
static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
/*
* 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
* 30..31 intrusion
*/
static const s8 NCT6775_BEEP_BITS[] = {
0, 1, 2, 3, 8, 9, 10, 16, /* in0.. in7 */
17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
21, /* global beep enable */
6, 7, 11, 28, -1, /* fan1..fan5 */
-1, -1, -1, /* unused */
4, 5, 13, -1, -1, -1, /* temp1..temp6 */
12, -1 }; /* intrusion0, intrusion1 */
static const s8 NCT6775_BEEP_BITS[NUM_BEEP_BITS] = {
0, 1, 2, 3, 8, 9, 10, 16, 17, -1, -1, -1, /* in0-in11 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
6, 7, 11, 28, -1, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
4, 5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
12, -1, 21 /* intr0-intr1, beep_en */
};
/* DC or PWM output fan configuration */
static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
@ -255,25 +251,24 @@ static const u16 NCT6775_REG_TSI_TEMP[] = { 0x669 };
#define NCT6776_REG_FAN_STEP_UP_TIME NCT6775_REG_FAN_STEP_DOWN_TIME
#define NCT6776_REG_FAN_STEP_DOWN_TIME NCT6775_REG_FAN_STEP_UP_TIME
static const s8 NCT6776_ALARM_BITS[] = {
0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
-1, /* unused */
6, 7, 11, 10, 23, /* fan1..fan5 */
-1, -1, -1, /* unused */
4, 5, 13, -1, -1, -1, /* temp1..temp6 */
12, 9 }; /* intrusion0, intrusion1 */
static const s8 NCT6776_ALARM_BITS[NUM_ALARM_BITS] = {
0, 1, 2, 3, 8, 21, 20, 16, 17, -1, -1, -1, /* in0-in11 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
6, 7, 11, 10, 23, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
4, 5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
12, 9, /* intr0-intr1 */
};
static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
/* 0xbf: nct6799 only */
static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
static const s8 NCT6776_BEEP_BITS[] = {
0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
8, -1, -1, -1, -1, -1, -1, /* in8..in14 */
24, /* global beep enable */
25, 26, 27, 28, 29, /* fan1..fan5 */
-1, -1, -1, /* unused */
16, 17, 18, 19, 20, 21, /* temp1..temp6 */
30, 31 }; /* intrusion0, intrusion1 */
static const s8 NCT6776_BEEP_BITS[NUM_BEEP_BITS] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, /* in0-in11 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
25, 26, 27, 28, 29, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
30, 31, 24 /* intr0-intr1, beep_en */
};
static const u16 NCT6776_REG_TOLERANCE_H[] = {
0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c, 0xb0c };
@ -337,30 +332,35 @@ static const u16 NCT6776_REG_TSI_TEMP[] = {
/* NCT6779 specific data */
/*
* 15-17 for NCT6799 only, register labels are:
* CPUVC, VIN1, AVSB, 3VCC, VIN0, VIN8, VIN4, 3VSB
* VBAT, VTT, VIN5, VIN6, VIN2, VIN3, VIN7, VIN9
* VHIF, VIN10
*/
static const u16 NCT6779_REG_IN[] = {
0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e, 0x48f,
0x470, 0x471};
static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
0x459, 0x45A, 0x45B, 0x568 };
static const s8 NCT6779_ALARM_BITS[] = {
0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
-1, /* unused */
6, 7, 11, 10, 23, /* fan1..fan5 */
-1, -1, -1, /* unused */
4, 5, 13, -1, -1, -1, /* temp1..temp6 */
12, 9 }; /* intrusion0, intrusion1 */
static const s8 NCT6779_ALARM_BITS[NUM_ALARM_BITS] = {
0, 1, 2, 3, 8, 21, 20, 16, 17, 24, 25, 26, /* in0-in11 */
27, 28, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
6, 7, 11, 10, 23, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
4, 5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
12, 9, /* intr0-intr1 */
};
static const s8 NCT6779_BEEP_BITS[] = {
0, 1, 2, 3, 4, 5, 6, 7, /* in0.. in7 */
8, 9, 10, 11, 12, 13, 14, /* in8..in14 */
24, /* global beep enable */
25, 26, 27, 28, 29, /* fan1..fan5 */
-1, -1, -1, /* unused */
16, 17, -1, -1, -1, -1, /* temp1..temp6 */
30, 31 }; /* intrusion0, intrusion1 */
static const s8 NCT6779_BEEP_BITS[NUM_BEEP_BITS] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, /* in0-in11 */
12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
25, 26, 27, 28, 29, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
30, 31, 24 /* intr0-intr1, beep_en */
};
static const u16 NCT6779_REG_FAN[] = {
0x4c0, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4ce };
@ -448,14 +448,13 @@ static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[NUM_FAN] = { 0, 0x23e };
static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
0x459, 0x45A, 0x45B, 0x568, 0x45D };
static const s8 NCT6791_ALARM_BITS[] = {
0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
-1, /* unused */
6, 7, 11, 10, 23, 33, /* fan1..fan6 */
-1, -1, /* unused */
4, 5, 13, -1, -1, -1, /* temp1..temp6 */
12, 9 }; /* intrusion0, intrusion1 */
static const s8 NCT6791_ALARM_BITS[NUM_ALARM_BITS] = {
0, 1, 2, 3, 8, 21, 20, 16, 17, 24, 25, 26, /* in0-in11 */
27, 28, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
6, 7, 11, 10, 23, 33, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
4, 5, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
12, 9, /* intr0-intr1 */
};
/* NCT6792/NCT6793 specific data */
@ -618,6 +617,28 @@ static const char *const nct6796_temp_label[] = {
static const u16 NCT6796_REG_TSI_TEMP[] = { 0x409, 0x40b };
static const u16 NCT6798_REG_TEMP[] = {
0x27, 0x150, 0x670, 0x672, 0x674, 0x676, 0x678, 0x67a};
static const u16 NCT6798_REG_TEMP_SOURCE[] = {
0x621, 0x622, 0xc26, 0xc27, 0xc28, 0xc29, 0xc2a, 0xc2b };
static const u16 NCT6798_REG_TEMP_MON[] = {
0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d, 0x4a0 };
static const u16 NCT6798_REG_TEMP_OVER[] = {
0x39, 0x155, 0xc1a, 0xc1b, 0xc1c, 0xc1d, 0xc1e, 0xc1f };
static const u16 NCT6798_REG_TEMP_HYST[] = {
0x3a, 0x153, 0xc20, 0xc21, 0xc22, 0xc23, 0xc24, 0xc25 };
static const u16 NCT6798_REG_TEMP_CRIT[32] = {
0x135, 0x235, 0x335, 0x835, 0x935, 0xa35, 0xb35, 0 };
static const u16 NCT6798_REG_TEMP_ALTERNATE[32] = {
0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0x496, 0,
0, 0, 0, 0, 0x4a2, 0, 0, 0,
0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
0x408, 0x419, 0x41a, 0x4f4, 0x4f5 };
static const char *const nct6798_temp_label[] = {
"",
"SYSTIN",
@ -656,6 +677,26 @@ static const char *const nct6798_temp_label[] = {
#define NCT6798_TEMP_MASK 0xbfff0ffe
#define NCT6798_VIRT_TEMP_MASK 0x80000c00
static const u16 NCT6799_REG_ALARM[NUM_REG_ALARM] = {
0x459, 0x45A, 0x45B, 0x568, 0x45D, 0xc01 };
static const s8 NCT6799_ALARM_BITS[NUM_ALARM_BITS] = {
0, 1, 2, 3, 8, -1, 20, 16, 17, 24, 25, 26, /* in0-in11 */
27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
6, 7, 11, 10, 23, 33, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
4, 5, 40, 41, 42, 43, 44, -1, -1, -1, -1, -1, /* temp1-temp12 */
12, 9, /* intr0-intr1 */
};
static const s8 NCT6799_BEEP_BITS[NUM_BEEP_BITS] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, /* in0-in11 */
12, 13, 14, 15, 34, 35, -1, -1, -1, -1, -1, -1, /* in12-in23 */
25, 26, 27, 28, 29, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
16, 17, 18, 19, 20, 21, 22, 23, -1, -1, -1, -1, /* temp1-temp12 */
30, 31, 24 /* intr0-intr1, beep_en */
};
/* PECI Calibration only for NCT6799D, not NCT6796D-S */
static const char *const nct6799_temp_label[] = {
"",
"SYSTIN",
@ -685,8 +726,8 @@ static const char *const nct6799_temp_label[] = {
"Agent1 Dimm1",
"BYTE_TEMP0",
"BYTE_TEMP1",
"PECI Agent 0 Calibration", /* undocumented */
"PECI Agent 1 Calibration", /* undocumented */
"PECI/TSI Agent 0 Calibration",
"PECI/TSI Agent 1 Calibration",
"",
"Virtual_TEMP"
};
@ -763,27 +804,23 @@ static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
static const s8 NCT6106_ALARM_BITS[] = {
0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
9, -1, -1, -1, -1, -1, -1, /* in8..in14 */
-1, /* unused */
32, 33, 34, -1, -1, /* fan1..fan5 */
-1, -1, -1, /* unused */
16, 17, 18, 19, 20, 21, /* temp1..temp6 */
48, -1 /* intrusion0, intrusion1 */
static const s8 NCT6106_ALARM_BITS[NUM_ALARM_BITS] = {
0, 1, 2, 3, 4, 5, 7, 8, 9, -1, -1, -1, /* in0-in11 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
32, 33, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
48, -1, /* intr0-intr1 */
};
static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
static const s8 NCT6106_BEEP_BITS[] = {
0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
32, /* global beep enable */
24, 25, 26, 27, 28, /* fan1..fan5 */
-1, -1, -1, /* unused */
16, 17, 18, 19, 20, 21, /* temp1..temp6 */
34, -1 /* intrusion0, intrusion1 */
static const s8 NCT6106_BEEP_BITS[NUM_BEEP_BITS] = {
0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, /* in0-in11 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
24, 25, 26, 27, 28, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
16, 17, 18, 19, 20, 21, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
34, -1, 32 /* intr0-intr1, beep_en */
};
static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = {
@ -843,24 +880,20 @@ static const u16 NCT6116_REG_AUTO_TEMP[] = {
static const u16 NCT6116_REG_AUTO_PWM[] = {
0x164, 0x174, 0x184, 0x1d4, 0x1e4 };
static const s8 NCT6116_ALARM_BITS[] = {
0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
9, -1, -1, -1, -1, -1, -1, /* in8..in9 */
-1, /* unused */
32, 33, 34, 35, 36, /* fan1..fan5 */
-1, -1, -1, /* unused */
16, 17, 18, -1, -1, -1, /* temp1..temp6 */
48, -1 /* intrusion0, intrusion1 */
static const s8 NCT6116_ALARM_BITS[NUM_ALARM_BITS] = {
0, 1, 2, 3, 4, 5, 7, 8, 9, -1, -1, -1, /* in0-in11 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
32, 33, 34, 35, 36, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
16, 17, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
48, -1, /* intr0-intr1 */
};
static const s8 NCT6116_BEEP_BITS[] = {
0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
32, /* global beep enable */
24, 25, 26, 27, 28, /* fan1..fan5 */
-1, -1, -1, /* unused */
16, 17, 18, -1, -1, -1, /* temp1..temp6 */
34, -1 /* intrusion0, intrusion1 */
static const s8 NCT6116_BEEP_BITS[NUM_BEEP_BITS] = {
0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, /* in0-in11 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* in12-in23 */
24, 25, 26, 27, 28, -1, -1, -1, -1, -1, -1, -1, /* fan1-fan12 */
16, 17, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* temp1-temp12 */
34, -1, 32 /* intr0-intr1, beep_en */
};
static const u16 NCT6116_REG_TSI_TEMP[] = { 0x59, 0x5b };
@ -958,12 +991,12 @@ static const u16 scale_in[15] = {
/*
* NCT6798 scaling:
* CPUVC, IN1, AVSB, 3VCC, IN0, IN8, IN4, 3VSB, VBAT, VTT, IN5, IN6, IN2,
* IN3, IN7
* Additional scales to be added later: IN9 (800), VHIF (1600)
* IN3, IN7, IN9, VHIF, IN10
* 15-17 for NCT6799 only
*/
static const u16 scale_in_6798[15] = {
static const u16 scale_in_6798[NUM_IN] = {
800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 1600, 1600, 1600, 800,
800, 800
800, 800, 800, 1600, 800
};
static inline long in_from_reg(u8 reg, u8 nr, const u16 *scales)
@ -3862,13 +3895,9 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
case nct6795:
case nct6796:
case nct6797:
case nct6798:
case nct6799:
data->in_num = 15;
data->pwm_num = (data->kind == nct6796 ||
data->kind == nct6797 ||
data->kind == nct6798 ||
data->kind == nct6799) ? 7 : 6;
data->kind == nct6797) ? 7 : 6;
data->auto_pwm_num = 4;
data->has_fan_div = false;
data->temp_fixed_num = 6;
@ -3912,16 +3941,6 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
data->temp_mask = NCT6796_TEMP_MASK;
data->virt_temp_mask = NCT6796_VIRT_TEMP_MASK;
break;
case nct6798:
data->temp_label = nct6798_temp_label;
data->temp_mask = NCT6798_TEMP_MASK;
data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK;
break;
case nct6799:
data->temp_label = nct6799_temp_label;
data->temp_mask = NCT6799_TEMP_MASK;
data->virt_temp_mask = NCT6799_VIRT_TEMP_MASK;
break;
}
data->REG_CONFIG = NCT6775_REG_CONFIG;
@ -3980,8 +3999,6 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
case nct6795:
case nct6796:
case nct6797:
case nct6798:
case nct6799:
data->REG_TSI_TEMP = NCT6796_REG_TSI_TEMP;
num_reg_tsi_temp = ARRAY_SIZE(NCT6796_REG_TSI_TEMP);
break;
@ -3990,9 +4007,6 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
break;
}
if (data->kind == nct6798 || data->kind == nct6799)
data->scale_in = scale_in_6798;
reg_temp = NCT6779_REG_TEMP;
num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
if (data->kind == nct6791) {
@ -4008,6 +4022,95 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
reg_temp_crit = NCT6779_REG_TEMP_CRIT;
break;
case nct6798:
case nct6799:
data->in_num = data->kind == nct6799 ? 18 : 15;
data->scale_in = scale_in_6798;
data->pwm_num = 7;
data->auto_pwm_num = 4;
data->has_fan_div = false;
data->temp_fixed_num = 6;
data->num_temp_alarms = 7;
data->num_temp_beeps = 8;
data->ALARM_BITS = NCT6799_ALARM_BITS;
data->BEEP_BITS = NCT6799_BEEP_BITS;
data->fan_from_reg = fan_from_reg_rpm;
data->fan_from_reg_min = fan_from_reg13;
data->target_temp_mask = 0xff;
data->tolerance_mask = 0x07;
data->speed_tolerance_limit = 63;
switch (data->kind) {
default:
case nct6798:
data->temp_label = nct6798_temp_label;
data->temp_mask = NCT6798_TEMP_MASK;
data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK;
break;
case nct6799:
data->temp_label = nct6799_temp_label;
data->temp_mask = NCT6799_TEMP_MASK;
data->virt_temp_mask = NCT6799_VIRT_TEMP_MASK;
break;
}
data->REG_CONFIG = NCT6775_REG_CONFIG;
data->REG_VBAT = NCT6775_REG_VBAT;
data->REG_DIODE = NCT6775_REG_DIODE;
data->DIODE_MASK = NCT6775_DIODE_MASK;
data->REG_VIN = NCT6779_REG_IN;
data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
data->REG_TARGET = NCT6775_REG_TARGET;
data->REG_FAN = NCT6779_REG_FAN;
data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
data->REG_FAN_TIME[1] = NCT6776_REG_FAN_STEP_UP_TIME;
data->REG_FAN_TIME[2] = NCT6776_REG_FAN_STEP_DOWN_TIME;
data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
data->REG_PWM[0] = NCT6775_REG_PWM;
data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP;
data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE;
data->REG_PWM_READ = NCT6775_REG_PWM_READ;
data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
data->REG_CRITICAL_TEMP_TOLERANCE = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
data->CRITICAL_PWM_ENABLE_MASK = NCT6779_CRITICAL_PWM_ENABLE_MASK;
data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
data->REG_TEMP_SOURCE = NCT6798_REG_TEMP_SOURCE;
data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL;
data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP;
data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
data->REG_ALARM = NCT6799_REG_ALARM;
data->REG_BEEP = NCT6792_REG_BEEP;
data->REG_TSI_TEMP = NCT6796_REG_TSI_TEMP;
num_reg_tsi_temp = ARRAY_SIZE(NCT6796_REG_TSI_TEMP);
reg_temp = NCT6798_REG_TEMP;
num_reg_temp = ARRAY_SIZE(NCT6798_REG_TEMP);
reg_temp_mon = NCT6798_REG_TEMP_MON;
num_reg_temp_mon = ARRAY_SIZE(NCT6798_REG_TEMP_MON);
reg_temp_over = NCT6798_REG_TEMP_OVER;
reg_temp_hyst = NCT6798_REG_TEMP_HYST;
reg_temp_config = NCT6779_REG_TEMP_CONFIG;
reg_temp_alternate = NCT6798_REG_TEMP_ALTERNATE;
reg_temp_crit = NCT6798_REG_TEMP_CRIT;
break;
default:
return -ENODEV;

View file

@ -35,7 +35,7 @@ static const char * const nct6775_sio_names[] __initconst = {
"NCT6796D",
"NCT6797D",
"NCT6798D",
"NCT6799D",
"NCT6796D-S/NCT6799D-R",
};
static unsigned short force_id;

View file

@ -8,7 +8,7 @@ enum kinds { nct6106, nct6116, nct6775, nct6776, nct6779, nct6791, nct6792,
nct6793, nct6795, nct6796, nct6797, nct6798, nct6799 };
enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
#define NUM_TEMP 12 /* Max number of temp attribute sets w/ limits*/
#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
#define NUM_TSI_TEMP 8 /* Max number of TSI temp register pairs */
@ -16,6 +16,7 @@ enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
#define NUM_REG_BEEP 5 /* Max number of beep registers */
#define NUM_FAN 7
#define NUM_IN 18
struct nct6775_data {
int addr; /* IO base of hw monitor block */
@ -97,7 +98,7 @@ struct nct6775_data {
/* Register values */
u8 bank; /* current register bank */
u8 in_num; /* number of in inputs we have */
u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
u8 in[NUM_IN][3]; /* [0]=in, [1]=in_max, [2]=in_min */
const u16 *scale_in; /* internal scaling factors */
unsigned int rpm[NUM_FAN];
u16 fan_min[NUM_FAN];
@ -166,7 +167,7 @@ struct nct6775_data {
u16 have_temp;
u16 have_temp_fixed;
u16 have_tsi_temp;
u16 have_in;
u32 have_in;
/* Remember extra register values over suspend/resume */
u8 vbat;
@ -239,10 +240,25 @@ nct6775_add_attr_group(struct nct6775_data *data, const struct attribute_group *
#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
#define FAN_ALARM_BASE 16
#define TEMP_ALARM_BASE 24
#define INTRUSION_ALARM_BASE 30
#define BEEP_ENABLE_BASE 15
/*
* ALARM_BITS and BEEP_BITS store bit-index for the mask of the registers
* loaded into data->alarm and data->beep.
*
* Every input register (IN/TEMP/FAN) must have a corresponding
* ALARM/BEEP bit at the same index BITS[BASE + index]
* Set value to -1 to disable the visibility of that '*_alarm' attribute and
* to pad the bits until the next BASE
*
* Beep has an additional GLOBAL_BEEP_ENABLE bit
*/
#define VIN_ALARM_BASE 0
#define FAN_ALARM_BASE 24
#define TEMP_ALARM_BASE 36
#define INTRUSION_ALARM_BASE 48
#define BEEP_ENABLE_BASE 50
#define NUM_ALARM_BITS (INTRUSION_ALARM_BASE + 4)
#define NUM_BEEP_BITS (BEEP_ENABLE_BASE + 1)
/*
* Not currently used:

View file

@ -20,8 +20,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
/* Tests for error return values rely upon this value being < 0x80 */
@ -193,7 +191,7 @@ static struct platform_driver nsa320_hwmon_driver = {
.probe = nsa320_hwmon_probe,
.driver = {
.name = "nsa320-hwmon",
.of_match_table = of_match_ptr(of_nsa320_hwmon_match),
.of_match_table = of_nsa320_hwmon_match,
},
};

View file

@ -434,23 +434,9 @@ static const struct hwmon_chip_info oxp_ec_chip_info = {
/* 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 apart
* 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)(unsigned long)dmi_entry->driver_data;
hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL,
&oxp_ec_chip_info, NULL);
@ -469,6 +455,21 @@ static struct platform_device *oxp_platform_device;
static int __init oxp_platform_init(void)
{
const struct dmi_system_id *dmi_entry;
/*
* Have to check for AMD processor here because DMI strings are the
* same between Intel and AMD boards, the only way to tell them apart
* 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)(unsigned long)dmi_entry->driver_data;
oxp_platform_device =
platform_create_bundle(&oxp_platform_driver,
oxp_platform_probe, NULL, 0, NULL, 0);

View file

@ -219,19 +219,21 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
{
int chan_rank_max = priv->gen_info->chan_rank_max;
int dimm_idx_max = priv->gen_info->dimm_idx_max;
u32 chan_rank_empty = 0;
u32 dimm_mask = 0;
int chan_rank, dimm_idx, ret;
DECLARE_BITMAP(dimm_mask, DIMM_NUMS_MAX);
DECLARE_BITMAP(chan_rank_empty, CHAN_RANK_MAX);
int chan_rank, dimm_idx, ret, i;
u32 pcs;
BUILD_BUG_ON(BITS_PER_TYPE(chan_rank_empty) < CHAN_RANK_MAX);
BUILD_BUG_ON(BITS_PER_TYPE(dimm_mask) < DIMM_NUMS_MAX);
if (chan_rank_max * dimm_idx_max > DIMM_NUMS_MAX) {
WARN_ONCE(1, "Unsupported number of DIMMs - chan_rank_max: %d, dimm_idx_max: %d",
chan_rank_max, dimm_idx_max);
return -EINVAL;
}
bitmap_zero(dimm_mask, DIMM_NUMS_MAX);
bitmap_zero(chan_rank_empty, CHAN_RANK_MAX);
for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) {
ret = peci_pcs_read(priv->peci_dev, PECI_PCS_DDR_DIMM_TEMP, chan_rank, &pcs);
if (ret) {
@ -242,7 +244,7 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
* detection to be performed at a later point in time.
*/
if (ret == -EINVAL) {
chan_rank_empty |= BIT(chan_rank);
bitmap_set(chan_rank_empty, chan_rank, 1);
continue;
}
@ -251,7 +253,7 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++)
if (__dimm_temp(pcs, dimm_idx))
dimm_mask |= BIT(chan_rank * dimm_idx_max + dimm_idx);
bitmap_set(dimm_mask, chan_rank * dimm_idx_max + dimm_idx, 1);
}
/*
@ -260,7 +262,7 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
* host platform boot. Retrying a couple of times lets us make sure
* that the state is persistent.
*/
if (chan_rank_empty == GENMASK(chan_rank_max - 1, 0)) {
if (bitmap_full(chan_rank_empty, chan_rank_max)) {
if (priv->no_dimm_retry_count < NO_DIMM_RETRY_COUNT_MAX) {
priv->no_dimm_retry_count++;
@ -274,14 +276,16 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
* It's possible that memory training is not done yet. In this case we
* defer the detection to be performed at a later point in time.
*/
if (!dimm_mask) {
if (bitmap_empty(dimm_mask, DIMM_NUMS_MAX)) {
priv->no_dimm_retry_count = 0;
return -EAGAIN;
}
dev_dbg(priv->dev, "Scanned populated DIMMs: %#x\n", dimm_mask);
for_each_set_bit(i, dimm_mask, DIMM_NUMS_MAX) {
dev_dbg(priv->dev, "Found DIMM%#x\n", i);
}
bitmap_from_arr32(priv->dimm_mask, &dimm_mask, DIMM_NUMS_MAX);
bitmap_copy(priv->dimm_mask, dimm_mask, DIMM_NUMS_MAX);
return 0;
}

View file

@ -317,6 +317,13 @@ config SENSORS_MP2975
This driver can also be built as a module. If so, the module will
be called mp2975.
config SENSORS_MP2975_REGULATOR
depends on SENSORS_MP2975 && REGULATOR
bool "Regulator support for MPS MP2975"
help
If you say yes here you get regulator support for MPS MP2975
Dual Loop Digital Multi-Phase Controller.
config SENSORS_MP5023
tristate "MPS MP5023"
help

View file

@ -3,14 +3,51 @@
* Copyright 2023 IBM Corp.
*/
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/pmbus.h>
#include <linux/hwmon-sysfs.h>
#include "pmbus.h"
#define ACBEL_MFR_FW_REVISION 0xd9
static ssize_t acbel_fsg032_debugfs_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
struct i2c_client *client = file->private_data;
u8 data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
char out[8];
int rc;
rc = i2c_smbus_read_block_data(client, ACBEL_MFR_FW_REVISION, data);
if (rc < 0)
return rc;
rc = snprintf(out, sizeof(out), "%*phN\n", min(rc, 3), data);
return simple_read_from_buffer(buf, count, ppos, out, rc);
}
static const struct file_operations acbel_debugfs_ops = {
.llseek = noop_llseek,
.read = acbel_fsg032_debugfs_read,
.write = NULL,
.open = simple_open,
};
static void acbel_fsg032_init_debugfs(struct i2c_client *client)
{
struct dentry *debugfs = pmbus_get_debugfs_dir(client);
if (!debugfs)
return;
debugfs_create_file("fw_version", 0444, debugfs, client, &acbel_debugfs_ops);
}
static const struct i2c_device_id acbel_fsg032_id[] = {
{ "acbel_fsg032" },
{}
@ -59,6 +96,7 @@ static int acbel_fsg032_probe(struct i2c_client *client)
if (rc)
return rc;
acbel_fsg032_init_debugfs(client);
return 0;
}

View file

@ -9,7 +9,7 @@
#include <linux/debugfs.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include "pmbus.h"
struct dps920ab_data {

View file

@ -13,7 +13,7 @@
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/pmbus.h>
#include "pmbus.h"
@ -489,7 +489,7 @@ static int ibm_cffps_probe(struct i2c_client *client)
const struct i2c_device_id *id;
if (md) {
vs = (enum versions)md;
vs = (uintptr_t)md;
} else {
id = i2c_match_id(ibm_cffps_id, client);
if (id)

View file

@ -6,7 +6,7 @@
*
* VOUT_MODE is not supported by the device. The driver fakes VOUT linear16
* mode with exponent value -8 as direct mode with m=256/b=0/R=0.
*
*
* The device supports VOUT_PEAK, IOUT_PEAK, and TEMPERATURE_PEAK, however
* this driver does not currently support them.
*/
@ -16,7 +16,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/regulator/driver.h>
#include "pmbus.h"

View file

@ -15,7 +15,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/pmbus.h>
#include <linux/util_macros.h>
#include "pmbus.h"
@ -114,6 +114,7 @@ static ssize_t max20730_debugfs_read(struct file *file, char __user *buf,
const struct pmbus_driver_info *info;
const struct max20730_data *data;
char tbuf[DEBUG_FS_DATA_MAX] = { 0 };
char *result = tbuf;
u16 val;
info = pmbus_get_driver_info(psu->client);
@ -148,13 +149,13 @@ static ssize_t max20730_debugfs_read(struct file *file, char __user *buf,
>> MAX20730_MFR_DEVSET1_TSTAT_BIT_POS;
if (val == 0)
len = strlcpy(tbuf, "2000\n", DEBUG_FS_DATA_MAX);
result = "2000\n";
else if (val == 1)
len = strlcpy(tbuf, "125\n", DEBUG_FS_DATA_MAX);
result = "125\n";
else if (val == 2)
len = strlcpy(tbuf, "62.5\n", DEBUG_FS_DATA_MAX);
result = "62.5\n";
else
len = strlcpy(tbuf, "32\n", DEBUG_FS_DATA_MAX);
result = "32\n";
break;
case MAX20730_DEBUGFS_INTERNAL_GAIN:
val = (data->mfr_devset1 & MAX20730_MFR_DEVSET1_RGAIN_MASK)
@ -163,35 +164,35 @@ static ssize_t max20730_debugfs_read(struct file *file, char __user *buf,
if (data->id == max20734) {
/* AN6209 */
if (val == 0)
len = strlcpy(tbuf, "0.8\n", DEBUG_FS_DATA_MAX);
result = "0.8\n";
else if (val == 1)
len = strlcpy(tbuf, "3.2\n", DEBUG_FS_DATA_MAX);
result = "3.2\n";
else if (val == 2)
len = strlcpy(tbuf, "1.6\n", DEBUG_FS_DATA_MAX);
result = "1.6\n";
else
len = strlcpy(tbuf, "6.4\n", DEBUG_FS_DATA_MAX);
result = "6.4\n";
} else if (data->id == max20730 || data->id == max20710) {
/* AN6042 or AN6140 */
if (val == 0)
len = strlcpy(tbuf, "0.9\n", DEBUG_FS_DATA_MAX);
result = "0.9\n";
else if (val == 1)
len = strlcpy(tbuf, "3.6\n", DEBUG_FS_DATA_MAX);
result = "3.6\n";
else if (val == 2)
len = strlcpy(tbuf, "1.8\n", DEBUG_FS_DATA_MAX);
result = "1.8\n";
else
len = strlcpy(tbuf, "7.2\n", DEBUG_FS_DATA_MAX);
result = "7.2\n";
} else if (data->id == max20743) {
/* AN6042 */
if (val == 0)
len = strlcpy(tbuf, "0.45\n", DEBUG_FS_DATA_MAX);
result = "0.45\n";
else if (val == 1)
len = strlcpy(tbuf, "1.8\n", DEBUG_FS_DATA_MAX);
result = "1.8\n";
else if (val == 2)
len = strlcpy(tbuf, "0.9\n", DEBUG_FS_DATA_MAX);
result = "0.9\n";
else
len = strlcpy(tbuf, "3.6\n", DEBUG_FS_DATA_MAX);
result = "3.6\n";
} else {
len = strlcpy(tbuf, "Not supported\n", DEBUG_FS_DATA_MAX);
result = "Not supported\n";
}
break;
case MAX20730_DEBUGFS_BOOT_VOLTAGE:
@ -199,26 +200,26 @@ static ssize_t max20730_debugfs_read(struct file *file, char __user *buf,
>> MAX20730_MFR_DEVSET1_VBOOT_BIT_POS;
if (val == 0)
len = strlcpy(tbuf, "0.6484\n", DEBUG_FS_DATA_MAX);
result = "0.6484\n";
else if (val == 1)
len = strlcpy(tbuf, "0.8984\n", DEBUG_FS_DATA_MAX);
result = "0.8984\n";
else if (val == 2)
len = strlcpy(tbuf, "1.0\n", DEBUG_FS_DATA_MAX);
result = "1.0\n";
else
len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX);
result = "Invalid\n";
break;
case MAX20730_DEBUGFS_OUT_V_RAMP_RATE:
val = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_VRATE)
>> MAX20730_MFR_DEVSET2_VRATE_BIT_POS;
if (val == 0)
len = strlcpy(tbuf, "4\n", DEBUG_FS_DATA_MAX);
result = "4\n";
else if (val == 1)
len = strlcpy(tbuf, "2\n", DEBUG_FS_DATA_MAX);
result = "2\n";
else if (val == 2)
len = strlcpy(tbuf, "1\n", DEBUG_FS_DATA_MAX);
result = "1\n";
else
len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX);
result = "Invalid\n";
break;
case MAX20730_DEBUGFS_OC_PROTECT_MODE:
ret = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_OCPM_MASK)
@ -230,13 +231,13 @@ static ssize_t max20730_debugfs_read(struct file *file, char __user *buf,
>> MAX20730_MFR_DEVSET2_SS_BIT_POS;
if (val == 0)
len = strlcpy(tbuf, "0.75\n", DEBUG_FS_DATA_MAX);
result = "0.75\n";
else if (val == 1)
len = strlcpy(tbuf, "1.5\n", DEBUG_FS_DATA_MAX);
result = "1.5\n";
else if (val == 2)
len = strlcpy(tbuf, "3\n", DEBUG_FS_DATA_MAX);
result = "3\n";
else
len = strlcpy(tbuf, "6\n", DEBUG_FS_DATA_MAX);
result = "6\n";
break;
case MAX20730_DEBUGFS_IMAX:
ret = (data->mfr_devset2 & MAX20730_MFR_DEVSET2_IMAX_MASK)
@ -287,10 +288,11 @@ static ssize_t max20730_debugfs_read(struct file *file, char __user *buf,
"%d.%d\n", ret / 10000, ret % 10000);
break;
default:
len = strlcpy(tbuf, "Invalid\n", DEBUG_FS_DATA_MAX);
result = "Invalid\n";
}
return simple_read_from_buffer(buf, count, ppos, tbuf, len);
len = strlen(result);
return simple_read_from_buffer(buf, count, ppos, result, len);
}
static const struct file_operations max20730_fops = {
@ -714,7 +716,7 @@ static int max20730_probe(struct i2c_client *client)
}
if (client->dev.of_node)
chip_id = (enum chips)of_device_get_match_data(dev);
chip_id = (uintptr_t)of_device_get_match_data(dev);
else
chip_id = i2c_match_id(max20730_id, client)->driver_data;

View file

@ -10,6 +10,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include "pmbus.h"
/* Vendor specific registers. */
@ -34,6 +35,8 @@
#define MP2975_MFR_OVP_TH_SET 0xe5
#define MP2975_MFR_UVP_SET 0xe6
#define MP2973_MFR_RESO_SET 0xc7
#define MP2975_VOUT_FORMAT BIT(15)
#define MP2975_VID_STEP_SEL_R1 BIT(4)
#define MP2975_IMVP9_EN_R1 BIT(13)
@ -48,43 +51,80 @@
#define MP2975_SENSE_AMPL_HALF 2
#define MP2975_VIN_UV_LIMIT_UNIT 8
#define MP2973_VOUT_FORMAT_R1 GENMASK(7, 6)
#define MP2973_VOUT_FORMAT_R2 GENMASK(4, 3)
#define MP2973_VOUT_FORMAT_DIRECT_R1 BIT(7)
#define MP2973_VOUT_FORMAT_LINEAR_R1 BIT(6)
#define MP2973_VOUT_FORMAT_DIRECT_R2 BIT(4)
#define MP2973_VOUT_FORMAT_LINEAR_R2 BIT(3)
#define MP2973_MFR_VR_MULTI_CONFIG_R1 0x0d
#define MP2973_MFR_VR_MULTI_CONFIG_R2 0x1d
#define MP2973_VID_STEP_SEL_R1 BIT(4)
#define MP2973_IMVP9_EN_R1 BIT(14)
#define MP2973_VID_STEP_SEL_R2 BIT(3)
#define MP2973_IMVP9_EN_R2 BIT(13)
#define MP2973_MFR_OCP_TOTAL_SET 0x5f
#define MP2973_OCP_TOTAL_CUR_MASK GENMASK(6, 0)
#define MP2973_MFR_OCP_LEVEL_RES BIT(15)
#define MP2973_MFR_READ_IOUT_PK 0x90
#define MP2973_MFR_READ_POUT_PK 0x91
#define MP2975_MAX_PHASE_RAIL1 8
#define MP2975_MAX_PHASE_RAIL2 4
#define MP2973_MAX_PHASE_RAIL1 14
#define MP2973_MAX_PHASE_RAIL2 6
#define MP2971_MAX_PHASE_RAIL1 8
#define MP2971_MAX_PHASE_RAIL2 3
#define MP2975_PAGE_NUM 2
#define MP2975_RAIL2_FUNC (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | \
PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | \
PMBUS_HAVE_POUT | PMBUS_PHASE_VIRTUAL)
enum chips {
mp2971, mp2973, mp2975
};
static const int mp2975_max_phases[][MP2975_PAGE_NUM] = {
[mp2975] = { MP2975_MAX_PHASE_RAIL1, MP2975_MAX_PHASE_RAIL2 },
[mp2973] = { MP2973_MAX_PHASE_RAIL1, MP2973_MAX_PHASE_RAIL2 },
[mp2971] = { MP2971_MAX_PHASE_RAIL1, MP2971_MAX_PHASE_RAIL2 },
};
struct mp2975_data {
struct pmbus_driver_info info;
enum chips chip_id;
int vout_scale;
int max_phases[MP2975_PAGE_NUM];
int vid_step[MP2975_PAGE_NUM];
int vref[MP2975_PAGE_NUM];
int vref_off[MP2975_PAGE_NUM];
int vout_max[MP2975_PAGE_NUM];
int vout_ov_fixed[MP2975_PAGE_NUM];
int vout_format[MP2975_PAGE_NUM];
int curr_sense_gain[MP2975_PAGE_NUM];
};
#define to_mp2975_data(x) container_of(x, struct mp2975_data, info)
static const struct i2c_device_id mp2975_id[] = {
{"mp2971", mp2971},
{"mp2973", mp2973},
{"mp2975", mp2975},
{}
};
static int mp2975_read_byte_data(struct i2c_client *client, int page, int reg)
{
switch (reg) {
case PMBUS_VOUT_MODE:
/*
* Enforce VOUT direct format, since device allows to set the
* different formats for the different rails. Conversion from
* VID to direct provided by driver internally, in case it is
* necessary.
*/
return PB_VOUT_MODE_DIRECT;
default:
return -ENODATA;
}
}
MODULE_DEVICE_TABLE(i2c, mp2975_id);
static const struct regulator_desc __maybe_unused mp2975_reg_desc[] = {
PMBUS_REGULATOR("vout", 0),
PMBUS_REGULATOR("vout", 1),
};
#define to_mp2975_data(x) container_of(x, struct mp2975_data, info)
static int
mp2975_read_word_helper(struct i2c_client *client, int page, int phase, u8 reg,
@ -117,6 +157,41 @@ mp2975_vid2direct(int vrf, int val)
return 0;
}
#define MAX_LIN_MANTISSA (1023 * 1000)
#define MIN_LIN_MANTISSA (511 * 1000)
/* Converts a milli-unit DIRECT value to LINEAR11 format */
static u16 mp2975_data2reg_linear11(s64 val)
{
s16 exponent = 0, mantissa;
bool negative = false;
/* simple case */
if (val == 0)
return 0;
/* Reduce large mantissa until it fits into 10 bit */
while (val >= MAX_LIN_MANTISSA && exponent < 15) {
exponent++;
val >>= 1;
}
/* Increase small mantissa to improve precision */
while (val < MIN_LIN_MANTISSA && exponent > -15) {
exponent--;
val <<= 1;
}
/* Convert mantissa from milli-units to units */
mantissa = clamp_val(DIV_ROUND_CLOSEST_ULL(val, 1000), 0, 0x3ff);
/* restore sign */
if (negative)
mantissa = -mantissa;
/* Convert to 5 bit exponent, 11 bit mantissa */
return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
}
static int
mp2975_read_phase(struct i2c_client *client, struct mp2975_data *data,
int page, int phase, u8 reg)
@ -214,6 +289,89 @@ mp2975_read_phases(struct i2c_client *client, struct mp2975_data *data,
return ret;
}
static int mp2973_read_word_data(struct i2c_client *client, int page,
int phase, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct mp2975_data *data = to_mp2975_data(info);
int ret;
switch (reg) {
case PMBUS_OT_FAULT_LIMIT:
ret = mp2975_read_word_helper(client, page, phase, reg,
GENMASK(7, 0));
break;
case PMBUS_VIN_OV_FAULT_LIMIT:
ret = mp2975_read_word_helper(client, page, phase, reg,
GENMASK(7, 0));
if (ret < 0)
return ret;
ret = DIV_ROUND_CLOSEST(ret, MP2975_VIN_UV_LIMIT_UNIT);
break;
case PMBUS_VOUT_OV_FAULT_LIMIT:
/*
* MP2971 and mp2973 only supports tracking (ovp1) mode.
*/
ret = mp2975_read_word_helper(client, page, phase,
MP2975_MFR_OVP_TH_SET,
GENMASK(2, 0));
if (ret < 0)
return ret;
ret = data->vout_max[page] + 50 * (ret + 1);
break;
case PMBUS_VOUT_UV_FAULT_LIMIT:
ret = mp2975_read_word_helper(client, page, phase, reg,
GENMASK(8, 0));
if (ret < 0)
return ret;
ret = mp2975_vid2direct(info->vrm_version[page], ret);
break;
case PMBUS_VIRT_READ_POUT_MAX:
ret = pmbus_read_word_data(client, page, phase,
MP2973_MFR_READ_POUT_PK);
break;
case PMBUS_VIRT_READ_IOUT_MAX:
ret = pmbus_read_word_data(client, page, phase,
MP2973_MFR_READ_IOUT_PK);
break;
case PMBUS_IOUT_OC_FAULT_LIMIT:
ret = mp2975_read_word_helper(client, page, phase,
MP2973_MFR_OCP_TOTAL_SET,
GENMASK(15, 0));
if (ret < 0)
return ret;
if (ret & MP2973_MFR_OCP_LEVEL_RES)
ret = 2 * (ret & MP2973_OCP_TOTAL_CUR_MASK);
else
ret = ret & MP2973_OCP_TOTAL_CUR_MASK;
ret = mp2975_data2reg_linear11(ret * info->phases[page] * 1000);
break;
case PMBUS_UT_WARN_LIMIT:
case PMBUS_UT_FAULT_LIMIT:
case PMBUS_VIN_UV_WARN_LIMIT:
case PMBUS_VIN_UV_FAULT_LIMIT:
case PMBUS_VOUT_UV_WARN_LIMIT:
case PMBUS_VOUT_OV_WARN_LIMIT:
case PMBUS_VIN_OV_WARN_LIMIT:
case PMBUS_IIN_OC_FAULT_LIMIT:
case PMBUS_IOUT_OC_LV_FAULT_LIMIT:
case PMBUS_IOUT_OC_WARN_LIMIT:
case PMBUS_IOUT_UC_FAULT_LIMIT:
case PMBUS_POUT_OP_FAULT_LIMIT:
case PMBUS_POUT_OP_WARN_LIMIT:
case PMBUS_PIN_OP_WARN_LIMIT:
return -ENXIO;
default:
return -ENODATA;
}
return ret;
}
static int mp2975_read_word_data(struct i2c_client *client, int page,
int phase, int reg)
{
@ -222,6 +380,11 @@ static int mp2975_read_word_data(struct i2c_client *client, int page,
int ret;
switch (reg) {
case PMBUS_STATUS_WORD:
/* MP2973 & MP2971 return PGOOD instead of PB_STATUS_POWER_GOOD_N. */
ret = pmbus_read_word_data(client, page, phase, reg);
ret ^= PB_STATUS_POWER_GOOD_N;
break;
case PMBUS_OT_FAULT_LIMIT:
ret = mp2975_read_word_helper(client, page, phase, reg,
GENMASK(7, 0));
@ -260,24 +423,6 @@ static int mp2975_read_word_data(struct i2c_client *client, int page,
ret = DIV_ROUND_CLOSEST(data->vref[page] * 10 - 50 *
(ret + 1) * data->vout_scale, 10);
break;
case PMBUS_READ_VOUT:
ret = mp2975_read_word_helper(client, page, phase, reg,
GENMASK(11, 0));
if (ret < 0)
return ret;
/*
* READ_VOUT can be provided in VID or direct format. The
* format type is specified by bit 15 of the register
* MP2975_MFR_DC_LOOP_CTRL. The driver enforces VOUT direct
* format, since device allows to set the different formats for
* the different rails and also all VOUT limits registers are
* provided in a direct format. In case format is VID - convert
* to direct.
*/
if (data->vout_format[page] == vid)
ret = mp2975_vid2direct(info->vrm_version[page], ret);
break;
case PMBUS_VIRT_READ_POUT_MAX:
ret = mp2975_read_word_helper(client, page, phase,
MP2975_MFR_READ_POUT_PK,
@ -326,25 +471,25 @@ static int mp2975_read_word_data(struct i2c_client *client, int page,
return ret;
}
static int mp2975_identify_multiphase_rail2(struct i2c_client *client)
static int mp2975_identify_multiphase_rail2(struct i2c_client *client,
struct mp2975_data *data)
{
int ret;
/*
* Identify multiphase for rail 2 - could be from 0 to 4.
* Identify multiphase for rail 2 - could be from 0 to data->max_phases[1].
* In case phase number is zero only page zero is supported
*/
ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2);
if (ret < 0)
return ret;
/* Identify multiphase for rail 2 - could be from 0 to 4. */
ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R2);
if (ret < 0)
return ret;
ret &= GENMASK(2, 0);
return (ret >= 4) ? 4 : ret;
return (ret >= data->max_phases[1]) ? data->max_phases[1] : ret;
}
static void mp2975_set_phase_rail1(struct pmbus_driver_info *info)
@ -375,7 +520,7 @@ mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data,
if (ret < 0)
return ret;
/* Identify multiphase for rail 1 - could be from 1 to 8. */
/* Identify multiphase for rail 1 - could be from 1 to data->max_phases[0]. */
ret = i2c_smbus_read_word_data(client, MP2975_MFR_VR_MULTI_CONFIG_R1);
if (ret <= 0)
return ret;
@ -383,21 +528,23 @@ mp2975_identify_multiphase(struct i2c_client *client, struct mp2975_data *data,
info->phases[0] = ret & GENMASK(3, 0);
/*
* The device provides a total of 8 PWM pins, and can be configured
* The device provides a total of $n PWM pins, and can be configured
* to different phase count applications for rail 1 and rail 2.
* Rail 1 can be set to 8 phases, while rail 2 can only be set to 4
* phases at most. When rail 1s phase count is configured as 0, rail
* Rail 1 can be set to $n phases, while rail 2 can be set to less than
* that. When rail 1s phase count is configured as 0, rail
* 1 operates with 1-phase DCM. When rail 2 phase count is configured
* as 0, rail 2 is disabled.
*/
if (info->phases[0] > MP2975_MAX_PHASE_RAIL1)
if (info->phases[0] > data->max_phases[0])
return -EINVAL;
mp2975_set_phase_rail1(info);
num_phases2 = min(MP2975_MAX_PHASE_RAIL1 - info->phases[0],
MP2975_MAX_PHASE_RAIL2);
if (info->phases[1] && info->phases[1] <= num_phases2)
mp2975_set_phase_rail2(info, num_phases2);
if (data->chip_id == mp2975) {
mp2975_set_phase_rail1(info);
num_phases2 = min(data->max_phases[0] - info->phases[0],
data->max_phases[1]);
if (info->phases[1] && info->phases[1] <= num_phases2)
mp2975_set_phase_rail2(info, num_phases2);
}
return 0;
}
@ -451,6 +598,35 @@ mp2975_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data,
MP2975_MFR_VR_MULTI_CONFIG_R2, 1,
MP2975_IMVP9_EN_R2,
MP2975_VID_STEP_SEL_R2);
return ret;
}
static int
mp2973_identify_rails_vid(struct i2c_client *client, struct mp2975_data *data,
struct pmbus_driver_info *info)
{
int ret;
ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 2);
if (ret < 0)
return ret;
/* Identify VID mode for rail 1. */
ret = mp2975_identify_vid(client, data, info,
MP2973_MFR_VR_MULTI_CONFIG_R1, 0,
MP2973_IMVP9_EN_R1, MP2973_VID_STEP_SEL_R1);
if (ret < 0)
return ret;
/* Identify VID mode for rail 2, if connected. */
if (info->phases[1])
ret = mp2975_identify_vid(client, data, info,
MP2973_MFR_VR_MULTI_CONFIG_R2, 1,
MP2973_IMVP9_EN_R2,
MP2973_VID_STEP_SEL_R2);
return ret;
}
@ -565,20 +741,37 @@ mp2975_vout_max_get(struct i2c_client *client, struct mp2975_data *data,
}
static int
mp2975_identify_vout_format(struct i2c_client *client,
struct mp2975_data *data, int page)
mp2975_set_vout_format(struct i2c_client *client,
struct mp2975_data *data, int page)
{
int ret;
int ret, i;
ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL);
if (ret < 0)
return ret;
/* Enable DIRECT VOUT format 1mV/LSB */
if (data->chip_id == mp2975) {
ret = i2c_smbus_read_word_data(client, MP2975_MFR_DC_LOOP_CTRL);
if (ret < 0)
return ret;
if (ret & MP2975_VOUT_FORMAT) {
ret &= ~MP2975_VOUT_FORMAT;
ret = i2c_smbus_write_word_data(client, MP2975_MFR_DC_LOOP_CTRL, ret);
}
} else {
ret = i2c_smbus_read_word_data(client, MP2973_MFR_RESO_SET);
if (ret < 0)
return ret;
i = ret;
if (ret & MP2975_VOUT_FORMAT)
data->vout_format[page] = vid;
else
data->vout_format[page] = direct;
return 0;
if (page == 0) {
i &= ~MP2973_VOUT_FORMAT_R1;
i |= MP2973_VOUT_FORMAT_DIRECT_R1;
} else {
i &= ~MP2973_VOUT_FORMAT_R2;
i |= MP2973_VOUT_FORMAT_DIRECT_R2;
}
if (i != ret)
ret = i2c_smbus_write_word_data(client, MP2973_MFR_RESO_SET, i);
}
return ret;
}
static int
@ -600,7 +793,7 @@ mp2975_vout_ov_scale_get(struct i2c_client *client, struct mp2975_data *data,
if (ret < 0)
return ret;
thres_dev = ret & MP2975_PRT_THRES_DIV_OV_EN ? MP2975_PROT_DEV_OV_ON :
MP2975_PROT_DEV_OV_OFF;
MP2975_PROT_DEV_OV_OFF;
/* Select the gain of remote sense amplifier. */
ret = i2c_smbus_read_word_data(client, PMBUS_VOUT_SCALE_LOOP);
@ -624,10 +817,10 @@ mp2975_vout_per_rail_config_get(struct i2c_client *client,
for (i = 0; i < data->info.pages; i++) {
ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
if (ret < 0)
return ret;
continue;
/* Obtain voltage reference offsets. */
ret = mp2975_vref_offset_get(client, data, i);
/* Set VOUT format for READ_VOUT command : direct. */
ret = mp2975_set_vout_format(client, data, i);
if (ret < 0)
return ret;
@ -636,12 +829,12 @@ mp2975_vout_per_rail_config_get(struct i2c_client *client,
if (ret < 0)
return ret;
/*
* Get VOUT format for READ_VOUT command : VID or direct.
* Pages on same device can be configured with different
* formats.
*/
ret = mp2975_identify_vout_format(client, data, i);
/* Skip if reading Vref is unsupported */
if (data->chip_id != mp2975)
continue;
/* Obtain voltage reference offsets. */
ret = mp2975_vref_offset_get(client, data, i);
if (ret < 0)
return ret;
@ -676,8 +869,32 @@ static struct pmbus_driver_info mp2975_info = {
PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT |
PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_PHASE_VIRTUAL,
.read_byte_data = mp2975_read_byte_data,
.read_word_data = mp2975_read_word_data,
#if IS_ENABLED(CONFIG_SENSORS_MP2975_REGULATOR)
.num_regulators = 1,
.reg_desc = mp2975_reg_desc,
#endif
};
static struct pmbus_driver_info mp2973_info = {
.pages = 1,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = direct,
.format[PSC_TEMPERATURE] = linear,
.format[PSC_CURRENT_IN] = linear,
.format[PSC_CURRENT_OUT] = linear,
.format[PSC_POWER] = linear,
.m[PSC_VOLTAGE_OUT] = 1,
.R[PSC_VOLTAGE_OUT] = 3,
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT |
PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
.read_word_data = mp2973_read_word_data,
#if IS_ENABLED(CONFIG_SENSORS_MP2975_REGULATOR)
.num_regulators = 1,
.reg_desc = mp2975_reg_desc,
#endif
};
static int mp2975_probe(struct i2c_client *client)
@ -691,11 +908,23 @@ static int mp2975_probe(struct i2c_client *client)
if (!data)
return -ENOMEM;
memcpy(&data->info, &mp2975_info, sizeof(*info));
if (client->dev.of_node)
data->chip_id = (enum chips)(unsigned long)of_device_get_match_data(&client->dev);
else
data->chip_id = i2c_match_id(mp2975_id, client)->driver_data;
memcpy(data->max_phases, mp2975_max_phases[data->chip_id],
sizeof(data->max_phases));
if (data->chip_id == mp2975)
memcpy(&data->info, &mp2975_info, sizeof(*info));
else
memcpy(&data->info, &mp2973_info, sizeof(*info));
info = &data->info;
/* Identify multiphase configuration for rail 2. */
ret = mp2975_identify_multiphase_rail2(client);
ret = mp2975_identify_multiphase_rail2(client, data);
if (ret < 0)
return ret;
@ -704,6 +933,8 @@ static int mp2975_probe(struct i2c_client *client)
data->info.pages = MP2975_PAGE_NUM;
data->info.phases[1] = ret;
data->info.func[1] = MP2975_RAIL2_FUNC;
if (IS_ENABLED(CONFIG_SENSORS_MP2975_REGULATOR))
data->info.num_regulators = MP2975_PAGE_NUM;
}
/* Identify multiphase configuration. */
@ -711,25 +942,32 @@ static int mp2975_probe(struct i2c_client *client)
if (ret)
return ret;
/* Identify VID setting per rail. */
ret = mp2975_identify_rails_vid(client, data, info);
if (ret < 0)
return ret;
if (data->chip_id == mp2975) {
/* Identify VID setting per rail. */
ret = mp2975_identify_rails_vid(client, data, info);
if (ret < 0)
return ret;
/* Obtain current sense gain of power stage. */
ret = mp2975_current_sense_gain_get(client, data);
if (ret)
return ret;
/* Obtain current sense gain of power stage. */
ret = mp2975_current_sense_gain_get(client, data);
if (ret)
return ret;
/* Obtain voltage reference values. */
ret = mp2975_vref_get(client, data, info);
if (ret)
return ret;
/* Obtain voltage reference values. */
ret = mp2975_vref_get(client, data, info);
if (ret)
return ret;
/* Obtain vout over-voltage scales. */
ret = mp2975_vout_ov_scale_get(client, data, info);
if (ret < 0)
return ret;
/* Obtain vout over-voltage scales. */
ret = mp2975_vout_ov_scale_get(client, data, info);
if (ret < 0)
return ret;
} else {
/* Identify VID setting per rail. */
ret = mp2973_identify_rails_vid(client, data, info);
if (ret < 0)
return ret;
}
/* Obtain offsets, maximum and format for vout. */
ret = mp2975_vout_per_rail_config_get(client, data, info);
@ -739,15 +977,10 @@ static int mp2975_probe(struct i2c_client *client)
return pmbus_do_probe(client, info);
}
static const struct i2c_device_id mp2975_id[] = {
{"mp2975", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, mp2975_id);
static const struct of_device_id __maybe_unused mp2975_of_match[] = {
{.compatible = "mps,mp2975"},
{.compatible = "mps,mp2971", .data = (void *)mp2971},
{.compatible = "mps,mp2973", .data = (void *)mp2973},
{.compatible = "mps,mp2975", .data = (void *)mp2975},
{}
};
MODULE_DEVICE_TABLE(of, mp2975_of_match);

View file

@ -5,7 +5,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include "pmbus.h"
static struct pmbus_driver_info mp5023_info = {

View file

@ -12,7 +12,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/pmbus.h>
#include "pmbus.h"

View file

@ -5,6 +5,7 @@
* Copyright (c) 2022 9elements GmbH
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pmbus.h>
@ -53,6 +54,30 @@ static int pli1209bc_read_word_data(struct i2c_client *client, int page,
}
}
static int pli1209bc_write_byte(struct i2c_client *client, int page, u8 reg)
{
int ret;
switch (reg) {
case PMBUS_CLEAR_FAULTS:
ret = pmbus_write_byte(client, page, reg);
/*
* PLI1209 takes 230 usec to execute the CLEAR_FAULTS command.
* During that time it's busy and NACKs all requests on the
* SMBUS interface. It also NACKs reads on PMBUS_STATUS_BYTE
* making it impossible to poll the BUSY flag.
*
* Just wait for not BUSY unconditionally.
*/
usleep_range(250, 300);
break;
default:
ret = -ENODATA;
break;
}
return ret;
}
#if IS_ENABLED(CONFIG_SENSORS_PLI1209BC_REGULATOR)
static const struct regulator_desc pli1209bc_reg_desc = {
.name = "vout2",
@ -102,6 +127,7 @@ static struct pmbus_driver_info pli1209bc_info = {
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
| PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT,
.read_word_data = pli1209bc_read_word_data,
.write_byte = pli1209bc_write_byte,
#if IS_ENABLED(CONFIG_SENSORS_PLI1209BC_REGULATOR)
.num_regulators = 1,
.reg_desc = &pli1209bc_reg_desc,

View file

@ -561,7 +561,8 @@ static bool pmbus_check_register(struct i2c_client *client,
rv = pmbus_check_status_cml(client);
if (rv < 0 && (data->flags & PMBUS_READ_STATUS_AFTER_FAILED_CHECK))
data->read_status(client, -1);
pmbus_clear_fault_page(client, -1);
if (reg < PMBUS_VIRT_BASE)
pmbus_clear_fault_page(client, -1);
return rv >= 0;
}
@ -2540,7 +2541,6 @@ static int pmbus_identify_common(struct i2c_client *client,
}
}
pmbus_clear_fault_page(client, page);
return 0;
}

View file

@ -10,7 +10,7 @@
#include <linux/i2c.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include "pmbus.h"
#define STORE_DEFAULT_ALL 0x11

View file

@ -12,7 +12,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include "pmbus.h"
enum chips {
@ -235,7 +235,7 @@ static int tps53679_probe(struct i2c_client *client)
enum chips chip_id;
if (dev->of_node)
chip_id = (enum chips)of_device_get_match_data(dev);
chip_id = (uintptr_t)of_device_get_match_data(dev);
else
chip_id = i2c_match_id(tps53679_id, client)->driver_data;

View file

@ -10,7 +10,7 @@
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
@ -588,7 +588,7 @@ static int ucd9000_probe(struct i2c_client *client)
}
if (client->dev.of_node)
chip = (enum chips)of_device_get_match_data(&client->dev);
chip = (uintptr_t)of_device_get_match_data(&client->dev);
else
chip = mid->driver_data;

View file

@ -7,7 +7,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
@ -103,7 +103,7 @@ static int ucd9200_probe(struct i2c_client *client)
}
if (client->dev.of_node)
chip = (enum chips)of_device_get_match_data(&client->dev);
chip = (uintptr_t)of_device_get_match_data(&client->dev);
else
chip = mid->driver_data;

View file

@ -13,7 +13,6 @@
#include <linux/hwmon.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of.h>
/*

View file

@ -8,7 +8,7 @@
#include <linux/hwmon.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/scpi_protocol.h>
#include <linux/slab.h>

View file

@ -147,8 +147,20 @@ static const u16 mode_to_update_interval[] = {
100,
};
static const struct hwmon_channel_info * const sht3x_channel_info[] = {
HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL),
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MIN |
HWMON_T_MIN_HYST | HWMON_T_MAX |
HWMON_T_MAX_HYST | HWMON_T_ALARM),
HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT | HWMON_H_MIN |
HWMON_H_MIN_HYST | HWMON_H_MAX |
HWMON_H_MAX_HYST | HWMON_H_ALARM),
NULL,
};
struct sht3x_data {
struct i2c_client *client;
enum sht3x_chips chip_id;
struct mutex i2c_lock; /* lock for sending i2c commands */
struct mutex data_lock; /* lock for updating driver data */
@ -276,27 +288,24 @@ out:
return data;
}
/* sysfs attributes */
static ssize_t temp1_input_show(struct device *dev,
struct device_attribute *attr, char *buf)
static int temp1_input_read(struct device *dev)
{
struct sht3x_data *data = sht3x_update_client(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%d\n", data->temperature);
return data->temperature;
}
static ssize_t humidity1_input_show(struct device *dev,
struct device_attribute *attr, char *buf)
static int humidity1_input_read(struct device *dev)
{
struct sht3x_data *data = sht3x_update_client(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%u\n", data->humidity);
return data->humidity;
}
/*
@ -332,33 +341,24 @@ static int limits_update(struct sht3x_data *data)
return ret;
}
static ssize_t temp1_limit_show(struct device *dev,
struct device_attribute *attr,
char *buf)
static int temp1_limit_read(struct device *dev, int index)
{
struct sht3x_data *data = dev_get_drvdata(dev);
u8 index = to_sensor_dev_attr(attr)->index;
int temperature_limit = data->temperature_limits[index];
return sysfs_emit(buf, "%d\n", temperature_limit);
return data->temperature_limits[index];
}
static ssize_t humidity1_limit_show(struct device *dev,
struct device_attribute *attr,
char *buf)
static int humidity1_limit_read(struct device *dev, int index)
{
struct sht3x_data *data = dev_get_drvdata(dev);
u8 index = to_sensor_dev_attr(attr)->index;
u32 humidity_limit = data->humidity_limits[index];
return sysfs_emit(buf, "%u\n", humidity_limit);
return data->humidity_limits[index];
}
/*
* limit_store must only be called with data_lock held
* limit_write must only be called with data_lock held
*/
static size_t limit_store(struct device *dev,
size_t count,
static size_t limit_write(struct device *dev,
u8 index,
int temperature,
u32 humidity)
@ -379,7 +379,7 @@ static size_t limit_store(struct device *dev,
* ST = (T + 45) / 175 * 2^16
* SRH = RH / 100 * 2^16
* adapted for fixed point arithmetic and packed the same as
* in limit_show()
* in limit_read()
*/
raw = ((u32)(temperature + 45000) * 24543) >> (16 + 7);
raw |= ((humidity * 42950) >> 16) & 0xfe00;
@ -400,50 +400,35 @@ static size_t limit_store(struct device *dev,
data->temperature_limits[index] = temperature;
data->humidity_limits[index] = humidity;
return count;
return 0;
}
static ssize_t temp1_limit_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
static int temp1_limit_write(struct device *dev, int index, int val)
{
int temperature;
int ret;
struct sht3x_data *data = dev_get_drvdata(dev);
u8 index = to_sensor_dev_attr(attr)->index;
ret = kstrtoint(buf, 0, &temperature);
if (ret)
return ret;
temperature = clamp_val(temperature, SHT3X_MIN_TEMPERATURE,
temperature = clamp_val(val, SHT3X_MIN_TEMPERATURE,
SHT3X_MAX_TEMPERATURE);
mutex_lock(&data->data_lock);
ret = limit_store(dev, count, index, temperature,
ret = limit_write(dev, index, temperature,
data->humidity_limits[index]);
mutex_unlock(&data->data_lock);
return ret;
}
static ssize_t humidity1_limit_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
static int humidity1_limit_write(struct device *dev, int index, int val)
{
u32 humidity;
int ret;
struct sht3x_data *data = dev_get_drvdata(dev);
u8 index = to_sensor_dev_attr(attr)->index;
ret = kstrtou32(buf, 0, &humidity);
if (ret)
return ret;
humidity = clamp_val(humidity, SHT3X_MIN_HUMIDITY, SHT3X_MAX_HUMIDITY);
humidity = clamp_val(val, SHT3X_MIN_HUMIDITY, SHT3X_MAX_HUMIDITY);
mutex_lock(&data->data_lock);
ret = limit_store(dev, count, index, data->temperature_limits[index],
ret = limit_write(dev, index, data->temperature_limits[index],
humidity);
mutex_unlock(&data->data_lock);
@ -474,7 +459,6 @@ static void sht3x_select_command(struct sht3x_data *data)
}
static int status_register_read(struct device *dev,
struct device_attribute *attr,
char *buffer, int length)
{
int ret;
@ -487,34 +471,30 @@ static int status_register_read(struct device *dev,
return ret;
}
static ssize_t temp1_alarm_show(struct device *dev,
struct device_attribute *attr,
char *buf)
static int temp1_alarm_read(struct device *dev)
{
char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN];
int ret;
ret = status_register_read(dev, attr, buffer,
ret = status_register_read(dev, buffer,
SHT3X_WORD_LEN + SHT3X_CRC8_LEN);
if (ret)
return ret;
return sysfs_emit(buf, "%d\n", !!(buffer[0] & 0x04));
return !!(buffer[0] & 0x04);
}
static ssize_t humidity1_alarm_show(struct device *dev,
struct device_attribute *attr,
char *buf)
static int humidity1_alarm_read(struct device *dev)
{
char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN];
int ret;
ret = status_register_read(dev, attr, buffer,
ret = status_register_read(dev, buffer,
SHT3X_WORD_LEN + SHT3X_CRC8_LEN);
if (ret)
return ret;
return sysfs_emit(buf, "%d\n", !!(buffer[0] & 0x08));
return !!(buffer[0] & 0x08);
}
static ssize_t heater_enable_show(struct device *dev,
@ -524,7 +504,7 @@ static ssize_t heater_enable_show(struct device *dev,
char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN];
int ret;
ret = status_register_read(dev, attr, buffer,
ret = status_register_read(dev, buffer,
SHT3X_WORD_LEN + SHT3X_CRC8_LEN);
if (ret)
return ret;
@ -560,39 +540,28 @@ static ssize_t heater_enable_store(struct device *dev,
return ret;
}
static ssize_t update_interval_show(struct device *dev,
struct device_attribute *attr,
char *buf)
static int update_interval_read(struct device *dev)
{
struct sht3x_data *data = dev_get_drvdata(dev);
return sysfs_emit(buf, "%u\n",
mode_to_update_interval[data->mode]);
return mode_to_update_interval[data->mode];
}
static ssize_t update_interval_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
static int update_interval_write(struct device *dev, int val)
{
u16 update_interval;
u8 mode;
int ret;
const char *command;
struct sht3x_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
ret = kstrtou16(buf, 0, &update_interval);
if (ret)
return ret;
mode = get_mode_from_update_interval(update_interval);
mode = get_mode_from_update_interval(val);
mutex_lock(&data->data_lock);
/* mode did not change */
if (mode == data->mode) {
mutex_unlock(&data->data_lock);
return count;
return 0;
}
mutex_lock(&data->i2c_lock);
@ -634,7 +603,7 @@ out:
if (ret != SHT3X_CMD_LENGTH)
return ret < 0 ? ret : -EIO;
return count;
return 0;
}
static ssize_t repeatability_show(struct device *dev,
@ -668,60 +637,219 @@ static ssize_t repeatability_store(struct device *dev,
return count;
}
static SENSOR_DEVICE_ATTR_RO(temp1_input, temp1_input, 0);
static SENSOR_DEVICE_ATTR_RO(humidity1_input, humidity1_input, 0);
static SENSOR_DEVICE_ATTR_RW(temp1_max, temp1_limit, limit_max);
static SENSOR_DEVICE_ATTR_RW(humidity1_max, humidity1_limit, limit_max);
static SENSOR_DEVICE_ATTR_RW(temp1_max_hyst, temp1_limit, limit_max_hyst);
static SENSOR_DEVICE_ATTR_RW(humidity1_max_hyst, humidity1_limit,
limit_max_hyst);
static SENSOR_DEVICE_ATTR_RW(temp1_min, temp1_limit, limit_min);
static SENSOR_DEVICE_ATTR_RW(humidity1_min, humidity1_limit, limit_min);
static SENSOR_DEVICE_ATTR_RW(temp1_min_hyst, temp1_limit, limit_min_hyst);
static SENSOR_DEVICE_ATTR_RW(humidity1_min_hyst, humidity1_limit,
limit_min_hyst);
static SENSOR_DEVICE_ATTR_RO(temp1_alarm, temp1_alarm, 0);
static SENSOR_DEVICE_ATTR_RO(humidity1_alarm, humidity1_alarm, 0);
static SENSOR_DEVICE_ATTR_RW(heater_enable, heater_enable, 0);
static SENSOR_DEVICE_ATTR_RW(update_interval, update_interval, 0);
static SENSOR_DEVICE_ATTR_RW(repeatability, repeatability, 0);
static struct attribute *sht3x_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_humidity1_input.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_humidity1_max.dev_attr.attr,
&sensor_dev_attr_humidity1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
&sensor_dev_attr_humidity1_min.dev_attr.attr,
&sensor_dev_attr_humidity1_min_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_humidity1_alarm.dev_attr.attr,
&sensor_dev_attr_heater_enable.dev_attr.attr,
&sensor_dev_attr_update_interval.dev_attr.attr,
&sensor_dev_attr_repeatability.dev_attr.attr,
NULL
};
static struct attribute *sts3x_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_heater_enable.dev_attr.attr,
&sensor_dev_attr_update_interval.dev_attr.attr,
&sensor_dev_attr_repeatability.dev_attr.attr,
NULL
};
ATTRIBUTE_GROUPS(sht3x);
ATTRIBUTE_GROUPS(sts3x);
static const struct i2c_device_id sht3x_ids[];
static umode_t sht3x_is_visible(const void *data, enum hwmon_sensor_types type,
u32 attr, int channel)
{
const struct sht3x_data *chip_data = data;
switch (type) {
case hwmon_chip:
switch (attr) {
case hwmon_chip_update_interval:
return 0644;
default:
break;
}
break;
case hwmon_temp:
switch (attr) {
case hwmon_temp_input:
case hwmon_temp_alarm:
return 0444;
case hwmon_temp_max:
case hwmon_temp_max_hyst:
case hwmon_temp_min:
case hwmon_temp_min_hyst:
return 0644;
default:
break;
}
break;
case hwmon_humidity:
if (chip_data->chip_id == sts3x)
break;
switch (attr) {
case hwmon_humidity_input:
case hwmon_humidity_alarm:
return 0444;
case hwmon_humidity_max:
case hwmon_humidity_max_hyst:
case hwmon_humidity_min:
case hwmon_humidity_min_hyst:
return 0644;
default:
break;
}
break;
default:
break;
}
return 0;
}
static int sht3x_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
enum sht3x_limits index;
switch (type) {
case hwmon_chip:
switch (attr) {
case hwmon_chip_update_interval:
*val = update_interval_read(dev);
break;
default:
return -EOPNOTSUPP;
}
break;
case hwmon_temp:
switch (attr) {
case hwmon_temp_input:
*val = temp1_input_read(dev);
break;
case hwmon_temp_alarm:
*val = temp1_alarm_read(dev);
break;
case hwmon_temp_max:
index = limit_max;
*val = temp1_limit_read(dev, index);
break;
case hwmon_temp_max_hyst:
index = limit_max_hyst;
*val = temp1_limit_read(dev, index);
break;
case hwmon_temp_min:
index = limit_min;
*val = temp1_limit_read(dev, index);
break;
case hwmon_temp_min_hyst:
index = limit_min_hyst;
*val = temp1_limit_read(dev, index);
break;
default:
return -EOPNOTSUPP;
}
break;
case hwmon_humidity:
switch (attr) {
case hwmon_humidity_input:
*val = humidity1_input_read(dev);
break;
case hwmon_humidity_alarm:
*val = humidity1_alarm_read(dev);
break;
case hwmon_humidity_max:
index = limit_max;
*val = humidity1_limit_read(dev, index);
break;
case hwmon_humidity_max_hyst:
index = limit_max_hyst;
*val = humidity1_limit_read(dev, index);
break;
case hwmon_humidity_min:
index = limit_min;
*val = humidity1_limit_read(dev, index);
break;
case hwmon_humidity_min_hyst:
index = limit_min_hyst;
*val = humidity1_limit_read(dev, index);
break;
default:
return -EOPNOTSUPP;
}
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int sht3x_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{
enum sht3x_limits index;
switch (type) {
case hwmon_chip:
switch (attr) {
case hwmon_chip_update_interval:
return update_interval_write(dev, val);
default:
return -EOPNOTSUPP;
}
case hwmon_temp:
switch (attr) {
case hwmon_temp_max:
index = limit_max;
break;
case hwmon_temp_max_hyst:
index = limit_max_hyst;
break;
case hwmon_temp_min:
index = limit_min;
break;
case hwmon_temp_min_hyst:
index = limit_min_hyst;
break;
default:
return -EOPNOTSUPP;
}
return temp1_limit_write(dev, index, val);
case hwmon_humidity:
switch (attr) {
case hwmon_humidity_max:
index = limit_max;
break;
case hwmon_humidity_max_hyst:
index = limit_max_hyst;
break;
case hwmon_humidity_min:
index = limit_min;
break;
case hwmon_humidity_min_hyst:
index = limit_min_hyst;
break;
default:
return -EOPNOTSUPP;
}
return humidity1_limit_write(dev, index, val);
default:
return -EOPNOTSUPP;
}
}
static const struct hwmon_ops sht3x_ops = {
.is_visible = sht3x_is_visible,
.read = sht3x_read,
.write = sht3x_write,
};
static const struct hwmon_chip_info sht3x_chip_info = {
.ops = &sht3x_ops,
.info = sht3x_channel_info,
};
/* device ID table */
static const struct i2c_device_id sht3x_ids[] = {
{"sht3x", sht3x},
{"sts3x", sts3x},
{}
};
MODULE_DEVICE_TABLE(i2c, sht3x_ids);
static int sht3x_probe(struct i2c_client *client)
{
@ -730,7 +858,6 @@ static int sht3x_probe(struct i2c_client *client)
struct device *hwmon_dev;
struct i2c_adapter *adap = client->adapter;
struct device *dev = &client->dev;
const struct attribute_group **attribute_groups;
/*
* we require full i2c support since the sht3x uses multi-byte read and
@ -753,6 +880,7 @@ static int sht3x_probe(struct i2c_client *client)
data->mode = 0;
data->last_update = jiffies - msecs_to_jiffies(3000);
data->client = client;
data->chip_id = i2c_match_id(sht3x_ids, client)->driver_data;
crc8_populate_msb(sht3x_crc8_table, SHT3X_CRC8_POLYNOMIAL);
sht3x_select_command(data);
@ -771,15 +899,11 @@ static int sht3x_probe(struct i2c_client *client)
if (ret)
return ret;
if (i2c_match_id(sht3x_ids, client)->driver_data == sts3x)
attribute_groups = sts3x_groups;
else
attribute_groups = sht3x_groups;
hwmon_dev = devm_hwmon_device_register_with_groups(dev,
client->name,
data,
attribute_groups);
hwmon_dev = devm_hwmon_device_register_with_info(dev,
client->name,
data,
&sht3x_chip_info,
sht3x_groups);
if (IS_ERR(hwmon_dev))
dev_dbg(dev, "unable to register hwmon device\n");
@ -787,15 +911,6 @@ static int sht3x_probe(struct i2c_client *client)
return PTR_ERR_OR_ZERO(hwmon_dev);
}
/* device ID table */
static const struct i2c_device_id sht3x_ids[] = {
{"sht3x", sht3x},
{"sts3x", sts3x},
{}
};
MODULE_DEVICE_TABLE(i2c, sht3x_ids);
static struct i2c_driver sht3x_i2c_driver = {
.driver.name = "sht3x",
.probe = sht3x_probe,

View file

@ -798,7 +798,7 @@ static int sis5595_pci_probe(struct pci_dev *dev,
{
u16 address;
u8 enable;
int *i;
int *i, err;
for (i = blacklist; *i != 0; i++) {
struct pci_dev *d;
@ -818,8 +818,8 @@ static int sis5595_pci_probe(struct pci_dev *dev,
pci_write_config_word(dev, SIS5595_BASE_REG, force_addr);
}
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_word(dev, SIS5595_BASE_REG, &address)) {
err = pci_read_config_word(dev, SIS5595_BASE_REG, &address);
if (err != PCIBIOS_SUCCESSFUL) {
dev_err(&dev->dev, "Failed to read ISA address\n");
return -ENODEV;
}
@ -836,22 +836,23 @@ static int sis5595_pci_probe(struct pci_dev *dev,
return -ENODEV;
}
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable)) {
err = pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable);
if (err != PCIBIOS_SUCCESSFUL) {
dev_err(&dev->dev, "Failed to read enable register\n");
return -ENODEV;
}
if (!(enable & 0x80)) {
if ((PCIBIOS_SUCCESSFUL !=
pci_write_config_byte(dev, SIS5595_ENABLE_REG,
enable | 0x80))
|| (PCIBIOS_SUCCESSFUL !=
pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable))
|| (!(enable & 0x80))) {
/* doesn't work for some chips! */
dev_err(&dev->dev, "Failed to enable HWM device\n");
return -ENODEV;
}
err = pci_write_config_byte(dev, SIS5595_ENABLE_REG, enable | 0x80);
if (err != PCIBIOS_SUCCESSFUL)
goto enable_fail;
err = pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable);
if (err != PCIBIOS_SUCCESSFUL)
goto enable_fail;
/* doesn't work for some chips! */
if (!(enable & 0x80))
goto enable_fail;
}
if (platform_driver_register(&sis5595_driver)) {
@ -871,6 +872,10 @@ static int sis5595_pci_probe(struct pci_dev *dev,
*/
return -ENODEV;
enable_fail:
dev_err(&dev->dev, "Failed to enable HWM device\n");
goto exit;
exit_unregister:
pci_dev_put(dev);
platform_driver_unregister(&sis5595_driver);

View file

@ -1,706 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for SMM665 Power Controller / Monitor
*
* Copyright (C) 2010 Ericsson AB.
*
* This driver should also work for SMM465, SMM764, and SMM766, but is untested
* for those chips. Only monitoring functionality is implemented.
*
* Datasheets:
* http://www.summitmicro.com/prod_select/summary/SMM665/SMM665B_2089_20.pdf
* http://www.summitmicro.com/prod_select/summary/SMM766B/SMM766B_2122.pdf
*/
#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/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
/* Internal reference voltage (VREF, x 1000 */
#define SMM665_VREF_ADC_X1000 1250
/* module parameters */
static int vref = SMM665_VREF_ADC_X1000;
module_param(vref, int, 0);
MODULE_PARM_DESC(vref, "Reference voltage in mV");
enum chips { smm465, smm665, smm665c, smm764, smm766 };
/*
* ADC channel addresses
*/
#define SMM665_MISC16_ADC_DATA_A 0x00
#define SMM665_MISC16_ADC_DATA_B 0x01
#define SMM665_MISC16_ADC_DATA_C 0x02
#define SMM665_MISC16_ADC_DATA_D 0x03
#define SMM665_MISC16_ADC_DATA_E 0x04
#define SMM665_MISC16_ADC_DATA_F 0x05
#define SMM665_MISC16_ADC_DATA_VDD 0x06
#define SMM665_MISC16_ADC_DATA_12V 0x07
#define SMM665_MISC16_ADC_DATA_INT_TEMP 0x08
#define SMM665_MISC16_ADC_DATA_AIN1 0x09
#define SMM665_MISC16_ADC_DATA_AIN2 0x0a
/*
* Command registers
*/
#define SMM665_MISC8_CMD_STS 0x80
#define SMM665_MISC8_STATUS1 0x81
#define SMM665_MISC8_STATUSS2 0x82
#define SMM665_MISC8_IO_POLARITY 0x83
#define SMM665_MISC8_PUP_POLARITY 0x84
#define SMM665_MISC8_ADOC_STATUS1 0x85
#define SMM665_MISC8_ADOC_STATUS2 0x86
#define SMM665_MISC8_WRITE_PROT 0x87
#define SMM665_MISC8_STS_TRACK 0x88
/*
* Configuration registers and register groups
*/
#define SMM665_ADOC_ENABLE 0x0d
#define SMM665_LIMIT_BASE 0x80 /* First limit register */
/*
* Limit register bit masks
*/
#define SMM665_TRIGGER_RST 0x8000
#define SMM665_TRIGGER_HEALTHY 0x4000
#define SMM665_TRIGGER_POWEROFF 0x2000
#define SMM665_TRIGGER_SHUTDOWN 0x1000
#define SMM665_ADC_MASK 0x03ff
#define smm665_is_critical(lim) ((lim) & (SMM665_TRIGGER_RST \
| SMM665_TRIGGER_POWEROFF \
| SMM665_TRIGGER_SHUTDOWN))
/*
* Fault register bit definitions
* Values are merged from status registers 1/2,
* with status register 1 providing the upper 8 bits.
*/
#define SMM665_FAULT_A 0x0001
#define SMM665_FAULT_B 0x0002
#define SMM665_FAULT_C 0x0004
#define SMM665_FAULT_D 0x0008
#define SMM665_FAULT_E 0x0010
#define SMM665_FAULT_F 0x0020
#define SMM665_FAULT_VDD 0x0040
#define SMM665_FAULT_12V 0x0080
#define SMM665_FAULT_TEMP 0x0100
#define SMM665_FAULT_AIN1 0x0200
#define SMM665_FAULT_AIN2 0x0400
/*
* I2C Register addresses
*
* The configuration register needs to be the configured base register.
* The command/status register address is derived from it.
*/
#define SMM665_REGMASK 0x78
#define SMM665_CMDREG_BASE 0x48
#define SMM665_CONFREG_BASE 0x50
/*
* Equations given by chip manufacturer to calculate voltage/temperature values
* vref = Reference voltage on VREF_ADC pin (module parameter)
* adc = 10bit ADC value read back from registers
*/
/* Voltage A-F and VDD */
#define SMM665_VMON_ADC_TO_VOLTS(adc) ((adc) * vref / 256)
/* Voltage 12VIN */
#define SMM665_12VIN_ADC_TO_VOLTS(adc) ((adc) * vref * 3 / 256)
/* Voltage AIN1, AIN2 */
#define SMM665_AIN_ADC_TO_VOLTS(adc) ((adc) * vref / 512)
/* Temp Sensor */
#define SMM665_TEMP_ADC_TO_CELSIUS(adc) (((adc) <= 511) ? \
((int)(adc) * 1000 / 4) : \
(((int)(adc) - 0x400) * 1000 / 4))
#define SMM665_NUM_ADC 11
/*
* Chip dependent ADC conversion time, in uS
*/
#define SMM665_ADC_WAIT_SMM665 70
#define SMM665_ADC_WAIT_SMM766 185
struct smm665_data {
enum chips type;
int conversion_time; /* ADC conversion time */
struct i2c_client *client;
struct mutex update_lock;
bool valid;
unsigned long last_updated; /* in jiffies */
u16 adc[SMM665_NUM_ADC]; /* adc values (raw) */
u16 faults; /* fault status */
/* The following values are in mV */
int critical_min_limit[SMM665_NUM_ADC];
int alarm_min_limit[SMM665_NUM_ADC];
int critical_max_limit[SMM665_NUM_ADC];
int alarm_max_limit[SMM665_NUM_ADC];
struct i2c_client *cmdreg;
};
/*
* smm665_read16()
*
* Read 16 bit value from <reg>, <reg+1>. Upper 8 bits are in <reg>.
*/
static int smm665_read16(struct i2c_client *client, int reg)
{
int rv, val;
rv = i2c_smbus_read_byte_data(client, reg);
if (rv < 0)
return rv;
val = rv << 8;
rv = i2c_smbus_read_byte_data(client, reg + 1);
if (rv < 0)
return rv;
val |= rv;
return val;
}
/*
* Read adc value.
*/
static int smm665_read_adc(struct smm665_data *data, int adc)
{
struct i2c_client *client = data->cmdreg;
int rv;
int radc;
/*
* Algorithm for reading ADC, per SMM665 datasheet
*
* {[S][addr][W][Ack]} {[offset][Ack]} {[S][addr][R][Nack]}
* [wait conversion time]
* {[S][addr][R][Ack]} {[datahi][Ack]} {[datalo][Ack][P]}
*
* To implement the first part of this exchange,
* do a full read transaction and expect a failure/Nack.
* This sets up the address pointer on the SMM665
* and starts the ADC conversion.
* Then do a two-byte read transaction.
*/
rv = i2c_smbus_read_byte_data(client, adc << 3);
if (rv != -ENXIO) {
/*
* We expect ENXIO to reflect NACK
* (per Documentation/i2c/fault-codes.rst).
* Everything else is an error.
*/
dev_dbg(&client->dev,
"Unexpected return code %d when setting ADC index", rv);
return (rv < 0) ? rv : -EIO;
}
udelay(data->conversion_time);
/*
* Now read two bytes.
*
* Neither i2c_smbus_read_byte() nor
* i2c_smbus_read_block_data() worked here,
* so use i2c_smbus_read_word_swapped() instead.
* We could also try to use i2c_master_recv(),
* but that is not always supported.
*/
rv = i2c_smbus_read_word_swapped(client, 0);
if (rv < 0) {
dev_dbg(&client->dev, "Failed to read ADC value: error %d", rv);
return rv;
}
/*
* Validate/verify readback adc channel (in bit 11..14).
*/
radc = (rv >> 11) & 0x0f;
if (radc != adc) {
dev_dbg(&client->dev, "Unexpected RADC: Expected %d got %d",
adc, radc);
return -EIO;
}
return rv & SMM665_ADC_MASK;
}
static struct smm665_data *smm665_update_device(struct device *dev)
{
struct smm665_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
struct smm665_data *ret = data;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
int i, val;
/*
* read status registers
*/
val = smm665_read16(client, SMM665_MISC8_STATUS1);
if (unlikely(val < 0)) {
ret = ERR_PTR(val);
goto abort;
}
data->faults = val;
/* Read adc registers */
for (i = 0; i < SMM665_NUM_ADC; i++) {
val = smm665_read_adc(data, i);
if (unlikely(val < 0)) {
ret = ERR_PTR(val);
goto abort;
}
data->adc[i] = val;
}
data->last_updated = jiffies;
data->valid = true;
}
abort:
mutex_unlock(&data->update_lock);
return ret;
}
/* Return converted value from given adc */
static int smm665_convert(u16 adcval, int index)
{
int val = 0;
switch (index) {
case SMM665_MISC16_ADC_DATA_12V:
val = SMM665_12VIN_ADC_TO_VOLTS(adcval & SMM665_ADC_MASK);
break;
case SMM665_MISC16_ADC_DATA_VDD:
case SMM665_MISC16_ADC_DATA_A:
case SMM665_MISC16_ADC_DATA_B:
case SMM665_MISC16_ADC_DATA_C:
case SMM665_MISC16_ADC_DATA_D:
case SMM665_MISC16_ADC_DATA_E:
case SMM665_MISC16_ADC_DATA_F:
val = SMM665_VMON_ADC_TO_VOLTS(adcval & SMM665_ADC_MASK);
break;
case SMM665_MISC16_ADC_DATA_AIN1:
case SMM665_MISC16_ADC_DATA_AIN2:
val = SMM665_AIN_ADC_TO_VOLTS(adcval & SMM665_ADC_MASK);
break;
case SMM665_MISC16_ADC_DATA_INT_TEMP:
val = SMM665_TEMP_ADC_TO_CELSIUS(adcval & SMM665_ADC_MASK);
break;
default:
/* If we get here, the developer messed up */
WARN_ON_ONCE(1);
break;
}
return val;
}
static int smm665_get_min(struct device *dev, int index)
{
struct smm665_data *data = dev_get_drvdata(dev);
return data->alarm_min_limit[index];
}
static int smm665_get_max(struct device *dev, int index)
{
struct smm665_data *data = dev_get_drvdata(dev);
return data->alarm_max_limit[index];
}
static int smm665_get_lcrit(struct device *dev, int index)
{
struct smm665_data *data = dev_get_drvdata(dev);
return data->critical_min_limit[index];
}
static int smm665_get_crit(struct device *dev, int index)
{
struct smm665_data *data = dev_get_drvdata(dev);
return data->critical_max_limit[index];
}
static ssize_t smm665_show_crit_alarm(struct device *dev,
struct device_attribute *da, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct smm665_data *data = smm665_update_device(dev);
int val = 0;
if (IS_ERR(data))
return PTR_ERR(data);
if (data->faults & (1 << attr->index))
val = 1;
return sysfs_emit(buf, "%d\n", val);
}
static ssize_t smm665_show_input(struct device *dev,
struct device_attribute *da, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct smm665_data *data = smm665_update_device(dev);
int adc = attr->index;
int val;
if (IS_ERR(data))
return PTR_ERR(data);
val = smm665_convert(data->adc[adc], adc);
return sysfs_emit(buf, "%d\n", val);
}
#define SMM665_SHOW(what) \
static ssize_t smm665_show_##what(struct device *dev, \
struct device_attribute *da, char *buf) \
{ \
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
const int val = smm665_get_##what(dev, attr->index); \
return snprintf(buf, PAGE_SIZE, "%d\n", val); \
}
SMM665_SHOW(min);
SMM665_SHOW(max);
SMM665_SHOW(lcrit);
SMM665_SHOW(crit);
/*
* These macros are used below in constructing device attribute objects
* for use with sysfs_create_group() to make a sysfs device file
* for each register.
*/
#define SMM665_ATTR(name, type, cmd_idx) \
static SENSOR_DEVICE_ATTR(name##_##type, S_IRUGO, \
smm665_show_##type, NULL, cmd_idx)
/* Construct a sensor_device_attribute structure for each register */
/* Input voltages */
SMM665_ATTR(in1, input, SMM665_MISC16_ADC_DATA_12V);
SMM665_ATTR(in2, input, SMM665_MISC16_ADC_DATA_VDD);
SMM665_ATTR(in3, input, SMM665_MISC16_ADC_DATA_A);
SMM665_ATTR(in4, input, SMM665_MISC16_ADC_DATA_B);
SMM665_ATTR(in5, input, SMM665_MISC16_ADC_DATA_C);
SMM665_ATTR(in6, input, SMM665_MISC16_ADC_DATA_D);
SMM665_ATTR(in7, input, SMM665_MISC16_ADC_DATA_E);
SMM665_ATTR(in8, input, SMM665_MISC16_ADC_DATA_F);
SMM665_ATTR(in9, input, SMM665_MISC16_ADC_DATA_AIN1);
SMM665_ATTR(in10, input, SMM665_MISC16_ADC_DATA_AIN2);
/* Input voltages min */
SMM665_ATTR(in1, min, SMM665_MISC16_ADC_DATA_12V);
SMM665_ATTR(in2, min, SMM665_MISC16_ADC_DATA_VDD);
SMM665_ATTR(in3, min, SMM665_MISC16_ADC_DATA_A);
SMM665_ATTR(in4, min, SMM665_MISC16_ADC_DATA_B);
SMM665_ATTR(in5, min, SMM665_MISC16_ADC_DATA_C);
SMM665_ATTR(in6, min, SMM665_MISC16_ADC_DATA_D);
SMM665_ATTR(in7, min, SMM665_MISC16_ADC_DATA_E);
SMM665_ATTR(in8, min, SMM665_MISC16_ADC_DATA_F);
SMM665_ATTR(in9, min, SMM665_MISC16_ADC_DATA_AIN1);
SMM665_ATTR(in10, min, SMM665_MISC16_ADC_DATA_AIN2);
/* Input voltages max */
SMM665_ATTR(in1, max, SMM665_MISC16_ADC_DATA_12V);
SMM665_ATTR(in2, max, SMM665_MISC16_ADC_DATA_VDD);
SMM665_ATTR(in3, max, SMM665_MISC16_ADC_DATA_A);
SMM665_ATTR(in4, max, SMM665_MISC16_ADC_DATA_B);
SMM665_ATTR(in5, max, SMM665_MISC16_ADC_DATA_C);
SMM665_ATTR(in6, max, SMM665_MISC16_ADC_DATA_D);
SMM665_ATTR(in7, max, SMM665_MISC16_ADC_DATA_E);
SMM665_ATTR(in8, max, SMM665_MISC16_ADC_DATA_F);
SMM665_ATTR(in9, max, SMM665_MISC16_ADC_DATA_AIN1);
SMM665_ATTR(in10, max, SMM665_MISC16_ADC_DATA_AIN2);
/* Input voltages lcrit */
SMM665_ATTR(in1, lcrit, SMM665_MISC16_ADC_DATA_12V);
SMM665_ATTR(in2, lcrit, SMM665_MISC16_ADC_DATA_VDD);
SMM665_ATTR(in3, lcrit, SMM665_MISC16_ADC_DATA_A);
SMM665_ATTR(in4, lcrit, SMM665_MISC16_ADC_DATA_B);
SMM665_ATTR(in5, lcrit, SMM665_MISC16_ADC_DATA_C);
SMM665_ATTR(in6, lcrit, SMM665_MISC16_ADC_DATA_D);
SMM665_ATTR(in7, lcrit, SMM665_MISC16_ADC_DATA_E);
SMM665_ATTR(in8, lcrit, SMM665_MISC16_ADC_DATA_F);
SMM665_ATTR(in9, lcrit, SMM665_MISC16_ADC_DATA_AIN1);
SMM665_ATTR(in10, lcrit, SMM665_MISC16_ADC_DATA_AIN2);
/* Input voltages crit */
SMM665_ATTR(in1, crit, SMM665_MISC16_ADC_DATA_12V);
SMM665_ATTR(in2, crit, SMM665_MISC16_ADC_DATA_VDD);
SMM665_ATTR(in3, crit, SMM665_MISC16_ADC_DATA_A);
SMM665_ATTR(in4, crit, SMM665_MISC16_ADC_DATA_B);
SMM665_ATTR(in5, crit, SMM665_MISC16_ADC_DATA_C);
SMM665_ATTR(in6, crit, SMM665_MISC16_ADC_DATA_D);
SMM665_ATTR(in7, crit, SMM665_MISC16_ADC_DATA_E);
SMM665_ATTR(in8, crit, SMM665_MISC16_ADC_DATA_F);
SMM665_ATTR(in9, crit, SMM665_MISC16_ADC_DATA_AIN1);
SMM665_ATTR(in10, crit, SMM665_MISC16_ADC_DATA_AIN2);
/* critical alarms */
SMM665_ATTR(in1, crit_alarm, SMM665_FAULT_12V);
SMM665_ATTR(in2, crit_alarm, SMM665_FAULT_VDD);
SMM665_ATTR(in3, crit_alarm, SMM665_FAULT_A);
SMM665_ATTR(in4, crit_alarm, SMM665_FAULT_B);
SMM665_ATTR(in5, crit_alarm, SMM665_FAULT_C);
SMM665_ATTR(in6, crit_alarm, SMM665_FAULT_D);
SMM665_ATTR(in7, crit_alarm, SMM665_FAULT_E);
SMM665_ATTR(in8, crit_alarm, SMM665_FAULT_F);
SMM665_ATTR(in9, crit_alarm, SMM665_FAULT_AIN1);
SMM665_ATTR(in10, crit_alarm, SMM665_FAULT_AIN2);
/* Temperature */
SMM665_ATTR(temp1, input, SMM665_MISC16_ADC_DATA_INT_TEMP);
SMM665_ATTR(temp1, min, SMM665_MISC16_ADC_DATA_INT_TEMP);
SMM665_ATTR(temp1, max, SMM665_MISC16_ADC_DATA_INT_TEMP);
SMM665_ATTR(temp1, lcrit, SMM665_MISC16_ADC_DATA_INT_TEMP);
SMM665_ATTR(temp1, crit, SMM665_MISC16_ADC_DATA_INT_TEMP);
SMM665_ATTR(temp1, crit_alarm, SMM665_FAULT_TEMP);
/*
* Finally, construct an array of pointers to members of the above objects,
* as required for sysfs_create_group()
*/
static struct attribute *smm665_attrs[] = {
&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_lcrit.dev_attr.attr,
&sensor_dev_attr_in1_crit.dev_attr.attr,
&sensor_dev_attr_in1_crit_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_lcrit.dev_attr.attr,
&sensor_dev_attr_in2_crit.dev_attr.attr,
&sensor_dev_attr_in2_crit_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_lcrit.dev_attr.attr,
&sensor_dev_attr_in3_crit.dev_attr.attr,
&sensor_dev_attr_in3_crit_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_lcrit.dev_attr.attr,
&sensor_dev_attr_in4_crit.dev_attr.attr,
&sensor_dev_attr_in4_crit_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_lcrit.dev_attr.attr,
&sensor_dev_attr_in5_crit.dev_attr.attr,
&sensor_dev_attr_in5_crit_alarm.dev_attr.attr,
&sensor_dev_attr_in6_input.dev_attr.attr,
&sensor_dev_attr_in6_min.dev_attr.attr,
&sensor_dev_attr_in6_max.dev_attr.attr,
&sensor_dev_attr_in6_lcrit.dev_attr.attr,
&sensor_dev_attr_in6_crit.dev_attr.attr,
&sensor_dev_attr_in6_crit_alarm.dev_attr.attr,
&sensor_dev_attr_in7_input.dev_attr.attr,
&sensor_dev_attr_in7_min.dev_attr.attr,
&sensor_dev_attr_in7_max.dev_attr.attr,
&sensor_dev_attr_in7_lcrit.dev_attr.attr,
&sensor_dev_attr_in7_crit.dev_attr.attr,
&sensor_dev_attr_in7_crit_alarm.dev_attr.attr,
&sensor_dev_attr_in8_input.dev_attr.attr,
&sensor_dev_attr_in8_min.dev_attr.attr,
&sensor_dev_attr_in8_max.dev_attr.attr,
&sensor_dev_attr_in8_lcrit.dev_attr.attr,
&sensor_dev_attr_in8_crit.dev_attr.attr,
&sensor_dev_attr_in8_crit_alarm.dev_attr.attr,
&sensor_dev_attr_in9_input.dev_attr.attr,
&sensor_dev_attr_in9_min.dev_attr.attr,
&sensor_dev_attr_in9_max.dev_attr.attr,
&sensor_dev_attr_in9_lcrit.dev_attr.attr,
&sensor_dev_attr_in9_crit.dev_attr.attr,
&sensor_dev_attr_in9_crit_alarm.dev_attr.attr,
&sensor_dev_attr_in10_input.dev_attr.attr,
&sensor_dev_attr_in10_min.dev_attr.attr,
&sensor_dev_attr_in10_max.dev_attr.attr,
&sensor_dev_attr_in10_lcrit.dev_attr.attr,
&sensor_dev_attr_in10_crit.dev_attr.attr,
&sensor_dev_attr_in10_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_lcrit.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(smm665);
static const struct i2c_device_id smm665_id[];
static int smm665_probe(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
struct smm665_data *data;
struct device *hwmon_dev;
int i, ret;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
| I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
if (i2c_smbus_read_byte_data(client, SMM665_ADOC_ENABLE) < 0)
return -ENODEV;
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
data->client = client;
data->type = i2c_match_id(smm665_id, client)->driver_data;
data->cmdreg = i2c_new_dummy_device(adapter, (client->addr & ~SMM665_REGMASK)
| SMM665_CMDREG_BASE);
if (IS_ERR(data->cmdreg))
return PTR_ERR(data->cmdreg);
switch (data->type) {
case smm465:
case smm665:
data->conversion_time = SMM665_ADC_WAIT_SMM665;
break;
case smm665c:
case smm764:
case smm766:
data->conversion_time = SMM665_ADC_WAIT_SMM766;
break;
}
ret = -ENODEV;
if (i2c_smbus_read_byte_data(data->cmdreg, SMM665_MISC8_CMD_STS) < 0)
goto out_unregister;
/*
* Read limits.
*
* Limit registers start with register SMM665_LIMIT_BASE.
* Each channel uses 8 registers, providing four limit values
* per channel. Each limit value requires two registers, with the
* high byte in the first register and the low byte in the second
* register. The first two limits are under limit values, followed
* by two over limit values.
*
* Limit register order matches the ADC register order, so we use
* ADC register defines throughout the code to index limit registers.
*
* We save the first retrieved value both as "critical" and "alarm"
* value. The second value overwrites either the critical or the
* alarm value, depending on its configuration. This ensures that both
* critical and alarm values are initialized, even if both registers are
* configured as critical or non-critical.
*/
for (i = 0; i < SMM665_NUM_ADC; i++) {
int val;
val = smm665_read16(client, SMM665_LIMIT_BASE + i * 8);
if (unlikely(val < 0))
goto out_unregister;
data->critical_min_limit[i] = data->alarm_min_limit[i]
= smm665_convert(val, i);
val = smm665_read16(client, SMM665_LIMIT_BASE + i * 8 + 2);
if (unlikely(val < 0))
goto out_unregister;
if (smm665_is_critical(val))
data->critical_min_limit[i] = smm665_convert(val, i);
else
data->alarm_min_limit[i] = smm665_convert(val, i);
val = smm665_read16(client, SMM665_LIMIT_BASE + i * 8 + 4);
if (unlikely(val < 0))
goto out_unregister;
data->critical_max_limit[i] = data->alarm_max_limit[i]
= smm665_convert(val, i);
val = smm665_read16(client, SMM665_LIMIT_BASE + i * 8 + 6);
if (unlikely(val < 0))
goto out_unregister;
if (smm665_is_critical(val))
data->critical_max_limit[i] = smm665_convert(val, i);
else
data->alarm_max_limit[i] = smm665_convert(val, i);
}
hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
client->name, data,
smm665_groups);
if (IS_ERR(hwmon_dev)) {
ret = PTR_ERR(hwmon_dev);
goto out_unregister;
}
return 0;
out_unregister:
i2c_unregister_device(data->cmdreg);
return ret;
}
static void smm665_remove(struct i2c_client *client)
{
struct smm665_data *data = i2c_get_clientdata(client);
i2c_unregister_device(data->cmdreg);
}
static const struct i2c_device_id smm665_id[] = {
{"smm465", smm465},
{"smm665", smm665},
{"smm665c", smm665c},
{"smm764", smm764},
{"smm766", smm766},
{}
};
MODULE_DEVICE_TABLE(i2c, smm665_id);
/* This is the driver that will be inserted */
static struct i2c_driver smm665_driver = {
.driver = {
.name = "smm665",
},
.probe = smm665_probe,
.remove = smm665_remove,
.id_table = smm665_id,
};
module_i2c_driver(smm665_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("SMM665 driver");
MODULE_LICENSE("GPL");

View file

@ -20,7 +20,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/sysfs.h>
/* Addresses to scan */

View file

@ -14,7 +14,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/slab.h>

View file

@ -434,7 +434,7 @@ static umode_t tmp51x_is_visible(const void *_data,
switch (type) {
case hwmon_temp:
if (data->id == tmp512 && channel == 4)
if (data->id == tmp512 && channel == 3)
return 0;
switch (attr) {
case hwmon_temp_input:
@ -720,10 +720,7 @@ static int tmp51x_probe(struct i2c_client *client)
if (!data)
return -ENOMEM;
if (client->dev.of_node)
data->id = (enum tmp51x_ids)device_get_match_data(&client->dev);
else
data->id = i2c_match_id(tmp51x_id, client)->driver_data;
data->id = (uintptr_t)i2c_get_match_data(client);
ret = tmp51x_configure(dev, data);
if (ret < 0) {

View file

@ -14,7 +14,7 @@
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/regmap.h>
#define TEMPERATURE 0x2c

View file

@ -9,7 +9,8 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>

View file

@ -13,7 +13,6 @@
#include <linux/hwmon-sysfs.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/vexpress.h>

View file

@ -855,16 +855,17 @@ static int via686a_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
u16 address, val;
int ret;
if (force_addr) {
address = force_addr & ~(VIA686A_EXTENT - 1);
dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
ret = pci_write_config_word(dev, VIA686A_BASE_REG, address | 1);
if (ret != PCIBIOS_SUCCESSFUL)
return -ENODEV;
}
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_word(dev, VIA686A_BASE_REG, &val))
ret = pci_read_config_word(dev, VIA686A_BASE_REG, &val);
if (ret != PCIBIOS_SUCCESSFUL)
return -ENODEV;
address = val & ~(VIA686A_EXTENT - 1);
@ -874,8 +875,8 @@ static int via686a_pci_probe(struct pci_dev *dev,
return -ENODEV;
}
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
ret = pci_read_config_word(dev, VIA686A_ENABLE_REG, &val);
if (ret != PCIBIOS_SUCCESSFUL)
return -ENODEV;
if (!(val & 0x0001)) {
if (!force_addr) {
@ -886,9 +887,8 @@ static int via686a_pci_probe(struct pci_dev *dev,
}
dev_warn(&dev->dev, "Enabling sensors\n");
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(dev, VIA686A_ENABLE_REG,
val | 0x0001))
ret = pci_write_config_word(dev, VIA686A_ENABLE_REG, val | 0x1);
if (ret != PCIBIOS_SUCCESSFUL)
return -ENODEV;
}

View file

@ -971,13 +971,15 @@ static int vt8231_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
u16 address, val;
int ret;
if (force_addr) {
address = force_addr & 0xff00;
dev_warn(&dev->dev, "Forcing ISA address 0x%x\n",
address);
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(dev, VT8231_BASE_REG, address | 1))
ret = pci_write_config_word(dev, VT8231_BASE_REG, address | 1);
if (ret != PCIBIOS_SUCCESSFUL)
return -ENODEV;
}
@ -997,9 +999,8 @@ static int vt8231_pci_probe(struct pci_dev *dev,
if (!(val & 0x0001)) {
dev_warn(&dev->dev, "enabling sensors\n");
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(dev, VT8231_ENABLE_REG,
val | 0x0001))
ret = pci_write_config_word(dev, VT8231_ENABLE_REG, val | 0x1);
if (ret != PCIBIOS_SUCCESSFUL)
return -ENODEV;
}

View file

@ -12,7 +12,7 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/regmap.h>
/* W83773 has 3 channels */