Commit dd950695 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hwmon-for-linus-v4.8' of...

Merge tag 'hwmon-for-linus-v4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon updates from Guenter Roeck:

 - New drivers for FTS BMC "Teutates", TI INA3221, and Sensirion SHT3x.

 - Added support for Microchip MCP9808 and TI TMP461.

 - Cleanup and minor fixes in various drivers.

* tag 'hwmon-for-linus-v4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (37 commits)
  Documentation: dtb: xgene: Add hwmon dts binding documentation
  hwmon: (ftsteutates) Remove unused including <linux/version.h>
  hwmon: (adt7411) set bit 3 in CFG1 register
  hwmon: Add driver for FTS BMC chip "Teutates"
  hwmon: (sht3x) add humidity heater element control
  hwmon: (jc42) Add support for generic JC-42.4 devicetree binding
  dt/bindings: Add bindings for JC-42.4 compatible temperature sensors
  hwmon: (tmp102) Convert to use regmap, and drop local cache
  hwmon: (tmp102) Rework chip configuration
  hwmon: (tmp102) Improve handling of initial read delay
  hwmon: (lm90) Drop unnecessary else statements
  hwmon: (lm90) Use bool for valid flag
  hwmon: (lm90) Read limit registers only once
  hwmon: (lm90) Simplify read functions
  hwmon: (lm90) Use devm_hwmon_device_register_with_groups
  hwmon: (lm90) Use devm_add_action for cleanup
  hwmon: (lm75) Convert to use regmap
  hwmon: (lm75) Add update_interval attribute
  hwmon: (lm75) Drop lm75_read_value and lm75_write_value
  hwmon: (lm75) Handle cleanup with devm_add_action
  ...
parents 52770c37 1d3dd4ce
APM X-Gene hwmon driver
APM X-Gene SOC sensors are accessed over the "SLIMpro" mailbox.
Required properties :
- compatible : should be "apm,xgene-slimpro-hwmon"
- mboxes : use the label reference for the mailbox as the first parameter.
The second parameter is the channel number.
Example :
hwmonslimpro {
compatible = "apm,xgene-slimpro-hwmon";
mboxes = <&mailbox 7>;
};
Properties for Jedec JC-42.4 compatible temperature sensors
Required properties:
- compatible: May include a device-specific string consisting of the
manufacturer and the name of the chip. A list of supported
chip names follows.
Must include "jedec,jc-42.4-temp" for any Jedec JC-42.4
compatible temperature sensor.
Supported chip names:
adi,adt7408
atmel,at30ts00
atmel,at30tse004
onnn,cat6095
onnn,cat34ts02
maxim,max6604
microchip,mcp9804
microchip,mcp9805
microchip,mcp9808
microchip,mcp98243
microchip,mcp98244
microchip,mcp9843
nxp,se97
nxp,se98
st,stts2002
st,stts2004
st,stts3000
st,stts424
st,stts424e
idt,tse2002
idt,tse2004
idt,ts3000
idt,ts3001
- reg: I2C address
Example:
temp-sensor@1a {
compatible = "jedec,jc-42.4-temp";
reg = <0x1a>;
};
...@@ -24,7 +24,7 @@ Supported chips: ...@@ -24,7 +24,7 @@ Supported chips:
AW9D-MAX) (2) AW9D-MAX) (2)
1) For revisions 2 and 3 uGuru's the driver can autodetect the 1) For revisions 2 and 3 uGuru's the driver can autodetect the
sensortype (Volt or Temp) for bank1 sensors, for revision 1 uGuru's sensortype (Volt or Temp) for bank1 sensors, for revision 1 uGuru's
this doesnot always work. For these uGuru's the autodection can this does not always work. For these uGuru's the autodetection can
be overridden with the bank1_types module param. For all 3 known be overridden with the bank1_types module param. For all 3 known
revison 1 motherboards the correct use of this param is: revison 1 motherboards the correct use of this param is:
bank1_types=1,1,0,0,0,0,0,2,0,0,0,0,2,0,0,1 bank1_types=1,1,0,0,0,0,0,2,0,0,0,0,2,0,0,1
......
Kernel driver ftsteutates
=====================
Supported chips:
* FTS Teutates
Prefix: 'ftsteutates'
Addresses scanned: I2C 0x73 (7-Bit)
Author: Thilo Cestonaro <thilo.cestonaro@ts.fujitsu.com>
Description
-----------
The BMC Teutates is the Eleventh generation of Superior System
monitoring and thermal management solution. It is builds on the basic
functionality of the BMC Theseus and contains several new features and
enhancements. It can monitor up to 4 voltages, 16 temperatures and
8 fans. It also contains an integrated watchdog which is currently
implemented in this driver.
Specification of the chip can be found here:
ftp:///pub/Mainboard-OEM-Sales/Services/Software&Tools/Linux_SystemMonitoring&Watchdog&GPIO/BMC-Teutates_Specification_V1.21.pdf
ftp:///pub/Mainboard-OEM-Sales/Services/Software&Tools/Linux_SystemMonitoring&Watchdog&GPIO/Fujitsu_mainboards-1-Sensors_HowTo-en-US.pdf
Kernel driver ina3221
=====================
Supported chips:
* Texas Instruments INA3221
Prefix: 'ina3221'
Addresses: I2C 0x40 - 0x43
Datasheet: Publicly available at the Texas Instruments website
http://www.ti.com/
Author: Andrew F. Davis <afd@ti.com>
Description
-----------
The Texas Instruments INA3221 monitors voltage, current, and power on the high
side of up to three D.C. power supplies. The INA3221 monitors both shunt drop
and supply voltage, with programmable conversion times and averaging, current
and power are calculated host-side from these.
Sysfs entries
-------------
in[123]_input Bus voltage(mV) channels
curr[123]_input Current(mA) measurement channels
shunt[123]_resistor Shunt resistance(uOhm) channels
curr[123]_crit Critical alert current(mA) setting, activates the
corresponding alarm when the respective current
is above this value
curr[123]_crit_alarm Critical alert current limit exceeded
curr[123]_max Warning alert current(mA) setting, activates the
corresponding alarm when the respective current
average is above this value.
curr[123]_max_alarm Warning alert current limit exceeded
in[456]_input Shunt voltage(uV) for channels 1, 2, and 3 respectively
...@@ -18,10 +18,11 @@ Supported chips: ...@@ -18,10 +18,11 @@ Supported chips:
* Maxim MAX6604 * Maxim MAX6604
Datasheets: Datasheets:
http://datasheets.maxim-ic.com/en/ds/MAX6604.pdf http://datasheets.maxim-ic.com/en/ds/MAX6604.pdf
* Microchip MCP9804, MCP9805, MCP98242, MCP98243, MCP98244, MCP9843 * Microchip MCP9804, MCP9805, MCP9808, MCP98242, MCP98243, MCP98244, MCP9843
Datasheets: Datasheets:
http://ww1.microchip.com/downloads/en/DeviceDoc/22203C.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/22203C.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/21977b.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/21977b.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/25095A.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/21996a.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/21996a.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/22153c.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/22153c.pdf
http://ww1.microchip.com/downloads/en/DeviceDoc/22327A.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/22327A.pdf
......
...@@ -17,7 +17,7 @@ This driver implements support for the Maxim MAX1668, MAX1805 and MAX1989 ...@@ -17,7 +17,7 @@ This driver implements support for the Maxim MAX1668, MAX1805 and MAX1989
chips. chips.
The three devices are very similar, but the MAX1805 has a reduced feature The three devices are very similar, but the MAX1805 has a reduced feature
set; only two remote temperature inputs vs the four avaible on the other set; only two remote temperature inputs vs the four available on the other
two ICs. two ICs.
The driver is able to distinguish between the devices and creates sysfs The driver is able to distinguish between the devices and creates sysfs
......
Kernel driver sht3x
===================
Supported chips:
* Sensirion SHT3x-DIS
Prefix: 'sht3x'
Addresses scanned: none
Datasheet: http://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/Humidity/Sensirion_Humidity_Datasheet_SHT3x_DIS.pdf
Author:
David Frey <david.frey@sensirion.com>
Pascal Sachs <pascal.sachs@sensirion.com>
Description
-----------
This driver implements support for the Sensirion SHT3x-DIS chip, a humidity
and temperature sensor. 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 can have the I2C
addresses 0x44 or 0x45, depending on the wiring. See
Documentation/i2c/instantiating-devices for methods to instantiate the device.
There are two options configurable by means of sht3x_platform_data:
1. blocking (pull the I2C clock line down while performing the measurement) or
non-blocking mode. Blocking mode will guarantee the fastest result but
the I2C bus will be busy during that time. By default, non-blocking mode
is used. Make sure clock-stretching works properly on your device if you
want to use blocking mode.
2. high or low accuracy. High accuracy is used by default and using it is
strongly recommended.
The sht3x sensor supports a single shot mode as well as 5 periodic measure
modes, which can be controlled with the update_interval sysfs interface.
The allowed update_interval in milliseconds are as follows:
* 0 single shot mode
* 2000 0.5 Hz periodic measurement
* 1000 1 Hz periodic measurement
* 500 2 Hz periodic measurement
* 250 4 Hz periodic measurement
* 100 10 Hz periodic measurement
In the periodic measure mode, the sensor automatically triggers a measurement
with the configured update interval on the chip. When a temperature or humidity
reading exceeds the configured limits, the alert attribute is set to 1 and
the alert pin on the sensor is set to high.
When the temperature and humidity readings move back between the hysteresis
values, the alert bit is set to 0 and the alert pin on the sensor is set to
low.
sysfs-Interface
---------------
temp1_input: temperature input
humidity1_input: humidity input
temp1_max: temperature max value
temp1_max_hyst: temperature hysteresis value for max limit
humidity1_max: humidity max value
humidity1_max_hyst: humidity hysteresis value for max limit
temp1_min: temperature min value
temp1_min_hyst: temperature hysteresis value for min limit
humidity1_min: humidity min value
humidity1_min_hyst: humidity hysteresis value for min limit
temp1_alarm: alarm flag is set to 1 if the temperature is outside the
configured limits. Alarm only works in periodic measure mode
humidity1_alarm: alarm flag is set to 1 if the humidity is outside the
configured limits. Alarm only works in periodic measure mode
heater_enable: heater enable, heating element removes excess humidity from
sensor
0: turned off
1: turned on
update_interval: update interval, 0 for single shot, interval in msec
for periodic measurement. If the interval is not supported
by the sensor, the next faster interval is chosen
...@@ -15,10 +15,15 @@ increase the chances of your change being accepted. ...@@ -15,10 +15,15 @@ increase the chances of your change being accepted.
Documentation/SubmittingPatches Documentation/SubmittingPatches
Documentation/CodingStyle Documentation/CodingStyle
* If your patch generates checkpatch warnings, please refrain from explanations * Please run your patch through 'checkpatch --strict'. There should be no
such as "I don't like that coding style". Keep in mind that each unnecessary errors, no warnings, and few if any check messages. If there are any
warning helps hiding a real problem. If you don't like the kernel coding messages, please be prepared to explain.
style, don't write kernel drivers.
* If your patch generates checkpatch errors, warnings, or check messages,
please refrain from explanations such as "I prefer that coding style".
Keep in mind that each unnecessary message helps hiding a real problem,
and a consistent coding style makes it easier for others to understand
and review the code.
* Please test your patch thoroughly. We are not your test group. * Please test your patch thoroughly. We are not your test group.
Sometimes a patch can not or not completely be tested because of missing Sometimes a patch can not or not completely be tested because of missing
...@@ -61,15 +66,30 @@ increase the chances of your change being accepted. ...@@ -61,15 +66,30 @@ increase the chances of your change being accepted.
* Make sure that all dependencies are listed in Kconfig. * Make sure that all dependencies are listed in Kconfig.
* Please list include files in alphabetic order.
* Please align continuation lines with '(' on the previous line.
* Avoid forward declarations if you can. Rearrange the code if necessary. * Avoid forward declarations if you can. Rearrange the code if necessary.
* Avoid macros to generate groups of sensor attributes. It not only confuses
checkpatch, but also makes it more difficult to review the code.
* Avoid calculations in macros and macro-generated functions. While such macros * Avoid calculations in macros and macro-generated functions. While such macros
may save a line or so in the source, it obfuscates the code and makes code may save a line or so in the source, it obfuscates the code and makes code
review more difficult. It may also result in code which is more complicated review more difficult. It may also result in code which is more complicated
than necessary. Use inline functions or just regular functions instead. than necessary. Use inline functions or just regular functions instead.
* Limit the number of kernel log messages. In general, your driver should not
generate an error message just because a runtime operation failed. Report
errors to user space instead, using an appropriate error code. Keep in mind
that kernel error log messages not only fill up the kernel log, but also are
printed synchronously, most likely with interrupt disabled, often to a serial
console. Excessive logging can seriously affect system performance.
* Use devres functions whenever possible to allocate resources. For rationale * Use devres functions whenever possible to allocate resources. For rationale
and supported functions, please see Documentation/driver-model/devres.txt. and supported functions, please see Documentation/driver-model/devres.txt.
If a function is not supported by devres, consider using devm_add_action().
* If the driver has a detect function, make sure it is silent. Debug messages * If the driver has a detect function, make sure it is silent. Debug messages
and messages printed after a successful detection are acceptable, but it and messages printed after a successful detection are acceptable, but it
...@@ -96,8 +116,16 @@ increase the chances of your change being accepted. ...@@ -96,8 +116,16 @@ increase the chances of your change being accepted.
writing to it might cause a bad misconfiguration. writing to it might cause a bad misconfiguration.
* Make sure there are no race conditions in the probe function. Specifically, * Make sure there are no race conditions in the probe function. Specifically,
completely initialize your chip first, then create sysfs entries and register completely initialize your chip and your driver first, then register with
with the hwmon subsystem. the hwmon subsystem.
* Use devm_hwmon_device_register_with_groups() or, if your driver needs a remove
function, hwmon_device_register_with_groups() to register your driver with the
hwmon subsystem. Try using devm_add_action() instead of a remove function if
possible. Do not use hwmon_device_register().
* Your driver should be buildable as module. If not, please be prepared to
explain why it has to be built into the kernel.
* Do not provide support for deprecated sysfs attributes. * Do not provide support for deprecated sysfs attributes.
......
...@@ -22,6 +22,9 @@ Supported chips: ...@@ -22,6 +22,9 @@ Supported chips:
Prefix: 'tmp435' Prefix: 'tmp435'
Addresses scanned: I2C 0x48 - 0x4f Addresses scanned: I2C 0x48 - 0x4f
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp435.html Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp435.html
* Texas Instruments TMP461
Prefix: 'tmp461'
Datasheet: http://www.ti.com/product/tmp461
Authors: Authors:
Hans de Goede <hdegoede@redhat.com> Hans de Goede <hdegoede@redhat.com>
...@@ -31,8 +34,8 @@ Description ...@@ -31,8 +34,8 @@ Description
----------- -----------
This driver implements support for Texas Instruments TMP401, TMP411, This driver implements support for Texas Instruments TMP401, TMP411,
TMP431, TMP432 and TMP435 chips. These chips implement one or two remote TMP431, TMP432, TMP435, and TMP461 chips. These chips implement one or two
and one local temperature sensors. Temperature is measured in degrees remote and one local temperature sensors. Temperature is measured in degrees
Celsius. Resolution of the remote sensor is 0.0625 degree. Local Celsius. Resolution of the remote sensor is 0.0625 degree. Local
sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not
supported by the driver so far, so using the default resolution of 0.5 supported by the driver so far, so using the default resolution of 0.5
...@@ -55,3 +58,10 @@ some additional features. ...@@ -55,3 +58,10 @@ some additional features.
TMP432 is compatible with TMP401 and TMP431. It supports two external TMP432 is compatible with TMP401 and TMP431. It supports two external
temperature sensors. temperature sensors.
TMP461 is compatible with TMP401. It supports offset correction
that is applied to the remote sensor.
* Sensor offset values are temperature values
Exported via sysfs attribute tempX_offset
...@@ -486,6 +486,18 @@ config SENSORS_FSCHMD ...@@ -486,6 +486,18 @@ config SENSORS_FSCHMD
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called fschmd. will be called fschmd.
config SENSORS_FTSTEUTATES
tristate "Fujitsu Technology Solutions sensor chip Teutates"
depends on I2C && WATCHDOG
select WATCHDOG_CORE
help
If you say yes here you get support for the Fujitsu Technology
Solutions (FTS) sensor chip "Teutates" including support for
the integrated watchdog.
This driver can also be built as a module. If so, the module
will be called ftsteutates.
config SENSORS_GL518SM config SENSORS_GL518SM
tristate "Genesys Logic GL518SM" tristate "Genesys Logic GL518SM"
depends on I2C depends on I2C
...@@ -645,8 +657,8 @@ config SENSORS_JC42 ...@@ -645,8 +657,8 @@ config SENSORS_JC42
temperature sensors, which are used on many DDR3 memory modules for temperature sensors, which are used on many DDR3 memory modules for
mobile devices and servers. Support will include, but not be limited mobile devices and servers. Support will include, but not be limited
to, ADT7408, AT30TS00, CAT34TS02, CAT6095, MAX6604, MCP9804, MCP9805, to, ADT7408, AT30TS00, CAT34TS02, CAT6095, MAX6604, MCP9804, MCP9805,
MCP98242, MCP98243, MCP98244, MCP9843, SE97, SE98, STTS424(E), MCP9808, MCP98242, MCP98243, MCP98244, MCP9843, SE97, SE98,
STTS2002, STTS3000, TSE2002, TSE2004, TS3000, and TS3001. STTS424(E), STTS2002, STTS3000, TSE2002, TSE2004, TS3000, and TS3001.
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called jc42. will be called jc42.
...@@ -958,6 +970,7 @@ config SENSORS_LM75 ...@@ -958,6 +970,7 @@ config SENSORS_LM75
tristate "National Semiconductor LM75 and compatibles" tristate "National Semiconductor LM75 and compatibles"
depends on I2C depends on I2C
depends on THERMAL || !THERMAL_OF depends on THERMAL || !THERMAL_OF
select REGMAP_I2C
help help
If you say yes here you get support for one common type of If you say yes here you get support for one common type of
temperature sensor chip, with models including: temperature sensor chip, with models including:
...@@ -1265,6 +1278,17 @@ config SENSORS_SHT21 ...@@ -1265,6 +1278,17 @@ config SENSORS_SHT21
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called sht21. will be called sht21.
config SENSORS_SHT3x
tristate "Sensiron humidity and temperature sensors. SHT3x and compat."
depends on I2C
select CRC8
help
If you say yes here you get support for the Sensiron SHT30 and SHT31
humidity and temperature sensors.
This driver can also be built as a module. If so, the module
will be called sht3x.
config SENSORS_SHTC1 config SENSORS_SHTC1
tristate "Sensiron humidity and temperature sensors. SHTC1 and compat." tristate "Sensiron humidity and temperature sensors. SHTC1 and compat."
depends on I2C depends on I2C
...@@ -1514,6 +1538,17 @@ config SENSORS_INA2XX ...@@ -1514,6 +1538,17 @@ config SENSORS_INA2XX
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called ina2xx. will be called ina2xx.
config SENSORS_INA3221
tristate "Texas Instruments INA3221 Triple Power Monitor"
depends on I2C
select REGMAP_I2C
help
If you say yes here you get support for the TI INA3221 Triple Power
Monitor.
This driver can also be built as a module. If so, the module
will be called ina3221.
config SENSORS_TC74 config SENSORS_TC74
tristate "Microchip TC74" tristate "Microchip TC74"
depends on I2C depends on I2C
...@@ -1538,6 +1573,7 @@ config SENSORS_TMP102 ...@@ -1538,6 +1573,7 @@ config SENSORS_TMP102
tristate "Texas Instruments TMP102" tristate "Texas Instruments TMP102"
depends on I2C depends on I2C
depends on THERMAL || !THERMAL_OF depends on THERMAL || !THERMAL_OF
select REGMAP_I2C
help help
If you say yes here you get support for Texas Instruments TMP102 If you say yes here you get support for Texas Instruments TMP102
sensor chips. sensor chips.
...@@ -1561,7 +1597,7 @@ config SENSORS_TMP401 ...@@ -1561,7 +1597,7 @@ config SENSORS_TMP401
depends on I2C depends on I2C
help help
If you say yes here you get support for Texas Instruments TMP401, If you say yes here you get support for Texas Instruments TMP401,
TMP411, TMP431, TMP432 and TMP435 temperature sensor chips. TMP411, TMP431, TMP432, TMP435, and TMP461 temperature sensor chips.
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called tmp401. will be called tmp401.
......
...@@ -62,6 +62,7 @@ obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o ...@@ -62,6 +62,7 @@ obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
obj-$(CONFIG_SENSORS_F75375S) += f75375s.o obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
obj-$(CONFIG_SENSORS_FAM15H_POWER) += fam15h_power.o obj-$(CONFIG_SENSORS_FAM15H_POWER) += fam15h_power.o
obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o
obj-$(CONFIG_SENSORS_FTSTEUTATES) += ftsteutates.o
obj-$(CONFIG_SENSORS_G760A) += g760a.o obj-$(CONFIG_SENSORS_G760A) += g760a.o
obj-$(CONFIG_SENSORS_G762) += g762.o obj-$(CONFIG_SENSORS_G762) += g762.o
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
...@@ -77,6 +78,7 @@ obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o ...@@ -77,6 +78,7 @@ obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o
obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o
obj-$(CONFIG_SENSORS_INA209) += ina209.o obj-$(CONFIG_SENSORS_INA209) += ina209.o
obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o
obj-$(CONFIG_SENSORS_INA3221) += ina3221.o
obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_JC42) += jc42.o obj-$(CONFIG_SENSORS_JC42) += jc42.o
obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o
...@@ -138,6 +140,7 @@ obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o ...@@ -138,6 +140,7 @@ obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o
obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o
obj-$(CONFIG_SENSORS_SHT15) += sht15.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o
obj-$(CONFIG_SENSORS_SHT21) += sht21.o obj-$(CONFIG_SENSORS_SHT21) += sht21.o
obj-$(CONFIG_SENSORS_SHT3x) += sht3x.o
obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o
obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
obj-$(CONFIG_SENSORS_SMM665) += smm665.o obj-$(CONFIG_SENSORS_SMM665) += smm665.o
......
...@@ -37,7 +37,6 @@ enum ad7314_variant { ...@@ -37,7 +37,6 @@ enum ad7314_variant {
struct ad7314_data { struct ad7314_data {
struct spi_device *spi_dev; struct spi_device *spi_dev;
struct device *hwmon_dev;
u16 rx ____cacheline_aligned; u16 rx ____cacheline_aligned;
}; };
...@@ -88,62 +87,30 @@ static ssize_t ad7314_show_temperature(struct device *dev, ...@@ -88,62 +87,30 @@ static ssize_t ad7314_show_temperature(struct device *dev,
} }
} }
static ssize_t ad7314_show_name(struct device *dev,
struct device_attribute *devattr, char *buf)
{
return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
}
static DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
ad7314_show_temperature, NULL, 0); ad7314_show_temperature, NULL, 0);
static struct attribute *ad7314_attributes[] = { static struct attribute *ad7314_attrs[] = {
&dev_attr_name.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr,
NULL, NULL,
}; };
static const struct attribute_group ad7314_group = { ATTRIBUTE_GROUPS(ad7314);
.attrs = ad7314_attributes,
};
static int ad7314_probe(struct spi_device *spi_dev) static int ad7314_probe(struct spi_device *spi_dev)
{ {
int ret;
struct ad7314_data *chip; struct ad7314_data *chip;
struct device *hwmon_dev;
chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL); chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL);
if (chip == NULL) if (chip == NULL)
return -ENOMEM; return -ENOMEM;
spi_set_drvdata(spi_dev, chip);
ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
if (ret < 0)
return ret;
chip->hwmon_dev = hwmon_device_register(&spi_dev->dev);
if (IS_ERR(chip->hwmon_dev)) {
ret = PTR_ERR(chip->hwmon_dev);
goto error_remove_group;
}
chip->spi_dev = spi_dev; chip->spi_dev = spi_dev;
hwmon_dev = devm_hwmon_device_register_with_groups(&spi_dev->dev,
return 0; spi_dev->modalias,
error_remove_group: chip, ad7314_groups);
sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group); return PTR_ERR_OR_ZERO(hwmon_dev);
return ret;
}
static int ad7314_remove(struct spi_device *spi_dev)
{
struct ad7314_data *chip = spi_get_drvdata(spi_dev);
hwmon_device_unregister(chip->hwmon_dev);
sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
return 0;
} }
static const struct spi_device_id ad7314_id[] = { static const struct spi_device_id ad7314_id[] = {
...@@ -159,7 +126,6 @@ static struct spi_driver ad7314_driver = { ...@@ -159,7 +126,6 @@ static struct spi_driver ad7314_driver = {
.name = "ad7314", .name = "ad7314",
}, },
.probe = ad7314_probe, .probe = ad7314_probe,
.remove = ad7314_remove,
.id_table = ad7314_id, .id_table = ad7314_id,
}; };
......
...@@ -66,14 +66,12 @@ ...@@ -66,14 +66,12 @@
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h> #include <linux/hwmon-sysfs.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h>
#include <linux/delay.h> #include <linux/delay.h>
#define DEVICE_NAME "ads7871" #define DEVICE_NAME "ads7871"
struct ads7871_data { struct ads7871_data {
struct device *hwmon_dev; struct spi_device *spi;
struct mutex update_lock;
}; };
static int ads7871_read_reg8(struct spi_device *spi, int reg) static int ads7871_read_reg8(struct spi_device *spi, int reg)
...@@ -101,7 +99,8 @@ static int ads7871_write_reg8(struct spi_device *spi, int reg, u8 val) ...@@ -101,7 +99,8 @@ static int ads7871_write_reg8(struct spi_device *spi, int reg, u8 val)
static ssize_t show_voltage(struct device *dev, static ssize_t show_voltage(struct device *dev,
struct device_attribute *da, char *buf) struct device_attribute *da, char *buf)
{ {
struct spi_device *spi = to_spi_device(dev); struct ads7871_data *pdata = dev_get_drvdata(dev);
struct spi_device *spi = pdata->spi;
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int ret, val, i = 0; int ret, val, i = 0;
uint8_t channel, mux_cnv; uint8_t channel, mux_cnv;
...@@ -139,12 +138,6 @@ static ssize_t show_voltage(struct device *dev, ...@@ -139,12 +138,6 @@ static ssize_t show_voltage(struct device *dev,
} }
} }
static ssize_t ads7871_show_name(struct device *dev,
struct device_attribute *devattr, char *buf)
{
return sprintf(buf, "%s\n", to_spi_device(dev)->modalias);
}
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_voltage, NULL, 0); static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_voltage, NULL, 0);
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 1); static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 1);
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 2); static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 2);
...@@ -154,9 +147,7 @@ static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 5); ...@@ -154,9 +147,7 @@ static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 5);
static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 6); static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 6);
static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 7); static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 7);
static DEVICE_ATTR(name, S_IRUGO, ads7871_show_name, NULL); static struct attribute *ads7871_attrs[] = {
static struct attribute *ads7871_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr,
...@@ -165,21 +156,18 @@ static struct attribute *ads7871_attributes[] = { ...@@ -165,21 +156,18 @@ static struct attribute *ads7871_attributes[] = {
&sensor_dev_attr_in5_input.dev_attr.attr, &sensor_dev_attr_in5_input.dev_attr.attr,
&sensor_dev_attr_in6_input.dev_attr.attr, &sensor_dev_attr_in6_input.dev_attr.attr,
&sensor_dev_attr_in7_input.dev_attr.attr, &sensor_dev_attr_in7_input.dev_attr.attr,
&dev_attr_name.attr,
NULL NULL
}; };
static const struct attribute_group ads7871_group = { ATTRIBUTE_GROUPS(ads7871);
.attrs = ads7871_attributes,
};
static int ads7871_probe(struct spi_device *spi) static int ads7871_probe(struct spi_device *spi)
{ {
int ret, err; struct device *dev = &spi->dev;
int ret;
uint8_t val; uint8_t val;
struct ads7871_data *pdata; struct ads7871_data *pdata;
struct device *hwmon_dev;
dev_dbg(&spi->dev, "probe\n");
/* Configure the SPI bus */ /* Configure the SPI bus */
spi->mode = (SPI_MODE_0); spi->mode = (SPI_MODE_0);
...@@ -193,7 +181,7 @@ static int ads7871_probe(struct spi_device *spi) ...@@ -193,7 +181,7 @@ static int ads7871_probe(struct spi_device *spi)
ads7871_write_reg8(spi, REG_OSC_CONTROL, val); ads7871_write_reg8(spi, REG_OSC_CONTROL, val);
ret = ads7871_read_reg8(spi, REG_OSC_CONTROL); ret = ads7871_read_reg8(spi, REG_OSC_CONTROL);
dev_dbg(&spi->dev, "REG_OSC_CONTROL write:%x, read:%x\n", val, ret); dev_dbg(dev, "REG_OSC_CONTROL write:%x, read:%x\n", val, ret);
/* /*
* because there is no other error checking on an SPI bus * because there is no other error checking on an SPI bus
* we need to make sure we really have a chip * we need to make sure we really have a chip
...@@ -201,46 +189,23 @@ static int ads7871_probe(struct spi_device *spi) ...@@ -201,46 +189,23 @@ static int ads7871_probe(struct spi_device *spi)
if (val != ret) if (val != ret)
return -ENODEV; return -ENODEV;
pdata = devm_kzalloc(&spi->dev, sizeof(struct ads7871_data), pdata = devm_kzalloc(dev, sizeof(struct ads7871_data), GFP_KERNEL);
GFP_KERNEL);
if (!pdata) if (!pdata)
return -ENOMEM; return -ENOMEM;
err = sysfs_create_group(&spi->dev.kobj, &ads7871_group); pdata->spi = spi;
if (err < 0)
return err;
spi_set_drvdata(spi, pdata); hwmon_dev = devm_hwmon_device_register_with_groups(dev, spi->modalias,
pdata,
pdata->hwmon_dev = hwmon_device_register(&spi->dev); ads7871_groups);
if (IS_ERR(pdata->hwmon_dev)) { return PTR_ERR_OR_ZERO(hwmon_dev);
err = PTR_ERR(pdata->hwmon_dev);
goto error_remove;
}
return 0;
error_remove:
sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
return err;
}
static int ads7871_remove(struct spi_device *spi)
{
struct ads7871_data *pdata = spi_get_drvdata(spi);
hwmon_device_unregister(pdata->hwmon_dev);
sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
return 0;
} }
static struct spi_driver ads7871_driver = { static struct spi_driver ads7871_driver = {
.driver = { .driver = {
.name = DEVICE_NAME, .name = DEVICE_NAME,
}, },
.probe = ads7871_probe, .probe = ads7871_probe,
.remove = ads7871_remove,
}; };
module_spi_driver(ads7871_driver); module_spi_driver(ads7871_driver);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#define ADT7411_REG_CFG1 0x18 #define ADT7411_REG_CFG1 0x18
#define ADT7411_CFG1_START_MONITOR (1 << 0) #define ADT7411_CFG1_START_MONITOR (1 << 0)
#define ADT7411_CFG1_RESERVED_BIT3 (1 << 3)
#define ADT7411_REG_CFG2 0x19 #define ADT7411_REG_CFG2 0x19
#define ADT7411_CFG2_DISABLE_AVG (1 << 5) #define ADT7411_CFG2_DISABLE_AVG (1 << 5)
...@@ -296,8 +297,10 @@ static int adt7411_probe(struct i2c_client *client, ...@@ -296,8 +297,10 @@ static int adt7411_probe(struct i2c_client *client,
mutex_init(&data->device_lock); mutex_init(&data->device_lock);
mutex_init(&data->update_lock); mutex_init(&data->update_lock);
/* According to the datasheet, we must only write 1 to bit 3 */
ret = adt7411_modify_bit(client, ADT7411_REG_CFG1, ret = adt7411_modify_bit(client, ADT7411_REG_CFG1,
ADT7411_CFG1_START_MONITOR, 1); ADT7411_CFG1_RESERVED_BIT3
| ADT7411_CFG1_START_MONITOR, 1);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -81,6 +81,7 @@ static bool disallow_fan_type_call; ...@@ -81,6 +81,7 @@ static bool disallow_fan_type_call;
#define I8K_HWMON_HAVE_TEMP4 (1 << 3) #define I8K_HWMON_HAVE_TEMP4 (1 << 3)
#define I8K_HWMON_HAVE_FAN1 (1 << 4) #define I8K_HWMON_HAVE_FAN1 (1 << 4)
#define I8K_HWMON_HAVE_FAN2 (1 << 5) #define I8K_HWMON_HAVE_FAN2 (1 << 5)
#define I8K_HWMON_HAVE_FAN3 (1 << 6)
MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
...@@ -139,6 +140,14 @@ static int i8k_smm(struct smm_regs *regs) ...@@ -139,6 +140,14 @@ static int i8k_smm(struct smm_regs *regs)
int eax = regs->eax; int eax = regs->eax;
cpumask_var_t old_mask; cpumask_var_t old_mask;
#ifdef DEBUG
int ebx = regs->ebx;
unsigned long duration;
ktime_t calltime, delta, rettime;
calltime = ktime_get();
#endif
/* SMM requires CPU 0 */ /* SMM requires CPU 0 */
if (!alloc_cpumask_var(&old_mask, GFP_KERNEL)) if (!alloc_cpumask_var(&old_mask, GFP_KERNEL))
return -ENOMEM; return -ENOMEM;
...@@ -210,6 +219,15 @@ static int i8k_smm(struct smm_regs *regs) ...@@ -210,6 +219,15 @@ static int i8k_smm(struct smm_regs *regs)
out: out:
set_cpus_allowed_ptr(current, old_mask); set_cpus_allowed_ptr(current, old_mask);
free_cpumask_var(old_mask); free_cpumask_var(old_mask);
#ifdef DEBUG
rettime = ktime_get();
delta = ktime_sub(rettime, calltime);
duration = ktime_to_ns(delta) >> 10;
pr_debug("smm(0x%.4x 0x%.4x) = 0x%.4x (took %7lu usecs)\n", eax, ebx,
(rc ? 0xffff : regs->eax & 0xffff), duration);
#endif
return rc; return rc;
} }
...@@ -252,7 +270,7 @@ static int _i8k_get_fan_type(int fan) ...@@ -252,7 +270,7 @@ static int _i8k_get_fan_type(int fan)
static int i8k_get_fan_type(int fan) static int i8k_get_fan_type(int fan)
{ {
/* I8K_SMM_GET_FAN_TYPE SMM call is expensive, so cache values */ /* I8K_SMM_GET_FAN_TYPE SMM call is expensive, so cache values */
static int types[2] = { INT_MIN, INT_MIN }; static int types[3] = { INT_MIN, INT_MIN, INT_MIN };
if (types[fan] == INT_MIN) if (types[fan] == INT_MIN)
types[fan] = _i8k_get_fan_type(fan); types[fan] = _i8k_get_fan_type(fan);
...@@ -719,6 +737,12 @@ static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, ...@@ -719,6 +737,12 @@ static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
1); 1);
static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
i8k_hwmon_set_pwm, 1); i8k_hwmon_set_pwm, 1);
static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
2);
static SENSOR_DEVICE_ATTR(fan3_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
2);
static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
i8k_hwmon_set_pwm, 2);
static struct attribute *i8k_attrs[] = { static struct attribute *i8k_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */
...@@ -735,6 +759,9 @@ static struct attribute *i8k_attrs[] = { ...@@ -735,6 +759,9 @@ static struct attribute *i8k_attrs[] = {
&sensor_dev_attr_fan2_input.dev_attr.attr, /* 11 */ &sensor_dev_attr_fan2_input.dev_attr.attr, /* 11 */
&sensor_dev_attr_fan2_label.dev_attr.attr, /* 12 */ &sensor_dev_attr_fan2_label.dev_attr.attr, /* 12 */
&sensor_dev_attr_pwm2.dev_attr.attr, /* 13 */ &sensor_dev_attr_pwm2.dev_attr.attr, /* 13 */
&sensor_dev_attr_fan3_input.dev_attr.attr, /* 14 */
&sensor_dev_attr_fan3_label.dev_attr.attr, /* 15 */
&sensor_dev_attr_pwm3.dev_attr.attr, /* 16 */
NULL NULL
}; };
...@@ -742,7 +769,7 @@ static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, ...@@ -742,7 +769,7 @@ static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
int index) int index)
{ {
if (disallow_fan_type_call && if (disallow_fan_type_call &&
(index == 9 || index == 12)) (index == 9 || index == 12 || index == 15))
return 0; return 0;
if (index >= 0 && index <= 1 && if (index >= 0 && index <= 1 &&
!(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1)) !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
...@@ -762,6 +789,9 @@ static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, ...@@ -762,6 +789,9 @@ static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
if (index >= 11 && index <= 13 && if (index >= 11 && index <= 13 &&
!(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2))
return 0; return 0;
if (index >= 14 && index <= 16 &&
!(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN3))
return 0;
return attr->mode; return attr->mode;
} }
...@@ -807,6 +837,13 @@ static int __init i8k_init_hwmon(void) ...@@ -807,6 +837,13 @@ static int __init i8k_init_hwmon(void)
if (err >= 0) if (err >= 0)
i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2; i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2;
/* Third fan attributes, if fan status or type is OK */
err = i8k_get_fan_status(2);
if (err < 0)
err = i8k_get_fan_type(2);
if (err >= 0)
i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN3;
i8k_hwmon_dev = hwmon_device_register_with_groups(NULL, "dell_smm", i8k_hwmon_dev = hwmon_device_register_with_groups(NULL, "dell_smm",
NULL, i8k_groups); NULL, i8k_groups);
if (IS_ERR(i8k_hwmon_dev)) { if (IS_ERR(i8k_hwmon_dev)) {
......
...@@ -464,7 +464,7 @@ static int emc6w201_detect(struct i2c_client *client, ...@@ -464,7 +464,7 @@ static int emc6w201_detect(struct i2c_client *client,
if (verstep < 0 || (verstep & 0xF0) != 0xB0) if (verstep < 0 || (verstep & 0xF0) != 0xB0)
return -ENODEV; return -ENODEV;
if ((verstep & 0x0F) > 2) { if ((verstep & 0x0F) > 2) {
dev_dbg(&client->dev, "Unknwown EMC6W201 stepping %d\n", dev_dbg(&client->dev, "Unknown EMC6W201 stepping %d\n",
verstep & 0x0F); verstep & 0x0F);
return -ENODEV; return -ENODEV;
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/hwmon-sysfs.h> #include <linux/hwmon-sysfs.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/of.h>
/* Addresses to scan */ /* Addresses to scan */
static const unsigned short normal_i2c[] = { static const unsigned short normal_i2c[] = {
...@@ -104,6 +105,9 @@ static const unsigned short normal_i2c[] = { ...@@ -104,6 +105,9 @@ static const unsigned short normal_i2c[] = {
#define MCP9804_DEVID 0x0200 #define MCP9804_DEVID 0x0200
#define MCP9804_DEVID_MASK 0xfffc #define MCP9804_DEVID_MASK 0xfffc
#define MCP9808_DEVID 0x0400
#define MCP9808_DEVID_MASK 0xfffc
#define MCP98242_DEVID 0x2000 #define MCP98242_DEVID 0x2000
#define MCP98242_DEVID_MASK 0xfffc #define MCP98242_DEVID_MASK 0xfffc
...@@ -160,6 +164,7 @@ static struct jc42_chips jc42_chips[] = { ...@@ -160,6 +164,7 @@ static struct jc42_chips jc42_chips[] = {
{ IDT_MANID, TS3001_DEVID, TS3001_DEVID_MASK }, { IDT_MANID, TS3001_DEVID, TS3001_DEVID_MASK },
{ MAX_MANID, MAX6604_DEVID, MAX6604_DEVID_MASK }, { MAX_MANID, MAX6604_DEVID, MAX6604_DEVID_MASK },
{ MCP_MANID, MCP9804_DEVID, MCP9804_DEVID_MASK }, { MCP_MANID, MCP9804_DEVID, MCP9804_DEVID_MASK },
{ MCP_MANID, MCP9808_DEVID, MCP9808_DEVID_MASK },
{ MCP_MANID, MCP98242_DEVID, MCP98242_DEVID_MASK }, { MCP_MANID, MCP98242_DEVID, MCP98242_DEVID_MASK },
{ MCP_MANID, MCP98243_DEVID, MCP98243_DEVID_MASK }, { MCP_MANID, MCP98243_DEVID, MCP98243_DEVID_MASK },
{ MCP_MANID, MCP98244_DEVID, MCP98244_DEVID_MASK }, { MCP_MANID, MCP98244_DEVID, MCP98244_DEVID_MASK },
...@@ -537,11 +542,20 @@ static const struct i2c_device_id jc42_id[] = { ...@@ -537,11 +542,20 @@ static const struct i2c_device_id jc42_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, jc42_id); MODULE_DEVICE_TABLE(i2c, jc42_id);
#ifdef CONFIG_OF
static const struct of_device_id jc42_of_ids[] = {
{ .compatible = "jedec,jc-42.4-temp", },
{ }
};
MODULE_DEVICE_TABLE(of, jc42_of_ids);
#endif
static struct i2c_driver jc42_driver = { static struct i2c_driver jc42_driver = {
.class = I2C_CLASS_SPD, .class = I2C_CLASS_SPD | I2C_CLASS_HWMON,
.driver = { .driver = {
.name = "jc42", .name = "jc42",
.pm = JC42_DEV_PM_OPS, .pm = JC42_DEV_PM_OPS,
.of_match_table = of_match_ptr(jc42_of_ids),
}, },
.probe = jc42_probe, .probe = jc42_probe,
.remove = jc42_remove, .remove = jc42_remove,
......
...@@ -29,23 +29,13 @@ ...@@ -29,23 +29,13 @@
struct jz4740_hwmon { struct jz4740_hwmon {
void __iomem *base; void __iomem *base;
int irq; int irq;
const struct mfd_cell *cell; const struct mfd_cell *cell;
struct device *hwmon; struct platform_device *pdev;
struct completion read_completion; struct completion read_completion;
struct mutex lock; struct mutex lock;
}; };
static ssize_t jz4740_hwmon_show_name(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
return sprintf(buf, "jz4740\n");
}
static irqreturn_t jz4740_hwmon_irq(int irq, void *data) static irqreturn_t jz4740_hwmon_irq(int irq, void *data)
{ {
struct jz4740_hwmon *hwmon = data; struct jz4740_hwmon *hwmon = data;
...@@ -58,6 +48,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev, ...@@ -58,6 +48,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev,
struct device_attribute *dev_attr, char *buf) struct device_attribute *dev_attr, char *buf)
{ {
struct jz4740_hwmon *hwmon = dev_get_drvdata(dev); struct jz4740_hwmon *hwmon = dev_get_drvdata(dev);
struct platform_device *pdev = hwmon->pdev;
struct completion *completion = &hwmon->read_completion; struct completion *completion = &hwmon->read_completion;
long t; long t;
unsigned long val; unsigned long val;
...@@ -68,7 +59,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev, ...@@ -68,7 +59,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev,
reinit_completion(completion); reinit_completion(completion);
enable_irq(hwmon->irq); enable_irq(hwmon->irq);
hwmon->cell->enable(to_platform_device(dev)); hwmon->cell->enable(pdev);
t = wait_for_completion_interruptible_timeout(completion, HZ); t = wait_for_completion_interruptible_timeout(completion, HZ);
...@@ -80,7 +71,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev, ...@@ -80,7 +71,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev,
ret = t ? t : -ETIMEDOUT; ret = t ? t : -ETIMEDOUT;
} }
hwmon->cell->disable(to_platform_device(dev)); hwmon->cell->disable(pdev);
disable_irq(hwmon->irq); disable_irq(hwmon->irq);
mutex_unlock(&hwmon->lock); mutex_unlock(&hwmon->lock);
...@@ -88,26 +79,24 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev, ...@@ -88,26 +79,24 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev,
return ret; return ret;
} }
static DEVICE_ATTR(name, S_IRUGO, jz4740_hwmon_show_name, NULL);
static DEVICE_ATTR(in0_input, S_IRUGO, jz4740_hwmon_read_adcin, NULL); static DEVICE_ATTR(in0_input, S_IRUGO, jz4740_hwmon_read_adcin, NULL);
static struct attribute *jz4740_hwmon_attributes[] = { static struct attribute *jz4740_attrs[] = {
&dev_attr_name.attr,
&dev_attr_in0_input.attr, &dev_attr_in0_input.attr,
NULL NULL
}; };
static const struct attribute_group jz4740_hwmon_attr_group = { ATTRIBUTE_GROUPS(jz4740);
.attrs = jz4740_hwmon_attributes,
};
static int jz4740_hwmon_probe(struct platform_device *pdev) static int jz4740_hwmon_probe(struct platform_device *pdev)
{ {
int ret; int ret;
struct device *dev = &pdev->dev;
struct jz4740_hwmon *hwmon; struct jz4740_hwmon *hwmon;
struct device *hwmon_dev;
struct resource *mem; struct resource *mem;
hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL); hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL);
if (!hwmon) if (!hwmon)
return -ENOMEM; return -ENOMEM;
...@@ -125,12 +114,11 @@ static int jz4740_hwmon_probe(struct platform_device *pdev) ...@@ -125,12 +114,11 @@ static int jz4740_hwmon_probe(struct platform_device *pdev)
if (IS_ERR(hwmon->base)) if (IS_ERR(hwmon->base))
return PTR_ERR(hwmon->base); return PTR_ERR(hwmon->base);
hwmon->pdev = pdev;
init_completion(&hwmon->read_completion); init_completion(&hwmon->read_completion);
mutex_init(&hwmon->lock); mutex_init(&hwmon->lock);
platform_set_drvdata(pdev, hwmon); ret = devm_request_irq(dev, hwmon->irq, jz4740_hwmon_irq, 0,
ret = devm_request_irq(&pdev->dev, hwmon->irq, jz4740_hwmon_irq, 0,
pdev->name, hwmon); pdev->name, hwmon);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
...@@ -138,38 +126,13 @@ static int jz4740_hwmon_probe(struct platform_device *pdev) ...@@ -138,38 +126,13 @@ static int jz4740_hwmon_probe(struct platform_device *pdev)
} }
disable_irq(hwmon->irq); disable_irq(hwmon->irq);
ret = sysfs_create_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group); hwmon_dev = devm_hwmon_device_register_with_groups(dev, "jz4740", hwmon,
if (ret) { jz4740_groups);
dev_err(&pdev->dev, "Failed to create sysfs group: %d\n", ret); return PTR_ERR_OR_ZERO(hwmon_dev);
return ret;
}
hwmon->hwmon = hwmon_device_register(&pdev->dev);
if (IS_ERR(hwmon->hwmon)) {
ret = PTR_ERR(hwmon->hwmon);
goto err_remove_file;
}
return 0;
err_remove_file:
sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
return ret;
}
static int jz4740_hwmon_remove(struct platform_device *pdev)
{
struct jz4740_hwmon *hwmon = platform_get_drvdata(pdev);
hwmon_device_unregister(hwmon->hwmon);
sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
return 0;
} }
static struct platform_driver jz4740_hwmon_driver = { static struct platform_driver jz4740_hwmon_driver = {
.probe = jz4740_hwmon_probe, .probe = jz4740_hwmon_probe,
.remove = jz4740_hwmon_remove,
.driver = { .driver = {
.name = "jz4740-hwmon", .name = "jz4740-hwmon",
}, },
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c, 0x4d, static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4c, 0x4d,
0x4e, 0x4f, I2C_CLIENT_END }; 0x4e, 0x4f, I2C_CLIENT_END };
enum chips { tmp401, tmp411, tmp431, tmp432, tmp435 }; enum chips { tmp401, tmp411, tmp431, tmp432, tmp435, tmp461 };
/* /*
* The TMP401 registers, note some registers have different addresses for * The TMP401 registers, note some registers have different addresses for
...@@ -62,31 +62,34 @@ enum chips { tmp401, tmp411, tmp431, tmp432, tmp435 }; ...@@ -62,31 +62,34 @@ enum chips { tmp401, tmp411, tmp431, tmp432, tmp435 };
#define TMP401_MANUFACTURER_ID_REG 0xFE #define TMP401_MANUFACTURER_ID_REG 0xFE
#define TMP401_DEVICE_ID_REG 0xFF #define TMP401_DEVICE_ID_REG 0xFF
static const u8 TMP401_TEMP_MSB_READ[6][2] = { static const u8 TMP401_TEMP_MSB_READ[7][2] = {
{ 0x00, 0x01 }, /* temp */ { 0x00, 0x01 }, /* temp */
{ 0x06, 0x08 }, /* low limit */ { 0x06, 0x08 }, /* low limit */
{ 0x05, 0x07 }, /* high limit */ { 0x05, 0x07 }, /* high limit */
{ 0x20, 0x19 }, /* therm (crit) limit */ { 0x20, 0x19 }, /* therm (crit) limit */
{ 0x30, 0x34 }, /* lowest */ { 0x30, 0x34 }, /* lowest */
{ 0x32, 0x36 }, /* highest */ { 0x32, 0x36 }, /* highest */
{ 0, 0x11 }, /* offset */
}; };
static const u8 TMP401_TEMP_MSB_WRITE[6][2] = { static const u8 TMP401_TEMP_MSB_WRITE[7][2] = {
{ 0, 0 }, /* temp (unused) */ { 0, 0 }, /* temp (unused) */
{ 0x0C, 0x0E }, /* low limit */ { 0x0C, 0x0E }, /* low limit */
{ 0x0B, 0x0D }, /* high limit */ { 0x0B, 0x0D }, /* high limit */
{ 0x20, 0x19 }, /* therm (crit) limit */ { 0x20, 0x19 }, /* therm (crit) limit */
{ 0x30, 0x34 }, /* lowest */ { 0x30, 0x34 }, /* lowest */
{ 0x32, 0x36 }, /* highest */ { 0x32, 0x36 }, /* highest */
{ 0, 0x11 }, /* offset */
}; };
static const u8 TMP401_TEMP_LSB[6][2] = { static const u8 TMP401_TEMP_LSB[7][2] = {
{ 0x15, 0x10 }, /* temp */ { 0x15, 0x10 }, /* temp */
{ 0x17, 0x14 }, /* low limit */ { 0x17, 0x14 }, /* low limit */
{ 0x16, 0x13 }, /* high limit */ { 0x16, 0x13 }, /* high limit */
{ 0, 0 }, /* therm (crit) limit (unused) */ { 0, 0 }, /* therm (crit) limit (unused) */
{ 0x31, 0x35 }, /* lowest */ { 0x31, 0x35 }, /* lowest */
{ 0x33, 0x37 }, /* highest */ { 0x33, 0x37 }, /* highest */
{ 0, 0x12 }, /* offset */
}; };
static const u8 TMP432_TEMP_MSB_READ[4][3] = { static const u8 TMP432_TEMP_MSB_READ[4][3] = {
...@@ -149,6 +152,7 @@ static const struct i2c_device_id tmp401_id[] = { ...@@ -149,6 +152,7 @@ static const struct i2c_device_id tmp401_id[] = {
{ "tmp431", tmp431 }, { "tmp431", tmp431 },
{ "tmp432", tmp432 }, { "tmp432", tmp432 },
{ "tmp435", tmp435 }, { "tmp435", tmp435 },
{ "tmp461", tmp461 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, tmp401_id); MODULE_DEVICE_TABLE(i2c, tmp401_id);
...@@ -170,7 +174,7 @@ struct tmp401_data { ...@@ -170,7 +174,7 @@ struct tmp401_data {
/* register values */ /* register values */
u8 status[4]; u8 status[4];
u8 config; u8 config;
u16 temp[6][3]; u16 temp[7][3];
u8 temp_crit_hyst; u8 temp_crit_hyst;
}; };
...@@ -612,6 +616,22 @@ static const struct attribute_group tmp432_group = { ...@@ -612,6 +616,22 @@ static const struct attribute_group tmp432_group = {
.attrs = tmp432_attributes, .attrs = tmp432_attributes,
}; };
/*
* Additional features of the TMP461 chip.
* The TMP461 temperature offset for the remote channel.
*/
static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IWUSR | S_IRUGO, show_temp,
store_temp, 6, 1);
static struct attribute *tmp461_attributes[] = {
&sensor_dev_attr_temp2_offset.dev_attr.attr,
NULL
};
static const struct attribute_group tmp461_group = {
.attrs = tmp461_attributes,
};
/* /*
* Begin non sysfs callback code (aka Real code) * Begin non sysfs callback code (aka Real code)
*/ */
...@@ -714,7 +734,7 @@ static int tmp401_probe(struct i2c_client *client, ...@@ -714,7 +734,7 @@ static int tmp401_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
static const char * const names[] = { static const char * const names[] = {
"TMP401", "TMP411", "TMP431", "TMP432", "TMP435" "TMP401", "TMP411", "TMP431", "TMP432", "TMP435", "TMP461"
}; };
struct device *dev = &client->dev; struct device *dev = &client->dev;
struct device *hwmon_dev; struct device *hwmon_dev;
...@@ -745,6 +765,9 @@ static int tmp401_probe(struct i2c_client *client, ...@@ -745,6 +765,9 @@ static int tmp401_probe(struct i2c_client *client,
if (data->kind == tmp432) if (data->kind == tmp432)
data->groups[groups++] = &tmp432_group; data->groups[groups++] = &tmp432_group;
if (data->kind == tmp461)
data->groups[groups++] = &tmp461_group;
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
data, data->groups); data, data->groups);
if (IS_ERR(hwmon_dev)) if (IS_ERR(hwmon_dev))
......
/*
* Copyright (C) 2016 Sensirion AG, Switzerland
* Author: David Frey <david.frey@sensirion.com>
* Author: Pascal Sachs <pascal.sachs@sensirion.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __SHT3X_H_
#define __SHT3X_H_
struct sht3x_platform_data {
bool blocking_io;
bool high_precision;
};
#endif /* __SHT3X_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment