mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-10-31 18:09:19 +00:00
New drivers for NCT6775, NCT6776, NCT6779, and LM95234.
Added support for LTC2974, LTC3883, LM25056, TMP431, TMP432, ADT7310, and ADT7320 to existing drivers. Various code cleanups and minor improvements. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJRfgHYAAoJEMsfJm/On5mBkJIP/2y4kfcgh+7Ye8nqs0xnPqA0 +8YR1HYboj8L3HHsWpK0Q3H17yN7bbwESSVeSRKx+UDfPXHYxqKPMdVaVdLU4FwA mIdKuOHoTt4dt57XvpXFfCzVeuAeBCoEsGlR5+KeoZV1VyGshSo7nBAZdpUtDghc 6ZDPROaYY3rCLDsFRuctap3pWZodZSkprt1Kw/Akx8kByv7R/esA9IHRsI/VkWCs m2EIaJPfsZANFyGqahauGDA9goj+cqBQqSdFN+hHY5m5Ur7CRfH8z9sDl+r+8L5s Ij68kPTdgn9tbCbiomaH1DMmJO/GUeMEc7LFBIAgbTzSbjmgDp7y13zN5rnzoINX idFJu7XWL7f6BsipYnIKGpGyd6S7Usfdis+RVxn9LTZ06KK+NYuST0cM+jtlmHwr pHNsFsxz5LizPo+ULBSfTb62uRRSfJ7TRaRcZdVS43ha+rsdk/oWf1KUU+U8dpug NSxkgZNSFPC98UUJ8VhwV3m09D3O7p60oA8aeP6CJ+ysML6Gq6xg7eipH3n7eft1 rUbZvVi4vGIFhag0xRTy1IyKXVNYNSAGWzfMpnB6fn5kblmdr0c+wa7rqMDmeThm PWNrYasc61zGexPqib7VPGrlt2SiDE2w+/y3kdDPG89smqlieqVS5tJjig8fFPIB oHw0Yu7v/6DBjp6a/pjd =RxMp -----END PGP SIGNATURE----- Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging Pull hwmon update from Guenter Roeck: - New drivers for NCT6775, NCT6776, NCT6779, and LM95234. - Added support for LTC2974, LTC3883, LM25056, TMP431, TMP432, ADT7310, and ADT7320 to existing drivers. - Various code cleanups and minor improvements. * tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (54 commits) hwmon: (nct6775) Fix coding style problems hwmon: (nct6775) Constify strings hwmon: (tmp401) Add support for TMP432 hwmon: (tmp401) Add support for update_interval attribute hwmon: (tmp401) Reset valid flag when resetting temperature history hwmon: (tmp401) Simplification and cleanup hwmon: (tmp401) Use sysfs_create_group / sysfs_remove_group hwmon: (tmp401) Drop unused defines, use BIT for bit masks hwmon: (nct6775) Use ARRAY_SIZE for loops where possible documentation: hwmon: Fix typo in documentation/hwmon hwmon: (nct6775) Enable both AUXTIN and VIN3 on NCT6776 hwmon: (ad7314) use spi_get_drvdata() and spi_set_drvdata() MAINTAINERS: Add myself as maintainer for the NCT6775 driver hwmon: (nct6775) Expand scope of supported chips hwmon: (gpio-fan) Use is_visible to determine if attributes should be created hwmon: (tmp401) Fix device detection for TMP411B and TMP411C hwmon: Add driver for LM95234 hwmon: (tmp401) Add support for TMP431 hwmon: (pmbus/lm25066) Add support for LM25056 hwmon: (pmbus/lm25066) Refactor device specific coefficients ...
This commit is contained in:
commit
92ddcf4a01
77 changed files with 7860 additions and 1791 deletions
29
Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt
Normal file
29
Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
NTC Thermistor hwmon sensors
|
||||
-------------------------------
|
||||
|
||||
Requires node properties:
|
||||
- "compatible" value : one of
|
||||
"ntc,ncp15wb473"
|
||||
"ntc,ncp18wb473"
|
||||
"ntc,ncp21wb473"
|
||||
"ntc,ncp03wb473"
|
||||
"ntc,ncp15wl333"
|
||||
- "pullup-uv" Pull up voltage in micro volts
|
||||
- "pullup-ohm" Pull up resistor value in ohms
|
||||
- "pulldown-ohm" Pull down resistor value in ohms
|
||||
- "connected-positive" Always ON, If not specified.
|
||||
Status change is possible.
|
||||
- "io-channels" Channel node of ADC to be used for
|
||||
conversion.
|
||||
|
||||
Read more about iio bindings at
|
||||
Documentation/devicetree/bindings/iio/iio-bindings.txt
|
||||
|
||||
Example:
|
||||
ncp15wb473@0 {
|
||||
compatible = "ntc,ncp15wb473";
|
||||
pullup-uv = <1800000>;
|
||||
pullup-ohm = <47000>;
|
||||
pulldown-ohm = <0>;
|
||||
io-channels = <&adc 3>;
|
||||
};
|
|
@ -12,29 +12,42 @@ Supported chips:
|
|||
Addresses scanned: None
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
http://www.analog.com/static/imported-files/data_sheets/ADT7420.pdf
|
||||
* Analog Devices ADT7310
|
||||
Prefix: 'adt7310'
|
||||
Addresses scanned: None
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
http://www.analog.com/static/imported-files/data_sheets/ADT7310.pdf
|
||||
* Analog Devices ADT7320
|
||||
Prefix: 'adt7320'
|
||||
Addresses scanned: None
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
http://www.analog.com/static/imported-files/data_sheets/ADT7320.pdf
|
||||
|
||||
Author: Hartmut Knaack <knaack.h@gmx.de>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ADT7410 is a temperature sensor with rated temperature range of -55°C to
|
||||
+150°C. It has a high accuracy of +/-0.5°C and can be operated at a resolution
|
||||
of 13 bits (0.0625°C) or 16 bits (0.0078°C). The sensor provides an INT pin to
|
||||
indicate that a minimum or maximum temperature set point has been exceeded, as
|
||||
well as a critical temperature (CT) pin to indicate that the critical
|
||||
temperature set point has been exceeded. Both pins can be set up with a common
|
||||
hysteresis of 0°C - 15°C and a fault queue, ranging from 1 to 4 events. Both
|
||||
pins can individually set to be active-low or active-high, while the whole
|
||||
device can either run in comparator mode or interrupt mode. The ADT7410
|
||||
supports continous temperature sampling, as well as sampling one temperature
|
||||
value per second or even justget one sample on demand for power saving.
|
||||
Besides, it can completely power down its ADC, if power management is
|
||||
required.
|
||||
The ADT7310/ADT7410 is a temperature sensor with rated temperature range of
|
||||
-55°C to +150°C. It has a high accuracy of +/-0.5°C and can be operated at a
|
||||
resolution of 13 bits (0.0625°C) or 16 bits (0.0078°C). The sensor provides an
|
||||
INT pin to indicate that a minimum or maximum temperature set point has been
|
||||
exceeded, as well as a critical temperature (CT) pin to indicate that the
|
||||
critical temperature set point has been exceeded. Both pins can be set up with a
|
||||
common hysteresis of 0°C - 15°C and a fault queue, ranging from 1 to 4 events.
|
||||
Both pins can individually set to be active-low or active-high, while the whole
|
||||
device can either run in comparator mode or interrupt mode. The ADT7410 supports
|
||||
continuous temperature sampling, as well as sampling one temperature value per
|
||||
second or even just get one sample on demand for power saving. Besides, it can
|
||||
completely power down its ADC, if power management is required.
|
||||
|
||||
The ADT7420 is register compatible, the only differences being the package,
|
||||
a slightly narrower operating temperature range (-40°C to +150°C), and a
|
||||
better accuracy (0.25°C instead of 0.50°C.)
|
||||
The ADT7320/ADT7420 is register compatible, the only differences being the
|
||||
package, a slightly narrower operating temperature range (-40°C to +150°C), and
|
||||
a better accuracy (0.25°C instead of 0.50°C.)
|
||||
|
||||
The difference between the ADT7310/ADT7320 and ADT7410/ADT7420 is the control
|
||||
interface, the ADT7310 and ADT7320 use SPI while the ADT7410 and ADT7420 use
|
||||
I2C.
|
||||
|
||||
Configuration Notes
|
||||
-------------------
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
Kernel driver max8688
|
||||
Kernel driver lm25066
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* TI LM25056
|
||||
Prefix: 'lm25056'
|
||||
Addresses scanned: -
|
||||
Datasheets:
|
||||
http://www.ti.com/lit/gpn/lm25056
|
||||
http://www.ti.com/lit/gpn/lm25056a
|
||||
* National Semiconductor LM25066
|
||||
Prefix: 'lm25066'
|
||||
Addresses scanned: -
|
||||
|
@ -25,8 +31,9 @@ Author: Guenter Roeck <linux@roeck-us.net>
|
|||
Description
|
||||
-----------
|
||||
|
||||
This driver supports hardware montoring for National Semiconductor LM25066,
|
||||
LM5064, and LM5064 Power Management, Monitoring, Control, and Protection ICs.
|
||||
This driver supports hardware montoring for National Semiconductor / TI LM25056,
|
||||
LM25066, LM5064, and LM5064 Power Management, Monitoring, Control, and
|
||||
Protection ICs.
|
||||
|
||||
The driver is a client driver to the core PMBus driver. Please see
|
||||
Documentation/hwmon/pmbus for details on PMBus client drivers.
|
||||
|
@ -60,14 +67,19 @@ in1_max Maximum input voltage.
|
|||
in1_min_alarm Input voltage low alarm.
|
||||
in1_max_alarm Input voltage high alarm.
|
||||
|
||||
in2_label "vout1"
|
||||
in2_input Measured output voltage.
|
||||
in2_average Average measured output voltage.
|
||||
in2_min Minimum output voltage.
|
||||
in2_min_alarm Output voltage low alarm.
|
||||
in2_label "vmon"
|
||||
in2_input Measured voltage on VAUX pin
|
||||
in2_min Minimum VAUX voltage (LM25056 only).
|
||||
in2_max Maximum VAUX voltage (LM25056 only).
|
||||
in2_min_alarm VAUX voltage low alarm (LM25056 only).
|
||||
in2_max_alarm VAUX voltage high alarm (LM25056 only).
|
||||
|
||||
in3_label "vout2"
|
||||
in3_input Measured voltage on vaux pin
|
||||
in3_label "vout1"
|
||||
Not supported on LM25056.
|
||||
in3_input Measured output voltage.
|
||||
in3_average Average measured output voltage.
|
||||
in3_min Minimum output voltage.
|
||||
in3_min_alarm Output voltage low alarm.
|
||||
|
||||
curr1_label "iin"
|
||||
curr1_input Measured input current.
|
||||
|
|
36
Documentation/hwmon/lm95234
Normal file
36
Documentation/hwmon/lm95234
Normal file
|
@ -0,0 +1,36 @@
|
|||
Kernel driver lm95234
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* National Semiconductor / Texas Instruments LM95234
|
||||
Addresses scanned: I2C 0x18, 0x4d, 0x4e
|
||||
Datasheet: Publicly available at the Texas Instruments website
|
||||
http://www.ti.com/product/lm95234
|
||||
|
||||
|
||||
Author: Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
LM95234 is an 11-bit digital temperature sensor with a 2-wire System Management
|
||||
Bus (SMBus) interface and TrueTherm technology that can very accurately monitor
|
||||
the temperature of four remote diodes as well as its own temperature.
|
||||
The four remote diodes can be external devices such as microprocessors,
|
||||
graphics processors or diode-connected 2N3904s. The LM95234's TruTherm
|
||||
beta compensation technology allows sensing of 90 nm or 65 nm process
|
||||
thermal diodes accurately.
|
||||
|
||||
All temperature values are given in millidegrees Celsius. Temperature
|
||||
is provided within a range of -127 to +255 degrees (+127.875 degrees for
|
||||
the internal sensor). Resolution depends on temperature input and range.
|
||||
|
||||
Each sensor has its own maximum limit, but the hysteresis is common to all
|
||||
channels. The hysteresis is configurable with the tem1_max_hyst attribute and
|
||||
affects the hysteresis on all channels. The first two external sensors also
|
||||
have a critical limit.
|
||||
|
||||
The lm95234 driver can change its update interval to a fixed set of values.
|
||||
It will round up to the next selectable interval. See the datasheet for exact
|
||||
values. Reading sensor values more often will do no harm, but will return
|
||||
'old' values.
|
|
@ -2,6 +2,10 @@ Kernel driver ltc2978
|
|||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Linear Technology LTC2974
|
||||
Prefix: 'ltc2974'
|
||||
Addresses scanned: -
|
||||
Datasheet: http://www.linear.com/product/ltc2974
|
||||
* Linear Technology LTC2978
|
||||
Prefix: 'ltc2978'
|
||||
Addresses scanned: -
|
||||
|
@ -10,6 +14,10 @@ Supported chips:
|
|||
Prefix: 'ltc3880'
|
||||
Addresses scanned: -
|
||||
Datasheet: http://www.linear.com/product/ltc3880
|
||||
* Linear Technology LTC3883
|
||||
Prefix: 'ltc3883'
|
||||
Addresses scanned: -
|
||||
Datasheet: http://www.linear.com/product/ltc3883
|
||||
|
||||
Author: Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
|
@ -17,9 +25,9 @@ Author: Guenter Roeck <linux@roeck-us.net>
|
|||
Description
|
||||
-----------
|
||||
|
||||
The LTC2978 is an octal power supply monitor, supervisor, sequencer and
|
||||
margin controller. The LTC3880 is a dual, PolyPhase DC/DC synchronous
|
||||
step-down switching regulator controller.
|
||||
LTC2974 is a quad digital power supply manager. LTC2978 is an octal power supply
|
||||
monitor. LTC3880 is a dual output poly-phase step-down DC/DC controller. LTC3883
|
||||
is a single phase step-down DC/DC controller.
|
||||
|
||||
|
||||
Usage Notes
|
||||
|
@ -41,63 +49,90 @@ Sysfs attributes
|
|||
in1_label "vin"
|
||||
in1_input Measured input voltage.
|
||||
in1_min Minimum input voltage.
|
||||
in1_max Maximum input voltage.
|
||||
in1_lcrit Critical minimum input voltage.
|
||||
in1_max Maximum input voltage. LTC2974 and LTC2978 only.
|
||||
in1_lcrit Critical minimum input voltage. LTC2974 and LTC2978
|
||||
only.
|
||||
in1_crit Critical maximum input voltage.
|
||||
in1_min_alarm Input voltage low alarm.
|
||||
in1_max_alarm Input voltage high alarm.
|
||||
in1_lcrit_alarm Input voltage critical low alarm.
|
||||
in1_max_alarm Input voltage high alarm. LTC2974 and LTC2978 only.
|
||||
in1_lcrit_alarm Input voltage critical low alarm. LTC2974 and LTC2978
|
||||
only.
|
||||
in1_crit_alarm Input voltage critical high alarm.
|
||||
in1_lowest Lowest input voltage. LTC2978 only.
|
||||
in1_lowest Lowest input voltage. LTC2974 and LTC2978 only.
|
||||
in1_highest Highest input voltage.
|
||||
in1_reset_history Reset history. Writing into this attribute will reset
|
||||
history for all attributes.
|
||||
in1_reset_history Reset input voltage history.
|
||||
|
||||
in[2-9]_label "vout[1-8]". Channels 3 to 9 on LTC2978 only.
|
||||
in[2-9]_input Measured output voltage.
|
||||
in[2-9]_min Minimum output voltage.
|
||||
in[2-9]_max Maximum output voltage.
|
||||
in[2-9]_lcrit Critical minimum output voltage.
|
||||
in[2-9]_crit Critical maximum output voltage.
|
||||
in[2-9]_min_alarm Output voltage low alarm.
|
||||
in[2-9]_max_alarm Output voltage high alarm.
|
||||
in[2-9]_lcrit_alarm Output voltage critical low alarm.
|
||||
in[2-9]_crit_alarm Output voltage critical high alarm.
|
||||
in[2-9]_lowest Lowest output voltage. LTC2978 only.
|
||||
in[2-9]_highest Lowest output voltage.
|
||||
in[2-9]_reset_history Reset history. Writing into this attribute will reset
|
||||
history for all attributes.
|
||||
in[N]_label "vout[1-8]".
|
||||
LTC2974: N=2-5
|
||||
LTC2978: N=2-9
|
||||
LTC3880: N=2-3
|
||||
LTC3883: N=2
|
||||
in[N]_input Measured output voltage.
|
||||
in[N]_min Minimum output voltage.
|
||||
in[N]_max Maximum output voltage.
|
||||
in[N]_lcrit Critical minimum output voltage.
|
||||
in[N]_crit Critical maximum output voltage.
|
||||
in[N]_min_alarm Output voltage low alarm.
|
||||
in[N]_max_alarm Output voltage high alarm.
|
||||
in[N]_lcrit_alarm Output voltage critical low alarm.
|
||||
in[N]_crit_alarm Output voltage critical high alarm.
|
||||
in[N]_lowest Lowest output voltage. LTC2974 and LTC2978 only.
|
||||
in[N]_highest Highest output voltage.
|
||||
in[N]_reset_history Reset output voltage history.
|
||||
|
||||
temp[1-3]_input Measured temperature.
|
||||
temp[N]_input Measured temperature.
|
||||
On LTC2974, temp[1-4] report external temperatures,
|
||||
and temp5 reports the chip temperature.
|
||||
On LTC2978, only one temperature measurement is
|
||||
supported and reflects the internal temperature.
|
||||
supported and reports the chip temperature.
|
||||
On LTC3880, temp1 and temp2 report external
|
||||
temperatures, and temp3 reports the internal
|
||||
temperature.
|
||||
temp[1-3]_min Mimimum temperature.
|
||||
temp[1-3]_max Maximum temperature.
|
||||
temp[1-3]_lcrit Critical low temperature.
|
||||
temp[1-3]_crit Critical high temperature.
|
||||
temp[1-3]_min_alarm Chip temperature low alarm.
|
||||
temp[1-3]_max_alarm Chip temperature high alarm.
|
||||
temp[1-3]_lcrit_alarm Chip temperature critical low alarm.
|
||||
temp[1-3]_crit_alarm Chip temperature critical high alarm.
|
||||
temp[1-3]_lowest Lowest measured temperature. LTC2978 only.
|
||||
temp[1-3]_highest Highest measured temperature.
|
||||
temp[1-3]_reset_history Reset history. Writing into this attribute will reset
|
||||
history for all attributes.
|
||||
temperatures, and temp3 reports the chip temperature.
|
||||
On LTC3883, temp1 reports an external temperature,
|
||||
and temp2 reports the chip temperature.
|
||||
temp[N]_min Mimimum temperature. LTC2974 and LTC2978 only.
|
||||
temp[N]_max Maximum temperature.
|
||||
temp[N]_lcrit Critical low temperature.
|
||||
temp[N]_crit Critical high temperature.
|
||||
temp[N]_min_alarm Temperature low alarm. LTC2974 and LTC2978 only.
|
||||
temp[N]_max_alarm Temperature high alarm.
|
||||
temp[N]_lcrit_alarm Temperature critical low alarm.
|
||||
temp[N]_crit_alarm Temperature critical high alarm.
|
||||
temp[N]_lowest Lowest measured temperature. LTC2974 and LTC2978 only.
|
||||
Not supported for chip temperature sensor on LTC2974.
|
||||
temp[N]_highest Highest measured temperature. Not supported for chip
|
||||
temperature sensor on LTC2974.
|
||||
temp[N]_reset_history Reset temperature history. Not supported for chip
|
||||
temperature sensor on LTC2974.
|
||||
|
||||
power[1-2]_label "pout[1-2]". LTC3880 only.
|
||||
power[1-2]_input Measured power.
|
||||
power1_label "pin". LTC3883 only.
|
||||
power1_input Measured input power.
|
||||
|
||||
curr1_label "iin". LTC3880 only.
|
||||
power[N]_label "pout[1-4]".
|
||||
LTC2974: N=1-4
|
||||
LTC2978: Not supported
|
||||
LTC3880: N=1-2
|
||||
LTC3883: N=2
|
||||
power[N]_input Measured output power.
|
||||
|
||||
curr1_label "iin". LTC3880 and LTC3883 only.
|
||||
curr1_input Measured input current.
|
||||
curr1_max Maximum input current.
|
||||
curr1_max_alarm Input current high alarm.
|
||||
curr1_highest Highest input current. LTC3883 only.
|
||||
curr1_reset_history Reset input current history. LTC3883 only.
|
||||
|
||||
curr[2-3]_label "iout[1-2]". LTC3880 only.
|
||||
curr[2-3]_input Measured input current.
|
||||
curr[2-3]_max Maximum input current.
|
||||
curr[2-3]_crit Critical input current.
|
||||
curr[2-3]_max_alarm Input current high alarm.
|
||||
curr[2-3]_crit_alarm Input current critical high alarm.
|
||||
curr[N]_label "iout[1-4]".
|
||||
LTC2974: N=1-4
|
||||
LTC2978: not supported
|
||||
LTC3880: N=2-3
|
||||
LTC3883: N=2
|
||||
curr[N]_input Measured output current.
|
||||
curr[N]_max Maximum output current.
|
||||
curr[N]_crit Critical high output current.
|
||||
curr[N]_lcrit Critical low output current. LTC2974 only.
|
||||
curr[N]_max_alarm Output current high alarm.
|
||||
curr[N]_crit_alarm Output current critical high alarm.
|
||||
curr[N]_lcrit_alarm Output current critical low alarm. LTC2974 only.
|
||||
curr[N]_lowest Lowest output current. LTC2974 only.
|
||||
curr[N]_highest Highest output current.
|
||||
curr[N]_reset_history Reset output current history.
|
||||
|
|
188
Documentation/hwmon/nct6775
Normal file
188
Documentation/hwmon/nct6775
Normal file
|
@ -0,0 +1,188 @@
|
|||
Note
|
||||
====
|
||||
|
||||
This driver supersedes the NCT6775F and NCT6776F support in the W83627EHF
|
||||
driver.
|
||||
|
||||
Kernel driver NCT6775
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Nuvoton NCT5572D/NCT6771F/NCT6772F/NCT6775F/W83677HG-I
|
||||
Prefix: 'nct6775'
|
||||
Addresses scanned: ISA address retrieved from Super I/O registers
|
||||
Datasheet: Available from Nuvoton upon request
|
||||
* Nuvoton NCT5577D/NCT6776D/NCT6776F
|
||||
Prefix: 'nct6776'
|
||||
Addresses scanned: ISA address retrieved from Super I/O registers
|
||||
Datasheet: Available from Nuvoton upon request
|
||||
* Nuvoton NCT5532D/NCT6779D
|
||||
Prefix: 'nct6779'
|
||||
Addresses scanned: ISA address retrieved from Super I/O registers
|
||||
Datasheet: Available from Nuvoton upon request
|
||||
|
||||
Authors:
|
||||
Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the Nuvoton NCT6775F, NCT6776F, and NCT6779D
|
||||
and compatible super I/O chips.
|
||||
|
||||
The chips support up to 25 temperature monitoring sources. Up to 6 of those are
|
||||
direct temperature sensor inputs, the others are special sources such as PECI,
|
||||
PCH, and SMBUS. Depending on the chip type, 2 to 6 of the temperature sources
|
||||
can be monitored and compared against minimum, maximum, and critical
|
||||
temperatures. The driver reports up to 10 of the temperatures to the user.
|
||||
There are 4 to 5 fan rotation speed sensors, 8 to 15 analog voltage sensors,
|
||||
one VID, alarms with beep warnings (control unimplemented), and some automatic
|
||||
fan regulation strategies (plus manual fan control mode).
|
||||
|
||||
The temperature sensor sources on all chips are configurable. The configured
|
||||
source for each of the temperature sensors is provided in tempX_label.
|
||||
|
||||
Temperatures are measured in degrees Celsius and measurement resolution is
|
||||
either 1 degC or 0.5 degC, depending on the temperature source and
|
||||
configuration. An alarm is triggered when the temperature gets higher than
|
||||
the high limit; it stays on until the temperature falls below the hysteresis
|
||||
value. Alarms are only supported for temp1 to temp6, depending on the chip type.
|
||||
|
||||
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||
triggered if the rotation speed has dropped below a programmable limit. On
|
||||
NCT6775F, fan readings can be divided by a programmable divider (1, 2, 4, 8,
|
||||
16, 32, 64 or 128) to give the readings more range or accuracy; the other chips
|
||||
do not have a fan speed divider. The driver sets the most suitable fan divisor
|
||||
itself; specifically, it increases the divider value each time a fan speed
|
||||
reading returns an invalid value, and it reduces it if the fan speed reading
|
||||
is lower than optimal. Some fans might not be present because they share pins
|
||||
with other functions.
|
||||
|
||||
Voltage sensors (also known as IN sensors) report their values in millivolts.
|
||||
An alarm is triggered if the voltage has crossed a programmable minimum
|
||||
or maximum limit.
|
||||
|
||||
The driver supports automatic fan control mode known as Thermal Cruise.
|
||||
In this mode, the chip attempts to keep the measured temperature in a
|
||||
predefined temperature range. If the temperature goes out of range, fan
|
||||
is driven slower/faster to reach the predefined range again.
|
||||
|
||||
The mode works for fan1-fan5.
|
||||
|
||||
sysfs attributes
|
||||
----------------
|
||||
|
||||
pwm[1-5] - this file stores PWM duty cycle or DC value (fan speed) in range:
|
||||
0 (lowest speed) to 255 (full)
|
||||
|
||||
pwm[1-5]_enable - this file controls mode of fan/temperature control:
|
||||
* 0 Fan control disabled (fans set to maximum speed)
|
||||
* 1 Manual mode, write to pwm[0-5] any value 0-255
|
||||
* 2 "Thermal Cruise" mode
|
||||
* 3 "Fan Speed Cruise" mode
|
||||
* 4 "Smart Fan III" mode (NCT6775F only)
|
||||
* 5 "Smart Fan IV" mode
|
||||
|
||||
pwm[1-5]_mode - controls if output is PWM or DC level
|
||||
* 0 DC output
|
||||
* 1 PWM output
|
||||
|
||||
Common fan control attributes
|
||||
-----------------------------
|
||||
|
||||
pwm[1-5]_temp_sel Temperature source. Value is temperature sensor index.
|
||||
For example, select '1' for temp1_input.
|
||||
pwm[1-5]_weight_temp_sel
|
||||
Secondary temperature source. Value is temperature
|
||||
sensor index. For example, select '1' for temp1_input.
|
||||
Set to 0 to disable secondary temperature control.
|
||||
|
||||
If secondary temperature functionality is enabled, it is controlled with the
|
||||
following attributes.
|
||||
|
||||
pwm[1-5]_weight_duty_step
|
||||
Duty step size.
|
||||
pwm[1-5]_weight_temp_step
|
||||
Temperature step size. With each step over
|
||||
temp_step_base, the value of weight_duty_step is added
|
||||
to the current pwm value.
|
||||
pwm[1-5]_weight_temp_step_base
|
||||
Temperature at which secondary temperature control kicks
|
||||
in.
|
||||
pwm[1-5]_weight_temp_step_tol
|
||||
Temperature step tolerance.
|
||||
|
||||
Thermal Cruise mode (2)
|
||||
-----------------------
|
||||
|
||||
If the temperature is in the range defined by:
|
||||
|
||||
pwm[1-5]_target_temp Target temperature, unit millidegree Celsius
|
||||
(range 0 - 127000)
|
||||
pwm[1-5]_temp_tolerance
|
||||
Target temperature tolerance, unit millidegree Celsius
|
||||
|
||||
there are no changes to fan speed. Once the temperature leaves the interval, fan
|
||||
speed increases (if temperature is higher that desired) or decreases (if
|
||||
temperature is lower than desired), using the following limits and time
|
||||
intervals.
|
||||
|
||||
pwm[1-5]_start fan pwm start value (range 1 - 255), to start fan
|
||||
when the temperature is above defined range.
|
||||
pwm[1-5]_floor lowest fan pwm (range 0 - 255) if temperature is below
|
||||
the defined range. If set to 0, the fan is expected to
|
||||
stop if the temperature is below the defined range.
|
||||
pwm[1-5]_step_up_time milliseconds before fan speed is increased
|
||||
pwm[1-5]_step_down_time milliseconds before fan speed is decreased
|
||||
pwm[1-5]_stop_time how many milliseconds must elapse to switch
|
||||
corresponding fan off (when the temperature was below
|
||||
defined range).
|
||||
|
||||
Speed Cruise mode (3)
|
||||
---------------------
|
||||
|
||||
This modes tries to keep the fan speed constant.
|
||||
|
||||
fan[1-5]_target Target fan speed
|
||||
fan[1-5]_tolerance
|
||||
Target speed tolerance
|
||||
|
||||
|
||||
Untested; use at your own risk.
|
||||
|
||||
Smart Fan IV mode (5)
|
||||
---------------------
|
||||
|
||||
This mode offers multiple slopes to control the fan speed. The slopes can be
|
||||
controlled by setting the pwm and temperature attributes. When the temperature
|
||||
rises, the chip will calculate the DC/PWM output based on the current slope.
|
||||
There are up to seven data points depending on the chip type. Subsequent data
|
||||
points should be set to higher temperatures and higher pwm values to achieve
|
||||
higher fan speeds with increasing temperature. The last data point reflects
|
||||
critical temperature mode, in which the fans should run at full speed.
|
||||
|
||||
pwm[1-5]_auto_point[1-7]_pwm
|
||||
pwm value to be set if temperature reaches matching
|
||||
temperature range.
|
||||
pwm[1-5]_auto_point[1-7]_temp
|
||||
Temperature over which the matching pwm is enabled.
|
||||
pwm[1-5]_temp_tolerance
|
||||
Temperature tolerance, unit millidegree Celsius
|
||||
pwm[1-5]_crit_temp_tolerance
|
||||
Temperature tolerance for critical temperature,
|
||||
unit millidegree Celsius
|
||||
|
||||
pwm[1-5]_step_up_time milliseconds before fan speed is increased
|
||||
pwm[1-5]_step_down_time milliseconds before fan speed is decreased
|
||||
|
||||
Usage Notes
|
||||
-----------
|
||||
|
||||
On various ASUS boards with NCT6776F, it appears that CPUTIN is not really
|
||||
connected to anything and floats, or that it is connected to some non-standard
|
||||
temperature measurement device. As a result, the temperature reported on CPUTIN
|
||||
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 be ignored on ASUS
|
||||
boards. The CPU temperature on ASUS boards is reported from PECI 0.
|
|
@ -40,7 +40,7 @@ bits for humidity, or 12 bits for temperature and 8 bits for humidity.
|
|||
The humidity calibration coefficients are programmed into an OTP memory on the
|
||||
chip. These coefficients are used to internally calibrate the signals from the
|
||||
sensors. Disabling the reload of those coefficients allows saving 10ms for each
|
||||
measurement and decrease power consumption, while loosing on precision.
|
||||
measurement and decrease power consumption, while losing on precision.
|
||||
|
||||
Some options may be set directly in the sht15_platform_data structure
|
||||
or via sysfs attributes.
|
||||
|
|
|
@ -8,8 +8,16 @@ Supported chips:
|
|||
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp401.html
|
||||
* Texas Instruments TMP411
|
||||
Prefix: 'tmp411'
|
||||
Addresses scanned: I2C 0x4c
|
||||
Addresses scanned: I2C 0x4c, 0x4d, 0x4e
|
||||
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp411.html
|
||||
* Texas Instruments TMP431
|
||||
Prefix: 'tmp431'
|
||||
Addresses scanned: I2C 0x4c, 0x4d
|
||||
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp431.html
|
||||
* Texas Instruments TMP432
|
||||
Prefix: 'tmp432'
|
||||
Addresses scanned: I2C 0x4c, 0x4d
|
||||
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp432.html
|
||||
|
||||
Authors:
|
||||
Hans de Goede <hdegoede@redhat.com>
|
||||
|
@ -18,19 +26,19 @@ Authors:
|
|||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for Texas Instruments TMP401 and
|
||||
TMP411 chips. These chips implements one remote and one local
|
||||
temperature sensor. Temperature is measured in degrees
|
||||
This driver implements support for Texas Instruments TMP401, TMP411,
|
||||
TMP431, and TMP432 chips. These chips implement one or two remote and
|
||||
one local temperature sensors. Temperature is measured in degrees
|
||||
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
|
||||
supported by the driver so far, so using the default resolution of 0.5
|
||||
degree).
|
||||
|
||||
The driver provides the common sysfs-interface for temperatures (see
|
||||
/Documentation/hwmon/sysfs-interface under Temperatures).
|
||||
Documentation/hwmon/sysfs-interface under Temperatures).
|
||||
|
||||
The TMP411 chip is compatible with TMP401. It provides some additional
|
||||
features.
|
||||
The TMP411 and TMP431 chips are compatible with TMP401. TMP411 provides
|
||||
some additional features.
|
||||
|
||||
* Minimum and Maximum temperature measured since power-on, chip-reset
|
||||
|
||||
|
@ -40,3 +48,6 @@ features.
|
|||
|
||||
Exported via sysfs attribute temp_reset_history. Writing 1 to this
|
||||
file triggers a reset.
|
||||
|
||||
TMP432 is compatible with TMP401 and TMP431. It supports two external
|
||||
temperature sensors.
|
||||
|
|
|
@ -125,7 +125,7 @@ in2_label "vmon"
|
|||
in2_input Measured voltage on VMON (ZL2004) or VDRV (ZL9101M,
|
||||
ZL9117M) pin. Reported voltage is 16x the voltage on the
|
||||
pin (adjusted internally by the chip).
|
||||
in2_lcrit Critical minumum VMON/VDRV Voltage.
|
||||
in2_lcrit Critical minimum VMON/VDRV Voltage.
|
||||
in2_crit Critical maximum VMON/VDRV voltage.
|
||||
in2_lcrit_alarm VMON/VDRV voltage critical low alarm.
|
||||
in2_crit_alarm VMON/VDRV voltage critical high alarm.
|
||||
|
|
|
@ -5412,6 +5412,13 @@ L: linux-scsi@vger.kernel.org
|
|||
S: Maintained
|
||||
F: drivers/scsi/NCR_D700.*
|
||||
|
||||
NCT6775 HARDWARE MONITOR DRIVER
|
||||
M: Guenter Roeck <linux@roeck-us.net>
|
||||
L: lm-sensors@lm-sensors.org
|
||||
S: Maintained
|
||||
F: Documentation/hwmon/nct6775
|
||||
F: drivers/hwmon/nct6775.c
|
||||
|
||||
NETEFFECT IWARP RNIC DRIVER (IW_NES)
|
||||
M: Faisal Latif <faisal.latif@intel.com>
|
||||
L: linux-rdma@vger.kernel.org
|
||||
|
|
|
@ -179,9 +179,29 @@ config SENSORS_ADM9240
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called adm9240.
|
||||
|
||||
config SENSORS_ADT7X10
|
||||
tristate
|
||||
help
|
||||
This module contains common code shared by the ADT7310/ADT7320 and
|
||||
ADT7410/ADT7420 temperature monitoring chip drivers.
|
||||
|
||||
If build as a module, the module will be called adt7x10.
|
||||
|
||||
config SENSORS_ADT7310
|
||||
tristate "Analog Devices ADT7310/ADT7320"
|
||||
depends on SPI_MASTER
|
||||
select SENSORS_ADT7X10
|
||||
help
|
||||
If you say yes here you get support for the Analog Devices
|
||||
ADT7310 and ADT7320 temperature monitoring chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adt7310.
|
||||
|
||||
config SENSORS_ADT7410
|
||||
tristate "Analog Devices ADT7410/ADT7420"
|
||||
depends on I2C
|
||||
select SENSORS_ADT7X10
|
||||
help
|
||||
If you say yes here you get support for the Analog Devices
|
||||
ADT7410 and ADT7420 temperature monitoring chips.
|
||||
|
@ -751,6 +771,16 @@ config SENSORS_LTC4261
|
|||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc4261.
|
||||
|
||||
config SENSORS_LM95234
|
||||
tristate "National Semiconductor LM95234"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the LM95234 temperature
|
||||
sensor.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called lm95234.
|
||||
|
||||
config SENSORS_LM95241
|
||||
tristate "National Semiconductor LM95241 and compatibles"
|
||||
depends on I2C
|
||||
|
@ -877,8 +907,22 @@ config SENSORS_MCP3021
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called mcp3021.
|
||||
|
||||
config SENSORS_NCT6775
|
||||
tristate "Nuvoton NCT6775F and compatibles"
|
||||
depends on !PPC
|
||||
select HWMON_VID
|
||||
help
|
||||
If you say yes here you get support for the hardware monitoring
|
||||
functionality of the Nuvoton NCT6775F, NCT6776F, NCT6779D
|
||||
and compatible Super-I/O chips. This driver replaces the
|
||||
w83627ehf driver for NCT6775F and NCT6776F.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called nct6775.
|
||||
|
||||
config SENSORS_NTC_THERMISTOR
|
||||
tristate "NTC thermistor support"
|
||||
depends on (!OF && !IIO) || (OF && IIO)
|
||||
help
|
||||
This driver supports NTC thermistors sensor reading and its
|
||||
interpretation. The driver can also monitor the temperature and
|
||||
|
@ -1204,8 +1248,8 @@ config SENSORS_TMP401
|
|||
tristate "Texas Instruments TMP401 and compatibles"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for Texas Instruments TMP401 and
|
||||
TMP411 temperature sensor chips.
|
||||
If you say yes here you get support for Texas Instruments TMP401,
|
||||
TMP411, TMP431, and TMP432 temperature sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tmp401.
|
||||
|
|
|
@ -34,6 +34,8 @@ obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
|
|||
obj-$(CONFIG_SENSORS_ADS1015) += ads1015.o
|
||||
obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
|
||||
obj-$(CONFIG_SENSORS_ADS7871) += ads7871.o
|
||||
obj-$(CONFIG_SENSORS_ADT7X10) += adt7x10.o
|
||||
obj-$(CONFIG_SENSORS_ADT7310) += adt7310.o
|
||||
obj-$(CONFIG_SENSORS_ADT7410) += adt7410.o
|
||||
obj-$(CONFIG_SENSORS_ADT7411) += adt7411.o
|
||||
obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o
|
||||
|
@ -86,6 +88,7 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o
|
|||
obj-$(CONFIG_SENSORS_LM90) += lm90.o
|
||||
obj-$(CONFIG_SENSORS_LM92) += lm92.o
|
||||
obj-$(CONFIG_SENSORS_LM93) += lm93.o
|
||||
obj-$(CONFIG_SENSORS_LM95234) += lm95234.o
|
||||
obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
|
||||
obj-$(CONFIG_SENSORS_LM95245) += lm95245.o
|
||||
obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
|
||||
|
@ -103,6 +106,7 @@ obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
|
|||
obj-$(CONFIG_SENSORS_MAX6697) += max6697.o
|
||||
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
|
||||
obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
|
||||
obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o
|
||||
obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
|
||||
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
|
||||
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
|
||||
|
|
|
@ -96,9 +96,12 @@
|
|||
#define ABIT_UGURU_MAX_TIMEOUTS 2
|
||||
/* utility macros */
|
||||
#define ABIT_UGURU_NAME "abituguru"
|
||||
#define ABIT_UGURU_DEBUG(level, format, arg...) \
|
||||
if (level <= verbose) \
|
||||
printk(KERN_DEBUG ABIT_UGURU_NAME ": " format , ## arg)
|
||||
#define ABIT_UGURU_DEBUG(level, format, arg...) \
|
||||
do { \
|
||||
if (level <= verbose) \
|
||||
pr_debug(format , ## arg); \
|
||||
} while (0)
|
||||
|
||||
/* Macros to help calculate the sysfs_names array length */
|
||||
/*
|
||||
* sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
|
||||
|
@ -1533,7 +1536,7 @@ static int abituguru_resume(struct device *dev)
|
|||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(abituguru_pm, abituguru_suspend, abituguru_resume);
|
||||
#define ABIT_UGURU_PM &abituguru_pm
|
||||
#define ABIT_UGURU_PM (&abituguru_pm)
|
||||
#else
|
||||
#define ABIT_UGURU_PM NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
|
|
@ -76,9 +76,11 @@
|
|||
#define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT 5
|
||||
/* utility macros */
|
||||
#define ABIT_UGURU3_NAME "abituguru3"
|
||||
#define ABIT_UGURU3_DEBUG(format, arg...) \
|
||||
if (verbose) \
|
||||
printk(KERN_DEBUG ABIT_UGURU3_NAME ": " format , ## arg)
|
||||
#define ABIT_UGURU3_DEBUG(format, arg...) \
|
||||
do { \
|
||||
if (verbose) \
|
||||
pr_debug(format , ## arg); \
|
||||
} while (0)
|
||||
|
||||
/* Macros to help calculate the sysfs_names array length */
|
||||
#define ABIT_UGURU3_MAX_NO_SENSORS 26
|
||||
|
@ -1159,7 +1161,7 @@ static int abituguru3_resume(struct device *dev)
|
|||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(abituguru3_pm, abituguru3_suspend, abituguru3_resume);
|
||||
#define ABIT_UGURU3_PM &abituguru3_pm
|
||||
#define ABIT_UGURU3_PM (&abituguru3_pm)
|
||||
#else
|
||||
#define ABIT_UGURU3_PM NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
|
|
@ -116,7 +116,7 @@ static int ad7314_probe(struct spi_device *spi_dev)
|
|||
if (chip == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&spi_dev->dev, chip);
|
||||
spi_set_drvdata(spi_dev, chip);
|
||||
|
||||
ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
|
||||
if (ret < 0)
|
||||
|
@ -137,7 +137,7 @@ error_remove_group:
|
|||
|
||||
static int ad7314_remove(struct spi_device *spi_dev)
|
||||
{
|
||||
struct ad7314_data *chip = dev_get_drvdata(&spi_dev->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);
|
||||
|
@ -166,6 +166,5 @@ static struct spi_driver ad7314_driver = {
|
|||
module_spi_driver(ad7314_driver);
|
||||
|
||||
MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital"
|
||||
" temperature sensor driver");
|
||||
MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -312,8 +312,7 @@ static int adm1021_detect(struct i2c_client *client,
|
|||
int conv_rate, status, config, man_id, dev_id;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
pr_debug("adm1021: detect failed, "
|
||||
"smbus byte data not supported!\n");
|
||||
pr_debug("detect failed, smbus byte data not supported!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -324,7 +323,7 @@ static int adm1021_detect(struct i2c_client *client,
|
|||
|
||||
/* Check unused bits */
|
||||
if ((status & 0x03) || (config & 0x3F) || (conv_rate & 0xF8)) {
|
||||
pr_debug("adm1021: detect failed, chip not detected!\n");
|
||||
pr_debug("detect failed, chip not detected!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -353,7 +352,7 @@ static int adm1021_detect(struct i2c_client *client,
|
|||
else
|
||||
type_name = "max1617";
|
||||
|
||||
pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n",
|
||||
pr_debug("Detected chip %s at adapter %d, address 0x%02x.\n",
|
||||
type_name, i2c_adapter_id(adapter), client->addr);
|
||||
strlcpy(info->type, type_name, I2C_NAME_SIZE);
|
||||
|
||||
|
@ -368,10 +367,8 @@ static int adm1021_probe(struct i2c_client *client,
|
|||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct adm1021_data),
|
||||
GFP_KERNEL);
|
||||
if (!data) {
|
||||
pr_debug("adm1021: detect failed, devm_kzalloc failed!\n");
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->type = id->driver_data;
|
||||
|
|
|
@ -49,14 +49,14 @@ static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
|
|||
module_param_array(gpio_input, int, NULL, 0);
|
||||
MODULE_PARM_DESC(gpio_input, "List of GPIO pins (0-16) to program as inputs");
|
||||
module_param_array(gpio_output, int, NULL, 0);
|
||||
MODULE_PARM_DESC(gpio_output, "List of GPIO pins (0-16) to program as "
|
||||
"outputs");
|
||||
MODULE_PARM_DESC(gpio_output,
|
||||
"List of GPIO pins (0-16) to program as outputs");
|
||||
module_param_array(gpio_inverted, int, NULL, 0);
|
||||
MODULE_PARM_DESC(gpio_inverted, "List of GPIO pins (0-16) to program as "
|
||||
"inverted");
|
||||
MODULE_PARM_DESC(gpio_inverted,
|
||||
"List of GPIO pins (0-16) to program as inverted");
|
||||
module_param_array(gpio_normal, int, NULL, 0);
|
||||
MODULE_PARM_DESC(gpio_normal, "List of GPIO pins (0-16) to program as "
|
||||
"normal/non-inverted");
|
||||
MODULE_PARM_DESC(gpio_normal,
|
||||
"List of GPIO pins (0-16) to program as normal/non-inverted");
|
||||
module_param_array(gpio_fan, int, NULL, 0);
|
||||
MODULE_PARM_DESC(gpio_fan, "List of GPIO pins (0-7) to program as fan tachs");
|
||||
|
||||
|
@ -372,31 +372,31 @@ static void adm1026_init_client(struct i2c_client *client)
|
|||
dev_dbg(&client->dev, "ADM1026_REG_CONFIG1 is: 0x%02x\n",
|
||||
data->config1);
|
||||
if ((data->config1 & CFG1_MONITOR) == 0) {
|
||||
dev_dbg(&client->dev, "Monitoring not currently "
|
||||
"enabled.\n");
|
||||
dev_dbg(&client->dev,
|
||||
"Monitoring not currently enabled.\n");
|
||||
}
|
||||
if (data->config1 & CFG1_INT_ENABLE) {
|
||||
dev_dbg(&client->dev, "SMBALERT interrupts are "
|
||||
"enabled.\n");
|
||||
dev_dbg(&client->dev,
|
||||
"SMBALERT interrupts are enabled.\n");
|
||||
}
|
||||
if (data->config1 & CFG1_AIN8_9) {
|
||||
dev_dbg(&client->dev, "in8 and in9 enabled. "
|
||||
"temp3 disabled.\n");
|
||||
dev_dbg(&client->dev,
|
||||
"in8 and in9 enabled. temp3 disabled.\n");
|
||||
} else {
|
||||
dev_dbg(&client->dev, "temp3 enabled. in8 and "
|
||||
"in9 disabled.\n");
|
||||
dev_dbg(&client->dev,
|
||||
"temp3 enabled. in8 and in9 disabled.\n");
|
||||
}
|
||||
if (data->config1 & CFG1_THERM_HOT) {
|
||||
dev_dbg(&client->dev, "Automatic THERM, PWM, "
|
||||
"and temp limits enabled.\n");
|
||||
dev_dbg(&client->dev,
|
||||
"Automatic THERM, PWM, and temp limits enabled.\n");
|
||||
}
|
||||
|
||||
if (data->config3 & CFG3_GPIO16_ENABLE) {
|
||||
dev_dbg(&client->dev, "GPIO16 enabled. THERM "
|
||||
"pin disabled.\n");
|
||||
dev_dbg(&client->dev,
|
||||
"GPIO16 enabled. THERM pin disabled.\n");
|
||||
} else {
|
||||
dev_dbg(&client->dev, "THERM pin enabled. "
|
||||
"GPIO16 disabled.\n");
|
||||
dev_dbg(&client->dev,
|
||||
"THERM pin enabled. GPIO16 disabled.\n");
|
||||
}
|
||||
if (data->config3 & CFG3_VREF_250)
|
||||
dev_dbg(&client->dev, "Vref is 2.50 Volts.\n");
|
||||
|
@ -1798,8 +1798,8 @@ static int adm1026_detect(struct i2c_client *client,
|
|||
company = adm1026_read_value(client, ADM1026_REG_COMPANY);
|
||||
verstep = adm1026_read_value(client, ADM1026_REG_VERSTEP);
|
||||
|
||||
dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with"
|
||||
" COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
|
||||
dev_dbg(&adapter->dev,
|
||||
"Detecting device at %d,0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
|
||||
i2c_adapter_id(client->adapter), client->addr,
|
||||
company, verstep);
|
||||
|
||||
|
@ -1811,11 +1811,12 @@ static int adm1026_detect(struct i2c_client *client,
|
|||
/* Analog Devices ADM1026 */
|
||||
} else if (company == ADM1026_COMPANY_ANALOG_DEV
|
||||
&& (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
|
||||
dev_err(&adapter->dev, "Unrecognized stepping "
|
||||
"0x%02x. Defaulting to ADM1026.\n", verstep);
|
||||
dev_err(&adapter->dev,
|
||||
"Unrecognized stepping 0x%02x. Defaulting to ADM1026.\n",
|
||||
verstep);
|
||||
} else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
|
||||
dev_err(&adapter->dev, "Found version/stepping "
|
||||
"0x%02x. Assuming generic ADM1026.\n",
|
||||
dev_err(&adapter->dev,
|
||||
"Found version/stepping 0x%02x. Assuming generic ADM1026.\n",
|
||||
verstep);
|
||||
} else {
|
||||
dev_dbg(&adapter->dev, "Autodetection failed\n");
|
||||
|
|
|
@ -224,8 +224,9 @@ static ssize_t set_fan_div(struct device *dev,
|
|||
break;
|
||||
default:
|
||||
mutex_unlock(&data->update_lock);
|
||||
dev_err(&client->dev, "fan_div value %ld not "
|
||||
"supported. Choose one of 1, 2 or 4!\n", val);
|
||||
dev_err(&client->dev,
|
||||
"fan_div value %ld not supported. Choose one of 1, 2 or 4!\n",
|
||||
val);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Update the value */
|
||||
|
@ -326,8 +327,8 @@ static int adm1029_detect(struct i2c_client *client,
|
|||
* There are no "official" CHIP ID, so actually
|
||||
* we use Major/Minor revision for that
|
||||
*/
|
||||
pr_info("adm1029: Unknown major revision %x, "
|
||||
"please let us know\n", chip_id);
|
||||
pr_info("Unknown major revision %x, please let us know\n",
|
||||
chip_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
|
@ -351,8 +351,9 @@ static void adm9240_write_fan_div(struct i2c_client *client, int nr,
|
|||
reg &= ~(3 << shift);
|
||||
reg |= (fan_div << shift);
|
||||
i2c_smbus_write_byte_data(client, ADM9240_REG_VID_FAN_DIV, reg);
|
||||
dev_dbg(&client->dev, "fan%d clock divider changed from %u "
|
||||
"to %u\n", nr + 1, 1 << old, 1 << fan_div);
|
||||
dev_dbg(&client->dev,
|
||||
"fan%d clock divider changed from %u to %u\n",
|
||||
nr + 1, 1 << old, 1 << fan_div);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -699,8 +700,8 @@ static void adm9240_init_client(struct i2c_client *client)
|
|||
/* start measurement cycle */
|
||||
i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 1);
|
||||
|
||||
dev_info(&client->dev, "cold start: config was 0x%02x "
|
||||
"mode %u\n", conf, mode);
|
||||
dev_info(&client->dev,
|
||||
"cold start: config was 0x%02x mode %u\n", conf, mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,25 +40,25 @@
|
|||
* the instruction byte
|
||||
*/
|
||||
/*Instruction Bit masks*/
|
||||
#define INST_MODE_bm (1<<7)
|
||||
#define INST_READ_bm (1<<6)
|
||||
#define INST_16BIT_bm (1<<5)
|
||||
#define INST_MODE_BM (1 << 7)
|
||||
#define INST_READ_BM (1 << 6)
|
||||
#define INST_16BIT_BM (1 << 5)
|
||||
|
||||
/*From figure 18 in the datasheet*/
|
||||
/*bit masks for Rev/Oscillator Control Register*/
|
||||
#define MUX_CNV_bv 7
|
||||
#define MUX_CNV_bm (1<<MUX_CNV_bv)
|
||||
#define MUX_M3_bm (1<<3) /*M3 selects single ended*/
|
||||
#define MUX_G_bv 4 /*allows for reg = (gain << MUX_G_bv) | ...*/
|
||||
#define MUX_CNV_BV 7
|
||||
#define MUX_CNV_BM (1 << MUX_CNV_BV)
|
||||
#define MUX_M3_BM (1 << 3) /*M3 selects single ended*/
|
||||
#define MUX_G_BV 4 /*allows for reg = (gain << MUX_G_BV) | ...*/
|
||||
|
||||
/*From figure 18 in the datasheet*/
|
||||
/*bit masks for Rev/Oscillator Control Register*/
|
||||
#define OSC_OSCR_bm (1<<5)
|
||||
#define OSC_OSCE_bm (1<<4)
|
||||
#define OSC_REFE_bm (1<<3)
|
||||
#define OSC_BUFE_bm (1<<2)
|
||||
#define OSC_R2V_bm (1<<1)
|
||||
#define OSC_RBG_bm (1<<0)
|
||||
#define OSC_OSCR_BM (1 << 5)
|
||||
#define OSC_OSCE_BM (1 << 4)
|
||||
#define OSC_REFE_BM (1 << 3)
|
||||
#define OSC_BUFE_BM (1 << 2)
|
||||
#define OSC_R2V_BM (1 << 1)
|
||||
#define OSC_RBG_BM (1 << 0)
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -79,7 +79,7 @@ struct ads7871_data {
|
|||
static int ads7871_read_reg8(struct spi_device *spi, int reg)
|
||||
{
|
||||
int ret;
|
||||
reg = reg | INST_READ_bm;
|
||||
reg = reg | INST_READ_BM;
|
||||
ret = spi_w8r8(spi, reg);
|
||||
return ret;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ static int ads7871_read_reg8(struct spi_device *spi, int reg)
|
|||
static int ads7871_read_reg16(struct spi_device *spi, int reg)
|
||||
{
|
||||
int ret;
|
||||
reg = reg | INST_READ_bm | INST_16BIT_bm;
|
||||
reg = reg | INST_READ_BM | INST_16BIT_BM;
|
||||
ret = spi_w8r16(spi, reg);
|
||||
return ret;
|
||||
}
|
||||
|
@ -111,13 +111,13 @@ static ssize_t show_voltage(struct device *dev,
|
|||
* TODO: add support for conversions
|
||||
* other than single ended with a gain of 1
|
||||
*/
|
||||
/*MUX_M3_bm forces single ended*/
|
||||
/*MUX_M3_BM forces single ended*/
|
||||
/*This is also where the gain of the PGA would be set*/
|
||||
ads7871_write_reg8(spi, REG_GAIN_MUX,
|
||||
(MUX_CNV_bm | MUX_M3_bm | channel));
|
||||
(MUX_CNV_BM | MUX_M3_BM | channel));
|
||||
|
||||
ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
|
||||
mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
|
||||
mux_cnv = ((ret & MUX_CNV_BM) >> MUX_CNV_BV);
|
||||
/*
|
||||
* on 400MHz arm9 platform the conversion
|
||||
* is already done when we do this test
|
||||
|
@ -125,14 +125,14 @@ static ssize_t show_voltage(struct device *dev,
|
|||
while ((i < 2) && mux_cnv) {
|
||||
i++;
|
||||
ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
|
||||
mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
|
||||
mux_cnv = ((ret & MUX_CNV_BM) >> MUX_CNV_BV);
|
||||
msleep_interruptible(1);
|
||||
}
|
||||
|
||||
if (mux_cnv == 0) {
|
||||
val = ads7871_read_reg16(spi, REG_LS_BYTE);
|
||||
/*result in volts*10000 = (val/8192)*2.5*10000*/
|
||||
val = ((val>>2) * 25000) / 8192;
|
||||
val = ((val >> 2) * 25000) / 8192;
|
||||
return sprintf(buf, "%d\n", val);
|
||||
} else {
|
||||
return -1;
|
||||
|
@ -189,7 +189,7 @@ static int ads7871_probe(struct spi_device *spi)
|
|||
ads7871_write_reg8(spi, REG_SER_CONTROL, 0);
|
||||
ads7871_write_reg8(spi, REG_AD_CONTROL, 0);
|
||||
|
||||
val = (OSC_OSCR_bm | OSC_OSCE_bm | OSC_REFE_bm | OSC_BUFE_bm);
|
||||
val = (OSC_OSCR_BM | OSC_OSCE_BM | OSC_REFE_BM | OSC_BUFE_BM);
|
||||
ads7871_write_reg8(spi, REG_OSC_CONTROL, val);
|
||||
ret = ads7871_read_reg8(spi, REG_OSC_CONTROL);
|
||||
|
||||
|
|
123
drivers/hwmon/adt7310.c
Normal file
123
drivers/hwmon/adt7310.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* ADT7310/ADT7310 digital temperature sensor driver
|
||||
*
|
||||
* Copyright 2012-2013 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "adt7x10.h"
|
||||
|
||||
#define ADT7310_STATUS 0
|
||||
#define ADT7310_CONFIG 1
|
||||
#define ADT7310_TEMPERATURE 2
|
||||
#define ADT7310_ID 3
|
||||
#define ADT7310_T_CRIT 4
|
||||
#define ADT7310_T_HYST 5
|
||||
#define ADT7310_T_ALARM_HIGH 6
|
||||
#define ADT7310_T_ALARM_LOW 7
|
||||
|
||||
static const u8 adt7310_reg_table[] = {
|
||||
[ADT7X10_TEMPERATURE] = ADT7310_TEMPERATURE,
|
||||
[ADT7X10_STATUS] = ADT7310_STATUS,
|
||||
[ADT7X10_CONFIG] = ADT7310_CONFIG,
|
||||
[ADT7X10_T_ALARM_HIGH] = ADT7310_T_ALARM_HIGH,
|
||||
[ADT7X10_T_ALARM_LOW] = ADT7310_T_ALARM_LOW,
|
||||
[ADT7X10_T_CRIT] = ADT7310_T_CRIT,
|
||||
[ADT7X10_T_HYST] = ADT7310_T_HYST,
|
||||
[ADT7X10_ID] = ADT7310_ID,
|
||||
};
|
||||
|
||||
#define ADT7310_CMD_REG_OFFSET 3
|
||||
#define ADT7310_CMD_READ 0x40
|
||||
|
||||
#define AD7310_COMMAND(reg) (adt7310_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
|
||||
|
||||
static int adt7310_spi_read_word(struct device *dev, u8 reg)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
int ret;
|
||||
|
||||
ret = spi_w8r16(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return be16_to_cpu((__force __be16)ret);
|
||||
}
|
||||
|
||||
static int adt7310_spi_write_word(struct device *dev, u8 reg, u16 data)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
u8 buf[3];
|
||||
|
||||
buf[0] = AD7310_COMMAND(reg);
|
||||
put_unaligned_be16(data, &buf[1]);
|
||||
|
||||
return spi_write(spi, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static int adt7310_spi_read_byte(struct device *dev, u8 reg)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
return spi_w8r8(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
|
||||
}
|
||||
|
||||
static int adt7310_spi_write_byte(struct device *dev, u8 reg,
|
||||
u8 data)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
u8 buf[2];
|
||||
|
||||
buf[0] = AD7310_COMMAND(reg);
|
||||
buf[1] = data;
|
||||
|
||||
return spi_write(spi, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static const struct adt7x10_ops adt7310_spi_ops = {
|
||||
.read_word = adt7310_spi_read_word,
|
||||
.write_word = adt7310_spi_write_word,
|
||||
.read_byte = adt7310_spi_read_byte,
|
||||
.write_byte = adt7310_spi_write_byte,
|
||||
};
|
||||
|
||||
static int adt7310_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
return adt7x10_probe(&spi->dev, spi_get_device_id(spi)->name, spi->irq,
|
||||
&adt7310_spi_ops);
|
||||
}
|
||||
|
||||
static int adt7310_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
return adt7x10_remove(&spi->dev, spi->irq);
|
||||
}
|
||||
|
||||
static const struct spi_device_id adt7310_id[] = {
|
||||
{ "adt7310", 0 },
|
||||
{ "adt7320", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adt7310_id);
|
||||
|
||||
static struct spi_driver adt7310_driver = {
|
||||
.driver = {
|
||||
.name = "adt7310",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = ADT7X10_DEV_PM_OPS,
|
||||
},
|
||||
.probe = adt7310_spi_probe,
|
||||
.remove = adt7310_spi_remove,
|
||||
.id_table = adt7310_id,
|
||||
};
|
||||
module_spi_driver(adt7310_driver);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ADT7310/ADT7320 driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,460 +1,80 @@
|
|||
/*
|
||||
* adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* This driver handles the ADT7410 and compatible digital temperature sensors.
|
||||
* Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
|
||||
* based on lm75.c by Frodo Looijaard <frodol@dds.nl>
|
||||
* and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
|
||||
* ADT7410/ADT7420 digital temperature sensor driver
|
||||
*
|
||||
* 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.
|
||||
* Copyright 2012-2013 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
/*
|
||||
* ADT7410 registers definition
|
||||
*/
|
||||
#include "adt7x10.h"
|
||||
|
||||
#define ADT7410_TEMPERATURE 0
|
||||
#define ADT7410_STATUS 2
|
||||
#define ADT7410_CONFIG 3
|
||||
#define ADT7410_T_ALARM_HIGH 4
|
||||
#define ADT7410_T_ALARM_LOW 6
|
||||
#define ADT7410_T_CRIT 8
|
||||
#define ADT7410_T_HYST 0xA
|
||||
static int adt7410_i2c_read_word(struct device *dev, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_word_swapped(to_i2c_client(dev), reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* ADT7410 status
|
||||
*/
|
||||
#define ADT7410_STAT_T_LOW (1 << 4)
|
||||
#define ADT7410_STAT_T_HIGH (1 << 5)
|
||||
#define ADT7410_STAT_T_CRIT (1 << 6)
|
||||
#define ADT7410_STAT_NOT_RDY (1 << 7)
|
||||
static int adt7410_i2c_write_word(struct device *dev, u8 reg, u16 data)
|
||||
{
|
||||
return i2c_smbus_write_word_swapped(to_i2c_client(dev), reg, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* ADT7410 config
|
||||
*/
|
||||
#define ADT7410_FAULT_QUEUE_MASK (1 << 0 | 1 << 1)
|
||||
#define ADT7410_CT_POLARITY (1 << 2)
|
||||
#define ADT7410_INT_POLARITY (1 << 3)
|
||||
#define ADT7410_EVENT_MODE (1 << 4)
|
||||
#define ADT7410_MODE_MASK (1 << 5 | 1 << 6)
|
||||
#define ADT7410_FULL (0 << 5 | 0 << 6)
|
||||
#define ADT7410_PD (1 << 5 | 1 << 6)
|
||||
#define ADT7410_RESOLUTION (1 << 7)
|
||||
static int adt7410_i2c_read_byte(struct device *dev, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(to_i2c_client(dev), reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* ADT7410 masks
|
||||
*/
|
||||
#define ADT7410_T13_VALUE_MASK 0xFFF8
|
||||
#define ADT7410_T_HYST_MASK 0xF
|
||||
static int adt7410_i2c_write_byte(struct device *dev, u8 reg, u8 data)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(to_i2c_client(dev), reg, data);
|
||||
}
|
||||
|
||||
/* straight from the datasheet */
|
||||
#define ADT7410_TEMP_MIN (-55000)
|
||||
#define ADT7410_TEMP_MAX 150000
|
||||
|
||||
enum adt7410_type { /* keep sorted in alphabetical order */
|
||||
adt7410,
|
||||
static const struct adt7x10_ops adt7410_i2c_ops = {
|
||||
.read_word = adt7410_i2c_read_word,
|
||||
.write_word = adt7410_i2c_write_word,
|
||||
.read_byte = adt7410_i2c_read_byte,
|
||||
.write_byte = adt7410_i2c_write_byte,
|
||||
};
|
||||
|
||||
static const u8 ADT7410_REG_TEMP[4] = {
|
||||
ADT7410_TEMPERATURE, /* input */
|
||||
ADT7410_T_ALARM_HIGH, /* high */
|
||||
ADT7410_T_ALARM_LOW, /* low */
|
||||
ADT7410_T_CRIT, /* critical */
|
||||
};
|
||||
|
||||
/* Each client has this additional data */
|
||||
struct adt7410_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
u8 config;
|
||||
u8 oldconfig;
|
||||
bool valid; /* true if registers valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
s16 temp[4]; /* Register values,
|
||||
0 = input
|
||||
1 = high
|
||||
2 = low
|
||||
3 = critical */
|
||||
u8 hyst; /* hysteresis offset */
|
||||
};
|
||||
|
||||
/*
|
||||
* adt7410 register access by I2C
|
||||
*/
|
||||
static int adt7410_temp_ready(struct i2c_client *client)
|
||||
static int adt7410_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int i, status;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
|
||||
if (status < 0)
|
||||
return status;
|
||||
if (!(status & ADT7410_STAT_NOT_RDY))
|
||||
return 0;
|
||||
msleep(60);
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static struct adt7410_data *adt7410_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7410_data *data = i2c_get_clientdata(client);
|
||||
struct adt7410_data *ret = data;
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
int i, status;
|
||||
|
||||
dev_dbg(&client->dev, "Starting update\n");
|
||||
|
||||
status = adt7410_temp_ready(client); /* check for new value */
|
||||
if (unlikely(status)) {
|
||||
ret = ERR_PTR(status);
|
||||
goto abort;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
|
||||
status = i2c_smbus_read_word_swapped(client,
|
||||
ADT7410_REG_TEMP[i]);
|
||||
if (unlikely(status < 0)) {
|
||||
dev_dbg(dev,
|
||||
"Failed to read value: reg %d, error %d\n",
|
||||
ADT7410_REG_TEMP[i], status);
|
||||
ret = ERR_PTR(status);
|
||||
goto abort;
|
||||
}
|
||||
data->temp[i] = status;
|
||||
}
|
||||
status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
|
||||
if (unlikely(status < 0)) {
|
||||
dev_dbg(dev,
|
||||
"Failed to read value: reg %d, error %d\n",
|
||||
ADT7410_T_HYST, status);
|
||||
ret = ERR_PTR(status);
|
||||
goto abort;
|
||||
}
|
||||
data->hyst = status;
|
||||
data->last_updated = jiffies;
|
||||
data->valid = true;
|
||||
}
|
||||
|
||||
abort:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static s16 ADT7410_TEMP_TO_REG(long temp)
|
||||
{
|
||||
return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
|
||||
ADT7410_TEMP_MAX) * 128, 1000);
|
||||
}
|
||||
|
||||
static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
|
||||
{
|
||||
/* in 13 bit mode, bits 0-2 are status flags - mask them out */
|
||||
if (!(data->config & ADT7410_RESOLUTION))
|
||||
reg &= ADT7410_T13_VALUE_MASK;
|
||||
/*
|
||||
* temperature is stored in twos complement format, in steps of
|
||||
* 1/128°C
|
||||
*/
|
||||
return DIV_ROUND_CLOSEST(reg * 1000, 128);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
/* sysfs attributes for hwmon */
|
||||
|
||||
static ssize_t adt7410_show_temp(struct device *dev,
|
||||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct adt7410_data *data = adt7410_update_device(dev);
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
|
||||
data->temp[attr->index]));
|
||||
}
|
||||
|
||||
static ssize_t adt7410_set_temp(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7410_data *data = i2c_get_clientdata(client);
|
||||
int nr = attr->index;
|
||||
long temp;
|
||||
int ret;
|
||||
|
||||
ret = kstrtol(buf, 10, &temp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
|
||||
ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
|
||||
data->temp[nr]);
|
||||
if (ret)
|
||||
count = ret;
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t adt7410_show_t_hyst(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct adt7410_data *data;
|
||||
int nr = attr->index;
|
||||
int hyst;
|
||||
|
||||
data = adt7410_update_device(dev);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
|
||||
|
||||
/*
|
||||
* hysteresis is stored as a 4 bit offset in the device, convert it
|
||||
* to an absolute value
|
||||
*/
|
||||
if (nr == 2) /* min has positive offset, others have negative */
|
||||
hyst = -hyst;
|
||||
return sprintf(buf, "%d\n",
|
||||
ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
|
||||
}
|
||||
|
||||
static ssize_t adt7410_set_t_hyst(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7410_data *data = i2c_get_clientdata(client);
|
||||
int limit, ret;
|
||||
long hyst;
|
||||
|
||||
ret = kstrtol(buf, 10, &hyst);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* convert absolute hysteresis value to a 4 bit delta value */
|
||||
limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
|
||||
hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
|
||||
data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
|
||||
ADT7410_T_HYST_MASK);
|
||||
ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t adt7410_show_alarm(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", !!(ret & attr->index));
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
|
||||
adt7410_show_temp, adt7410_set_temp, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
|
||||
adt7410_show_temp, adt7410_set_temp, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
|
||||
adt7410_show_temp, adt7410_set_temp, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
|
||||
adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
|
||||
adt7410_show_t_hyst, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
|
||||
adt7410_show_t_hyst, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
|
||||
NULL, ADT7410_STAT_T_LOW);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
|
||||
NULL, ADT7410_STAT_T_HIGH);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
|
||||
NULL, ADT7410_STAT_T_CRIT);
|
||||
|
||||
static struct attribute *adt7410_attributes[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adt7410_group = {
|
||||
.attrs = adt7410_attributes,
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
/* device probe and removal */
|
||||
|
||||
static int adt7410_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adt7410_data *data;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* configure as specified */
|
||||
ret = i2c_smbus_read_byte_data(client, ADT7410_CONFIG);
|
||||
if (ret < 0) {
|
||||
dev_dbg(&client->dev, "Can't read config? %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
data->oldconfig = ret;
|
||||
/*
|
||||
* Set to 16 bit resolution, continous conversion and comparator mode.
|
||||
*/
|
||||
ret &= ~ADT7410_MODE_MASK;
|
||||
data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
|
||||
ADT7410_EVENT_MODE;
|
||||
if (data->config != data->oldconfig) {
|
||||
ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
|
||||
data->config);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
dev_dbg(&client->dev, "Config %02x\n", data->config);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
|
||||
if (ret)
|
||||
goto exit_restore;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
ret = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "sensor '%s'\n", client->name);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &adt7410_group);
|
||||
exit_restore:
|
||||
i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->oldconfig);
|
||||
return ret;
|
||||
return adt7x10_probe(&client->dev, NULL, client->irq, &adt7410_i2c_ops);
|
||||
}
|
||||
|
||||
static int adt7410_remove(struct i2c_client *client)
|
||||
static int adt7410_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct adt7410_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adt7410_group);
|
||||
if (data->oldconfig != data->config)
|
||||
i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
|
||||
data->oldconfig);
|
||||
return 0;
|
||||
return adt7x10_remove(&client->dev, client->irq);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adt7410_ids[] = {
|
||||
{ "adt7410", adt7410, },
|
||||
{ "adt7420", adt7410, },
|
||||
{ /* LIST END */ }
|
||||
{ "adt7410", 0 },
|
||||
{ "adt7420", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adt7410_ids);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int adt7410_suspend(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7410_data *data = i2c_get_clientdata(client);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
|
||||
data->config | ADT7410_PD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adt7410_resume(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7410_data *data = i2c_get_clientdata(client);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
|
||||
|
||||
#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
|
||||
#else
|
||||
#define ADT7410_DEV_PM_OPS NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct i2c_driver adt7410_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adt7410",
|
||||
.pm = ADT7410_DEV_PM_OPS,
|
||||
.pm = ADT7X10_DEV_PM_OPS,
|
||||
},
|
||||
.probe = adt7410_probe,
|
||||
.remove = adt7410_remove,
|
||||
.probe = adt7410_i2c_probe,
|
||||
.remove = adt7410_i2c_remove,
|
||||
.id_table = adt7410_ids,
|
||||
.address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
|
||||
};
|
||||
|
||||
module_i2c_driver(adt7410_driver);
|
||||
|
||||
MODULE_AUTHOR("Hartmut Knaack");
|
||||
MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ADT7410/AD7420 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -259,15 +259,17 @@ static int adt7411_detect(struct i2c_client *client,
|
|||
|
||||
val = i2c_smbus_read_byte_data(client, ADT7411_REG_MANUFACTURER_ID);
|
||||
if (val < 0 || val != ADT7411_MANUFACTURER_ID) {
|
||||
dev_dbg(&client->dev, "Wrong manufacturer ID. Got %d, "
|
||||
"expected %d\n", val, ADT7411_MANUFACTURER_ID);
|
||||
dev_dbg(&client->dev,
|
||||
"Wrong manufacturer ID. Got %d, expected %d\n",
|
||||
val, ADT7411_MANUFACTURER_ID);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
val = i2c_smbus_read_byte_data(client, ADT7411_REG_DEVICE_ID);
|
||||
if (val < 0 || val != ADT7411_DEVICE_ID) {
|
||||
dev_dbg(&client->dev, "Wrong device ID. Got %d, "
|
||||
"expected %d\n", val, ADT7411_DEVICE_ID);
|
||||
dev_dbg(&client->dev,
|
||||
"Wrong device ID. Got %d, expected %d\n",
|
||||
val, ADT7411_DEVICE_ID);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
511
drivers/hwmon/adt7x10.c
Normal file
511
drivers/hwmon/adt7x10.c
Normal file
|
@ -0,0 +1,511 @@
|
|||
/*
|
||||
* adt7x10.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* This driver handles the ADT7410 and compatible digital temperature sensors.
|
||||
* Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
|
||||
* based on lm75.c by Frodo Looijaard <frodol@dds.nl>
|
||||
* and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "adt7x10.h"
|
||||
|
||||
/*
|
||||
* ADT7X10 status
|
||||
*/
|
||||
#define ADT7X10_STAT_T_LOW (1 << 4)
|
||||
#define ADT7X10_STAT_T_HIGH (1 << 5)
|
||||
#define ADT7X10_STAT_T_CRIT (1 << 6)
|
||||
#define ADT7X10_STAT_NOT_RDY (1 << 7)
|
||||
|
||||
/*
|
||||
* ADT7X10 config
|
||||
*/
|
||||
#define ADT7X10_FAULT_QUEUE_MASK (1 << 0 | 1 << 1)
|
||||
#define ADT7X10_CT_POLARITY (1 << 2)
|
||||
#define ADT7X10_INT_POLARITY (1 << 3)
|
||||
#define ADT7X10_EVENT_MODE (1 << 4)
|
||||
#define ADT7X10_MODE_MASK (1 << 5 | 1 << 6)
|
||||
#define ADT7X10_FULL (0 << 5 | 0 << 6)
|
||||
#define ADT7X10_PD (1 << 5 | 1 << 6)
|
||||
#define ADT7X10_RESOLUTION (1 << 7)
|
||||
|
||||
/*
|
||||
* ADT7X10 masks
|
||||
*/
|
||||
#define ADT7X10_T13_VALUE_MASK 0xFFF8
|
||||
#define ADT7X10_T_HYST_MASK 0xF
|
||||
|
||||
/* straight from the datasheet */
|
||||
#define ADT7X10_TEMP_MIN (-55000)
|
||||
#define ADT7X10_TEMP_MAX 150000
|
||||
|
||||
/* Each client has this additional data */
|
||||
struct adt7x10_data {
|
||||
const struct adt7x10_ops *ops;
|
||||
const char *name;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
u8 config;
|
||||
u8 oldconfig;
|
||||
bool valid; /* true if registers valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
s16 temp[4]; /* Register values,
|
||||
0 = input
|
||||
1 = high
|
||||
2 = low
|
||||
3 = critical */
|
||||
u8 hyst; /* hysteresis offset */
|
||||
};
|
||||
|
||||
static int adt7x10_read_byte(struct device *dev, u8 reg)
|
||||
{
|
||||
struct adt7x10_data *d = dev_get_drvdata(dev);
|
||||
return d->ops->read_byte(dev, reg);
|
||||
}
|
||||
|
||||
static int adt7x10_write_byte(struct device *dev, u8 reg, u8 data)
|
||||
{
|
||||
struct adt7x10_data *d = dev_get_drvdata(dev);
|
||||
return d->ops->write_byte(dev, reg, data);
|
||||
}
|
||||
|
||||
static int adt7x10_read_word(struct device *dev, u8 reg)
|
||||
{
|
||||
struct adt7x10_data *d = dev_get_drvdata(dev);
|
||||
return d->ops->read_word(dev, reg);
|
||||
}
|
||||
|
||||
static int adt7x10_write_word(struct device *dev, u8 reg, u16 data)
|
||||
{
|
||||
struct adt7x10_data *d = dev_get_drvdata(dev);
|
||||
return d->ops->write_word(dev, reg, data);
|
||||
}
|
||||
|
||||
static const u8 ADT7X10_REG_TEMP[4] = {
|
||||
ADT7X10_TEMPERATURE, /* input */
|
||||
ADT7X10_T_ALARM_HIGH, /* high */
|
||||
ADT7X10_T_ALARM_LOW, /* low */
|
||||
ADT7X10_T_CRIT, /* critical */
|
||||
};
|
||||
|
||||
static irqreturn_t adt7x10_irq_handler(int irq, void *private)
|
||||
{
|
||||
struct device *dev = private;
|
||||
int status;
|
||||
|
||||
status = adt7x10_read_byte(dev, ADT7X10_STATUS);
|
||||
if (status < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (status & ADT7X10_STAT_T_HIGH)
|
||||
sysfs_notify(&dev->kobj, NULL, "temp1_max_alarm");
|
||||
if (status & ADT7X10_STAT_T_LOW)
|
||||
sysfs_notify(&dev->kobj, NULL, "temp1_min_alarm");
|
||||
if (status & ADT7X10_STAT_T_CRIT)
|
||||
sysfs_notify(&dev->kobj, NULL, "temp1_crit_alarm");
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int adt7x10_temp_ready(struct device *dev)
|
||||
{
|
||||
int i, status;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
status = adt7x10_read_byte(dev, ADT7X10_STATUS);
|
||||
if (status < 0)
|
||||
return status;
|
||||
if (!(status & ADT7X10_STAT_NOT_RDY))
|
||||
return 0;
|
||||
msleep(60);
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int adt7x10_update_temp(struct device *dev)
|
||||
{
|
||||
struct adt7x10_data *data = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
int temp;
|
||||
|
||||
dev_dbg(dev, "Starting update\n");
|
||||
|
||||
ret = adt7x10_temp_ready(dev); /* check for new value */
|
||||
if (ret)
|
||||
goto abort;
|
||||
|
||||
temp = adt7x10_read_word(dev, ADT7X10_REG_TEMP[0]);
|
||||
if (temp < 0) {
|
||||
ret = temp;
|
||||
dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
|
||||
ADT7X10_REG_TEMP[0], ret);
|
||||
goto abort;
|
||||
}
|
||||
data->temp[0] = temp;
|
||||
data->last_updated = jiffies;
|
||||
data->valid = true;
|
||||
}
|
||||
|
||||
abort:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adt7x10_fill_cache(struct device *dev)
|
||||
{
|
||||
struct adt7x10_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < ARRAY_SIZE(data->temp); i++) {
|
||||
ret = adt7x10_read_word(dev, ADT7X10_REG_TEMP[i]);
|
||||
if (ret < 0) {
|
||||
dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
|
||||
ADT7X10_REG_TEMP[i], ret);
|
||||
return ret;
|
||||
}
|
||||
data->temp[i] = ret;
|
||||
}
|
||||
|
||||
ret = adt7x10_read_byte(dev, ADT7X10_T_HYST);
|
||||
if (ret < 0) {
|
||||
dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
|
||||
ADT7X10_T_HYST, ret);
|
||||
return ret;
|
||||
}
|
||||
data->hyst = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s16 ADT7X10_TEMP_TO_REG(long temp)
|
||||
{
|
||||
return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7X10_TEMP_MIN,
|
||||
ADT7X10_TEMP_MAX) * 128, 1000);
|
||||
}
|
||||
|
||||
static int ADT7X10_REG_TO_TEMP(struct adt7x10_data *data, s16 reg)
|
||||
{
|
||||
/* in 13 bit mode, bits 0-2 are status flags - mask them out */
|
||||
if (!(data->config & ADT7X10_RESOLUTION))
|
||||
reg &= ADT7X10_T13_VALUE_MASK;
|
||||
/*
|
||||
* temperature is stored in twos complement format, in steps of
|
||||
* 1/128°C
|
||||
*/
|
||||
return DIV_ROUND_CLOSEST(reg * 1000, 128);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
/* sysfs attributes for hwmon */
|
||||
|
||||
static ssize_t adt7x10_show_temp(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct adt7x10_data *data = dev_get_drvdata(dev);
|
||||
|
||||
|
||||
if (attr->index == 0) {
|
||||
int ret;
|
||||
|
||||
ret = adt7x10_update_temp(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return sprintf(buf, "%d\n", ADT7X10_REG_TO_TEMP(data,
|
||||
data->temp[attr->index]));
|
||||
}
|
||||
|
||||
static ssize_t adt7x10_set_temp(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct adt7x10_data *data = dev_get_drvdata(dev);
|
||||
int nr = attr->index;
|
||||
long temp;
|
||||
int ret;
|
||||
|
||||
ret = kstrtol(buf, 10, &temp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp[nr] = ADT7X10_TEMP_TO_REG(temp);
|
||||
ret = adt7x10_write_word(dev, ADT7X10_REG_TEMP[nr], data->temp[nr]);
|
||||
if (ret)
|
||||
count = ret;
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t adt7x10_show_t_hyst(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct adt7x10_data *data = dev_get_drvdata(dev);
|
||||
int nr = attr->index;
|
||||
int hyst;
|
||||
|
||||
hyst = (data->hyst & ADT7X10_T_HYST_MASK) * 1000;
|
||||
|
||||
/*
|
||||
* hysteresis is stored as a 4 bit offset in the device, convert it
|
||||
* to an absolute value
|
||||
*/
|
||||
if (nr == 2) /* min has positive offset, others have negative */
|
||||
hyst = -hyst;
|
||||
return sprintf(buf, "%d\n",
|
||||
ADT7X10_REG_TO_TEMP(data, data->temp[nr]) - hyst);
|
||||
}
|
||||
|
||||
static ssize_t adt7x10_set_t_hyst(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct adt7x10_data *data = dev_get_drvdata(dev);
|
||||
int limit, ret;
|
||||
long hyst;
|
||||
|
||||
ret = kstrtol(buf, 10, &hyst);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* convert absolute hysteresis value to a 4 bit delta value */
|
||||
limit = ADT7X10_REG_TO_TEMP(data, data->temp[1]);
|
||||
hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX);
|
||||
data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000),
|
||||
0, ADT7X10_T_HYST_MASK);
|
||||
ret = adt7x10_write_byte(dev, ADT7X10_T_HYST, data->hyst);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t adt7x10_show_alarm(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
int ret;
|
||||
|
||||
ret = adt7x10_read_byte(dev, ADT7X10_STATUS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", !!(ret & attr->index));
|
||||
}
|
||||
|
||||
static ssize_t adt7x10_show_name(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct adt7x10_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", data->name);
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7x10_show_temp, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
|
||||
adt7x10_show_temp, adt7x10_set_temp, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
|
||||
adt7x10_show_temp, adt7x10_set_temp, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
|
||||
adt7x10_show_temp, adt7x10_set_temp, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
|
||||
adt7x10_show_t_hyst, adt7x10_set_t_hyst, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
|
||||
adt7x10_show_t_hyst, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
|
||||
adt7x10_show_t_hyst, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7x10_show_alarm,
|
||||
NULL, ADT7X10_STAT_T_LOW);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7x10_show_alarm,
|
||||
NULL, ADT7X10_STAT_T_HIGH);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7x10_show_alarm,
|
||||
NULL, ADT7X10_STAT_T_CRIT);
|
||||
static DEVICE_ATTR(name, S_IRUGO, adt7x10_show_name, NULL);
|
||||
|
||||
static struct attribute *adt7x10_attributes[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adt7x10_group = {
|
||||
.attrs = adt7x10_attributes,
|
||||
};
|
||||
|
||||
int adt7x10_probe(struct device *dev, const char *name, int irq,
|
||||
const struct adt7x10_ops *ops)
|
||||
{
|
||||
struct adt7x10_data *data;
|
||||
int ret;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->ops = ops;
|
||||
data->name = name;
|
||||
|
||||
dev_set_drvdata(dev, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* configure as specified */
|
||||
ret = adt7x10_read_byte(dev, ADT7X10_CONFIG);
|
||||
if (ret < 0) {
|
||||
dev_dbg(dev, "Can't read config? %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
data->oldconfig = ret;
|
||||
|
||||
/*
|
||||
* Set to 16 bit resolution, continous conversion and comparator mode.
|
||||
*/
|
||||
data->config = data->oldconfig;
|
||||
data->config &= ~(ADT7X10_MODE_MASK | ADT7X10_CT_POLARITY |
|
||||
ADT7X10_INT_POLARITY);
|
||||
data->config |= ADT7X10_FULL | ADT7X10_RESOLUTION | ADT7X10_EVENT_MODE;
|
||||
|
||||
if (data->config != data->oldconfig) {
|
||||
ret = adt7x10_write_byte(dev, ADT7X10_CONFIG, data->config);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
dev_dbg(dev, "Config %02x\n", data->config);
|
||||
|
||||
ret = adt7x10_fill_cache(dev);
|
||||
if (ret)
|
||||
goto exit_restore;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
ret = sysfs_create_group(&dev->kobj, &adt7x10_group);
|
||||
if (ret)
|
||||
goto exit_restore;
|
||||
|
||||
/*
|
||||
* The I2C device will already have it's own 'name' attribute, but for
|
||||
* the SPI device we need to register it. name will only be non NULL if
|
||||
* the device doesn't register the 'name' attribute on its own.
|
||||
*/
|
||||
if (name) {
|
||||
ret = device_create_file(dev, &dev_attr_name);
|
||||
if (ret)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
ret = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_name;
|
||||
}
|
||||
|
||||
if (irq > 0) {
|
||||
ret = request_threaded_irq(irq, NULL, adt7x10_irq_handler,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
dev_name(dev), dev);
|
||||
if (ret)
|
||||
goto exit_hwmon_device_unregister;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_hwmon_device_unregister:
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
exit_remove_name:
|
||||
if (name)
|
||||
device_remove_file(dev, &dev_attr_name);
|
||||
exit_remove:
|
||||
sysfs_remove_group(&dev->kobj, &adt7x10_group);
|
||||
exit_restore:
|
||||
adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adt7x10_probe);
|
||||
|
||||
int adt7x10_remove(struct device *dev, int irq)
|
||||
{
|
||||
struct adt7x10_data *data = dev_get_drvdata(dev);
|
||||
|
||||
if (irq > 0)
|
||||
free_irq(irq, dev);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
if (data->name)
|
||||
device_remove_file(dev, &dev_attr_name);
|
||||
sysfs_remove_group(&dev->kobj, &adt7x10_group);
|
||||
if (data->oldconfig != data->config)
|
||||
adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(adt7x10_remove);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int adt7x10_suspend(struct device *dev)
|
||||
{
|
||||
struct adt7x10_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return adt7x10_write_byte(dev, ADT7X10_CONFIG,
|
||||
data->config | ADT7X10_PD);
|
||||
}
|
||||
|
||||
static int adt7x10_resume(struct device *dev)
|
||||
{
|
||||
struct adt7x10_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return adt7x10_write_byte(dev, ADT7X10_CONFIG, data->config);
|
||||
}
|
||||
|
||||
SIMPLE_DEV_PM_OPS(adt7x10_dev_pm_ops, adt7x10_suspend, adt7x10_resume);
|
||||
EXPORT_SYMBOL_GPL(adt7x10_dev_pm_ops);
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
MODULE_AUTHOR("Hartmut Knaack");
|
||||
MODULE_DESCRIPTION("ADT7410/ADT7420, ADT7310/ADT7320 common code");
|
||||
MODULE_LICENSE("GPL");
|
37
drivers/hwmon/adt7x10.h
Normal file
37
drivers/hwmon/adt7x10.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef __HWMON_ADT7X10_H__
|
||||
#define __HWMON_ADT7X10_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
/* ADT7410 registers definition */
|
||||
#define ADT7X10_TEMPERATURE 0
|
||||
#define ADT7X10_STATUS 2
|
||||
#define ADT7X10_CONFIG 3
|
||||
#define ADT7X10_T_ALARM_HIGH 4
|
||||
#define ADT7X10_T_ALARM_LOW 6
|
||||
#define ADT7X10_T_CRIT 8
|
||||
#define ADT7X10_T_HYST 0xA
|
||||
#define ADT7X10_ID 0xB
|
||||
|
||||
struct device;
|
||||
|
||||
struct adt7x10_ops {
|
||||
int (*read_byte)(struct device *, u8 reg);
|
||||
int (*write_byte)(struct device *, u8 reg, u8 data);
|
||||
int (*read_word)(struct device *, u8 reg);
|
||||
int (*write_word)(struct device *, u8 reg, u16 data);
|
||||
};
|
||||
|
||||
int adt7x10_probe(struct device *dev, const char *name, int irq,
|
||||
const struct adt7x10_ops *ops);
|
||||
int adt7x10_remove(struct device *dev, int irq);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
extern const struct dev_pm_ops adt7x10_dev_pm_ops;
|
||||
#define ADT7X10_DEV_PM_OPS (&adt7x10_dev_pm_ops)
|
||||
#else
|
||||
#define ADT7X10_DEV_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -922,7 +922,7 @@ static void applesmc_brightness_set(struct led_classdev *led_cdev,
|
|||
ret = queue_work(applesmc_led_wq, &backlight_work);
|
||||
|
||||
if (debug && (!ret))
|
||||
printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
|
||||
dev_dbg(led_cdev->dev, "work was already on the queue.\n");
|
||||
}
|
||||
|
||||
static ssize_t applesmc_key_count_show(struct device *dev,
|
||||
|
|
|
@ -55,8 +55,8 @@ static const unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
|
|||
|
||||
static unsigned short force_subclients[4];
|
||||
module_param_array(force_subclients, short, NULL, 0);
|
||||
MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
|
||||
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
|
||||
MODULE_PARM_DESC(force_subclients,
|
||||
"List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
|
||||
|
||||
/* Voltage IN registers 0-6 */
|
||||
#define ASB100_REG_IN(nr) (0x20 + (nr))
|
||||
|
@ -689,8 +689,8 @@ static int asb100_detect_subclients(struct i2c_client *client)
|
|||
for (i = 2; i <= 3; i++) {
|
||||
if (force_subclients[i] < 0x48 ||
|
||||
force_subclients[i] > 0x4f) {
|
||||
dev_err(&client->dev, "invalid subclient "
|
||||
"address %d; must be 0x48-0x4f\n",
|
||||
dev_err(&client->dev,
|
||||
"invalid subclient address %d; must be 0x48-0x4f\n",
|
||||
force_subclients[i]);
|
||||
err = -ENODEV;
|
||||
goto ERROR_SC_2;
|
||||
|
@ -708,24 +708,27 @@ static int asb100_detect_subclients(struct i2c_client *client)
|
|||
}
|
||||
|
||||
if (sc_addr[0] == sc_addr[1]) {
|
||||
dev_err(&client->dev, "duplicate addresses 0x%x "
|
||||
"for subclients\n", sc_addr[0]);
|
||||
dev_err(&client->dev,
|
||||
"duplicate addresses 0x%x for subclients\n",
|
||||
sc_addr[0]);
|
||||
err = -ENODEV;
|
||||
goto ERROR_SC_2;
|
||||
}
|
||||
|
||||
data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
|
||||
if (!data->lm75[0]) {
|
||||
dev_err(&client->dev, "subclient %d registration "
|
||||
"at address 0x%x failed.\n", 1, sc_addr[0]);
|
||||
dev_err(&client->dev,
|
||||
"subclient %d registration at address 0x%x failed.\n",
|
||||
1, sc_addr[0]);
|
||||
err = -ENOMEM;
|
||||
goto ERROR_SC_2;
|
||||
}
|
||||
|
||||
data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
|
||||
if (!data->lm75[1]) {
|
||||
dev_err(&client->dev, "subclient %d registration "
|
||||
"at address 0x%x failed.\n", 2, sc_addr[1]);
|
||||
dev_err(&client->dev,
|
||||
"subclient %d registration at address 0x%x failed.\n",
|
||||
2, sc_addr[1]);
|
||||
err = -ENOMEM;
|
||||
goto ERROR_SC_3;
|
||||
}
|
||||
|
|
|
@ -159,12 +159,12 @@ static inline int write_byte(struct i2c_client *client, u8 reg, u8 data)
|
|||
* and retrieval of like parameters.
|
||||
*/
|
||||
|
||||
#define SETUP_SHOW_data_param(d, a) \
|
||||
#define SETUP_SHOW_DATA_PARAM(d, a) \
|
||||
struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
|
||||
struct asc7621_data *data = asc7621_update_device(d); \
|
||||
struct asc7621_param *param = to_asc7621_param(sda)
|
||||
|
||||
#define SETUP_STORE_data_param(d, a) \
|
||||
#define SETUP_STORE_DATA_PARAM(d, a) \
|
||||
struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
|
||||
struct i2c_client *client = to_i2c_client(d); \
|
||||
struct asc7621_data *data = i2c_get_clientdata(client); \
|
||||
|
@ -177,7 +177,7 @@ static inline int write_byte(struct i2c_client *client, u8 reg, u8 data)
|
|||
static ssize_t show_u8(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
|
||||
return sprintf(buf, "%u\n", data->reg[param->msb[0]]);
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ static ssize_t show_u8(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
SETUP_STORE_data_param(dev, attr);
|
||||
SETUP_STORE_DATA_PARAM(dev, attr);
|
||||
long reqval;
|
||||
|
||||
if (kstrtol(buf, 10, &reqval))
|
||||
|
@ -206,7 +206,7 @@ static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t show_bitmask(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
|
||||
return sprintf(buf, "%u\n",
|
||||
(data->reg[param->msb[0]] >> param->
|
||||
|
@ -217,7 +217,7 @@ static ssize_t store_bitmask(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
SETUP_STORE_data_param(dev, attr);
|
||||
SETUP_STORE_DATA_PARAM(dev, attr);
|
||||
long reqval;
|
||||
u8 currval;
|
||||
|
||||
|
@ -246,7 +246,7 @@ static ssize_t store_bitmask(struct device *dev,
|
|||
static ssize_t show_fan16(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
u16 regval;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
@ -262,7 +262,7 @@ static ssize_t store_fan16(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
SETUP_STORE_data_param(dev, attr);
|
||||
SETUP_STORE_DATA_PARAM(dev, attr);
|
||||
long reqval;
|
||||
|
||||
if (kstrtol(buf, 10, &reqval))
|
||||
|
@ -307,7 +307,7 @@ static int asc7621_in_scaling[] = {
|
|||
static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
u16 regval;
|
||||
u8 nr = sda->index;
|
||||
|
||||
|
@ -325,7 +325,7 @@ static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t show_in8(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
u8 nr = sda->index;
|
||||
|
||||
return sprintf(buf, "%u\n",
|
||||
|
@ -336,7 +336,7 @@ static ssize_t show_in8(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
SETUP_STORE_data_param(dev, attr);
|
||||
SETUP_STORE_DATA_PARAM(dev, attr);
|
||||
long reqval;
|
||||
u8 nr = sda->index;
|
||||
|
||||
|
@ -360,7 +360,7 @@ static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t show_temp8(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
|
||||
return sprintf(buf, "%d\n", ((s8) data->reg[param->msb[0]]) * 1000);
|
||||
}
|
||||
|
@ -369,7 +369,7 @@ static ssize_t store_temp8(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
SETUP_STORE_data_param(dev, attr);
|
||||
SETUP_STORE_DATA_PARAM(dev, attr);
|
||||
long reqval;
|
||||
s8 temp;
|
||||
|
||||
|
@ -397,7 +397,7 @@ static ssize_t store_temp8(struct device *dev,
|
|||
static ssize_t show_temp10(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
u8 msb, lsb;
|
||||
int temp;
|
||||
|
||||
|
@ -414,7 +414,7 @@ static ssize_t show_temp10(struct device *dev,
|
|||
static ssize_t show_temp62(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
u8 regval = data->reg[param->msb[0]];
|
||||
int temp = ((s8) (regval & 0xfc) * 1000) + ((regval & 0x03) * 250);
|
||||
|
||||
|
@ -425,7 +425,7 @@ static ssize_t store_temp62(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
SETUP_STORE_data_param(dev, attr);
|
||||
SETUP_STORE_DATA_PARAM(dev, attr);
|
||||
long reqval, i, f;
|
||||
s8 temp;
|
||||
|
||||
|
@ -459,7 +459,7 @@ static u32 asc7621_range_map[] = {
|
|||
static ssize_t show_ap2_temp(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
long auto_point1;
|
||||
u8 regval;
|
||||
int temp;
|
||||
|
@ -479,7 +479,7 @@ static ssize_t store_ap2_temp(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
SETUP_STORE_data_param(dev, attr);
|
||||
SETUP_STORE_DATA_PARAM(dev, attr);
|
||||
long reqval, auto_point1;
|
||||
int i;
|
||||
u8 currval, newval = 0;
|
||||
|
@ -510,7 +510,7 @@ static ssize_t store_ap2_temp(struct device *dev,
|
|||
static ssize_t show_pwm_ac(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
u8 config, altbit, regval;
|
||||
u8 map[] = {
|
||||
0x01, 0x02, 0x04, 0x1f, 0x00, 0x06, 0x07, 0x10,
|
||||
|
@ -530,7 +530,7 @@ static ssize_t store_pwm_ac(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
SETUP_STORE_data_param(dev, attr);
|
||||
SETUP_STORE_DATA_PARAM(dev, attr);
|
||||
unsigned long reqval;
|
||||
u8 currval, config, altbit, newval;
|
||||
u16 map[] = {
|
||||
|
@ -569,7 +569,7 @@ static ssize_t store_pwm_ac(struct device *dev,
|
|||
static ssize_t show_pwm_enable(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
u8 config, altbit, minoff, val, newval;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
@ -599,7 +599,7 @@ static ssize_t store_pwm_enable(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
SETUP_STORE_data_param(dev, attr);
|
||||
SETUP_STORE_DATA_PARAM(dev, attr);
|
||||
long reqval;
|
||||
u8 currval, config, altbit, newval, minoff = 255;
|
||||
|
||||
|
@ -659,7 +659,7 @@ static u32 asc7621_pwm_freq_map[] = {
|
|||
static ssize_t show_pwm_freq(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
u8 regval =
|
||||
(data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
|
||||
|
||||
|
@ -672,7 +672,7 @@ static ssize_t store_pwm_freq(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
SETUP_STORE_data_param(dev, attr);
|
||||
SETUP_STORE_DATA_PARAM(dev, attr);
|
||||
unsigned long reqval;
|
||||
u8 currval, newval = 255;
|
||||
int i;
|
||||
|
@ -707,7 +707,7 @@ static u32 asc7621_pwm_auto_spinup_map[] = {
|
|||
static ssize_t show_pwm_ast(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
u8 regval =
|
||||
(data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
|
||||
|
||||
|
@ -721,7 +721,7 @@ static ssize_t store_pwm_ast(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
SETUP_STORE_data_param(dev, attr);
|
||||
SETUP_STORE_DATA_PARAM(dev, attr);
|
||||
long reqval;
|
||||
u8 currval, newval = 255;
|
||||
u32 i;
|
||||
|
@ -756,7 +756,7 @@ static u32 asc7621_temp_smoothing_time_map[] = {
|
|||
static ssize_t show_temp_st(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
SETUP_SHOW_data_param(dev, attr);
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
u8 regval =
|
||||
(data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
|
||||
regval = clamp_val(regval, 0, 7);
|
||||
|
@ -768,7 +768,7 @@ static ssize_t store_temp_st(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
SETUP_STORE_data_param(dev, attr);
|
||||
SETUP_STORE_DATA_PARAM(dev, attr);
|
||||
long reqval;
|
||||
u8 currval, newval = 255;
|
||||
u32 i;
|
||||
|
|
|
@ -411,8 +411,7 @@ static int __cpuinit chk_ucode_version(unsigned int cpu)
|
|||
* fixed for stepping D0 (6EC).
|
||||
*/
|
||||
if (c->x86_model == 0xe && c->x86_mask < 0xc && c->microcode < 0x39) {
|
||||
pr_err("Errata AE18 not fixed, update BIOS or "
|
||||
"microcode of the CPU!\n");
|
||||
pr_err("Errata AE18 not fixed, update BIOS or microcode of the CPU!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -43,19 +43,19 @@ static const char * const input_names[] = {
|
|||
};
|
||||
|
||||
/* Conversion function for VDDOUT and VBAT */
|
||||
static inline int volt_reg_to_mV(int value)
|
||||
static inline int volt_reg_to_mv(int value)
|
||||
{
|
||||
return DIV_ROUND_CLOSEST(value * 1000, 512) + 2500;
|
||||
}
|
||||
|
||||
/* Conversion function for ADC channels 4, 5 and 6 */
|
||||
static inline int input_reg_to_mV(int value)
|
||||
static inline int input_reg_to_mv(int value)
|
||||
{
|
||||
return DIV_ROUND_CLOSEST(value * 2500, 1023);
|
||||
}
|
||||
|
||||
/* Conversion function for VBBAT */
|
||||
static inline int vbbat_reg_to_mV(int value)
|
||||
static inline int vbbat_reg_to_mv(int value)
|
||||
{
|
||||
return DIV_ROUND_CLOSEST(value * 2500, 512);
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ static ssize_t da9052_read_vddout(struct device *dev,
|
|||
goto hwmon_err;
|
||||
|
||||
mutex_unlock(&hwmon->hwmon_lock);
|
||||
return sprintf(buf, "%d\n", volt_reg_to_mV(vdd));
|
||||
return sprintf(buf, "%d\n", volt_reg_to_mv(vdd));
|
||||
|
||||
hwmon_err_release:
|
||||
da9052_disable_vddout_channel(hwmon->da9052);
|
||||
|
@ -137,7 +137,7 @@ static ssize_t da9052_read_vbat(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", volt_reg_to_mV(ret));
|
||||
return sprintf(buf, "%d\n", volt_reg_to_mv(ret));
|
||||
}
|
||||
|
||||
static ssize_t da9052_read_misc_channel(struct device *dev,
|
||||
|
@ -152,7 +152,7 @@ static ssize_t da9052_read_misc_channel(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", input_reg_to_mV(ret));
|
||||
return sprintf(buf, "%d\n", input_reg_to_mv(ret));
|
||||
}
|
||||
|
||||
static ssize_t da9052_read_tjunc(struct device *dev,
|
||||
|
@ -187,7 +187,7 @@ static ssize_t da9052_read_vbbat(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", vbbat_reg_to_mV(ret));
|
||||
return sprintf(buf, "%d\n", vbbat_reg_to_mv(ret));
|
||||
}
|
||||
|
||||
static ssize_t da9052_hwmon_show_name(struct device *dev,
|
||||
|
|
|
@ -119,7 +119,7 @@ static irqreturn_t da9055_auxadc_irq(int irq, void *irq_data)
|
|||
}
|
||||
|
||||
/* Conversion function for VSYS and ADCINx */
|
||||
static inline int volt_reg_to_mV(int value, int channel)
|
||||
static inline int volt_reg_to_mv(int value, int channel)
|
||||
{
|
||||
if (channel == DA9055_ADC_VSYS)
|
||||
return DIV_ROUND_CLOSEST(value * 1000, DA9055_VSYS_DIV) + 2500;
|
||||
|
@ -168,7 +168,7 @@ static ssize_t da9055_read_auto_ch(struct device *dev,
|
|||
|
||||
mutex_unlock(&hwmon->hwmon_lock);
|
||||
|
||||
return sprintf(buf, "%d\n", volt_reg_to_mV(adc, channel));
|
||||
return sprintf(buf, "%d\n", volt_reg_to_mv(adc, channel));
|
||||
|
||||
hwmon_err_release:
|
||||
da9055_disable_auto_mode(hwmon->da9055, channel);
|
||||
|
|
|
@ -55,14 +55,16 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
|
|||
|
||||
static bool probe_all_addr;
|
||||
module_param(probe_all_addr, bool, 0);
|
||||
MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC "
|
||||
"addresses");
|
||||
MODULE_PARM_DESC(probe_all_addr,
|
||||
"Include probing of non-standard LPC addresses");
|
||||
|
||||
/* Addresses to scan */
|
||||
static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
|
||||
|
||||
enum chips { dme1737, sch5027, sch311x, sch5127 };
|
||||
|
||||
#define DO_REPORT "Please report to the driver maintainer."
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* Registers
|
||||
*
|
||||
|
@ -566,9 +568,9 @@ static u8 dme1737_read(const struct dme1737_data *data, u8 reg)
|
|||
val = i2c_smbus_read_byte_data(client, reg);
|
||||
|
||||
if (val < 0) {
|
||||
dev_warn(&client->dev, "Read from register "
|
||||
"0x%02x failed! Please report to the driver "
|
||||
"maintainer.\n", reg);
|
||||
dev_warn(&client->dev,
|
||||
"Read from register 0x%02x failed! %s\n",
|
||||
reg, DO_REPORT);
|
||||
}
|
||||
} else { /* ISA device */
|
||||
outb(reg, data->addr);
|
||||
|
@ -587,9 +589,9 @@ static s32 dme1737_write(const struct dme1737_data *data, u8 reg, u8 val)
|
|||
res = i2c_smbus_write_byte_data(client, reg, val);
|
||||
|
||||
if (res < 0) {
|
||||
dev_warn(&client->dev, "Write to register "
|
||||
"0x%02x failed! Please report to the driver "
|
||||
"maintainer.\n", reg);
|
||||
dev_warn(&client->dev,
|
||||
"Write to register 0x%02x failed! %s\n",
|
||||
reg, DO_REPORT);
|
||||
}
|
||||
} else { /* ISA device */
|
||||
outb(reg, data->addr);
|
||||
|
@ -1167,8 +1169,8 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
|
|||
/* Only valid for fan[1-4] */
|
||||
if (!(val == 1 || val == 2 || val == 4)) {
|
||||
count = -EINVAL;
|
||||
dev_warn(dev, "Fan type value %ld not "
|
||||
"supported. Choose one of 1, 2, or 4.\n",
|
||||
dev_warn(dev,
|
||||
"Fan type value %ld not supported. Choose one of 1, 2, or 4.\n",
|
||||
val);
|
||||
goto exit;
|
||||
}
|
||||
|
@ -1294,8 +1296,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
|||
/* Only valid for pwm[1-3] */
|
||||
if (val < 0 || val > 2) {
|
||||
count = -EINVAL;
|
||||
dev_warn(dev, "PWM enable %ld not "
|
||||
"supported. Choose one of 0, 1, or 2.\n",
|
||||
dev_warn(dev,
|
||||
"PWM enable %ld not supported. Choose one of 0, 1, or 2.\n",
|
||||
val);
|
||||
goto exit;
|
||||
}
|
||||
|
@ -1399,8 +1401,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
|||
if (!(val == 1 || val == 2 || val == 4 ||
|
||||
val == 6 || val == 7)) {
|
||||
count = -EINVAL;
|
||||
dev_warn(dev, "PWM auto channels zone %ld "
|
||||
"not supported. Choose one of 1, 2, 4, 6, "
|
||||
dev_warn(dev,
|
||||
"PWM auto channels zone %ld not supported. Choose one of 1, 2, 4, 6, "
|
||||
"or 7.\n", val);
|
||||
goto exit;
|
||||
}
|
||||
|
@ -2178,8 +2180,8 @@ static int dme1737_create_files(struct device *dev)
|
|||
* selected attributes from read-only to read-writeable.
|
||||
*/
|
||||
if (data->config & 0x02) {
|
||||
dev_info(dev, "Device is locked. Some attributes "
|
||||
"will be read-only.\n");
|
||||
dev_info(dev,
|
||||
"Device is locked. Some attributes will be read-only.\n");
|
||||
} else {
|
||||
/* Change permissions of zone sysfs attributes */
|
||||
dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
|
||||
|
@ -2247,9 +2249,8 @@ static int dme1737_init_device(struct device *dev)
|
|||
/* Inform if part is not monitoring/started */
|
||||
if (!(data->config & 0x01)) {
|
||||
if (!force_start) {
|
||||
dev_err(dev, "Device is not monitoring. "
|
||||
"Use the force_start load parameter to "
|
||||
"override.\n");
|
||||
dev_err(dev,
|
||||
"Device is not monitoring. Use the force_start load parameter to override.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
|
@ -2289,8 +2290,8 @@ static int dme1737_init_device(struct device *dev)
|
|||
*/
|
||||
if (dme1737_i2c_get_features(0x2e, data) &&
|
||||
dme1737_i2c_get_features(0x4e, data)) {
|
||||
dev_warn(dev, "Failed to query Super-IO for optional "
|
||||
"features.\n");
|
||||
dev_warn(dev,
|
||||
"Failed to query Super-IO for optional features.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2317,8 +2318,8 @@ static int dme1737_init_device(struct device *dev)
|
|||
break;
|
||||
}
|
||||
|
||||
dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
|
||||
"fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
|
||||
dev_info(dev,
|
||||
"Optional features: pwm3=%s, pwm5=%s, pwm6=%s, fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
|
||||
(data->has_features & HAS_PWM(2)) ? "yes" : "no",
|
||||
(data->has_features & HAS_PWM(4)) ? "yes" : "no",
|
||||
(data->has_features & HAS_PWM(5)) ? "yes" : "no",
|
||||
|
@ -2330,18 +2331,16 @@ static int dme1737_init_device(struct device *dev)
|
|||
reg = dme1737_read(data, DME1737_REG_TACH_PWM);
|
||||
/* Inform if fan-to-pwm mapping differs from the default */
|
||||
if (client && reg != 0xa4) { /* I2C chip */
|
||||
dev_warn(dev, "Non-standard fan to pwm mapping: "
|
||||
"fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
|
||||
"fan4->pwm%d. Please report to the driver "
|
||||
"maintainer.\n",
|
||||
dev_warn(dev,
|
||||
"Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, fan4->pwm%d. %s\n",
|
||||
(reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
|
||||
((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
|
||||
((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1,
|
||||
DO_REPORT);
|
||||
} else if (!client && reg != 0x24) { /* ISA chip */
|
||||
dev_warn(dev, "Non-standard fan to pwm mapping: "
|
||||
"fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. "
|
||||
"Please report to the driver maintainer.\n",
|
||||
dev_warn(dev,
|
||||
"Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. %s\n",
|
||||
(reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
|
||||
((reg >> 4) & 0x03) + 1);
|
||||
((reg >> 4) & 0x03) + 1, DO_REPORT);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2355,8 +2354,9 @@ static int dme1737_init_device(struct device *dev)
|
|||
DME1737_REG_PWM_CONFIG(ix));
|
||||
if ((data->has_features & HAS_PWM(ix)) &&
|
||||
(PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
|
||||
dev_info(dev, "Switching pwm%d to "
|
||||
"manual mode.\n", ix + 1);
|
||||
dev_info(dev,
|
||||
"Switching pwm%d to manual mode.\n",
|
||||
ix + 1);
|
||||
data->pwm_config[ix] = PWM_EN_TO_REG(1,
|
||||
data->pwm_config[ix]);
|
||||
dme1737_write(data, DME1737_REG_PWM(ix), 0);
|
||||
|
|
|
@ -1350,8 +1350,7 @@ static void f71805f_init_device(struct f71805f_data *data)
|
|||
|
||||
reg = f71805f_read8(data, F71805F_REG_START);
|
||||
if ((reg & 0x41) != 0x01) {
|
||||
printk(KERN_DEBUG DRVNAME ": Starting monitoring "
|
||||
"operations\n");
|
||||
pr_debug("Starting monitoring operations\n");
|
||||
f71805f_write8(data, F71805F_REG_START, (reg | 0x01) & ~0x40);
|
||||
}
|
||||
|
||||
|
|
|
@ -189,8 +189,8 @@ static void fam15h_power_init_data(struct pci_dev *f4,
|
|||
|
||||
/* result not allowed to be >= 256W */
|
||||
if ((tmp >> 16) >= 256)
|
||||
dev_warn(&f4->dev, "Bogus value for ProcessorPwrWatts "
|
||||
"(processor_pwr_watts>=%u)\n",
|
||||
dev_warn(&f4->dev,
|
||||
"Bogus value for ProcessorPwrWatts (processor_pwr_watts>=%u)\n",
|
||||
(unsigned int) (tmp >> 16));
|
||||
|
||||
/* convert to microWatt */
|
||||
|
|
|
@ -463,8 +463,9 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute
|
|||
v = 3;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "fan_div value %lu not supported. "
|
||||
"Choose one of 2, 4 or 8!\n", v);
|
||||
dev_err(dev,
|
||||
"fan_div value %lu not supported. Choose one of 2, 4 or 8!\n",
|
||||
v);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1249,8 +1250,8 @@ static int fschmd_probe(struct i2c_client *client,
|
|||
}
|
||||
if (i == ARRAY_SIZE(watchdog_minors)) {
|
||||
data->watchdog_miscdev.minor = 0;
|
||||
dev_warn(&client->dev, "Couldn't register watchdog chardev "
|
||||
"(due to no free minor)\n");
|
||||
dev_warn(&client->dev,
|
||||
"Couldn't register watchdog chardev (due to no free minor)\n");
|
||||
}
|
||||
mutex_unlock(&watchdog_data_mutex);
|
||||
|
||||
|
|
|
@ -344,8 +344,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
|||
val = 3;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid fan clock divider %lu, choose one "
|
||||
"of 1, 2, 4 or 8\n", val);
|
||||
dev_err(dev,
|
||||
"Invalid fan clock divider %lu, choose one of 1, 2, 4 or 8\n",
|
||||
val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,10 +105,6 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = device_create_file(&pdev->dev, &dev_attr_fan1_alarm);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* If the alarm GPIO don't support interrupts, just leave
|
||||
* without initializing the fail notification support.
|
||||
|
@ -121,23 +117,9 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data,
|
|||
irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
|
||||
err = devm_request_irq(&pdev->dev, alarm_irq, fan_alarm_irq_handler,
|
||||
IRQF_SHARED, "GPIO fan alarm", fan_data);
|
||||
if (err)
|
||||
goto err_free_sysfs;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_sysfs:
|
||||
device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void fan_alarm_free(struct gpio_fan_data *fan_data)
|
||||
{
|
||||
struct platform_device *pdev = fan_data->pdev;
|
||||
|
||||
device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Control GPIOs.
|
||||
*/
|
||||
|
@ -327,6 +309,12 @@ exit_unlock:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t show_name(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "gpio-fan\n");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm);
|
||||
static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
|
||||
show_pwm_enable, set_pwm_enable);
|
||||
|
@ -336,8 +324,26 @@ static DEVICE_ATTR(fan1_max, S_IRUGO, show_rpm_max, NULL);
|
|||
static DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, NULL);
|
||||
static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_rpm, set_rpm);
|
||||
|
||||
static struct attribute *gpio_fan_ctrl_attributes[] = {
|
||||
&dev_attr_pwm1.attr,
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
static umode_t gpio_fan_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int index)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct gpio_fan_data *data = dev_get_drvdata(dev);
|
||||
|
||||
if (index == 1 && !data->alarm)
|
||||
return 0;
|
||||
if (index > 1 && !data->ctrl)
|
||||
return 0;
|
||||
|
||||
return attr->mode;
|
||||
}
|
||||
|
||||
static struct attribute *gpio_fan_attributes[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_fan1_alarm.attr, /* 1 */
|
||||
&dev_attr_pwm1.attr, /* 2 */
|
||||
&dev_attr_pwm1_enable.attr,
|
||||
&dev_attr_pwm1_mode.attr,
|
||||
&dev_attr_fan1_input.attr,
|
||||
|
@ -347,8 +353,9 @@ static struct attribute *gpio_fan_ctrl_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group gpio_fan_ctrl_group = {
|
||||
.attrs = gpio_fan_ctrl_attributes,
|
||||
static const struct attribute_group gpio_fan_group = {
|
||||
.attrs = gpio_fan_attributes,
|
||||
.is_visible = gpio_fan_is_visible,
|
||||
};
|
||||
|
||||
static int fan_ctrl_init(struct gpio_fan_data *fan_data,
|
||||
|
@ -379,30 +386,9 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data,
|
|||
if (fan_data->speed_index < 0)
|
||||
return -ENODEV;
|
||||
|
||||
err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fan_ctrl_free(struct gpio_fan_data *fan_data)
|
||||
{
|
||||
struct platform_device *pdev = fan_data->pdev;
|
||||
|
||||
sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
|
||||
}
|
||||
|
||||
/*
|
||||
* Platform driver.
|
||||
*/
|
||||
|
||||
static ssize_t show_name(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "gpio-fan\n");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
/*
|
||||
* Translate OpenFirmware node properties into platform_data
|
||||
|
@ -546,38 +532,30 @@ static int gpio_fan_probe(struct platform_device *pdev)
|
|||
|
||||
/* Configure control GPIOs if available. */
|
||||
if (pdata->ctrl && pdata->num_ctrl > 0) {
|
||||
if (!pdata->speed || pdata->num_speed <= 1) {
|
||||
err = -EINVAL;
|
||||
goto err_free_alarm;
|
||||
}
|
||||
if (!pdata->speed || pdata->num_speed <= 1)
|
||||
return -EINVAL;
|
||||
err = fan_ctrl_init(fan_data, pdata);
|
||||
if (err)
|
||||
goto err_free_alarm;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = device_create_file(&pdev->dev, &dev_attr_name);
|
||||
err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_group);
|
||||
if (err)
|
||||
goto err_free_ctrl;
|
||||
return err;
|
||||
|
||||
/* Make this driver part of hwmon class. */
|
||||
fan_data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(fan_data->hwmon_dev)) {
|
||||
err = PTR_ERR(fan_data->hwmon_dev);
|
||||
goto err_remove_name;
|
||||
goto err_remove;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "GPIO fan initialized\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_name:
|
||||
device_remove_file(&pdev->dev, &dev_attr_name);
|
||||
err_free_ctrl:
|
||||
if (fan_data->ctrl)
|
||||
fan_ctrl_free(fan_data);
|
||||
err_free_alarm:
|
||||
if (fan_data->alarm)
|
||||
fan_alarm_free(fan_data);
|
||||
err_remove:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -586,11 +564,7 @@ static int gpio_fan_remove(struct platform_device *pdev)
|
|||
struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(fan_data->hwmon_dev);
|
||||
device_remove_file(&pdev->dev, &dev_attr_name);
|
||||
if (fan_data->alarm)
|
||||
fan_alarm_free(fan_data);
|
||||
if (fan_data->ctrl)
|
||||
fan_ctrl_free(fan_data);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -619,7 +593,7 @@ static int gpio_fan_resume(struct device *dev)
|
|||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
|
||||
#define GPIO_FAN_PM &gpio_fan_pm
|
||||
#define GPIO_FAN_PM (&gpio_fan_pm)
|
||||
#else
|
||||
#define GPIO_FAN_PM NULL
|
||||
#endif
|
||||
|
|
|
@ -289,8 +289,9 @@ static int aem_init_ipmi_data(struct aem_ipmi_data *data, int iface,
|
|||
err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
|
||||
data, &data->user);
|
||||
if (err < 0) {
|
||||
dev_err(bmc, "Unable to register user with IPMI "
|
||||
"interface %d\n", data->interface);
|
||||
dev_err(bmc,
|
||||
"Unable to register user with IPMI interface %d\n",
|
||||
data->interface);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
|
@ -328,8 +329,8 @@ static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
|
|||
struct aem_ipmi_data *data = user_msg_data;
|
||||
|
||||
if (msg->msgid != data->tx_msgid) {
|
||||
dev_err(data->bmc_device, "Mismatch between received msgid "
|
||||
"(%02x) and transmitted msgid (%02x)!\n",
|
||||
dev_err(data->bmc_device,
|
||||
"Mismatch between received msgid (%02x) and transmitted msgid (%02x)!\n",
|
||||
(int)msg->msgid,
|
||||
(int)data->tx_msgid);
|
||||
ipmi_free_recv_msg(msg);
|
||||
|
@ -575,8 +576,8 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle)
|
|||
/* Register with hwmon */
|
||||
data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
dev_err(&data->pdev->dev, "Unable to register hwmon "
|
||||
"device for IPMI interface %d\n",
|
||||
dev_err(&data->pdev->dev,
|
||||
"Unable to register hwmon device for IPMI interface %d\n",
|
||||
probe->interface);
|
||||
res = PTR_ERR(data->hwmon_dev);
|
||||
goto hwmon_reg_err;
|
||||
|
@ -715,8 +716,8 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe,
|
|||
/* Register with hwmon */
|
||||
data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
dev_err(&data->pdev->dev, "Unable to register hwmon "
|
||||
"device for IPMI interface %d\n",
|
||||
dev_err(&data->pdev->dev,
|
||||
"Unable to register hwmon device for IPMI interface %d\n",
|
||||
probe->interface);
|
||||
res = PTR_ERR(data->hwmon_dev);
|
||||
goto hwmon_reg_err;
|
||||
|
@ -768,8 +769,8 @@ static void aem_init_aem2(struct aem_ipmi_data *probe)
|
|||
|
||||
while (!aem_find_aem2(probe, &fi_resp, i)) {
|
||||
if (fi_resp.major != 2) {
|
||||
dev_err(probe->bmc_device, "Unknown AEM v%d; please "
|
||||
"report this to the maintainer.\n",
|
||||
dev_err(probe->bmc_device,
|
||||
"Unknown AEM v%d; please report this to the maintainer.\n",
|
||||
fi_resp.major);
|
||||
i++;
|
||||
continue;
|
||||
|
|
|
@ -163,8 +163,8 @@ static int ibmpex_ver_check(struct ibmpex_bmc_data *data)
|
|||
data->sensor_major = data->rx_msg_data[0];
|
||||
data->sensor_minor = data->rx_msg_data[1];
|
||||
|
||||
dev_info(data->bmc_device, "Found BMC with sensor interface "
|
||||
"v%d.%d %d-%02d-%02d on interface %d\n",
|
||||
dev_info(data->bmc_device,
|
||||
"Found BMC with sensor interface v%d.%d %d-%02d-%02d on interface %d\n",
|
||||
data->sensor_major,
|
||||
data->sensor_minor,
|
||||
extract_value(data->rx_msg_data, 2),
|
||||
|
@ -478,8 +478,9 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
|
|||
err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
|
||||
data, &data->user);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Unable to register user with IPMI "
|
||||
"interface %d\n", data->interface);
|
||||
dev_err(dev,
|
||||
"Unable to register user with IPMI interface %d\n",
|
||||
data->interface);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -501,8 +502,8 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
|
|||
data->hwmon_dev = hwmon_device_register(data->bmc_device);
|
||||
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
dev_err(data->bmc_device, "Unable to register hwmon "
|
||||
"device for IPMI interface %d\n",
|
||||
dev_err(data->bmc_device,
|
||||
"Unable to register hwmon device for IPMI interface %d\n",
|
||||
data->interface);
|
||||
goto out_user;
|
||||
}
|
||||
|
@ -567,8 +568,8 @@ static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
|
|||
struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
|
||||
|
||||
if (msg->msgid != data->tx_msgid) {
|
||||
dev_err(data->bmc_device, "Mismatch between received msgid "
|
||||
"(%02x) and transmitted msgid (%02x)!\n",
|
||||
dev_err(data->bmc_device,
|
||||
"Mismatch between received msgid (%02x) and transmitted msgid (%02x)!\n",
|
||||
(int)msg->msgid,
|
||||
(int)data->tx_msgid);
|
||||
ipmi_free_recv_msg(msg);
|
||||
|
|
|
@ -186,20 +186,20 @@ static ssize_t ina2xx_show_value(struct device *dev,
|
|||
}
|
||||
|
||||
/* shunt voltage */
|
||||
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \
|
||||
ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE);
|
||||
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
|
||||
INA2XX_SHUNT_VOLTAGE);
|
||||
|
||||
/* bus voltage */
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
|
||||
ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE);
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina2xx_show_value, NULL,
|
||||
INA2XX_BUS_VOLTAGE);
|
||||
|
||||
/* calculated current */
|
||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
|
||||
ina2xx_show_value, NULL, INA2XX_CURRENT);
|
||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina2xx_show_value, NULL,
|
||||
INA2XX_CURRENT);
|
||||
|
||||
/* calculated power */
|
||||
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \
|
||||
ina2xx_show_value, NULL, INA2XX_POWER);
|
||||
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL,
|
||||
INA2XX_POWER);
|
||||
|
||||
/* pointers to created device attributes */
|
||||
static struct attribute *ina2xx_attributes[] = {
|
||||
|
|
|
@ -1778,7 +1778,7 @@ static int __init it87_find(unsigned short *address,
|
|||
superio_select(5);
|
||||
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
|
||||
} else if (sio_data->type == it8783) {
|
||||
int reg25, reg27, reg2A, reg2C, regEF;
|
||||
int reg25, reg27, reg2a, reg2c, regef;
|
||||
|
||||
sio_data->skip_vid = 1; /* No VID */
|
||||
|
||||
|
@ -1786,15 +1786,15 @@ static int __init it87_find(unsigned short *address,
|
|||
|
||||
reg25 = superio_inb(IT87_SIO_GPIO1_REG);
|
||||
reg27 = superio_inb(IT87_SIO_GPIO3_REG);
|
||||
reg2A = superio_inb(IT87_SIO_PINX1_REG);
|
||||
reg2C = superio_inb(IT87_SIO_PINX2_REG);
|
||||
regEF = superio_inb(IT87_SIO_SPI_REG);
|
||||
reg2a = superio_inb(IT87_SIO_PINX1_REG);
|
||||
reg2c = superio_inb(IT87_SIO_PINX2_REG);
|
||||
regef = superio_inb(IT87_SIO_SPI_REG);
|
||||
|
||||
/* Check if fan3 is there or not */
|
||||
if ((reg27 & (1 << 0)) || !(reg2C & (1 << 2)))
|
||||
if ((reg27 & (1 << 0)) || !(reg2c & (1 << 2)))
|
||||
sio_data->skip_fan |= (1 << 2);
|
||||
if ((reg25 & (1 << 4))
|
||||
|| (!(reg2A & (1 << 1)) && (regEF & (1 << 0))))
|
||||
|| (!(reg2a & (1 << 1)) && (regef & (1 << 0))))
|
||||
sio_data->skip_pwm |= (1 << 2);
|
||||
|
||||
/* Check if fan2 is there or not */
|
||||
|
@ -1804,7 +1804,7 @@ static int __init it87_find(unsigned short *address,
|
|||
sio_data->skip_pwm |= (1 << 1);
|
||||
|
||||
/* VIN5 */
|
||||
if ((reg27 & (1 << 0)) || (reg2C & (1 << 2)))
|
||||
if ((reg27 & (1 << 0)) || (reg2c & (1 << 2)))
|
||||
sio_data->skip_in |= (1 << 5); /* No VIN5 */
|
||||
|
||||
/* VIN6 */
|
||||
|
@ -1829,18 +1829,18 @@ static int __init it87_find(unsigned short *address,
|
|||
* not the case, and ask the user to report if the
|
||||
* resulting voltage is sane.
|
||||
*/
|
||||
if (!(reg2C & (1 << 1))) {
|
||||
reg2C |= (1 << 1);
|
||||
superio_outb(IT87_SIO_PINX2_REG, reg2C);
|
||||
if (!(reg2c & (1 << 1))) {
|
||||
reg2c |= (1 << 1);
|
||||
superio_outb(IT87_SIO_PINX2_REG, reg2c);
|
||||
pr_notice("Routing internal VCCH5V to in7.\n");
|
||||
}
|
||||
pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
|
||||
pr_notice("Please report if it displays a reasonable voltage.\n");
|
||||
}
|
||||
|
||||
if (reg2C & (1 << 0))
|
||||
if (reg2c & (1 << 0))
|
||||
sio_data->internal |= (1 << 0);
|
||||
if (reg2C & (1 << 1))
|
||||
if (reg2c & (1 << 1))
|
||||
sio_data->internal |= (1 << 1);
|
||||
|
||||
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
|
||||
|
|
|
@ -200,8 +200,8 @@ static int k8temp_probe(struct pci_dev *pdev,
|
|||
*/
|
||||
if (model >= 0x40) {
|
||||
data->swap_core_select = 1;
|
||||
dev_warn(&pdev->dev, "Temperature readouts might be wrong - "
|
||||
"check erratum #141\n");
|
||||
dev_warn(&pdev->dev,
|
||||
"Temperature readouts might be wrong - check erratum #141\n");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -386,8 +386,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
|
|||
data->fan_div[nr] = 3;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "fan_div value %ld not "
|
||||
"supported. Choose one of 1, 2, 4 or 8!\n", val);
|
||||
dev_err(dev,
|
||||
"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
|
||||
val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -636,8 +637,9 @@ static int lm78_i2c_detect(struct i2c_client *client,
|
|||
goto err_nodev;
|
||||
|
||||
if (lm78_alias_detect(client, i)) {
|
||||
dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
|
||||
"be the same as ISA device\n", address);
|
||||
dev_dbg(&adapter->dev,
|
||||
"Device at 0x%02x appears to be the same as ISA device\n",
|
||||
address);
|
||||
goto err_nodev;
|
||||
}
|
||||
|
||||
|
|
|
@ -286,8 +286,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
|||
data->fan_div[nr] = 3;
|
||||
break;
|
||||
default:
|
||||
dev_err(&client->dev, "fan_div value %ld not "
|
||||
"supported. Choose one of 1, 2, 4 or 8!\n", val);
|
||||
dev_err(&client->dev,
|
||||
"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
|
||||
val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -1293,8 +1293,8 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info)
|
|||
company = lm85_read_value(client, LM85_REG_COMPANY);
|
||||
verstep = lm85_read_value(client, LM85_REG_VERSTEP);
|
||||
|
||||
dev_dbg(&adapter->dev, "Detecting device at 0x%02x with "
|
||||
"COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
|
||||
dev_dbg(&adapter->dev,
|
||||
"Detecting device at 0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
|
||||
address, company, verstep);
|
||||
|
||||
/* All supported chips have the version in common */
|
||||
|
|
|
@ -354,12 +354,12 @@ static const unsigned long lm93_vin_val_max[16] = {
|
|||
|
||||
static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
|
||||
{
|
||||
const long uV_max = lm93_vin_val_max[nr] * 1000;
|
||||
const long uV_min = lm93_vin_val_min[nr] * 1000;
|
||||
const long uv_max = lm93_vin_val_max[nr] * 1000;
|
||||
const long uv_min = lm93_vin_val_min[nr] * 1000;
|
||||
|
||||
const long slope = (uV_max - uV_min) /
|
||||
const long slope = (uv_max - uv_min) /
|
||||
(lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
|
||||
const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
|
||||
const long intercept = uv_min - slope * lm93_vin_reg_min[nr];
|
||||
|
||||
return (slope * reg + intercept + 500) / 1000;
|
||||
}
|
||||
|
@ -371,20 +371,20 @@ static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
|
|||
static u8 LM93_IN_TO_REG(int nr, unsigned val)
|
||||
{
|
||||
/* range limit */
|
||||
const long mV = clamp_val(val,
|
||||
const long mv = clamp_val(val,
|
||||
lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
|
||||
|
||||
/* try not to lose too much precision here */
|
||||
const long uV = mV * 1000;
|
||||
const long uV_max = lm93_vin_val_max[nr] * 1000;
|
||||
const long uV_min = lm93_vin_val_min[nr] * 1000;
|
||||
const long uv = mv * 1000;
|
||||
const long uv_max = lm93_vin_val_max[nr] * 1000;
|
||||
const long uv_min = lm93_vin_val_min[nr] * 1000;
|
||||
|
||||
/* convert */
|
||||
const long slope = (uV_max - uV_min) /
|
||||
const long slope = (uv_max - uv_min) /
|
||||
(lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
|
||||
const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
|
||||
const long intercept = uv_min - slope * lm93_vin_reg_min[nr];
|
||||
|
||||
u8 result = ((uV - intercept + (slope/2)) / slope);
|
||||
u8 result = ((uv - intercept + (slope/2)) / slope);
|
||||
result = clamp_val(result,
|
||||
lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
|
||||
return result;
|
||||
|
@ -393,10 +393,10 @@ static u8 LM93_IN_TO_REG(int nr, unsigned val)
|
|||
/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */
|
||||
static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
|
||||
{
|
||||
const long uV_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) :
|
||||
const long uv_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) :
|
||||
(((reg >> 0 & 0x0f) + 1) * -25000);
|
||||
const long uV_vid = vid * 1000;
|
||||
return (uV_vid + uV_offset + 5000) / 10000;
|
||||
const long uv_vid = vid * 1000;
|
||||
return (uv_vid + uv_offset + 5000) / 10000;
|
||||
}
|
||||
|
||||
#define LM93_IN_MIN_FROM_REG(reg, vid) LM93_IN_REL_FROM_REG((reg), 0, (vid))
|
||||
|
@ -409,13 +409,13 @@ static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
|
|||
*/
|
||||
static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
|
||||
{
|
||||
long uV_offset = vid * 1000 - val * 10000;
|
||||
long uv_offset = vid * 1000 - val * 10000;
|
||||
if (upper) {
|
||||
uV_offset = clamp_val(uV_offset, 12500, 200000);
|
||||
return (u8)((uV_offset / 12500 - 1) << 4);
|
||||
uv_offset = clamp_val(uv_offset, 12500, 200000);
|
||||
return (u8)((uv_offset / 12500 - 1) << 4);
|
||||
} else {
|
||||
uV_offset = clamp_val(uV_offset, -400000, -25000);
|
||||
return (u8)((uV_offset / -25000 - 1) << 0);
|
||||
uv_offset = clamp_val(uv_offset, -400000, -25000);
|
||||
return (u8)((uv_offset / -25000 - 1) << 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -818,8 +818,9 @@ static u8 lm93_read_byte(struct i2c_client *client, u8 reg)
|
|||
if (value >= 0) {
|
||||
return value;
|
||||
} else {
|
||||
dev_warn(&client->dev, "lm93: read byte data failed, "
|
||||
"address 0x%02x.\n", reg);
|
||||
dev_warn(&client->dev,
|
||||
"lm93: read byte data failed, address 0x%02x.\n",
|
||||
reg);
|
||||
mdelay(i + 3);
|
||||
}
|
||||
|
||||
|
@ -838,8 +839,9 @@ static int lm93_write_byte(struct i2c_client *client, u8 reg, u8 value)
|
|||
result = i2c_smbus_write_byte_data(client, reg, value);
|
||||
|
||||
if (result < 0)
|
||||
dev_warn(&client->dev, "lm93: write byte data failed, "
|
||||
"0x%02x at address 0x%02x.\n", value, reg);
|
||||
dev_warn(&client->dev,
|
||||
"lm93: write byte data failed, 0x%02x at address 0x%02x.\n",
|
||||
value, reg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -854,8 +856,9 @@ static u16 lm93_read_word(struct i2c_client *client, u8 reg)
|
|||
if (value >= 0) {
|
||||
return value;
|
||||
} else {
|
||||
dev_warn(&client->dev, "lm93: read word data failed, "
|
||||
"address 0x%02x.\n", reg);
|
||||
dev_warn(&client->dev,
|
||||
"lm93: read word data failed, address 0x%02x.\n",
|
||||
reg);
|
||||
mdelay(i + 3);
|
||||
}
|
||||
|
||||
|
@ -874,8 +877,9 @@ static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value)
|
|||
result = i2c_smbus_write_word_data(client, reg, value);
|
||||
|
||||
if (result < 0)
|
||||
dev_warn(&client->dev, "lm93: write word data failed, "
|
||||
"0x%04x at address 0x%02x.\n", value, reg);
|
||||
dev_warn(&client->dev,
|
||||
"lm93: write word data failed, 0x%04x at address 0x%02x.\n",
|
||||
value, reg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -898,8 +902,8 @@ static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values)
|
|||
if (result == lm93_block_read_cmds[fbn].len) {
|
||||
break;
|
||||
} else {
|
||||
dev_warn(&client->dev, "lm93: block read data failed, "
|
||||
"command 0x%02x.\n",
|
||||
dev_warn(&client->dev,
|
||||
"lm93: block read data failed, command 0x%02x.\n",
|
||||
lm93_block_read_cmds[fbn].cmd);
|
||||
mdelay(i + 3);
|
||||
}
|
||||
|
@ -2672,8 +2676,8 @@ static void lm93_init_client(struct i2c_client *client)
|
|||
return;
|
||||
}
|
||||
|
||||
dev_warn(&client->dev, "timed out waiting for sensor "
|
||||
"chip to signal ready!\n");
|
||||
dev_warn(&client->dev,
|
||||
"timed out waiting for sensor chip to signal ready!\n");
|
||||
}
|
||||
|
||||
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||
|
@ -2733,12 +2737,12 @@ static int lm93_probe(struct i2c_client *client,
|
|||
dev_dbg(&client->dev, "using SMBus block data transactions\n");
|
||||
update = lm93_update_client_full;
|
||||
} else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
|
||||
dev_dbg(&client->dev, "disabled SMBus block data "
|
||||
"transactions\n");
|
||||
dev_dbg(&client->dev,
|
||||
"disabled SMBus block data transactions\n");
|
||||
update = lm93_update_client_min;
|
||||
} else {
|
||||
dev_dbg(&client->dev, "detect failed, "
|
||||
"smbus byte and/or word data not supported!\n");
|
||||
dev_dbg(&client->dev,
|
||||
"detect failed, smbus byte and/or word data not supported!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
769
drivers/hwmon/lm95234.c
Normal file
769
drivers/hwmon/lm95234.c
Normal file
|
@ -0,0 +1,769 @@
|
|||
/*
|
||||
* Driver for Texas Instruments / National Semiconductor LM95234
|
||||
*
|
||||
* Copyright (c) 2013 Guenter Roeck <linux@roeck-us.net>
|
||||
*
|
||||
* Derived from lm95241.c
|
||||
* Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#define DRVNAME "lm95234"
|
||||
|
||||
static const unsigned short normal_i2c[] = { 0x18, 0x4d, 0x4e, I2C_CLIENT_END };
|
||||
|
||||
/* LM95234 registers */
|
||||
#define LM95234_REG_MAN_ID 0xFE
|
||||
#define LM95234_REG_CHIP_ID 0xFF
|
||||
#define LM95234_REG_STATUS 0x02
|
||||
#define LM95234_REG_CONFIG 0x03
|
||||
#define LM95234_REG_CONVRATE 0x04
|
||||
#define LM95234_REG_STS_FAULT 0x07
|
||||
#define LM95234_REG_STS_TCRIT1 0x08
|
||||
#define LM95234_REG_STS_TCRIT2 0x09
|
||||
#define LM95234_REG_TEMPH(x) ((x) + 0x10)
|
||||
#define LM95234_REG_TEMPL(x) ((x) + 0x20)
|
||||
#define LM95234_REG_UTEMPH(x) ((x) + 0x19) /* Remote only */
|
||||
#define LM95234_REG_UTEMPL(x) ((x) + 0x29)
|
||||
#define LM95234_REG_REM_MODEL 0x30
|
||||
#define LM95234_REG_REM_MODEL_STS 0x38
|
||||
#define LM95234_REG_OFFSET(x) ((x) + 0x31) /* Remote only */
|
||||
#define LM95234_REG_TCRIT1(x) ((x) + 0x40)
|
||||
#define LM95234_REG_TCRIT2(x) ((x) + 0x49) /* Remote channel 1,2 */
|
||||
#define LM95234_REG_TCRIT_HYST 0x5a
|
||||
|
||||
#define NATSEMI_MAN_ID 0x01
|
||||
#define LM95234_CHIP_ID 0x79
|
||||
|
||||
/* Client data (each client gets its own) */
|
||||
struct lm95234_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
unsigned long last_updated, interval; /* in jiffies */
|
||||
bool valid; /* false until following fields are valid */
|
||||
/* registers values */
|
||||
int temp[5]; /* temperature (signed) */
|
||||
u32 status; /* fault/alarm status */
|
||||
u8 tcrit1[5]; /* critical temperature limit */
|
||||
u8 tcrit2[2]; /* high temperature limit */
|
||||
s8 toffset[4]; /* remote temperature offset */
|
||||
u8 thyst; /* common hysteresis */
|
||||
|
||||
u8 sensor_type; /* temperature sensor type */
|
||||
};
|
||||
|
||||
static int lm95234_read_temp(struct i2c_client *client, int index, int *t)
|
||||
{
|
||||
int val;
|
||||
u16 temp = 0;
|
||||
|
||||
if (index) {
|
||||
val = i2c_smbus_read_byte_data(client,
|
||||
LM95234_REG_UTEMPH(index - 1));
|
||||
if (val < 0)
|
||||
return val;
|
||||
temp = val << 8;
|
||||
val = i2c_smbus_read_byte_data(client,
|
||||
LM95234_REG_UTEMPL(index - 1));
|
||||
if (val < 0)
|
||||
return val;
|
||||
temp |= val;
|
||||
*t = temp;
|
||||
}
|
||||
/*
|
||||
* Read signed temperature if unsigned temperature is 0,
|
||||
* or if this is the local sensor.
|
||||
*/
|
||||
if (!temp) {
|
||||
val = i2c_smbus_read_byte_data(client,
|
||||
LM95234_REG_TEMPH(index));
|
||||
if (val < 0)
|
||||
return val;
|
||||
temp = val << 8;
|
||||
val = i2c_smbus_read_byte_data(client,
|
||||
LM95234_REG_TEMPL(index));
|
||||
if (val < 0)
|
||||
return val;
|
||||
temp |= val;
|
||||
*t = (s16)temp;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 update_intervals[] = { 143, 364, 1000, 2500 };
|
||||
|
||||
/* Fill value cache. Must be called with update lock held. */
|
||||
|
||||
static int lm95234_fill_cache(struct i2c_client *client)
|
||||
{
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
int i, ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->interval = msecs_to_jiffies(update_intervals[ret & 0x03]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(data->tcrit1); i++) {
|
||||
ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT1(i));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->tcrit1[i] = ret;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(data->tcrit2); i++) {
|
||||
ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT2(i));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->tcrit2[i] = ret;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(data->toffset); i++) {
|
||||
ret = i2c_smbus_read_byte_data(client, LM95234_REG_OFFSET(i));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->toffset[i] = ret;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT_HYST);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->thyst = ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->sensor_type = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm95234_update_device(struct i2c_client *client,
|
||||
struct lm95234_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + data->interval) ||
|
||||
!data->valid) {
|
||||
int i;
|
||||
|
||||
if (!data->valid) {
|
||||
ret = lm95234_fill_cache(client);
|
||||
if (ret < 0)
|
||||
goto abort;
|
||||
}
|
||||
|
||||
data->valid = false;
|
||||
for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
|
||||
ret = lm95234_read_temp(client, i, &data->temp[i]);
|
||||
if (ret < 0)
|
||||
goto abort;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_FAULT);
|
||||
if (ret < 0)
|
||||
goto abort;
|
||||
data->status = ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT1);
|
||||
if (ret < 0)
|
||||
goto abort;
|
||||
data->status |= ret << 8;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT2);
|
||||
if (ret < 0)
|
||||
goto abort;
|
||||
data->status |= ret << 16;
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = true;
|
||||
}
|
||||
ret = 0;
|
||||
abort:
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
DIV_ROUND_CLOSEST(data->temp[index] * 125, 32));
|
||||
}
|
||||
|
||||
static ssize_t show_alarm(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
u32 mask = to_sensor_dev_attr(attr)->index;
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%u", !!(data->status & mask));
|
||||
}
|
||||
|
||||
static ssize_t show_type(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
u8 mask = to_sensor_dev_attr(attr)->index;
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, data->sensor_type & mask ? "1\n" : "2\n");
|
||||
}
|
||||
|
||||
static ssize_t set_type(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val;
|
||||
u8 mask = to_sensor_dev_attr(attr)->index;
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (val != 1 && val != 2)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (val == 1)
|
||||
data->sensor_type |= mask;
|
||||
else
|
||||
data->sensor_type &= ~mask;
|
||||
data->valid = false;
|
||||
i2c_smbus_write_byte_data(client, LM95234_REG_REM_MODEL,
|
||||
data->sensor_type);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_tcrit2(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%u", data->tcrit2[index] * 1000);
|
||||
}
|
||||
|
||||
static ssize_t set_tcrit2(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = kstrtol(buf, 10, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, index ? 255 : 127);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->tcrit2[index] = val;
|
||||
i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT2(index), val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_tcrit2_hyst(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Result can be negative, so be careful with unsigned operands */
|
||||
return sprintf(buf, "%d",
|
||||
((int)data->tcrit2[index] - (int)data->thyst) * 1000);
|
||||
}
|
||||
|
||||
static ssize_t show_tcrit1(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
|
||||
return sprintf(buf, "%u", data->tcrit1[index] * 1000);
|
||||
}
|
||||
|
||||
static ssize_t set_tcrit1(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = kstrtol(buf, 10, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->tcrit1[index] = val;
|
||||
i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT1(index), val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_tcrit1_hyst(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Result can be negative, so be careful with unsigned operands */
|
||||
return sprintf(buf, "%d",
|
||||
((int)data->tcrit1[index] - (int)data->thyst) * 1000);
|
||||
}
|
||||
|
||||
static ssize_t set_tcrit1_hyst(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = kstrtol(buf, 10, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = DIV_ROUND_CLOSEST(val, 1000);
|
||||
val = clamp_val((int)data->tcrit1[index] - val, 0, 31);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->thyst = val;
|
||||
i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT_HYST, val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_offset(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d", data->toffset[index] * 500);
|
||||
}
|
||||
|
||||
static ssize_t set_offset(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = kstrtol(buf, 10, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Accuracy is 1/2 degrees C */
|
||||
val = clamp_val(DIV_ROUND_CLOSEST(val, 500), -128, 127);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->toffset[index] = val;
|
||||
i2c_smbus_write_byte_data(client, LM95234_REG_OFFSET(index), val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%lu\n",
|
||||
DIV_ROUND_CLOSEST(data->interval * 1000, HZ));
|
||||
}
|
||||
|
||||
static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val;
|
||||
u8 regval;
|
||||
int ret = lm95234_update_device(client, data);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (regval = 0; regval < 3; regval++) {
|
||||
if (val <= update_intervals[regval])
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->interval = msecs_to_jiffies(update_intervals[regval]);
|
||||
i2c_smbus_write_byte_data(client, LM95234_REG_CONVRATE, regval);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL,
|
||||
BIT(0) | BIT(1));
|
||||
static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL,
|
||||
BIT(2) | BIT(3));
|
||||
static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL,
|
||||
BIT(4) | BIT(5));
|
||||
static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_alarm, NULL,
|
||||
BIT(6) | BIT(7));
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type,
|
||||
BIT(1));
|
||||
static SENSOR_DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type, set_type,
|
||||
BIT(2));
|
||||
static SENSOR_DEVICE_ATTR(temp4_type, S_IWUSR | S_IRUGO, show_type, set_type,
|
||||
BIT(3));
|
||||
static SENSOR_DEVICE_ATTR(temp5_type, S_IWUSR | S_IRUGO, show_type, set_type,
|
||||
BIT(4));
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_tcrit1,
|
||||
set_tcrit1, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_tcrit2,
|
||||
set_tcrit2, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_tcrit2,
|
||||
set_tcrit2, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_tcrit1,
|
||||
set_tcrit1, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_tcrit1,
|
||||
set_tcrit1, 4);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_tcrit1_hyst,
|
||||
set_tcrit1_hyst, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO, show_tcrit2_hyst, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO, show_tcrit2_hyst, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp5_max_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 4);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
|
||||
BIT(0 + 8));
|
||||
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL,
|
||||
BIT(1 + 16));
|
||||
static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL,
|
||||
BIT(2 + 16));
|
||||
static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL,
|
||||
BIT(3 + 8));
|
||||
static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL,
|
||||
BIT(4 + 8));
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_tcrit1,
|
||||
set_tcrit1, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_tcrit1,
|
||||
set_tcrit1, 2);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 2);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
|
||||
BIT(1 + 8));
|
||||
static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL,
|
||||
BIT(2 + 8));
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_offset,
|
||||
set_offset, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp3_offset, S_IWUSR | S_IRUGO, show_offset,
|
||||
set_offset, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp4_offset, S_IWUSR | S_IRUGO, show_offset,
|
||||
set_offset, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp5_offset, S_IWUSR | S_IRUGO, show_offset,
|
||||
set_offset, 3);
|
||||
|
||||
static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
|
||||
set_interval);
|
||||
|
||||
static struct attribute *lm95234_attributes[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_offset.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_offset.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_offset.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_offset.dev_attr.attr,
|
||||
&dev_attr_update_interval.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm95234_group = {
|
||||
.attrs = lm95234_attributes,
|
||||
};
|
||||
|
||||
static int lm95234_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info)
|
||||
{
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
int mfg_id, chip_id, val;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
mfg_id = i2c_smbus_read_byte_data(client, LM95234_REG_MAN_ID);
|
||||
if (mfg_id != NATSEMI_MAN_ID)
|
||||
return -ENODEV;
|
||||
|
||||
chip_id = i2c_smbus_read_byte_data(client, LM95234_REG_CHIP_ID);
|
||||
if (chip_id != LM95234_CHIP_ID)
|
||||
return -ENODEV;
|
||||
|
||||
val = i2c_smbus_read_byte_data(client, LM95234_REG_STATUS);
|
||||
if (val & 0x30)
|
||||
return -ENODEV;
|
||||
|
||||
val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
|
||||
if (val & 0xbc)
|
||||
return -ENODEV;
|
||||
|
||||
val = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
|
||||
if (val & 0xfc)
|
||||
return -ENODEV;
|
||||
|
||||
val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
|
||||
if (val & 0xe1)
|
||||
return -ENODEV;
|
||||
|
||||
val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
|
||||
if (val & 0xe1)
|
||||
return -ENODEV;
|
||||
|
||||
strlcpy(info->type, "lm95234", I2C_NAME_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm95234_init_client(struct i2c_client *client)
|
||||
{
|
||||
int val, model;
|
||||
|
||||
/* start conversion if necessary */
|
||||
val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
|
||||
if (val < 0)
|
||||
return val;
|
||||
if (val & 0x40)
|
||||
i2c_smbus_write_byte_data(client, LM95234_REG_CONFIG,
|
||||
val & ~0x40);
|
||||
|
||||
/* If diode type status reports an error, try to fix it */
|
||||
val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
|
||||
if (val < 0)
|
||||
return val;
|
||||
model = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
|
||||
if (model < 0)
|
||||
return model;
|
||||
if (model & val) {
|
||||
dev_notice(&client->dev,
|
||||
"Fixing remote diode type misconfiguration (0x%x)\n",
|
||||
val);
|
||||
i2c_smbus_write_byte_data(client, LM95234_REG_REM_MODEL,
|
||||
model & ~val);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm95234_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct lm95234_data *data;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(struct lm95234_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the LM95234 chip */
|
||||
err = lm95234_init_client(client);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&dev->kobj, &lm95234_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&dev->kobj, &lm95234_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lm95234_remove(struct i2c_client *client)
|
||||
{
|
||||
struct lm95234_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm95234_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Driver data (common to all clients) */
|
||||
static const struct i2c_device_id lm95234_id[] = {
|
||||
{ "lm95234", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lm95234_id);
|
||||
|
||||
static struct i2c_driver lm95234_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
},
|
||||
.probe = lm95234_probe,
|
||||
.remove = lm95234_remove,
|
||||
.id_table = lm95234_id,
|
||||
.detect = lm95234_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(lm95234_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
|
||||
MODULE_DESCRIPTION("LM95234 sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -146,14 +146,14 @@ static ssize_t ltc4151_show_value(struct device *dev,
|
|||
/*
|
||||
* Input voltages.
|
||||
*/
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
|
||||
ltc4151_show_value, NULL, LTC4151_VIN_H);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, \
|
||||
ltc4151_show_value, NULL, LTC4151_ADIN_H);
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4151_show_value, NULL,
|
||||
LTC4151_VIN_H);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4151_show_value, NULL,
|
||||
LTC4151_ADIN_H);
|
||||
|
||||
/* Currents (via sense resistor) */
|
||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
|
||||
ltc4151_show_value, NULL, LTC4151_SENSE_H);
|
||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4151_show_value, NULL,
|
||||
LTC4151_SENSE_H);
|
||||
|
||||
/*
|
||||
* Finally, construct an array of pointers to members of the above objects,
|
||||
|
|
|
@ -172,12 +172,12 @@ static ssize_t ltc4215_show_alarm(struct device *dev,
|
|||
struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct ltc4215_data *data = ltc4215_update_device(dev);
|
||||
const u8 reg = data->regs[attr->index];
|
||||
const u32 mask = attr->nr;
|
||||
const u8 reg = data->regs[LTC4215_STATUS];
|
||||
const u32 mask = attr->index;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", !!(reg & mask));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -186,39 +186,29 @@ static ssize_t ltc4215_show_alarm(struct device *dev,
|
|||
* for each register.
|
||||
*/
|
||||
|
||||
#define LTC4215_VOLTAGE(name, ltc4215_cmd_idx) \
|
||||
static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
|
||||
ltc4215_show_voltage, NULL, ltc4215_cmd_idx)
|
||||
|
||||
#define LTC4215_CURRENT(name) \
|
||||
static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
|
||||
ltc4215_show_current, NULL, 0);
|
||||
|
||||
#define LTC4215_POWER(name) \
|
||||
static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
|
||||
ltc4215_show_power, NULL, 0);
|
||||
|
||||
#define LTC4215_ALARM(name, mask, reg) \
|
||||
static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \
|
||||
ltc4215_show_alarm, NULL, (mask), reg)
|
||||
|
||||
/* Construct a sensor_device_attribute structure for each register */
|
||||
|
||||
/* Current */
|
||||
LTC4215_CURRENT(curr1_input);
|
||||
LTC4215_ALARM(curr1_max_alarm, (1 << 2), LTC4215_STATUS);
|
||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4215_show_current, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
|
||||
1 << 2);
|
||||
|
||||
/* Power (virtual) */
|
||||
LTC4215_POWER(power1_input);
|
||||
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc4215_show_power, NULL, 0);
|
||||
|
||||
/* Input Voltage */
|
||||
LTC4215_VOLTAGE(in1_input, LTC4215_ADIN);
|
||||
LTC4215_ALARM(in1_max_alarm, (1 << 0), LTC4215_STATUS);
|
||||
LTC4215_ALARM(in1_min_alarm, (1 << 1), LTC4215_STATUS);
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4215_show_voltage, NULL,
|
||||
LTC4215_ADIN);
|
||||
static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
|
||||
1 << 0);
|
||||
static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
|
||||
1 << 1);
|
||||
|
||||
/* Output Voltage */
|
||||
LTC4215_VOLTAGE(in2_input, LTC4215_SOURCE);
|
||||
LTC4215_ALARM(in2_min_alarm, (1 << 3), LTC4215_STATUS);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4215_show_voltage, NULL,
|
||||
LTC4215_SOURCE);
|
||||
static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
|
||||
1 << 3);
|
||||
|
||||
/*
|
||||
* Finally, construct an array of pointers to members of the above objects,
|
||||
|
|
|
@ -319,80 +319,82 @@ static ssize_t ltc4245_show_gpio(struct device *dev,
|
|||
return snprintf(buf, PAGE_SIZE, "%u\n", val * 10);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 LTC4245_VOLTAGE(name, ltc4245_cmd_idx) \
|
||||
static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
|
||||
ltc4245_show_voltage, NULL, ltc4245_cmd_idx)
|
||||
|
||||
#define LTC4245_CURRENT(name, ltc4245_cmd_idx) \
|
||||
static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
|
||||
ltc4245_show_current, NULL, ltc4245_cmd_idx)
|
||||
|
||||
#define LTC4245_POWER(name, ltc4245_cmd_idx) \
|
||||
static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
|
||||
ltc4245_show_power, NULL, ltc4245_cmd_idx)
|
||||
|
||||
#define LTC4245_ALARM(name, mask, reg) \
|
||||
static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \
|
||||
ltc4245_show_alarm, NULL, (mask), reg)
|
||||
|
||||
#define LTC4245_GPIO_VOLTAGE(name, gpio_num) \
|
||||
static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
|
||||
ltc4245_show_gpio, NULL, gpio_num)
|
||||
|
||||
/* Construct a sensor_device_attribute structure for each register */
|
||||
|
||||
/* Input voltages */
|
||||
LTC4245_VOLTAGE(in1_input, LTC4245_12VIN);
|
||||
LTC4245_VOLTAGE(in2_input, LTC4245_5VIN);
|
||||
LTC4245_VOLTAGE(in3_input, LTC4245_3VIN);
|
||||
LTC4245_VOLTAGE(in4_input, LTC4245_VEEIN);
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_12VIN);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_5VIN);
|
||||
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_3VIN);
|
||||
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_VEEIN);
|
||||
|
||||
/* Input undervoltage alarms */
|
||||
LTC4245_ALARM(in1_min_alarm, (1 << 0), LTC4245_FAULT1);
|
||||
LTC4245_ALARM(in2_min_alarm, (1 << 1), LTC4245_FAULT1);
|
||||
LTC4245_ALARM(in3_min_alarm, (1 << 2), LTC4245_FAULT1);
|
||||
LTC4245_ALARM(in4_min_alarm, (1 << 3), LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(in1_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 0, LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(in2_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 1, LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(in3_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 2, LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(in4_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 3, LTC4245_FAULT1);
|
||||
|
||||
/* Currents (via sense resistor) */
|
||||
LTC4245_CURRENT(curr1_input, LTC4245_12VSENSE);
|
||||
LTC4245_CURRENT(curr2_input, LTC4245_5VSENSE);
|
||||
LTC4245_CURRENT(curr3_input, LTC4245_3VSENSE);
|
||||
LTC4245_CURRENT(curr4_input, LTC4245_VEESENSE);
|
||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4245_show_current, NULL,
|
||||
LTC4245_12VSENSE);
|
||||
static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc4245_show_current, NULL,
|
||||
LTC4245_5VSENSE);
|
||||
static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO, ltc4245_show_current, NULL,
|
||||
LTC4245_3VSENSE);
|
||||
static SENSOR_DEVICE_ATTR(curr4_input, S_IRUGO, ltc4245_show_current, NULL,
|
||||
LTC4245_VEESENSE);
|
||||
|
||||
/* Overcurrent alarms */
|
||||
LTC4245_ALARM(curr1_max_alarm, (1 << 4), LTC4245_FAULT1);
|
||||
LTC4245_ALARM(curr2_max_alarm, (1 << 5), LTC4245_FAULT1);
|
||||
LTC4245_ALARM(curr3_max_alarm, (1 << 6), LTC4245_FAULT1);
|
||||
LTC4245_ALARM(curr4_max_alarm, (1 << 7), LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(curr1_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 4, LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(curr2_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 5, LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(curr3_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 6, LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(curr4_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 7, LTC4245_FAULT1);
|
||||
|
||||
/* Output voltages */
|
||||
LTC4245_VOLTAGE(in5_input, LTC4245_12VOUT);
|
||||
LTC4245_VOLTAGE(in6_input, LTC4245_5VOUT);
|
||||
LTC4245_VOLTAGE(in7_input, LTC4245_3VOUT);
|
||||
LTC4245_VOLTAGE(in8_input, LTC4245_VEEOUT);
|
||||
static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_12VOUT);
|
||||
static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_5VOUT);
|
||||
static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_3VOUT);
|
||||
static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_VEEOUT);
|
||||
|
||||
/* Power Bad alarms */
|
||||
LTC4245_ALARM(in5_min_alarm, (1 << 0), LTC4245_FAULT2);
|
||||
LTC4245_ALARM(in6_min_alarm, (1 << 1), LTC4245_FAULT2);
|
||||
LTC4245_ALARM(in7_min_alarm, (1 << 2), LTC4245_FAULT2);
|
||||
LTC4245_ALARM(in8_min_alarm, (1 << 3), LTC4245_FAULT2);
|
||||
static SENSOR_DEVICE_ATTR_2(in5_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 0, LTC4245_FAULT2);
|
||||
static SENSOR_DEVICE_ATTR_2(in6_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 1, LTC4245_FAULT2);
|
||||
static SENSOR_DEVICE_ATTR_2(in7_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 2, LTC4245_FAULT2);
|
||||
static SENSOR_DEVICE_ATTR_2(in8_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 3, LTC4245_FAULT2);
|
||||
|
||||
/* GPIO voltages */
|
||||
LTC4245_GPIO_VOLTAGE(in9_input, 0);
|
||||
LTC4245_GPIO_VOLTAGE(in10_input, 1);
|
||||
LTC4245_GPIO_VOLTAGE(in11_input, 2);
|
||||
static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, ltc4245_show_gpio, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, ltc4245_show_gpio, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, ltc4245_show_gpio, NULL, 2);
|
||||
|
||||
/* Power Consumption (virtual) */
|
||||
LTC4245_POWER(power1_input, LTC4245_12VSENSE);
|
||||
LTC4245_POWER(power2_input, LTC4245_5VSENSE);
|
||||
LTC4245_POWER(power3_input, LTC4245_3VSENSE);
|
||||
LTC4245_POWER(power4_input, LTC4245_VEESENSE);
|
||||
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc4245_show_power, NULL,
|
||||
LTC4245_12VSENSE);
|
||||
static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, ltc4245_show_power, NULL,
|
||||
LTC4245_5VSENSE);
|
||||
static SENSOR_DEVICE_ATTR(power3_input, S_IRUGO, ltc4245_show_power, NULL,
|
||||
LTC4245_3VSENSE);
|
||||
static SENSOR_DEVICE_ATTR(power4_input, S_IRUGO, ltc4245_show_power, NULL,
|
||||
LTC4245_VEESENSE);
|
||||
|
||||
/*
|
||||
* Finally, construct an array of pointers to members of the above objects,
|
||||
|
|
|
@ -164,25 +164,13 @@ static ssize_t ltc4261_show_bool(struct device *dev,
|
|||
return snprintf(buf, PAGE_SIZE, "%d\n", fault ? 1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 LTC4261_VALUE(name, ltc4261_cmd_idx) \
|
||||
static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
|
||||
ltc4261_show_value, NULL, ltc4261_cmd_idx)
|
||||
|
||||
#define LTC4261_BOOL(name, mask) \
|
||||
static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
|
||||
ltc4261_show_bool, NULL, (mask))
|
||||
|
||||
/*
|
||||
* Input voltages.
|
||||
*/
|
||||
LTC4261_VALUE(in1_input, LTC4261_ADIN_H);
|
||||
LTC4261_VALUE(in2_input, LTC4261_ADIN2_H);
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4261_show_value, NULL,
|
||||
LTC4261_ADIN_H);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4261_show_value, NULL,
|
||||
LTC4261_ADIN2_H);
|
||||
|
||||
/*
|
||||
* Voltage alarms. The chip has only one set of voltage alarm status bits,
|
||||
|
@ -192,16 +180,22 @@ LTC4261_VALUE(in2_input, LTC4261_ADIN2_H);
|
|||
* To ensure that the alarm condition is reported to the user, report it
|
||||
* with both voltage sensors.
|
||||
*/
|
||||
LTC4261_BOOL(in1_min_alarm, FAULT_UV);
|
||||
LTC4261_BOOL(in1_max_alarm, FAULT_OV);
|
||||
LTC4261_BOOL(in2_min_alarm, FAULT_UV);
|
||||
LTC4261_BOOL(in2_max_alarm, FAULT_OV);
|
||||
static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4261_show_bool, NULL,
|
||||
FAULT_UV);
|
||||
static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
|
||||
FAULT_OV);
|
||||
static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4261_show_bool, NULL,
|
||||
FAULT_UV);
|
||||
static SENSOR_DEVICE_ATTR(in2_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
|
||||
FAULT_OV);
|
||||
|
||||
/* Currents (via sense resistor) */
|
||||
LTC4261_VALUE(curr1_input, LTC4261_SENSE_H);
|
||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4261_show_value, NULL,
|
||||
LTC4261_SENSE_H);
|
||||
|
||||
/* Overcurrent alarm */
|
||||
LTC4261_BOOL(curr1_max_alarm, FAULT_OC);
|
||||
static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
|
||||
FAULT_OC);
|
||||
|
||||
static struct attribute *ltc4261_attributes[] = {
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
|
|
|
@ -399,82 +399,95 @@ static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_alarm, NULL, 5);
|
|||
static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_alarm, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_alarm, NULL, 7);
|
||||
|
||||
static struct attribute *max6697_attributes[8][7] = {
|
||||
{
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_fault.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_fault.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_fault.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp7_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp7_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp7_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp7_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp7_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp7_fault.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp8_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp8_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp8_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp8_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp8_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp8_fault.dev_attr.attr,
|
||||
NULL
|
||||
}
|
||||
static DEVICE_ATTR(dummy, 0, NULL, NULL);
|
||||
|
||||
static umode_t max6697_is_visible(struct kobject *kobj, struct attribute *attr,
|
||||
int index)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct max6697_data *data = i2c_get_clientdata(client);
|
||||
const struct max6697_chip_data *chip = data->chip;
|
||||
int channel = index / 6; /* channel number */
|
||||
int nr = index % 6; /* attribute index within channel */
|
||||
|
||||
if (channel >= chip->channels)
|
||||
return 0;
|
||||
|
||||
if ((nr == 3 || nr == 4) && !(chip->have_crit & (1 << channel)))
|
||||
return 0;
|
||||
if (nr == 5 && !(chip->have_fault & (1 << channel)))
|
||||
return 0;
|
||||
|
||||
return attr->mode;
|
||||
}
|
||||
|
||||
/*
|
||||
* max6697_is_visible uses the index into the following array to determine
|
||||
* if attributes should be created or not. Any change in order or content
|
||||
* must be matched in max6697_is_visible.
|
||||
*/
|
||||
static struct attribute *max6697_attributes[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
|
||||
&dev_attr_dummy.attr,
|
||||
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_fault.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_fault.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_fault.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp7_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp7_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp7_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp7_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp7_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp7_fault.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp8_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp8_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp8_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp8_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp8_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp8_fault.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group max6697_group[8] = {
|
||||
{ .attrs = max6697_attributes[0] },
|
||||
{ .attrs = max6697_attributes[1] },
|
||||
{ .attrs = max6697_attributes[2] },
|
||||
{ .attrs = max6697_attributes[3] },
|
||||
{ .attrs = max6697_attributes[4] },
|
||||
{ .attrs = max6697_attributes[5] },
|
||||
{ .attrs = max6697_attributes[6] },
|
||||
{ .attrs = max6697_attributes[7] },
|
||||
static const struct attribute_group max6697_group = {
|
||||
.attrs = max6697_attributes, .is_visible = max6697_is_visible,
|
||||
};
|
||||
|
||||
static void max6697_get_config_of(struct device_node *node,
|
||||
|
@ -606,21 +619,13 @@ done:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void max6697_remove_files(struct i2c_client *client)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max6697_group); i++)
|
||||
sysfs_remove_group(&client->dev.kobj, &max6697_group[i]);
|
||||
}
|
||||
|
||||
static int max6697_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct device *dev = &client->dev;
|
||||
struct max6697_data *data;
|
||||
int i, err;
|
||||
int err;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
@ -639,37 +644,9 @@ static int max6697_probe(struct i2c_client *client,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < data->chip->channels; i++) {
|
||||
err = sysfs_create_file(&dev->kobj,
|
||||
max6697_attributes[i][0]);
|
||||
if (err)
|
||||
goto error;
|
||||
err = sysfs_create_file(&dev->kobj,
|
||||
max6697_attributes[i][1]);
|
||||
if (err)
|
||||
goto error;
|
||||
err = sysfs_create_file(&dev->kobj,
|
||||
max6697_attributes[i][2]);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
if (data->chip->have_crit & (1 << i)) {
|
||||
err = sysfs_create_file(&dev->kobj,
|
||||
max6697_attributes[i][3]);
|
||||
if (err)
|
||||
goto error;
|
||||
err = sysfs_create_file(&dev->kobj,
|
||||
max6697_attributes[i][4]);
|
||||
if (err)
|
||||
goto error;
|
||||
}
|
||||
if (data->chip->have_fault & (1 << i)) {
|
||||
err = sysfs_create_file(&dev->kobj,
|
||||
max6697_attributes[i][5]);
|
||||
if (err)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
err = sysfs_create_group(&client->dev.kobj, &max6697_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
|
@ -680,7 +657,7 @@ static int max6697_probe(struct i2c_client *client,
|
|||
return 0;
|
||||
|
||||
error:
|
||||
max6697_remove_files(client);
|
||||
sysfs_remove_group(&client->dev.kobj, &max6697_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -689,7 +666,7 @@ static int max6697_remove(struct i2c_client *client)
|
|||
struct max6697_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
max6697_remove_files(client);
|
||||
sysfs_remove_group(&client->dev.kobj, &max6697_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -273,18 +273,7 @@ static struct platform_driver mc13783_adc_driver = {
|
|||
.id_table = mc13783_adc_idtable,
|
||||
};
|
||||
|
||||
static int __init mc13783_adc_init(void)
|
||||
{
|
||||
return platform_driver_probe(&mc13783_adc_driver, mc13783_adc_probe);
|
||||
}
|
||||
|
||||
static void __exit mc13783_adc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mc13783_adc_driver);
|
||||
}
|
||||
|
||||
module_init(mc13783_adc_init);
|
||||
module_exit(mc13783_adc_exit);
|
||||
module_platform_driver_probe(mc13783_adc_driver, mc13783_adc_probe);
|
||||
|
||||
MODULE_DESCRIPTION("MC13783 ADC driver");
|
||||
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
|
||||
|
|
4191
drivers/hwmon/nct6775.c
Normal file
4191
drivers/hwmon/nct6775.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -26,17 +26,33 @@
|
|||
#include <linux/math64.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <linux/platform_data/ntc_thermistor.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/machine.h>
|
||||
#include <linux/iio/driver.h>
|
||||
#include <linux/iio/consumer.h>
|
||||
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
|
||||
struct ntc_compensation {
|
||||
int temp_C;
|
||||
int temp_c;
|
||||
unsigned int ohm;
|
||||
};
|
||||
|
||||
static const struct platform_device_id ntc_thermistor_id[] = {
|
||||
{ "ncp15wb473", TYPE_NCPXXWB473 },
|
||||
{ "ncp18wb473", TYPE_NCPXXWB473 },
|
||||
{ "ncp21wb473", TYPE_NCPXXWB473 },
|
||||
{ "ncp03wb473", TYPE_NCPXXWB473 },
|
||||
{ "ncp15wl333", TYPE_NCPXXWL333 },
|
||||
{ },
|
||||
};
|
||||
|
||||
/*
|
||||
* A compensation table should be sorted by the values of .ohm
|
||||
* in descending order.
|
||||
|
@ -44,76 +60,76 @@ struct ntc_compensation {
|
|||
* Thermistors Datasheet
|
||||
*/
|
||||
static const struct ntc_compensation ncpXXwb473[] = {
|
||||
{ .temp_C = -40, .ohm = 1747920 },
|
||||
{ .temp_C = -35, .ohm = 1245428 },
|
||||
{ .temp_C = -30, .ohm = 898485 },
|
||||
{ .temp_C = -25, .ohm = 655802 },
|
||||
{ .temp_C = -20, .ohm = 483954 },
|
||||
{ .temp_C = -15, .ohm = 360850 },
|
||||
{ .temp_C = -10, .ohm = 271697 },
|
||||
{ .temp_C = -5, .ohm = 206463 },
|
||||
{ .temp_C = 0, .ohm = 158214 },
|
||||
{ .temp_C = 5, .ohm = 122259 },
|
||||
{ .temp_C = 10, .ohm = 95227 },
|
||||
{ .temp_C = 15, .ohm = 74730 },
|
||||
{ .temp_C = 20, .ohm = 59065 },
|
||||
{ .temp_C = 25, .ohm = 47000 },
|
||||
{ .temp_C = 30, .ohm = 37643 },
|
||||
{ .temp_C = 35, .ohm = 30334 },
|
||||
{ .temp_C = 40, .ohm = 24591 },
|
||||
{ .temp_C = 45, .ohm = 20048 },
|
||||
{ .temp_C = 50, .ohm = 16433 },
|
||||
{ .temp_C = 55, .ohm = 13539 },
|
||||
{ .temp_C = 60, .ohm = 11209 },
|
||||
{ .temp_C = 65, .ohm = 9328 },
|
||||
{ .temp_C = 70, .ohm = 7798 },
|
||||
{ .temp_C = 75, .ohm = 6544 },
|
||||
{ .temp_C = 80, .ohm = 5518 },
|
||||
{ .temp_C = 85, .ohm = 4674 },
|
||||
{ .temp_C = 90, .ohm = 3972 },
|
||||
{ .temp_C = 95, .ohm = 3388 },
|
||||
{ .temp_C = 100, .ohm = 2902 },
|
||||
{ .temp_C = 105, .ohm = 2494 },
|
||||
{ .temp_C = 110, .ohm = 2150 },
|
||||
{ .temp_C = 115, .ohm = 1860 },
|
||||
{ .temp_C = 120, .ohm = 1615 },
|
||||
{ .temp_C = 125, .ohm = 1406 },
|
||||
{ .temp_c = -40, .ohm = 1747920 },
|
||||
{ .temp_c = -35, .ohm = 1245428 },
|
||||
{ .temp_c = -30, .ohm = 898485 },
|
||||
{ .temp_c = -25, .ohm = 655802 },
|
||||
{ .temp_c = -20, .ohm = 483954 },
|
||||
{ .temp_c = -15, .ohm = 360850 },
|
||||
{ .temp_c = -10, .ohm = 271697 },
|
||||
{ .temp_c = -5, .ohm = 206463 },
|
||||
{ .temp_c = 0, .ohm = 158214 },
|
||||
{ .temp_c = 5, .ohm = 122259 },
|
||||
{ .temp_c = 10, .ohm = 95227 },
|
||||
{ .temp_c = 15, .ohm = 74730 },
|
||||
{ .temp_c = 20, .ohm = 59065 },
|
||||
{ .temp_c = 25, .ohm = 47000 },
|
||||
{ .temp_c = 30, .ohm = 37643 },
|
||||
{ .temp_c = 35, .ohm = 30334 },
|
||||
{ .temp_c = 40, .ohm = 24591 },
|
||||
{ .temp_c = 45, .ohm = 20048 },
|
||||
{ .temp_c = 50, .ohm = 16433 },
|
||||
{ .temp_c = 55, .ohm = 13539 },
|
||||
{ .temp_c = 60, .ohm = 11209 },
|
||||
{ .temp_c = 65, .ohm = 9328 },
|
||||
{ .temp_c = 70, .ohm = 7798 },
|
||||
{ .temp_c = 75, .ohm = 6544 },
|
||||
{ .temp_c = 80, .ohm = 5518 },
|
||||
{ .temp_c = 85, .ohm = 4674 },
|
||||
{ .temp_c = 90, .ohm = 3972 },
|
||||
{ .temp_c = 95, .ohm = 3388 },
|
||||
{ .temp_c = 100, .ohm = 2902 },
|
||||
{ .temp_c = 105, .ohm = 2494 },
|
||||
{ .temp_c = 110, .ohm = 2150 },
|
||||
{ .temp_c = 115, .ohm = 1860 },
|
||||
{ .temp_c = 120, .ohm = 1615 },
|
||||
{ .temp_c = 125, .ohm = 1406 },
|
||||
};
|
||||
static const struct ntc_compensation ncpXXwl333[] = {
|
||||
{ .temp_C = -40, .ohm = 1610154 },
|
||||
{ .temp_C = -35, .ohm = 1130850 },
|
||||
{ .temp_C = -30, .ohm = 802609 },
|
||||
{ .temp_C = -25, .ohm = 575385 },
|
||||
{ .temp_C = -20, .ohm = 416464 },
|
||||
{ .temp_C = -15, .ohm = 304219 },
|
||||
{ .temp_C = -10, .ohm = 224193 },
|
||||
{ .temp_C = -5, .ohm = 166623 },
|
||||
{ .temp_C = 0, .ohm = 124850 },
|
||||
{ .temp_C = 5, .ohm = 94287 },
|
||||
{ .temp_C = 10, .ohm = 71747 },
|
||||
{ .temp_C = 15, .ohm = 54996 },
|
||||
{ .temp_C = 20, .ohm = 42455 },
|
||||
{ .temp_C = 25, .ohm = 33000 },
|
||||
{ .temp_C = 30, .ohm = 25822 },
|
||||
{ .temp_C = 35, .ohm = 20335 },
|
||||
{ .temp_C = 40, .ohm = 16115 },
|
||||
{ .temp_C = 45, .ohm = 12849 },
|
||||
{ .temp_C = 50, .ohm = 10306 },
|
||||
{ .temp_C = 55, .ohm = 8314 },
|
||||
{ .temp_C = 60, .ohm = 6746 },
|
||||
{ .temp_C = 65, .ohm = 5503 },
|
||||
{ .temp_C = 70, .ohm = 4513 },
|
||||
{ .temp_C = 75, .ohm = 3721 },
|
||||
{ .temp_C = 80, .ohm = 3084 },
|
||||
{ .temp_C = 85, .ohm = 2569 },
|
||||
{ .temp_C = 90, .ohm = 2151 },
|
||||
{ .temp_C = 95, .ohm = 1809 },
|
||||
{ .temp_C = 100, .ohm = 1529 },
|
||||
{ .temp_C = 105, .ohm = 1299 },
|
||||
{ .temp_C = 110, .ohm = 1108 },
|
||||
{ .temp_C = 115, .ohm = 949 },
|
||||
{ .temp_C = 120, .ohm = 817 },
|
||||
{ .temp_C = 125, .ohm = 707 },
|
||||
{ .temp_c = -40, .ohm = 1610154 },
|
||||
{ .temp_c = -35, .ohm = 1130850 },
|
||||
{ .temp_c = -30, .ohm = 802609 },
|
||||
{ .temp_c = -25, .ohm = 575385 },
|
||||
{ .temp_c = -20, .ohm = 416464 },
|
||||
{ .temp_c = -15, .ohm = 304219 },
|
||||
{ .temp_c = -10, .ohm = 224193 },
|
||||
{ .temp_c = -5, .ohm = 166623 },
|
||||
{ .temp_c = 0, .ohm = 124850 },
|
||||
{ .temp_c = 5, .ohm = 94287 },
|
||||
{ .temp_c = 10, .ohm = 71747 },
|
||||
{ .temp_c = 15, .ohm = 54996 },
|
||||
{ .temp_c = 20, .ohm = 42455 },
|
||||
{ .temp_c = 25, .ohm = 33000 },
|
||||
{ .temp_c = 30, .ohm = 25822 },
|
||||
{ .temp_c = 35, .ohm = 20335 },
|
||||
{ .temp_c = 40, .ohm = 16115 },
|
||||
{ .temp_c = 45, .ohm = 12849 },
|
||||
{ .temp_c = 50, .ohm = 10306 },
|
||||
{ .temp_c = 55, .ohm = 8314 },
|
||||
{ .temp_c = 60, .ohm = 6746 },
|
||||
{ .temp_c = 65, .ohm = 5503 },
|
||||
{ .temp_c = 70, .ohm = 4513 },
|
||||
{ .temp_c = 75, .ohm = 3721 },
|
||||
{ .temp_c = 80, .ohm = 3084 },
|
||||
{ .temp_c = 85, .ohm = 2569 },
|
||||
{ .temp_c = 90, .ohm = 2151 },
|
||||
{ .temp_c = 95, .ohm = 1809 },
|
||||
{ .temp_c = 100, .ohm = 1529 },
|
||||
{ .temp_c = 105, .ohm = 1299 },
|
||||
{ .temp_c = 110, .ohm = 1108 },
|
||||
{ .temp_c = 115, .ohm = 949 },
|
||||
{ .temp_c = 120, .ohm = 817 },
|
||||
{ .temp_c = 125, .ohm = 707 },
|
||||
};
|
||||
|
||||
struct ntc_data {
|
||||
|
@ -125,6 +141,92 @@ struct ntc_data {
|
|||
char name[PLATFORM_NAME_SIZE];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata)
|
||||
{
|
||||
struct iio_channel *channel = pdata->chan;
|
||||
unsigned int result;
|
||||
int val, ret;
|
||||
|
||||
ret = iio_read_channel_raw(channel, &val);
|
||||
if (ret < 0) {
|
||||
pr_err("read channel() error: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* unit: mV */
|
||||
result = pdata->pullup_uv * val;
|
||||
result >>= 12;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static const struct of_device_id ntc_match[] = {
|
||||
{ .compatible = "ntc,ncp15wb473",
|
||||
.data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
|
||||
{ .compatible = "ntc,ncp18wb473",
|
||||
.data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
|
||||
{ .compatible = "ntc,ncp21wb473",
|
||||
.data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
|
||||
{ .compatible = "ntc,ncp03wb473",
|
||||
.data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
|
||||
{ .compatible = "ntc,ncp15wl333",
|
||||
.data = &ntc_thermistor_id[TYPE_NCPXXWL333] },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ntc_match);
|
||||
|
||||
static struct ntc_thermistor_platform_data *
|
||||
ntc_thermistor_parse_dt(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_channel *chan;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct ntc_thermistor_platform_data *pdata;
|
||||
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
chan = iio_channel_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(chan))
|
||||
return ERR_CAST(chan);
|
||||
|
||||
if (of_property_read_u32(np, "pullup-uv", &pdata->pullup_uv))
|
||||
return ERR_PTR(-ENODEV);
|
||||
if (of_property_read_u32(np, "pullup-ohm", &pdata->pullup_ohm))
|
||||
return ERR_PTR(-ENODEV);
|
||||
if (of_property_read_u32(np, "pulldown-ohm", &pdata->pulldown_ohm))
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
if (of_find_property(np, "connected-positive", NULL))
|
||||
pdata->connect = NTC_CONNECTED_POSITIVE;
|
||||
else /* status change should be possible if not always on. */
|
||||
pdata->connect = NTC_CONNECTED_GROUND;
|
||||
|
||||
pdata->chan = chan;
|
||||
pdata->read_uv = ntc_adc_iio_read;
|
||||
|
||||
return pdata;
|
||||
}
|
||||
static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
|
||||
{
|
||||
if (pdata->chan)
|
||||
iio_channel_release(pdata->chan);
|
||||
}
|
||||
#else
|
||||
static struct ntc_thermistor_platform_data *
|
||||
ntc_thermistor_parse_dt(struct platform_device *pdev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
|
||||
{
|
||||
if (divisor == 0 && dividend == 0)
|
||||
|
@ -134,37 +236,37 @@ static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
|
|||
return div64_u64(dividend, divisor);
|
||||
}
|
||||
|
||||
static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uV)
|
||||
static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uv)
|
||||
{
|
||||
struct ntc_thermistor_platform_data *pdata = data->pdata;
|
||||
u64 mV = uV / 1000;
|
||||
u64 pmV = pdata->pullup_uV / 1000;
|
||||
u64 N, puO, pdO;
|
||||
puO = pdata->pullup_ohm;
|
||||
pdO = pdata->pulldown_ohm;
|
||||
u64 mv = uv / 1000;
|
||||
u64 pmv = pdata->pullup_uv / 1000;
|
||||
u64 n, puo, pdo;
|
||||
puo = pdata->pullup_ohm;
|
||||
pdo = pdata->pulldown_ohm;
|
||||
|
||||
if (mV == 0) {
|
||||
if (mv == 0) {
|
||||
if (pdata->connect == NTC_CONNECTED_POSITIVE)
|
||||
return INT_MAX;
|
||||
return 0;
|
||||
}
|
||||
if (mV >= pmV)
|
||||
if (mv >= pmv)
|
||||
return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
|
||||
0 : INT_MAX;
|
||||
|
||||
if (pdata->connect == NTC_CONNECTED_POSITIVE && puO == 0)
|
||||
N = div64_u64_safe(pdO * (pmV - mV), mV);
|
||||
else if (pdata->connect == NTC_CONNECTED_GROUND && pdO == 0)
|
||||
N = div64_u64_safe(puO * mV, pmV - mV);
|
||||
if (pdata->connect == NTC_CONNECTED_POSITIVE && puo == 0)
|
||||
n = div64_u64_safe(pdo * (pmv - mv), mv);
|
||||
else if (pdata->connect == NTC_CONNECTED_GROUND && pdo == 0)
|
||||
n = div64_u64_safe(puo * mv, pmv - mv);
|
||||
else if (pdata->connect == NTC_CONNECTED_POSITIVE)
|
||||
N = div64_u64_safe(pdO * puO * (pmV - mV),
|
||||
puO * mV - pdO * (pmV - mV));
|
||||
n = div64_u64_safe(pdo * puo * (pmv - mv),
|
||||
puo * mv - pdo * (pmv - mv));
|
||||
else
|
||||
N = div64_u64_safe(pdO * puO * mV, pdO * (pmV - mV) - puO * mV);
|
||||
n = div64_u64_safe(pdo * puo * mv, pdo * (pmv - mv) - puo * mv);
|
||||
|
||||
if (N > INT_MAX)
|
||||
N = INT_MAX;
|
||||
return N;
|
||||
if (n > INT_MAX)
|
||||
n = INT_MAX;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void lookup_comp(struct ntc_data *data, unsigned int ohm,
|
||||
|
@ -233,7 +335,7 @@ static void lookup_comp(struct ntc_data *data, unsigned int ohm,
|
|||
*i_high = end - 1;
|
||||
}
|
||||
|
||||
static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
|
||||
static int get_temp_mc(struct ntc_data *data, unsigned int ohm)
|
||||
{
|
||||
int low, high;
|
||||
int temp;
|
||||
|
@ -241,10 +343,10 @@ static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
|
|||
lookup_comp(data, ohm, &low, &high);
|
||||
if (low == high) {
|
||||
/* Unable to use linear approximation */
|
||||
temp = data->comp[low].temp_C * 1000;
|
||||
temp = data->comp[low].temp_c * 1000;
|
||||
} else {
|
||||
temp = data->comp[low].temp_C * 1000 +
|
||||
((data->comp[high].temp_C - data->comp[low].temp_C) *
|
||||
temp = data->comp[low].temp_c * 1000 +
|
||||
((data->comp[high].temp_c - data->comp[low].temp_c) *
|
||||
1000 * ((int)ohm - (int)data->comp[low].ohm)) /
|
||||
((int)data->comp[high].ohm - (int)data->comp[low].ohm);
|
||||
}
|
||||
|
@ -253,16 +355,16 @@ static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
|
|||
|
||||
static int ntc_thermistor_get_ohm(struct ntc_data *data)
|
||||
{
|
||||
int read_uV;
|
||||
int read_uv;
|
||||
|
||||
if (data->pdata->read_ohm)
|
||||
return data->pdata->read_ohm();
|
||||
|
||||
if (data->pdata->read_uV) {
|
||||
read_uV = data->pdata->read_uV();
|
||||
if (read_uV < 0)
|
||||
return read_uV;
|
||||
return get_ohm_of_thermistor(data, read_uV);
|
||||
if (data->pdata->read_uv) {
|
||||
read_uv = data->pdata->read_uv(data->pdata);
|
||||
if (read_uv < 0)
|
||||
return read_uv;
|
||||
return get_ohm_of_thermistor(data, read_uv);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -291,7 +393,7 @@ static ssize_t ntc_show_temp(struct device *dev,
|
|||
if (ohm < 0)
|
||||
return ohm;
|
||||
|
||||
return sprintf(buf, "%d\n", get_temp_mC(data, ohm));
|
||||
return sprintf(buf, "%d\n", get_temp_mc(data, ohm));
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
|
||||
|
@ -311,9 +413,18 @@ static const struct attribute_group ntc_attr_group = {
|
|||
|
||||
static int ntc_thermistor_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(of_match_ptr(ntc_match), &pdev->dev);
|
||||
const struct platform_device_id *pdev_id;
|
||||
struct ntc_thermistor_platform_data *pdata;
|
||||
struct ntc_data *data;
|
||||
struct ntc_thermistor_platform_data *pdata = pdev->dev.platform_data;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
pdata = ntc_thermistor_parse_dt(pdev);
|
||||
if (IS_ERR(pdata))
|
||||
return PTR_ERR(pdata);
|
||||
else if (pdata == NULL)
|
||||
pdata = pdev->dev.platform_data;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "No platform init data supplied.\n");
|
||||
|
@ -321,19 +432,19 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* Either one of the two is required. */
|
||||
if (!pdata->read_uV && !pdata->read_ohm) {
|
||||
if (!pdata->read_uv && !pdata->read_ohm) {
|
||||
dev_err(&pdev->dev,
|
||||
"Both read_uV and read_ohm missing. Need either one of the two.\n");
|
||||
"Both read_uv and read_ohm missing. Need either one of the two.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata->read_uV && pdata->read_ohm) {
|
||||
if (pdata->read_uv && pdata->read_ohm) {
|
||||
dev_warn(&pdev->dev,
|
||||
"Only one of read_uV and read_ohm is needed; ignoring read_uV.\n");
|
||||
pdata->read_uV = NULL;
|
||||
"Only one of read_uv and read_ohm is needed; ignoring read_uv.\n");
|
||||
pdata->read_uv = NULL;
|
||||
}
|
||||
|
||||
if (pdata->read_uV && (pdata->pullup_uV == 0 ||
|
||||
if (pdata->read_uv && (pdata->pullup_uv == 0 ||
|
||||
(pdata->pullup_ohm == 0 && pdata->connect ==
|
||||
NTC_CONNECTED_GROUND) ||
|
||||
(pdata->pulldown_ohm == 0 && pdata->connect ==
|
||||
|
@ -341,7 +452,7 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
|
|||
(pdata->connect != NTC_CONNECTED_POSITIVE &&
|
||||
pdata->connect != NTC_CONNECTED_GROUND))) {
|
||||
dev_err(&pdev->dev,
|
||||
"Required data to use read_uV not supplied.\n");
|
||||
"Required data to use read_uv not supplied.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -349,11 +460,13 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
|
|||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
|
||||
|
||||
data->dev = &pdev->dev;
|
||||
data->pdata = pdata;
|
||||
strlcpy(data->name, pdev->id_entry->name, sizeof(data->name));
|
||||
strlcpy(data->name, pdev_id->name, sizeof(data->name));
|
||||
|
||||
switch (pdev->id_entry->driver_data) {
|
||||
switch (pdev_id->driver_data) {
|
||||
case TYPE_NCPXXWB473:
|
||||
data->comp = ncpXXwb473;
|
||||
data->n_comp = ARRAY_SIZE(ncpXXwb473);
|
||||
|
@ -364,8 +477,7 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
|
|||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
|
||||
pdev->id_entry->driver_data,
|
||||
pdev->id_entry->name);
|
||||
pdev_id->driver_data, pdev_id->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -384,39 +496,34 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
|
|||
goto err_after_sysfs;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "Thermistor %s:%d (type: %s/%lu) successfully probed.\n",
|
||||
pdev->name, pdev->id, pdev->id_entry->name,
|
||||
pdev->id_entry->driver_data);
|
||||
dev_info(&pdev->dev, "Thermistor type: %s successfully probed.\n",
|
||||
pdev->name);
|
||||
|
||||
return 0;
|
||||
err_after_sysfs:
|
||||
sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
|
||||
ntc_iio_channel_release(pdata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ntc_thermistor_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ntc_data *data = platform_get_drvdata(pdev);
|
||||
struct ntc_thermistor_platform_data *pdata = data->pdata;
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
|
||||
ntc_iio_channel_release(pdata);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id ntc_thermistor_id[] = {
|
||||
{ "ncp15wb473", TYPE_NCPXXWB473 },
|
||||
{ "ncp18wb473", TYPE_NCPXXWB473 },
|
||||
{ "ncp21wb473", TYPE_NCPXXWB473 },
|
||||
{ "ncp03wb473", TYPE_NCPXXWB473 },
|
||||
{ "ncp15wl333", TYPE_NCPXXWL333 },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver ntc_thermistor_driver = {
|
||||
.driver = {
|
||||
.name = "ntc-thermistor",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(ntc_match),
|
||||
},
|
||||
.probe = ntc_thermistor_probe,
|
||||
.remove = ntc_thermistor_remove,
|
||||
|
|
|
@ -1190,8 +1190,7 @@ static int __init pc87360_find(int sioaddr, u8 *devid,
|
|||
confreg[3] = superio_inb(sioaddr, 0x25);
|
||||
|
||||
if (confreg[2] & 0x40) {
|
||||
pr_info("Using thermistors for "
|
||||
"temperature monitoring\n");
|
||||
pr_info("Using thermistors for temperature monitoring\n");
|
||||
}
|
||||
if (confreg[3] & 0xE0) {
|
||||
pr_info("VID inputs routed (mode %u)\n",
|
||||
|
@ -1271,9 +1270,9 @@ static int pc87360_probe(struct platform_device *pdev)
|
|||
if (data->address[i]
|
||||
&& !devm_request_region(dev, extra_isa[i], PC87360_EXTENT,
|
||||
pc87360_driver.driver.name)) {
|
||||
dev_err(dev, "Region 0x%x-0x%x already "
|
||||
"in use!\n", extra_isa[i],
|
||||
extra_isa[i]+PC87360_EXTENT-1);
|
||||
dev_err(dev,
|
||||
"Region 0x%x-0x%x already in use!\n",
|
||||
extra_isa[i], extra_isa[i]+PC87360_EXTENT-1);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
@ -1435,8 +1434,8 @@ static void pc87360_init_device(struct platform_device *pdev,
|
|||
if (init >= 2 && data->innr) {
|
||||
reg = pc87360_read_value(data, LD_IN, NO_BANK,
|
||||
PC87365_REG_IN_CONVRATE);
|
||||
dev_info(&pdev->dev, "VLM conversion set to "
|
||||
"1s period, 160us delay\n");
|
||||
dev_info(&pdev->dev,
|
||||
"VLM conversion set to 1s period, 160us delay\n");
|
||||
pc87360_write_value(data, LD_IN, NO_BANK,
|
||||
PC87365_REG_IN_CONVRATE,
|
||||
(reg & 0xC0) | 0x11);
|
||||
|
@ -1450,8 +1449,8 @@ static void pc87360_init_device(struct platform_device *pdev,
|
|||
if (init >= init_in[i]) {
|
||||
/* Forcibly enable voltage channel */
|
||||
if (!(reg & CHAN_ENA)) {
|
||||
dev_dbg(&pdev->dev, "Forcibly "
|
||||
"enabling in%d\n", i);
|
||||
dev_dbg(&pdev->dev, "Forcibly enabling in%d\n",
|
||||
i);
|
||||
pc87360_write_value(data, LD_IN, i,
|
||||
PC87365_REG_IN_STATUS,
|
||||
(reg & 0x68) | 0x87);
|
||||
|
@ -1575,8 +1574,8 @@ static void pc87360_autodiv(struct device *dev, int nr)
|
|||
data->fan_status[nr] += 0x20;
|
||||
data->fan_min[nr] >>= 1;
|
||||
data->fan[nr] >>= 1;
|
||||
dev_dbg(dev, "Increasing "
|
||||
"clock divider to %d for fan %d\n",
|
||||
dev_dbg(dev,
|
||||
"Increasing clock divider to %d for fan %d\n",
|
||||
FAN_DIV_FROM_REG(data->fan_status[nr]), nr + 1);
|
||||
}
|
||||
} else {
|
||||
|
@ -1587,8 +1586,8 @@ static void pc87360_autodiv(struct device *dev, int nr)
|
|||
data->fan_status[nr] -= 0x20;
|
||||
data->fan_min[nr] <<= 1;
|
||||
data->fan[nr] <<= 1;
|
||||
dev_dbg(dev, "Decreasing "
|
||||
"clock divider to %d for fan %d\n",
|
||||
dev_dbg(dev,
|
||||
"Decreasing clock divider to %d for fan %d\n",
|
||||
FAN_DIV_FROM_REG(data->fan_status[nr]),
|
||||
nr + 1);
|
||||
}
|
||||
|
|
|
@ -627,8 +627,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute
|
|||
pc87427_readall_pwm(data, nr);
|
||||
mode = data->pwm_enable[nr] & PWM_ENABLE_MODE_MASK;
|
||||
if (mode != PWM_MODE_MANUAL && mode != PWM_MODE_OFF) {
|
||||
dev_notice(dev, "Can't set PWM%d duty cycle while not in "
|
||||
"manual mode\n", nr + 1);
|
||||
dev_notice(dev,
|
||||
"Can't set PWM%d duty cycle while not in manual mode\n",
|
||||
nr + 1);
|
||||
mutex_unlock(&data->lock);
|
||||
return -EPERM;
|
||||
}
|
||||
|
@ -1245,16 +1246,16 @@ static int __init pc87427_find(int sioaddr, struct pc87427_sio_data *sio_data)
|
|||
|
||||
val = superio_inb(sioaddr, SIOREG_MAP);
|
||||
if (val & 0x01) {
|
||||
pr_warn("Logical device 0x%02x is memory-mapped, "
|
||||
"can't use\n", logdev[i]);
|
||||
pr_warn("Logical device 0x%02x is memory-mapped, can't use\n",
|
||||
logdev[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8)
|
||||
| superio_inb(sioaddr, SIOREG_IOBASE + 1);
|
||||
if (!val) {
|
||||
pr_info("I/O base address not set for logical device "
|
||||
"0x%02x\n", logdev[i]);
|
||||
pr_info("I/O base address not set for logical device 0x%02x\n",
|
||||
logdev[i]);
|
||||
continue;
|
||||
}
|
||||
sio_data->address[i] = val;
|
||||
|
|
|
@ -42,17 +42,17 @@ config SENSORS_LM25066
|
|||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for National
|
||||
Semiconductor LM25066, LM5064, and LM5066.
|
||||
Semiconductor LM25056, LM25066, LM5064, and LM5066.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called lm25066.
|
||||
|
||||
config SENSORS_LTC2978
|
||||
tristate "Linear Technologies LTC2978 and LTC3880"
|
||||
tristate "Linear Technologies LTC2974, LTC2978, LTC3880, and LTC3883"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Linear
|
||||
Technology LTC2978 and LTC3880.
|
||||
Technology LTC2974, LTC2978, LTC3880, and LTC3883.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called ltc2978.
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* Hardware monitoring driver for LM25066 / LM5064 / LM5066
|
||||
* Hardware monitoring driver for LM25056 / LM25066 / LM5064 / LM5066
|
||||
*
|
||||
* Copyright (c) 2011 Ericsson AB.
|
||||
* Copyright (c) 2013 Guenter Roeck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -26,7 +27,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
enum chips { lm25066, lm5064, lm5066 };
|
||||
enum chips { lm25056, lm25066, lm5064, lm5066 };
|
||||
|
||||
#define LM25066_READ_VAUX 0xd0
|
||||
#define LM25066_MFR_READ_IIN 0xd1
|
||||
|
@ -43,6 +44,138 @@ enum chips { lm25066, lm5064, lm5066 };
|
|||
|
||||
#define LM25066_DEV_SETUP_CL (1 << 4) /* Current limit */
|
||||
|
||||
/* LM25056 only */
|
||||
|
||||
#define LM25056_VAUX_OV_WARN_LIMIT 0xe3
|
||||
#define LM25056_VAUX_UV_WARN_LIMIT 0xe4
|
||||
|
||||
#define LM25056_MFR_STS_VAUX_OV_WARN (1 << 1)
|
||||
#define LM25056_MFR_STS_VAUX_UV_WARN (1 << 0)
|
||||
|
||||
struct __coeff {
|
||||
short m, b, R;
|
||||
};
|
||||
|
||||
#define PSC_CURRENT_IN_L (PSC_NUM_CLASSES)
|
||||
#define PSC_POWER_L (PSC_NUM_CLASSES + 1)
|
||||
|
||||
static struct __coeff lm25066_coeff[4][PSC_NUM_CLASSES + 2] = {
|
||||
[lm25056] = {
|
||||
[PSC_VOLTAGE_IN] = {
|
||||
.m = 16296,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_CURRENT_IN] = {
|
||||
.m = 13797,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_CURRENT_IN_L] = {
|
||||
.m = 6726,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_POWER] = {
|
||||
.m = 5501,
|
||||
.R = -3,
|
||||
},
|
||||
[PSC_POWER_L] = {
|
||||
.m = 26882,
|
||||
.R = -4,
|
||||
},
|
||||
[PSC_TEMPERATURE] = {
|
||||
.m = 1580,
|
||||
.b = -14500,
|
||||
.R = -2,
|
||||
},
|
||||
},
|
||||
[lm25066] = {
|
||||
[PSC_VOLTAGE_IN] = {
|
||||
.m = 22070,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_VOLTAGE_OUT] = {
|
||||
.m = 22070,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_CURRENT_IN] = {
|
||||
.m = 13661,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_CURRENT_IN_L] = {
|
||||
.m = 6852,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_POWER] = {
|
||||
.m = 736,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_POWER_L] = {
|
||||
.m = 369,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_TEMPERATURE] = {
|
||||
.m = 16,
|
||||
},
|
||||
},
|
||||
[lm5064] = {
|
||||
[PSC_VOLTAGE_IN] = {
|
||||
.m = 4611,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_VOLTAGE_OUT] = {
|
||||
.m = 4621,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_CURRENT_IN] = {
|
||||
.m = 10742,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_CURRENT_IN_L] = {
|
||||
.m = 5456,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_POWER] = {
|
||||
.m = 1204,
|
||||
.R = -3,
|
||||
},
|
||||
[PSC_POWER_L] = {
|
||||
.m = 612,
|
||||
.R = -3,
|
||||
},
|
||||
[PSC_TEMPERATURE] = {
|
||||
.m = 16,
|
||||
},
|
||||
},
|
||||
[lm5066] = {
|
||||
[PSC_VOLTAGE_IN] = {
|
||||
.m = 4587,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_VOLTAGE_OUT] = {
|
||||
.m = 4587,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_CURRENT_IN] = {
|
||||
.m = 10753,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_CURRENT_IN_L] = {
|
||||
.m = 5405,
|
||||
.R = -2,
|
||||
},
|
||||
[PSC_POWER] = {
|
||||
.m = 1204,
|
||||
.R = -3,
|
||||
},
|
||||
[PSC_POWER_L] = {
|
||||
.m = 605,
|
||||
.R = -3,
|
||||
},
|
||||
[PSC_TEMPERATURE] = {
|
||||
.m = 16,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
struct lm25066_data {
|
||||
int id;
|
||||
struct pmbus_driver_info info;
|
||||
|
@ -56,42 +189,31 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
const struct lm25066_data *data = to_lm25066_data(info);
|
||||
int ret;
|
||||
|
||||
if (page > 1)
|
||||
return -ENXIO;
|
||||
|
||||
/* Map READ_VAUX into READ_VOUT register on page 1 */
|
||||
if (page == 1) {
|
||||
switch (reg) {
|
||||
case PMBUS_READ_VOUT:
|
||||
ret = pmbus_read_word_data(client, 0,
|
||||
LM25066_READ_VAUX);
|
||||
if (ret < 0)
|
||||
break;
|
||||
/* Adjust returned value to match VOUT coefficients */
|
||||
switch (data->id) {
|
||||
case lm25066:
|
||||
/* VOUT: 4.54 mV VAUX: 283.2 uV LSB */
|
||||
ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
|
||||
break;
|
||||
case lm5064:
|
||||
/* VOUT: 4.53 mV VAUX: 700 uV LSB */
|
||||
ret = DIV_ROUND_CLOSEST(ret * 70, 453);
|
||||
break;
|
||||
case lm5066:
|
||||
/* VOUT: 2.18 mV VAUX: 725 uV LSB */
|
||||
ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
|
||||
break;
|
||||
}
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_READ_VMON:
|
||||
ret = pmbus_read_word_data(client, 0, LM25066_READ_VAUX);
|
||||
if (ret < 0)
|
||||
break;
|
||||
default:
|
||||
/* No other valid registers on page 1 */
|
||||
ret = -ENXIO;
|
||||
/* Adjust returned value to match VIN coefficients */
|
||||
switch (data->id) {
|
||||
case lm25056:
|
||||
/* VIN: 6.14 mV VAUX: 293 uV LSB */
|
||||
ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
|
||||
break;
|
||||
case lm25066:
|
||||
/* VIN: 4.54 mV VAUX: 283.2 uV LSB */
|
||||
ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
|
||||
break;
|
||||
case lm5064:
|
||||
/* VIN: 4.53 mV VAUX: 700 uV LSB */
|
||||
ret = DIV_ROUND_CLOSEST(ret * 70, 453);
|
||||
break;
|
||||
case lm5066:
|
||||
/* VIN: 2.18 mV VAUX: 725 uV LSB */
|
||||
ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
|
||||
break;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
break;
|
||||
case PMBUS_READ_IIN:
|
||||
ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN);
|
||||
break;
|
||||
|
@ -128,7 +250,58 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
ret = -ENODATA;
|
||||
break;
|
||||
}
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
|
||||
ret = pmbus_read_word_data(client, 0,
|
||||
LM25056_VAUX_UV_WARN_LIMIT);
|
||||
if (ret < 0)
|
||||
break;
|
||||
/* Adjust returned value to match VIN coefficients */
|
||||
ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
|
||||
break;
|
||||
case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
|
||||
ret = pmbus_read_word_data(client, 0,
|
||||
LM25056_VAUX_OV_WARN_LIMIT);
|
||||
if (ret < 0)
|
||||
break;
|
||||
/* Adjust returned value to match VIN coefficients */
|
||||
ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
|
||||
break;
|
||||
default:
|
||||
ret = lm25066_read_word_data(client, page, reg);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lm25056_read_byte_data(struct i2c_client *client, int page, int reg)
|
||||
{
|
||||
int ret, s;
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_STATUS_VMON:
|
||||
ret = pmbus_read_byte_data(client, 0,
|
||||
PMBUS_STATUS_MFR_SPECIFIC);
|
||||
if (ret < 0)
|
||||
break;
|
||||
s = 0;
|
||||
if (ret & LM25056_MFR_STS_VAUX_UV_WARN)
|
||||
s |= PB_VOLTAGE_UV_WARNING;
|
||||
if (ret & LM25056_MFR_STS_VAUX_OV_WARN)
|
||||
s |= PB_VOLTAGE_OV_WARNING;
|
||||
ret = s;
|
||||
break;
|
||||
default:
|
||||
ret = -ENODATA;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -137,19 +310,45 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (page > 1)
|
||||
return -ENXIO;
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_VOUT_UV_WARN_LIMIT:
|
||||
case PMBUS_OT_FAULT_LIMIT:
|
||||
case PMBUS_OT_WARN_LIMIT:
|
||||
case PMBUS_VIN_UV_WARN_LIMIT:
|
||||
case PMBUS_VIN_OV_WARN_LIMIT:
|
||||
word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
|
||||
ret = pmbus_write_word_data(client, 0, reg, word);
|
||||
pmbus_clear_cache(client);
|
||||
break;
|
||||
case PMBUS_IIN_OC_WARN_LIMIT:
|
||||
word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
|
||||
ret = pmbus_write_word_data(client, 0,
|
||||
LM25066_MFR_IIN_OC_WARN_LIMIT,
|
||||
word);
|
||||
pmbus_clear_cache(client);
|
||||
break;
|
||||
case PMBUS_PIN_OP_WARN_LIMIT:
|
||||
word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
|
||||
ret = pmbus_write_word_data(client, 0,
|
||||
LM25066_MFR_PIN_OP_WARN_LIMIT,
|
||||
word);
|
||||
pmbus_clear_cache(client);
|
||||
break;
|
||||
case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
|
||||
/* Adjust from VIN coefficients (for LM25056) */
|
||||
word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
|
||||
word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
|
||||
ret = pmbus_write_word_data(client, 0,
|
||||
LM25056_VAUX_UV_WARN_LIMIT, word);
|
||||
pmbus_clear_cache(client);
|
||||
break;
|
||||
case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
|
||||
/* Adjust from VIN coefficients (for LM25056) */
|
||||
word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
|
||||
word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
|
||||
ret = pmbus_write_word_data(client, 0,
|
||||
LM25056_VAUX_OV_WARN_LIMIT, word);
|
||||
pmbus_clear_cache(client);
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_PIN_HISTORY:
|
||||
ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK);
|
||||
|
@ -161,23 +360,13 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int lm25066_write_byte(struct i2c_client *client, int page, u8 value)
|
||||
{
|
||||
if (page > 1)
|
||||
return -ENXIO;
|
||||
|
||||
if (page <= 0)
|
||||
return pmbus_write_byte(client, page, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm25066_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int config;
|
||||
struct lm25066_data *data;
|
||||
struct pmbus_driver_info *info;
|
||||
struct __coeff *coeff;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_READ_BYTE_DATA))
|
||||
|
@ -195,107 +384,54 @@ static int lm25066_probe(struct i2c_client *client,
|
|||
data->id = id->driver_data;
|
||||
info = &data->info;
|
||||
|
||||
info->pages = 2;
|
||||
info->pages = 1;
|
||||
info->format[PSC_VOLTAGE_IN] = direct;
|
||||
info->format[PSC_VOLTAGE_OUT] = direct;
|
||||
info->format[PSC_CURRENT_IN] = direct;
|
||||
info->format[PSC_TEMPERATURE] = direct;
|
||||
info->format[PSC_POWER] = direct;
|
||||
|
||||
info->m[PSC_TEMPERATURE] = 16;
|
||||
info->b[PSC_TEMPERATURE] = 0;
|
||||
info->R[PSC_TEMPERATURE] = 0;
|
||||
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VMON
|
||||
| PMBUS_HAVE_PIN | PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT
|
||||
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
|
||||
|
||||
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT
|
||||
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN
|
||||
| PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
|
||||
info->func[1] = PMBUS_HAVE_VOUT;
|
||||
|
||||
info->read_word_data = lm25066_read_word_data;
|
||||
if (data->id == lm25056) {
|
||||
info->func[0] |= PMBUS_HAVE_STATUS_VMON;
|
||||
info->read_word_data = lm25056_read_word_data;
|
||||
info->read_byte_data = lm25056_read_byte_data;
|
||||
} else {
|
||||
info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
|
||||
info->read_word_data = lm25066_read_word_data;
|
||||
}
|
||||
info->write_word_data = lm25066_write_word_data;
|
||||
info->write_byte = lm25066_write_byte;
|
||||
|
||||
switch (id->driver_data) {
|
||||
case lm25066:
|
||||
info->m[PSC_VOLTAGE_IN] = 22070;
|
||||
info->b[PSC_VOLTAGE_IN] = 0;
|
||||
info->R[PSC_VOLTAGE_IN] = -2;
|
||||
info->m[PSC_VOLTAGE_OUT] = 22070;
|
||||
info->b[PSC_VOLTAGE_OUT] = 0;
|
||||
info->R[PSC_VOLTAGE_OUT] = -2;
|
||||
|
||||
if (config & LM25066_DEV_SETUP_CL) {
|
||||
info->m[PSC_CURRENT_IN] = 6852;
|
||||
info->b[PSC_CURRENT_IN] = 0;
|
||||
info->R[PSC_CURRENT_IN] = -2;
|
||||
info->m[PSC_POWER] = 369;
|
||||
info->b[PSC_POWER] = 0;
|
||||
info->R[PSC_POWER] = -2;
|
||||
} else {
|
||||
info->m[PSC_CURRENT_IN] = 13661;
|
||||
info->b[PSC_CURRENT_IN] = 0;
|
||||
info->R[PSC_CURRENT_IN] = -2;
|
||||
info->m[PSC_POWER] = 736;
|
||||
info->b[PSC_POWER] = 0;
|
||||
info->R[PSC_POWER] = -2;
|
||||
}
|
||||
break;
|
||||
case lm5064:
|
||||
info->m[PSC_VOLTAGE_IN] = 22075;
|
||||
info->b[PSC_VOLTAGE_IN] = 0;
|
||||
info->R[PSC_VOLTAGE_IN] = -2;
|
||||
info->m[PSC_VOLTAGE_OUT] = 22075;
|
||||
info->b[PSC_VOLTAGE_OUT] = 0;
|
||||
info->R[PSC_VOLTAGE_OUT] = -2;
|
||||
|
||||
if (config & LM25066_DEV_SETUP_CL) {
|
||||
info->m[PSC_CURRENT_IN] = 6713;
|
||||
info->b[PSC_CURRENT_IN] = 0;
|
||||
info->R[PSC_CURRENT_IN] = -2;
|
||||
info->m[PSC_POWER] = 3619;
|
||||
info->b[PSC_POWER] = 0;
|
||||
info->R[PSC_POWER] = -3;
|
||||
} else {
|
||||
info->m[PSC_CURRENT_IN] = 13426;
|
||||
info->b[PSC_CURRENT_IN] = 0;
|
||||
info->R[PSC_CURRENT_IN] = -2;
|
||||
info->m[PSC_POWER] = 7238;
|
||||
info->b[PSC_POWER] = 0;
|
||||
info->R[PSC_POWER] = -3;
|
||||
}
|
||||
break;
|
||||
case lm5066:
|
||||
info->m[PSC_VOLTAGE_IN] = 4587;
|
||||
info->b[PSC_VOLTAGE_IN] = 0;
|
||||
info->R[PSC_VOLTAGE_IN] = -2;
|
||||
info->m[PSC_VOLTAGE_OUT] = 4587;
|
||||
info->b[PSC_VOLTAGE_OUT] = 0;
|
||||
info->R[PSC_VOLTAGE_OUT] = -2;
|
||||
|
||||
if (config & LM25066_DEV_SETUP_CL) {
|
||||
info->m[PSC_CURRENT_IN] = 10753;
|
||||
info->b[PSC_CURRENT_IN] = 0;
|
||||
info->R[PSC_CURRENT_IN] = -2;
|
||||
info->m[PSC_POWER] = 1204;
|
||||
info->b[PSC_POWER] = 0;
|
||||
info->R[PSC_POWER] = -3;
|
||||
} else {
|
||||
info->m[PSC_CURRENT_IN] = 5405;
|
||||
info->b[PSC_CURRENT_IN] = 0;
|
||||
info->R[PSC_CURRENT_IN] = -2;
|
||||
info->m[PSC_POWER] = 605;
|
||||
info->b[PSC_POWER] = 0;
|
||||
info->R[PSC_POWER] = -3;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
coeff = &lm25066_coeff[data->id][0];
|
||||
info->m[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].m;
|
||||
info->b[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].b;
|
||||
info->R[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].R;
|
||||
info->m[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].m;
|
||||
info->b[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].b;
|
||||
info->R[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].R;
|
||||
info->m[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].m;
|
||||
info->b[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].b;
|
||||
info->R[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].R;
|
||||
info->b[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].b;
|
||||
info->R[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].R;
|
||||
info->b[PSC_POWER] = coeff[PSC_POWER].b;
|
||||
info->R[PSC_POWER] = coeff[PSC_POWER].R;
|
||||
if (config & LM25066_DEV_SETUP_CL) {
|
||||
info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN_L].m;
|
||||
info->m[PSC_POWER] = coeff[PSC_POWER_L].m;
|
||||
} else {
|
||||
info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].m;
|
||||
info->m[PSC_POWER] = coeff[PSC_POWER].m;
|
||||
}
|
||||
|
||||
return pmbus_do_probe(client, id, info);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id lm25066_id[] = {
|
||||
{"lm25056", lm25056},
|
||||
{"lm25066", lm25066},
|
||||
{"lm5064", lm5064},
|
||||
{"lm5066", lm5066},
|
||||
|
@ -317,5 +453,5 @@ static struct i2c_driver lm25066_driver = {
|
|||
module_i2c_driver(lm25066_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("PMBus driver for LM25066/LM5064/LM5066");
|
||||
MODULE_DESCRIPTION("PMBus driver for LM25056/LM25066/LM5064/LM5066");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* Hardware monitoring driver for LTC2978 and LTC3880
|
||||
* Hardware monitoring driver for LTC2974, LTC2978, LTC3880, and LTC3883
|
||||
*
|
||||
* Copyright (c) 2011 Ericsson AB.
|
||||
* Copyright (c) 2013 Guenter Roeck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -26,28 +27,43 @@
|
|||
#include <linux/i2c.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
enum chips { ltc2978, ltc3880 };
|
||||
enum chips { ltc2974, ltc2978, ltc3880, ltc3883 };
|
||||
|
||||
/* LTC2978 and LTC3880 */
|
||||
/* Common for all chips */
|
||||
#define LTC2978_MFR_VOUT_PEAK 0xdd
|
||||
#define LTC2978_MFR_VIN_PEAK 0xde
|
||||
#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf
|
||||
#define LTC2978_MFR_SPECIAL_ID 0xe7
|
||||
|
||||
/* LTC2978 only */
|
||||
/* LTC2974 and LTC2978 */
|
||||
#define LTC2978_MFR_VOUT_MIN 0xfb
|
||||
#define LTC2978_MFR_VIN_MIN 0xfc
|
||||
#define LTC2978_MFR_TEMPERATURE_MIN 0xfd
|
||||
|
||||
/* LTC3880 only */
|
||||
/* LTC2974 only */
|
||||
#define LTC2974_MFR_IOUT_PEAK 0xd7
|
||||
#define LTC2974_MFR_IOUT_MIN 0xd8
|
||||
|
||||
/* LTC3880 and LTC3883 */
|
||||
#define LTC3880_MFR_IOUT_PEAK 0xd7
|
||||
#define LTC3880_MFR_CLEAR_PEAKS 0xe3
|
||||
#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4
|
||||
|
||||
/* LTC3883 only */
|
||||
#define LTC3883_MFR_IIN_PEAK 0xe1
|
||||
|
||||
#define LTC2974_ID 0x0212
|
||||
#define LTC2978_ID_REV1 0x0121
|
||||
#define LTC2978_ID_REV2 0x0122
|
||||
#define LTC3880_ID 0x4000
|
||||
#define LTC3880_ID_MASK 0xff00
|
||||
#define LTC3883_ID 0x4300
|
||||
#define LTC3883_ID_MASK 0xff00
|
||||
|
||||
#define LTC2974_NUM_PAGES 4
|
||||
#define LTC2978_NUM_PAGES 8
|
||||
#define LTC3880_NUM_PAGES 2
|
||||
#define LTC3883_NUM_PAGES 1
|
||||
|
||||
/*
|
||||
* LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
|
||||
|
@ -56,13 +72,15 @@ enum chips { ltc2978, ltc3880 };
|
|||
* internal cache of measured peak data, which is only cleared if an explicit
|
||||
* "clear peak" command is executed for the sensor in question.
|
||||
*/
|
||||
|
||||
struct ltc2978_data {
|
||||
enum chips id;
|
||||
int vin_min, vin_max;
|
||||
int temp_min, temp_max[2];
|
||||
int vout_min[8], vout_max[8];
|
||||
int iout_max[2];
|
||||
int temp2_max;
|
||||
u16 vin_min, vin_max;
|
||||
u16 temp_min[LTC2974_NUM_PAGES], temp_max[LTC2974_NUM_PAGES];
|
||||
u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES];
|
||||
u16 iout_min[LTC2974_NUM_PAGES], iout_max[LTC2974_NUM_PAGES];
|
||||
u16 iin_max;
|
||||
u16 temp2_max;
|
||||
struct pmbus_driver_info info;
|
||||
};
|
||||
|
||||
|
@ -167,9 +185,9 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
LTC2978_MFR_TEMPERATURE_MIN);
|
||||
if (ret >= 0) {
|
||||
if (lin11_to_val(ret)
|
||||
< lin11_to_val(data->temp_min))
|
||||
data->temp_min = ret;
|
||||
ret = data->temp_min;
|
||||
< lin11_to_val(data->temp_min[page]))
|
||||
data->temp_min[page] = ret;
|
||||
ret = data->temp_min[page];
|
||||
}
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IOUT_MAX:
|
||||
|
@ -185,6 +203,41 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
struct ltc2978_data *data = to_ltc2978_data(info);
|
||||
int ret;
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_READ_IOUT_MAX:
|
||||
ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_PEAK);
|
||||
if (ret >= 0) {
|
||||
if (lin11_to_val(ret)
|
||||
> lin11_to_val(data->iout_max[page]))
|
||||
data->iout_max[page] = ret;
|
||||
ret = data->iout_max[page];
|
||||
}
|
||||
break;
|
||||
case PMBUS_VIRT_READ_IOUT_MIN:
|
||||
ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_MIN);
|
||||
if (ret >= 0) {
|
||||
if (lin11_to_val(ret)
|
||||
< lin11_to_val(data->iout_min[page]))
|
||||
data->iout_min[page] = ret;
|
||||
ret = data->iout_min[page];
|
||||
}
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_IOUT_HISTORY:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ret = ltc2978_read_word_data(client, page, reg);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
|
@ -226,15 +279,41 @@ static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg)
|
||||
{
|
||||
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
||||
struct ltc2978_data *data = to_ltc2978_data(info);
|
||||
int ret;
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_READ_IIN_MAX:
|
||||
ret = pmbus_read_word_data(client, page, LTC3883_MFR_IIN_PEAK);
|
||||
if (ret >= 0) {
|
||||
if (lin11_to_val(ret)
|
||||
> lin11_to_val(data->iin_max))
|
||||
data->iin_max = ret;
|
||||
ret = data->iin_max;
|
||||
}
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_IIN_HISTORY:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ret = ltc3880_read_word_data(client, page, reg);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ltc2978_clear_peaks(struct i2c_client *client, int page,
|
||||
enum chips id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (id == ltc2978)
|
||||
ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
|
||||
else
|
||||
if (id == ltc3880 || id == ltc3883)
|
||||
ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
|
||||
else
|
||||
ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -247,8 +326,13 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
|
|||
int ret;
|
||||
|
||||
switch (reg) {
|
||||
case PMBUS_VIRT_RESET_IIN_HISTORY:
|
||||
data->iin_max = 0x7c00;
|
||||
ret = ltc2978_clear_peaks(client, page, data->id);
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_IOUT_HISTORY:
|
||||
data->iout_max[page] = 0x7c00;
|
||||
data->iout_min[page] = 0xfbff;
|
||||
ret = ltc2978_clear_peaks(client, page, data->id);
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_TEMP2_HISTORY:
|
||||
|
@ -266,7 +350,7 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
|
|||
ret = ltc2978_clear_peaks(client, page, data->id);
|
||||
break;
|
||||
case PMBUS_VIRT_RESET_TEMP_HISTORY:
|
||||
data->temp_min = 0x7bff;
|
||||
data->temp_min[page] = 0x7bff;
|
||||
data->temp_max[page] = 0x7c00;
|
||||
ret = ltc2978_clear_peaks(client, page, data->id);
|
||||
break;
|
||||
|
@ -278,8 +362,10 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
|
|||
}
|
||||
|
||||
static const struct i2c_device_id ltc2978_id[] = {
|
||||
{"ltc2974", ltc2974},
|
||||
{"ltc2978", ltc2978},
|
||||
{"ltc3880", ltc3880},
|
||||
{"ltc3883", ltc3883},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltc2978_id);
|
||||
|
@ -304,10 +390,14 @@ static int ltc2978_probe(struct i2c_client *client,
|
|||
if (chip_id < 0)
|
||||
return chip_id;
|
||||
|
||||
if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
|
||||
if (chip_id == LTC2974_ID) {
|
||||
data->id = ltc2974;
|
||||
} else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
|
||||
data->id = ltc2978;
|
||||
} else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) {
|
||||
data->id = ltc3880;
|
||||
} else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) {
|
||||
data->id = ltc3883;
|
||||
} else {
|
||||
dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
|
||||
return -ENODEV;
|
||||
|
@ -323,26 +413,45 @@ static int ltc2978_probe(struct i2c_client *client,
|
|||
|
||||
data->vin_min = 0x7bff;
|
||||
data->vin_max = 0x7c00;
|
||||
data->temp_min = 0x7bff;
|
||||
for (i = 0; i < ARRAY_SIZE(data->vout_min); i++)
|
||||
data->vout_min[i] = 0xffff;
|
||||
for (i = 0; i < ARRAY_SIZE(data->iout_min); i++)
|
||||
data->iout_min[i] = 0xfbff;
|
||||
for (i = 0; i < ARRAY_SIZE(data->iout_max); i++)
|
||||
data->iout_max[i] = 0x7c00;
|
||||
for (i = 0; i < ARRAY_SIZE(data->temp_min); i++)
|
||||
data->temp_min[i] = 0x7bff;
|
||||
for (i = 0; i < ARRAY_SIZE(data->temp_max); i++)
|
||||
data->temp_max[i] = 0x7c00;
|
||||
data->temp2_max = 0x7c00;
|
||||
|
||||
switch (data->id) {
|
||||
case ltc2974:
|
||||
info->read_word_data = ltc2974_read_word_data;
|
||||
info->pages = LTC2974_NUM_PAGES;
|
||||
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
|
||||
| PMBUS_HAVE_TEMP2;
|
||||
for (i = 0; i < info->pages; i++) {
|
||||
info->func[i] |= PMBUS_HAVE_VOUT
|
||||
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
|
||||
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
|
||||
}
|
||||
break;
|
||||
case ltc2978:
|
||||
info->read_word_data = ltc2978_read_word_data;
|
||||
info->pages = 8;
|
||||
info->pages = LTC2978_NUM_PAGES;
|
||||
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
|
||||
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
|
||||
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
|
||||
for (i = 1; i < 8; i++) {
|
||||
for (i = 1; i < LTC2978_NUM_PAGES; i++) {
|
||||
info->func[i] = PMBUS_HAVE_VOUT
|
||||
| PMBUS_HAVE_STATUS_VOUT;
|
||||
}
|
||||
break;
|
||||
case ltc3880:
|
||||
info->read_word_data = ltc3880_read_word_data;
|
||||
info->pages = 2;
|
||||
info->pages = LTC3880_NUM_PAGES;
|
||||
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
|
||||
| PMBUS_HAVE_STATUS_INPUT
|
||||
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
|
||||
|
@ -353,15 +462,20 @@ static int ltc2978_probe(struct i2c_client *client,
|
|||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
|
||||
| PMBUS_HAVE_POUT
|
||||
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
|
||||
data->iout_max[0] = 0x7c00;
|
||||
data->iout_max[1] = 0x7c00;
|
||||
break;
|
||||
case ltc3883:
|
||||
info->read_word_data = ltc3883_read_word_data;
|
||||
info->pages = LTC3883_NUM_PAGES;
|
||||
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
|
||||
| PMBUS_HAVE_STATUS_INPUT
|
||||
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
|
||||
| PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
|
||||
| PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
for (i = 0; i < info->pages; i++)
|
||||
data->vout_min[i] = 0xffff;
|
||||
|
||||
return pmbus_do_probe(client, id, info);
|
||||
}
|
||||
|
||||
|
@ -378,5 +492,5 @@ static struct i2c_driver ltc2978_driver = {
|
|||
module_i2c_driver(ltc2978_driver);
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck");
|
||||
MODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880");
|
||||
MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, and LTC3883");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -107,17 +107,14 @@ static ssize_t s3c_hwmon_show_raw(struct device *dev,
|
|||
return (ret < 0) ? ret : snprintf(buf, PAGE_SIZE, "%d\n", ret);
|
||||
}
|
||||
|
||||
#define DEF_ADC_ATTR(x) \
|
||||
static SENSOR_DEVICE_ATTR(adc##x##_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, x)
|
||||
|
||||
DEF_ADC_ATTR(0);
|
||||
DEF_ADC_ATTR(1);
|
||||
DEF_ADC_ATTR(2);
|
||||
DEF_ADC_ATTR(3);
|
||||
DEF_ADC_ATTR(4);
|
||||
DEF_ADC_ATTR(5);
|
||||
DEF_ADC_ATTR(6);
|
||||
DEF_ADC_ATTR(7);
|
||||
static SENSOR_DEVICE_ATTR(adc0_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(adc1_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(adc2_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(adc3_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(adc4_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(adc5_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(adc6_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(adc7_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 7);
|
||||
|
||||
static struct attribute *s3c_hwmon_attrs[9] = {
|
||||
&sensor_dev_attr_adc0_raw.dev_attr.attr,
|
||||
|
|
|
@ -161,8 +161,8 @@ static int sch56xx_send_cmd(u16 addr, u8 cmd, u16 reg, u8 v)
|
|||
break;
|
||||
}
|
||||
if (i == max_busy_polls + max_lazy_polls) {
|
||||
pr_err("Max retries exceeded reading virtual "
|
||||
"register 0x%04hx (%d)\n", reg, 1);
|
||||
pr_err("Max retries exceeded reading virtual register 0x%04hx (%d)\n",
|
||||
reg, 1);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -178,12 +178,12 @@ static int sch56xx_send_cmd(u16 addr, u8 cmd, u16 reg, u8 v)
|
|||
break;
|
||||
|
||||
if (i == 0)
|
||||
pr_warn("EC reports: 0x%02x reading virtual register "
|
||||
"0x%04hx\n", (unsigned int)val, reg);
|
||||
pr_warn("EC reports: 0x%02x reading virtual register 0x%04hx\n",
|
||||
(unsigned int)val, reg);
|
||||
}
|
||||
if (i == max_busy_polls) {
|
||||
pr_err("Max retries exceeded reading virtual "
|
||||
"register 0x%04hx (%d)\n", reg, 2);
|
||||
pr_err("Max retries exceeded reading virtual register 0x%04hx (%d)\n",
|
||||
reg, 2);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
|
@ -456,8 +456,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
|
|||
data->fan_div[nr] = 3;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "fan_div value %ld not "
|
||||
"supported. Choose one of 1, 2, 4 or 8!\n", val);
|
||||
dev_err(dev,
|
||||
"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
|
||||
val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -41,8 +41,8 @@ enum chips { thmc50, adm1022 };
|
|||
static unsigned short adm1022_temp3[16];
|
||||
static unsigned int adm1022_temp3_num;
|
||||
module_param_array(adm1022_temp3, ushort, &adm1022_temp3_num, 0);
|
||||
MODULE_PARM_DESC(adm1022_temp3, "List of adapter,address pairs "
|
||||
"to enable 3rd temperature (ADM1022 only)");
|
||||
MODULE_PARM_DESC(adm1022_temp3,
|
||||
"List of adapter,address pairs to enable 3rd temperature (ADM1022 only)");
|
||||
|
||||
/* Many THMC50 constants specified below */
|
||||
|
||||
|
@ -312,8 +312,7 @@ static int thmc50_detect(struct i2c_client *client,
|
|||
const char *type_name;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
pr_debug("thmc50: detect failed, "
|
||||
"smbus byte data not supported!\n");
|
||||
pr_debug("thmc50: detect failed, smbus byte data not supported!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
|
@ -155,8 +155,8 @@ static int tmp102_probe(struct i2c_client *client,
|
|||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_WORD_DATA)) {
|
||||
dev_err(&client->dev, "adapter doesn't support SMBus word "
|
||||
"transactions\n");
|
||||
dev_err(&client->dev,
|
||||
"adapter doesn't support SMBus word transactions\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
* Gabriel Konat, Sander Leget, Wouter Willems
|
||||
* Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de>
|
||||
*
|
||||
* Cleanup and support for TMP431 and TMP432 by Guenter Roeck
|
||||
* Copyright (c) 2013 Guenter Roeck <linux@roeck-us.net>
|
||||
*
|
||||
* 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
|
||||
|
@ -30,6 +33,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
|
@ -40,9 +44,9 @@
|
|||
#include <linux/sysfs.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
|
||||
static const unsigned short normal_i2c[] = { 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
|
||||
|
||||
enum chips { tmp401, tmp411 };
|
||||
enum chips { tmp401, tmp411, tmp431, tmp432 };
|
||||
|
||||
/*
|
||||
* The TMP401 registers, note some registers have different addresses for
|
||||
|
@ -54,42 +58,84 @@ enum chips { tmp401, tmp411 };
|
|||
#define TMP401_CONVERSION_RATE_READ 0x04
|
||||
#define TMP401_CONVERSION_RATE_WRITE 0x0A
|
||||
#define TMP401_TEMP_CRIT_HYST 0x21
|
||||
#define TMP401_CONSECUTIVE_ALERT 0x22
|
||||
#define TMP401_MANUFACTURER_ID_REG 0xFE
|
||||
#define TMP401_DEVICE_ID_REG 0xFF
|
||||
#define TMP411_N_FACTOR_REG 0x18
|
||||
|
||||
static const u8 TMP401_TEMP_MSB[2] = { 0x00, 0x01 };
|
||||
static const u8 TMP401_TEMP_LSB[2] = { 0x15, 0x10 };
|
||||
static const u8 TMP401_TEMP_LOW_LIMIT_MSB_READ[2] = { 0x06, 0x08 };
|
||||
static const u8 TMP401_TEMP_LOW_LIMIT_MSB_WRITE[2] = { 0x0C, 0x0E };
|
||||
static const u8 TMP401_TEMP_LOW_LIMIT_LSB[2] = { 0x17, 0x14 };
|
||||
static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_READ[2] = { 0x05, 0x07 };
|
||||
static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[2] = { 0x0B, 0x0D };
|
||||
static const u8 TMP401_TEMP_HIGH_LIMIT_LSB[2] = { 0x16, 0x13 };
|
||||
/* These are called the THERM limit / hysteresis / mask in the datasheet */
|
||||
static const u8 TMP401_TEMP_CRIT_LIMIT[2] = { 0x20, 0x19 };
|
||||
static const u8 TMP401_TEMP_MSB_READ[6][2] = {
|
||||
{ 0x00, 0x01 }, /* temp */
|
||||
{ 0x06, 0x08 }, /* low limit */
|
||||
{ 0x05, 0x07 }, /* high limit */
|
||||
{ 0x20, 0x19 }, /* therm (crit) limit */
|
||||
{ 0x30, 0x34 }, /* lowest */
|
||||
{ 0x32, 0x36 }, /* highest */
|
||||
};
|
||||
|
||||
static const u8 TMP411_TEMP_LOWEST_MSB[2] = { 0x30, 0x34 };
|
||||
static const u8 TMP411_TEMP_LOWEST_LSB[2] = { 0x31, 0x35 };
|
||||
static const u8 TMP411_TEMP_HIGHEST_MSB[2] = { 0x32, 0x36 };
|
||||
static const u8 TMP411_TEMP_HIGHEST_LSB[2] = { 0x33, 0x37 };
|
||||
static const u8 TMP401_TEMP_MSB_WRITE[6][2] = {
|
||||
{ 0, 0 }, /* temp (unused) */
|
||||
{ 0x0C, 0x0E }, /* low limit */
|
||||
{ 0x0B, 0x0D }, /* high limit */
|
||||
{ 0x20, 0x19 }, /* therm (crit) limit */
|
||||
{ 0x30, 0x34 }, /* lowest */
|
||||
{ 0x32, 0x36 }, /* highest */
|
||||
};
|
||||
|
||||
static const u8 TMP401_TEMP_LSB[6][2] = {
|
||||
{ 0x15, 0x10 }, /* temp */
|
||||
{ 0x17, 0x14 }, /* low limit */
|
||||
{ 0x16, 0x13 }, /* high limit */
|
||||
{ 0, 0 }, /* therm (crit) limit (unused) */
|
||||
{ 0x31, 0x35 }, /* lowest */
|
||||
{ 0x33, 0x37 }, /* highest */
|
||||
};
|
||||
|
||||
static const u8 TMP432_TEMP_MSB_READ[4][3] = {
|
||||
{ 0x00, 0x01, 0x23 }, /* temp */
|
||||
{ 0x06, 0x08, 0x16 }, /* low limit */
|
||||
{ 0x05, 0x07, 0x15 }, /* high limit */
|
||||
{ 0x20, 0x19, 0x1A }, /* therm (crit) limit */
|
||||
};
|
||||
|
||||
static const u8 TMP432_TEMP_MSB_WRITE[4][3] = {
|
||||
{ 0, 0, 0 }, /* temp - unused */
|
||||
{ 0x0C, 0x0E, 0x16 }, /* low limit */
|
||||
{ 0x0B, 0x0D, 0x15 }, /* high limit */
|
||||
{ 0x20, 0x19, 0x1A }, /* therm (crit) limit */
|
||||
};
|
||||
|
||||
static const u8 TMP432_TEMP_LSB[3][3] = {
|
||||
{ 0x29, 0x10, 0x24 }, /* temp */
|
||||
{ 0x3E, 0x14, 0x18 }, /* low limit */
|
||||
{ 0x3D, 0x13, 0x17 }, /* high limit */
|
||||
};
|
||||
|
||||
/* [0] = fault, [1] = low, [2] = high, [3] = therm/crit */
|
||||
static const u8 TMP432_STATUS_REG[] = {
|
||||
0x1b, 0x36, 0x35, 0x37 };
|
||||
|
||||
/* Flags */
|
||||
#define TMP401_CONFIG_RANGE 0x04
|
||||
#define TMP401_CONFIG_SHUTDOWN 0x40
|
||||
#define TMP401_STATUS_LOCAL_CRIT 0x01
|
||||
#define TMP401_STATUS_REMOTE_CRIT 0x02
|
||||
#define TMP401_STATUS_REMOTE_OPEN 0x04
|
||||
#define TMP401_STATUS_REMOTE_LOW 0x08
|
||||
#define TMP401_STATUS_REMOTE_HIGH 0x10
|
||||
#define TMP401_STATUS_LOCAL_LOW 0x20
|
||||
#define TMP401_STATUS_LOCAL_HIGH 0x40
|
||||
#define TMP401_CONFIG_RANGE BIT(2)
|
||||
#define TMP401_CONFIG_SHUTDOWN BIT(6)
|
||||
#define TMP401_STATUS_LOCAL_CRIT BIT(0)
|
||||
#define TMP401_STATUS_REMOTE_CRIT BIT(1)
|
||||
#define TMP401_STATUS_REMOTE_OPEN BIT(2)
|
||||
#define TMP401_STATUS_REMOTE_LOW BIT(3)
|
||||
#define TMP401_STATUS_REMOTE_HIGH BIT(4)
|
||||
#define TMP401_STATUS_LOCAL_LOW BIT(5)
|
||||
#define TMP401_STATUS_LOCAL_HIGH BIT(6)
|
||||
|
||||
/* On TMP432, each status has its own register */
|
||||
#define TMP432_STATUS_LOCAL BIT(0)
|
||||
#define TMP432_STATUS_REMOTE1 BIT(1)
|
||||
#define TMP432_STATUS_REMOTE2 BIT(2)
|
||||
|
||||
/* Manufacturer / Device ID's */
|
||||
#define TMP401_MANUFACTURER_ID 0x55
|
||||
#define TMP401_DEVICE_ID 0x11
|
||||
#define TMP411_DEVICE_ID 0x12
|
||||
#define TMP411A_DEVICE_ID 0x12
|
||||
#define TMP411B_DEVICE_ID 0x13
|
||||
#define TMP411C_DEVICE_ID 0x10
|
||||
#define TMP431_DEVICE_ID 0x31
|
||||
#define TMP432_DEVICE_ID 0x32
|
||||
|
||||
/*
|
||||
* Driver data (common to all clients)
|
||||
|
@ -98,6 +144,8 @@ static const u8 TMP411_TEMP_HIGHEST_LSB[2] = { 0x33, 0x37 };
|
|||
static const struct i2c_device_id tmp401_id[] = {
|
||||
{ "tmp401", tmp401 },
|
||||
{ "tmp411", tmp411 },
|
||||
{ "tmp431", tmp431 },
|
||||
{ "tmp432", tmp432 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tmp401_id);
|
||||
|
@ -113,16 +161,13 @@ struct tmp401_data {
|
|||
unsigned long last_updated; /* in jiffies */
|
||||
enum chips kind;
|
||||
|
||||
unsigned int update_interval; /* in milliseconds */
|
||||
|
||||
/* register values */
|
||||
u8 status;
|
||||
u8 status[4];
|
||||
u8 config;
|
||||
u16 temp[2];
|
||||
u16 temp_low[2];
|
||||
u16 temp_high[2];
|
||||
u8 temp_crit[2];
|
||||
u16 temp[6][3];
|
||||
u8 temp_crit_hyst;
|
||||
u16 temp_lowest[2];
|
||||
u16 temp_highest[2];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -136,10 +181,10 @@ static int tmp401_register_to_temp(u16 reg, u8 config)
|
|||
if (config & TMP401_CONFIG_RANGE)
|
||||
temp -= 64 * 256;
|
||||
|
||||
return (temp * 625 + 80) / 160;
|
||||
return DIV_ROUND_CLOSEST(temp * 125, 32);
|
||||
}
|
||||
|
||||
static u16 tmp401_temp_to_register(long temp, u8 config)
|
||||
static u16 tmp401_temp_to_register(long temp, u8 config, int zbits)
|
||||
{
|
||||
if (config & TMP401_CONFIG_RANGE) {
|
||||
temp = clamp_val(temp, -64000, 191000);
|
||||
|
@ -147,134 +192,127 @@ static u16 tmp401_temp_to_register(long temp, u8 config)
|
|||
} else
|
||||
temp = clamp_val(temp, 0, 127000);
|
||||
|
||||
return (temp * 160 + 312) / 625;
|
||||
return DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits;
|
||||
}
|
||||
|
||||
static int tmp401_crit_register_to_temp(u8 reg, u8 config)
|
||||
static int tmp401_update_device_reg16(struct i2c_client *client,
|
||||
struct tmp401_data *data)
|
||||
{
|
||||
int temp = reg;
|
||||
int i, j, val;
|
||||
int num_regs = data->kind == tmp411 ? 6 : 4;
|
||||
int num_sensors = data->kind == tmp432 ? 3 : 2;
|
||||
|
||||
if (config & TMP401_CONFIG_RANGE)
|
||||
temp -= 64;
|
||||
|
||||
return temp * 1000;
|
||||
}
|
||||
|
||||
static u8 tmp401_crit_temp_to_register(long temp, u8 config)
|
||||
{
|
||||
if (config & TMP401_CONFIG_RANGE) {
|
||||
temp = clamp_val(temp, -64000, 191000);
|
||||
temp += 64000;
|
||||
} else
|
||||
temp = clamp_val(temp, 0, 127000);
|
||||
|
||||
return (temp + 500) / 1000;
|
||||
}
|
||||
|
||||
static struct tmp401_data *tmp401_update_device_reg16(
|
||||
struct i2c_client *client, struct tmp401_data *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
/*
|
||||
* High byte must be read first immediately followed
|
||||
* by the low byte
|
||||
*/
|
||||
data->temp[i] = i2c_smbus_read_byte_data(client,
|
||||
TMP401_TEMP_MSB[i]) << 8;
|
||||
data->temp[i] |= i2c_smbus_read_byte_data(client,
|
||||
TMP401_TEMP_LSB[i]);
|
||||
data->temp_low[i] = i2c_smbus_read_byte_data(client,
|
||||
TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8;
|
||||
data->temp_low[i] |= i2c_smbus_read_byte_data(client,
|
||||
TMP401_TEMP_LOW_LIMIT_LSB[i]);
|
||||
data->temp_high[i] = i2c_smbus_read_byte_data(client,
|
||||
TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8;
|
||||
data->temp_high[i] |= i2c_smbus_read_byte_data(client,
|
||||
TMP401_TEMP_HIGH_LIMIT_LSB[i]);
|
||||
data->temp_crit[i] = i2c_smbus_read_byte_data(client,
|
||||
TMP401_TEMP_CRIT_LIMIT[i]);
|
||||
|
||||
if (data->kind == tmp411) {
|
||||
data->temp_lowest[i] = i2c_smbus_read_byte_data(client,
|
||||
TMP411_TEMP_LOWEST_MSB[i]) << 8;
|
||||
data->temp_lowest[i] |= i2c_smbus_read_byte_data(
|
||||
client, TMP411_TEMP_LOWEST_LSB[i]);
|
||||
|
||||
data->temp_highest[i] = i2c_smbus_read_byte_data(
|
||||
client, TMP411_TEMP_HIGHEST_MSB[i]) << 8;
|
||||
data->temp_highest[i] |= i2c_smbus_read_byte_data(
|
||||
client, TMP411_TEMP_HIGHEST_LSB[i]);
|
||||
for (i = 0; i < num_sensors; i++) { /* local / r1 / r2 */
|
||||
for (j = 0; j < num_regs; j++) { /* temp / low / ... */
|
||||
u8 regaddr;
|
||||
/*
|
||||
* High byte must be read first immediately followed
|
||||
* by the low byte
|
||||
*/
|
||||
regaddr = data->kind == tmp432 ?
|
||||
TMP432_TEMP_MSB_READ[j][i] :
|
||||
TMP401_TEMP_MSB_READ[j][i];
|
||||
val = i2c_smbus_read_byte_data(client, regaddr);
|
||||
if (val < 0)
|
||||
return val;
|
||||
data->temp[j][i] = val << 8;
|
||||
if (j == 3) /* crit is msb only */
|
||||
continue;
|
||||
regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[j][i]
|
||||
: TMP401_TEMP_LSB[j][i];
|
||||
val = i2c_smbus_read_byte_data(client, regaddr);
|
||||
if (val < 0)
|
||||
return val;
|
||||
data->temp[j][i] |= val;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct tmp401_data *tmp401_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct tmp401_data *data = i2c_get_clientdata(client);
|
||||
struct tmp401_data *ret = data;
|
||||
int i, val;
|
||||
unsigned long next_update;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
|
||||
data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS);
|
||||
data->config = i2c_smbus_read_byte_data(client,
|
||||
TMP401_CONFIG_READ);
|
||||
tmp401_update_device_reg16(client, data);
|
||||
next_update = data->last_updated +
|
||||
msecs_to_jiffies(data->update_interval) + 1;
|
||||
if (time_after(jiffies, next_update) || !data->valid) {
|
||||
if (data->kind != tmp432) {
|
||||
/*
|
||||
* The driver uses the TMP432 status format internally.
|
||||
* Convert status to TMP432 format for other chips.
|
||||
*/
|
||||
val = i2c_smbus_read_byte_data(client, TMP401_STATUS);
|
||||
if (val < 0) {
|
||||
ret = ERR_PTR(val);
|
||||
goto abort;
|
||||
}
|
||||
data->status[0] =
|
||||
(val & TMP401_STATUS_REMOTE_OPEN) >> 1;
|
||||
data->status[1] =
|
||||
((val & TMP401_STATUS_REMOTE_LOW) >> 2) |
|
||||
((val & TMP401_STATUS_LOCAL_LOW) >> 5);
|
||||
data->status[2] =
|
||||
((val & TMP401_STATUS_REMOTE_HIGH) >> 3) |
|
||||
((val & TMP401_STATUS_LOCAL_HIGH) >> 6);
|
||||
data->status[3] = val & (TMP401_STATUS_LOCAL_CRIT
|
||||
| TMP401_STATUS_REMOTE_CRIT);
|
||||
} else {
|
||||
for (i = 0; i < ARRAY_SIZE(data->status); i++) {
|
||||
val = i2c_smbus_read_byte_data(client,
|
||||
TMP432_STATUS_REG[i]);
|
||||
if (val < 0) {
|
||||
ret = ERR_PTR(val);
|
||||
goto abort;
|
||||
}
|
||||
data->status[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
data->temp_crit_hyst = i2c_smbus_read_byte_data(client,
|
||||
TMP401_TEMP_CRIT_HYST);
|
||||
val = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
|
||||
if (val < 0) {
|
||||
ret = ERR_PTR(val);
|
||||
goto abort;
|
||||
}
|
||||
data->config = val;
|
||||
val = tmp401_update_device_reg16(client, data);
|
||||
if (val < 0) {
|
||||
ret = ERR_PTR(val);
|
||||
goto abort;
|
||||
}
|
||||
val = i2c_smbus_read_byte_data(client, TMP401_TEMP_CRIT_HYST);
|
||||
if (val < 0) {
|
||||
ret = ERR_PTR(val);
|
||||
goto abort;
|
||||
}
|
||||
data->temp_crit_hyst = val;
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
abort:
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t show_temp_value(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
static ssize_t show_temp(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
int nr = to_sensor_dev_attr_2(devattr)->nr;
|
||||
int index = to_sensor_dev_attr_2(devattr)->index;
|
||||
struct tmp401_data *data = tmp401_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
tmp401_register_to_temp(data->temp[index], data->config));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_min(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct tmp401_data *data = tmp401_update_device(dev);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
tmp401_register_to_temp(data->temp_low[index], data->config));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_max(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct tmp401_data *data = tmp401_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
tmp401_register_to_temp(data->temp_high[index], data->config));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_crit(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct tmp401_data *data = tmp401_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
tmp401_crit_register_to_temp(data->temp_crit[index],
|
||||
data->config));
|
||||
tmp401_register_to_temp(data->temp[nr][index], data->config));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_crit_hyst(struct device *dev,
|
||||
|
@ -283,122 +321,60 @@ static ssize_t show_temp_crit_hyst(struct device *dev,
|
|||
int temp, index = to_sensor_dev_attr(devattr)->index;
|
||||
struct tmp401_data *data = tmp401_update_device(dev);
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
temp = tmp401_crit_register_to_temp(data->temp_crit[index],
|
||||
data->config);
|
||||
temp = tmp401_register_to_temp(data->temp[3][index], data->config);
|
||||
temp -= data->temp_crit_hyst * 1000;
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return sprintf(buf, "%d\n", temp);
|
||||
}
|
||||
|
||||
static ssize_t show_temp_lowest(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct tmp401_data *data = tmp401_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
tmp401_register_to_temp(data->temp_lowest[index],
|
||||
data->config));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_highest(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct tmp401_data *data = tmp401_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
tmp401_register_to_temp(data->temp_highest[index],
|
||||
data->config));
|
||||
}
|
||||
|
||||
static ssize_t show_status(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int mask = to_sensor_dev_attr(devattr)->index;
|
||||
int nr = to_sensor_dev_attr_2(devattr)->nr;
|
||||
int mask = to_sensor_dev_attr_2(devattr)->index;
|
||||
struct tmp401_data *data = tmp401_update_device(dev);
|
||||
|
||||
if (data->status & mask)
|
||||
return sprintf(buf, "1\n");
|
||||
else
|
||||
return sprintf(buf, "0\n");
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%d\n", !!(data->status[nr] & mask));
|
||||
}
|
||||
|
||||
static ssize_t store_temp_min(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
static ssize_t store_temp(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
int nr = to_sensor_dev_attr_2(devattr)->nr;
|
||||
int index = to_sensor_dev_attr_2(devattr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct tmp401_data *data = tmp401_update_device(dev);
|
||||
long val;
|
||||
u16 reg;
|
||||
u8 regaddr;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
if (kstrtol(buf, 10, &val))
|
||||
return -EINVAL;
|
||||
|
||||
reg = tmp401_temp_to_register(val, data->config);
|
||||
reg = tmp401_temp_to_register(val, data->config, nr == 3 ? 8 : 4);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
i2c_smbus_write_byte_data(to_i2c_client(dev),
|
||||
TMP401_TEMP_LOW_LIMIT_MSB_WRITE[index], reg >> 8);
|
||||
i2c_smbus_write_byte_data(to_i2c_client(dev),
|
||||
TMP401_TEMP_LOW_LIMIT_LSB[index], reg & 0xFF);
|
||||
|
||||
data->temp_low[index] = reg;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_temp_max(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct tmp401_data *data = tmp401_update_device(dev);
|
||||
long val;
|
||||
u16 reg;
|
||||
|
||||
if (kstrtol(buf, 10, &val))
|
||||
return -EINVAL;
|
||||
|
||||
reg = tmp401_temp_to_register(val, data->config);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
i2c_smbus_write_byte_data(to_i2c_client(dev),
|
||||
TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[index], reg >> 8);
|
||||
i2c_smbus_write_byte_data(to_i2c_client(dev),
|
||||
TMP401_TEMP_HIGH_LIMIT_LSB[index], reg & 0xFF);
|
||||
|
||||
data->temp_high[index] = reg;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_temp_crit(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct tmp401_data *data = tmp401_update_device(dev);
|
||||
long val;
|
||||
u8 reg;
|
||||
|
||||
if (kstrtol(buf, 10, &val))
|
||||
return -EINVAL;
|
||||
|
||||
reg = tmp401_crit_temp_to_register(val, data->config);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
i2c_smbus_write_byte_data(to_i2c_client(dev),
|
||||
TMP401_TEMP_CRIT_LIMIT[index], reg);
|
||||
|
||||
data->temp_crit[index] = reg;
|
||||
regaddr = data->kind == tmp432 ? TMP432_TEMP_MSB_WRITE[nr][index]
|
||||
: TMP401_TEMP_MSB_WRITE[nr][index];
|
||||
i2c_smbus_write_byte_data(client, regaddr, reg >> 8);
|
||||
if (nr != 3) {
|
||||
regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[nr][index]
|
||||
: TMP401_TEMP_LSB[nr][index];
|
||||
i2c_smbus_write_byte_data(client, regaddr, reg & 0xFF);
|
||||
}
|
||||
data->temp[nr][index] = reg;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
|
@ -413,6 +389,9 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
|
|||
long val;
|
||||
u8 reg;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
if (kstrtol(buf, 10, &val))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -422,13 +401,12 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
|
|||
val = clamp_val(val, 0, 127000);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
temp = tmp401_crit_register_to_temp(data->temp_crit[index],
|
||||
data->config);
|
||||
temp = tmp401_register_to_temp(data->temp[3][index], data->config);
|
||||
val = clamp_val(val, temp - 255000, temp);
|
||||
reg = ((temp - val) + 500) / 1000;
|
||||
|
||||
i2c_smbus_write_byte_data(to_i2c_client(dev),
|
||||
TMP401_TEMP_CRIT_HYST, reg);
|
||||
i2c_smbus_write_byte_data(to_i2c_client(dev), TMP401_TEMP_CRIT_HYST,
|
||||
reg);
|
||||
|
||||
data->temp_crit_hyst = reg;
|
||||
|
||||
|
@ -445,54 +423,130 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
|
|||
static ssize_t reset_temp_history(struct device *dev,
|
||||
struct device_attribute *devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct tmp401_data *data = i2c_get_clientdata(client);
|
||||
long val;
|
||||
|
||||
if (kstrtol(buf, 10, &val))
|
||||
return -EINVAL;
|
||||
|
||||
if (val != 1) {
|
||||
dev_err(dev, "temp_reset_history value %ld not"
|
||||
" supported. Use 1 to reset the history!\n", val);
|
||||
dev_err(dev,
|
||||
"temp_reset_history value %ld not supported. Use 1 to reset the history!\n",
|
||||
val);
|
||||
return -EINVAL;
|
||||
}
|
||||
i2c_smbus_write_byte_data(to_i2c_client(dev),
|
||||
TMP411_TEMP_LOWEST_MSB[0], val);
|
||||
mutex_lock(&data->update_lock);
|
||||
i2c_smbus_write_byte_data(client, TMP401_TEMP_MSB_WRITE[5][0], val);
|
||||
data->valid = 0;
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct sensor_device_attribute tmp401_attr[] = {
|
||||
SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0),
|
||||
SENSOR_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
|
||||
store_temp_min, 0),
|
||||
SENSOR_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
|
||||
store_temp_max, 0),
|
||||
SENSOR_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit,
|
||||
store_temp_crit, 0),
|
||||
SENSOR_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_crit_hyst,
|
||||
store_temp_crit_hyst, 0),
|
||||
SENSOR_ATTR(temp1_min_alarm, S_IRUGO, show_status, NULL,
|
||||
TMP401_STATUS_LOCAL_LOW),
|
||||
SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_status, NULL,
|
||||
TMP401_STATUS_LOCAL_HIGH),
|
||||
SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_status, NULL,
|
||||
TMP401_STATUS_LOCAL_CRIT),
|
||||
SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1),
|
||||
SENSOR_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
|
||||
store_temp_min, 1),
|
||||
SENSOR_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
|
||||
store_temp_max, 1),
|
||||
SENSOR_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit,
|
||||
store_temp_crit, 1),
|
||||
SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1),
|
||||
SENSOR_ATTR(temp2_fault, S_IRUGO, show_status, NULL,
|
||||
TMP401_STATUS_REMOTE_OPEN),
|
||||
SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_status, NULL,
|
||||
TMP401_STATUS_REMOTE_LOW),
|
||||
SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_status, NULL,
|
||||
TMP401_STATUS_REMOTE_HIGH),
|
||||
SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_status, NULL,
|
||||
TMP401_STATUS_REMOTE_CRIT),
|
||||
static ssize_t show_update_interval(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct tmp401_data *data = i2c_get_clientdata(client);
|
||||
|
||||
return sprintf(buf, "%u\n", data->update_interval);
|
||||
}
|
||||
|
||||
static ssize_t set_update_interval(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct tmp401_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val;
|
||||
int err, rate;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* For valid rates, interval can be calculated as
|
||||
* interval = (1 << (7 - rate)) * 125;
|
||||
* Rounded rate is therefore
|
||||
* rate = 7 - __fls(interval * 4 / (125 * 3));
|
||||
* Use clamp_val() to avoid overflows, and to ensure valid input
|
||||
* for __fls.
|
||||
*/
|
||||
val = clamp_val(val, 125, 16000);
|
||||
rate = 7 - __fls(val * 4 / (125 * 3));
|
||||
mutex_lock(&data->update_lock);
|
||||
i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, rate);
|
||||
data->update_interval = (1 << (7 - rate)) * 125;
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(temp1_min, S_IWUSR | S_IRUGO, show_temp,
|
||||
store_temp, 1, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp,
|
||||
store_temp, 2, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IWUSR | S_IRUGO, show_temp,
|
||||
store_temp, 3, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
|
||||
show_temp_crit_hyst, store_temp_crit_hyst, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_status, NULL,
|
||||
1, TMP432_STATUS_LOCAL);
|
||||
static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_status, NULL,
|
||||
2, TMP432_STATUS_LOCAL);
|
||||
static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_status, NULL,
|
||||
3, TMP432_STATUS_LOCAL);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp,
|
||||
store_temp, 1, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp,
|
||||
store_temp, 2, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IWUSR | S_IRUGO, show_temp,
|
||||
store_temp, 3, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst,
|
||||
NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_status, NULL,
|
||||
0, TMP432_STATUS_REMOTE1);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_status, NULL,
|
||||
1, TMP432_STATUS_REMOTE1);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_status, NULL,
|
||||
2, TMP432_STATUS_REMOTE1);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_status, NULL,
|
||||
3, TMP432_STATUS_REMOTE1);
|
||||
|
||||
static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
|
||||
set_update_interval);
|
||||
|
||||
static struct attribute *tmp401_attributes[] = {
|
||||
&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_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
|
||||
|
||||
&dev_attr_update_interval.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group tmp401_group = {
|
||||
.attrs = tmp401_attributes,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -502,12 +556,60 @@ static struct sensor_device_attribute tmp401_attr[] = {
|
|||
* minimum and maximum register reset for both the local
|
||||
* and remote channels.
|
||||
*/
|
||||
static struct sensor_device_attribute tmp411_attr[] = {
|
||||
SENSOR_ATTR(temp1_highest, S_IRUGO, show_temp_highest, NULL, 0),
|
||||
SENSOR_ATTR(temp1_lowest, S_IRUGO, show_temp_lowest, NULL, 0),
|
||||
SENSOR_ATTR(temp2_highest, S_IRUGO, show_temp_highest, NULL, 1),
|
||||
SENSOR_ATTR(temp2_lowest, S_IRUGO, show_temp_lowest, NULL, 1),
|
||||
SENSOR_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history, 0),
|
||||
static SENSOR_DEVICE_ATTR_2(temp1_lowest, S_IRUGO, show_temp, NULL, 4, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(temp1_highest, S_IRUGO, show_temp, NULL, 5, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_lowest, S_IRUGO, show_temp, NULL, 4, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_highest, S_IRUGO, show_temp, NULL, 5, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history,
|
||||
0);
|
||||
|
||||
static struct attribute *tmp411_attributes[] = {
|
||||
&sensor_dev_attr_temp1_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_lowest.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_lowest.dev_attr.attr,
|
||||
&sensor_dev_attr_temp_reset_history.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group tmp411_group = {
|
||||
.attrs = tmp411_attributes,
|
||||
};
|
||||
|
||||
static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp,
|
||||
store_temp, 1, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp,
|
||||
store_temp, 2, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IWUSR | S_IRUGO, show_temp,
|
||||
store_temp, 3, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst,
|
||||
NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_status, NULL,
|
||||
0, TMP432_STATUS_REMOTE2);
|
||||
static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_status, NULL,
|
||||
1, TMP432_STATUS_REMOTE2);
|
||||
static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_status, NULL,
|
||||
2, TMP432_STATUS_REMOTE2);
|
||||
static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_status, NULL,
|
||||
3, TMP432_STATUS_REMOTE2);
|
||||
|
||||
static struct attribute *tmp432_attributes[] = {
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group tmp432_group = {
|
||||
.attrs = tmp432_attributes,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -517,9 +619,11 @@ static struct sensor_device_attribute tmp411_attr[] = {
|
|||
static void tmp401_init_client(struct i2c_client *client)
|
||||
{
|
||||
int config, config_orig;
|
||||
struct tmp401_data *data = i2c_get_clientdata(client);
|
||||
|
||||
/* Set the conversion rate to 2 Hz */
|
||||
i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5);
|
||||
data->update_interval = 500;
|
||||
|
||||
/* Start conversions (disable shutdown if necessary) */
|
||||
config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
|
||||
|
@ -554,11 +658,35 @@ static int tmp401_detect(struct i2c_client *client,
|
|||
|
||||
switch (reg) {
|
||||
case TMP401_DEVICE_ID:
|
||||
if (client->addr != 0x4c)
|
||||
return -ENODEV;
|
||||
kind = tmp401;
|
||||
break;
|
||||
case TMP411_DEVICE_ID:
|
||||
case TMP411A_DEVICE_ID:
|
||||
if (client->addr != 0x4c)
|
||||
return -ENODEV;
|
||||
kind = tmp411;
|
||||
break;
|
||||
case TMP411B_DEVICE_ID:
|
||||
if (client->addr != 0x4d)
|
||||
return -ENODEV;
|
||||
kind = tmp411;
|
||||
break;
|
||||
case TMP411C_DEVICE_ID:
|
||||
if (client->addr != 0x4e)
|
||||
return -ENODEV;
|
||||
kind = tmp411;
|
||||
break;
|
||||
case TMP431_DEVICE_ID:
|
||||
if (client->addr == 0x4e)
|
||||
return -ENODEV;
|
||||
kind = tmp431;
|
||||
break;
|
||||
case TMP432_DEVICE_ID:
|
||||
if (client->addr == 0x4e)
|
||||
return -ENODEV;
|
||||
kind = tmp432;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -579,20 +707,19 @@ static int tmp401_detect(struct i2c_client *client,
|
|||
|
||||
static int tmp401_remove(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct tmp401_data *data = i2c_get_clientdata(client);
|
||||
int i;
|
||||
|
||||
if (data->hwmon_dev)
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++)
|
||||
device_remove_file(&client->dev, &tmp401_attr[i].dev_attr);
|
||||
sysfs_remove_group(&dev->kobj, &tmp401_group);
|
||||
|
||||
if (data->kind == tmp411) {
|
||||
for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++)
|
||||
device_remove_file(&client->dev,
|
||||
&tmp411_attr[i].dev_attr);
|
||||
}
|
||||
if (data->kind == tmp411)
|
||||
sysfs_remove_group(&dev->kobj, &tmp411_group);
|
||||
|
||||
if (data->kind == tmp432)
|
||||
sysfs_remove_group(&dev->kobj, &tmp432_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -600,12 +727,12 @@ static int tmp401_remove(struct i2c_client *client)
|
|||
static int tmp401_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int i, err = 0;
|
||||
struct device *dev = &client->dev;
|
||||
int err;
|
||||
struct tmp401_data *data;
|
||||
const char *names[] = { "TMP401", "TMP411" };
|
||||
const char *names[] = { "TMP401", "TMP411", "TMP431", "TMP432" };
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct tmp401_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -617,31 +744,32 @@ static int tmp401_probe(struct i2c_client *client,
|
|||
tmp401_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) {
|
||||
err = device_create_file(&client->dev,
|
||||
&tmp401_attr[i].dev_attr);
|
||||
err = sysfs_create_group(&dev->kobj, &tmp401_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Register additional tmp411 sysfs hooks */
|
||||
if (data->kind == tmp411) {
|
||||
err = sysfs_create_group(&dev->kobj, &tmp411_group);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
/* Register additional tmp411 sysfs hooks */
|
||||
if (data->kind == tmp411) {
|
||||
for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) {
|
||||
err = device_create_file(&client->dev,
|
||||
&tmp411_attr[i].dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
}
|
||||
/* Register additional tmp432 sysfs hooks */
|
||||
if (data->kind == tmp432) {
|
||||
err = sysfs_create_group(&dev->kobj, &tmp432_group);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
data->hwmon_dev = NULL;
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "Detected TI %s chip\n", names[data->kind]);
|
||||
dev_info(dev, "Detected TI %s chip\n", names[data->kind]);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -208,8 +208,8 @@ static int tmp421_init_client(struct i2c_client *client)
|
|||
/* Start conversions (disable shutdown if necessary) */
|
||||
config = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1);
|
||||
if (config < 0) {
|
||||
dev_err(&client->dev, "Could not read configuration"
|
||||
" register (%d)\n", config);
|
||||
dev_err(&client->dev,
|
||||
"Could not read configuration register (%d)\n", config);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -322,6 +322,5 @@ static struct i2c_driver tmp421_driver = {
|
|||
module_i2c_driver(tmp421_driver);
|
||||
|
||||
MODULE_AUTHOR("Andre Prendel <andre.prendel@gmx.de>");
|
||||
MODULE_DESCRIPTION("Texas Instruments TMP421/422/423 temperature sensor"
|
||||
" driver");
|
||||
MODULE_DESCRIPTION("Texas Instruments TMP421/422/423 temperature sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -125,7 +125,7 @@ static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e };
|
|||
* (These conversions were contributed by Jonathan Teh Soon Yew
|
||||
* <j.teh@iname.com>)
|
||||
*/
|
||||
static inline u8 IN_TO_REG(long val, int inNum)
|
||||
static inline u8 IN_TO_REG(long val, int in_num)
|
||||
{
|
||||
/*
|
||||
* To avoid floating point, we multiply constants by 10 (100 for +12V).
|
||||
|
@ -134,29 +134,29 @@ static inline u8 IN_TO_REG(long val, int inNum)
|
|||
* by an additional 10000 (100000 for +12V): 1000 for val and 10 (100)
|
||||
* for the constants.
|
||||
*/
|
||||
if (inNum <= 1)
|
||||
if (in_num <= 1)
|
||||
return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255);
|
||||
else if (inNum == 2)
|
||||
else if (in_num == 2)
|
||||
return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255);
|
||||
else if (inNum == 3)
|
||||
else if (in_num == 3)
|
||||
return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255);
|
||||
else
|
||||
return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0,
|
||||
255);
|
||||
}
|
||||
|
||||
static inline long IN_FROM_REG(u8 val, int inNum)
|
||||
static inline long IN_FROM_REG(u8 val, int in_num)
|
||||
{
|
||||
/*
|
||||
* To avoid floating point, we multiply constants by 10 (100 for +12V).
|
||||
* We also multiply them by 1000 because we want 0.001V/bit for the
|
||||
* output value. Rounding is done.
|
||||
*/
|
||||
if (inNum <= 1)
|
||||
if (in_num <= 1)
|
||||
return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
|
||||
else if (inNum == 2)
|
||||
else if (in_num == 2)
|
||||
return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
|
||||
else if (inNum == 3)
|
||||
else if (in_num == 3)
|
||||
return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108);
|
||||
else
|
||||
return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714);
|
||||
|
@ -210,10 +210,10 @@ static inline u8 FAN_TO_REG(long rpm, int div)
|
|||
* VIA register values 0-255. I *10 before rounding, so we get tenth-degree
|
||||
* precision. (I could have done all 1024 values for our 10-bit readings,
|
||||
* but the function is very linear in the useful range (0-80 deg C), so
|
||||
* we'll just use linear interpolation for 10-bit readings.) So, tempLUT
|
||||
* we'll just use linear interpolation for 10-bit readings.) So, temp_lut
|
||||
* is the temp at via register values 0-255:
|
||||
*/
|
||||
static const s16 tempLUT[] = {
|
||||
static const s16 temp_lut[] = {
|
||||
-709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
|
||||
-503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
|
||||
-362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
|
||||
|
@ -261,7 +261,7 @@ static const s16 tempLUT[] = {
|
|||
* - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
|
||||
* Note that n=161:
|
||||
*/
|
||||
static const u8 viaLUT[] = {
|
||||
static const u8 via_lut[] = {
|
||||
12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
|
||||
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
|
||||
41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
|
||||
|
@ -284,26 +284,26 @@ static const u8 viaLUT[] = {
|
|||
*/
|
||||
static inline u8 TEMP_TO_REG(long val)
|
||||
{
|
||||
return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 :
|
||||
return via_lut[val <= -50000 ? 0 : val >= 110000 ? 160 :
|
||||
(val < 0 ? val - 500 : val + 500) / 1000 + 50];
|
||||
}
|
||||
|
||||
/* for 8-bit temperature hyst and over registers */
|
||||
#define TEMP_FROM_REG(val) ((long)tempLUT[val] * 100)
|
||||
#define TEMP_FROM_REG(val) ((long)temp_lut[val] * 100)
|
||||
|
||||
/* for 10-bit temperature readings */
|
||||
static inline long TEMP_FROM_REG10(u16 val)
|
||||
{
|
||||
u16 eightBits = val >> 2;
|
||||
u16 twoBits = val & 3;
|
||||
u16 eight_bits = val >> 2;
|
||||
u16 two_bits = val & 3;
|
||||
|
||||
/* no interpolation for these */
|
||||
if (twoBits == 0 || eightBits == 255)
|
||||
return TEMP_FROM_REG(eightBits);
|
||||
if (two_bits == 0 || eight_bits == 255)
|
||||
return TEMP_FROM_REG(eight_bits);
|
||||
|
||||
/* do some linear interpolation */
|
||||
return (tempLUT[eightBits] * (4 - twoBits) +
|
||||
tempLUT[eightBits + 1] * twoBits) * 25;
|
||||
return (temp_lut[eight_bits] * (4 - two_bits) +
|
||||
temp_lut[eight_bits + 1] * two_bits) * 25;
|
||||
}
|
||||
|
||||
#define DIV_FROM_REG(val) (1 << (val))
|
||||
|
@ -889,8 +889,8 @@ static int via686a_pci_probe(struct pci_dev *dev,
|
|||
|
||||
address = val & ~(VIA686A_EXTENT - 1);
|
||||
if (address == 0) {
|
||||
dev_err(&dev->dev, "base address not set - upgrade BIOS "
|
||||
"or use force_addr=0xaddr\n");
|
||||
dev_err(&dev->dev,
|
||||
"base address not set - upgrade BIOS or use force_addr=0xaddr\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -899,8 +899,9 @@ static int via686a_pci_probe(struct pci_dev *dev,
|
|||
return -ENODEV;
|
||||
if (!(val & 0x0001)) {
|
||||
if (!force_addr) {
|
||||
dev_warn(&dev->dev, "Sensors disabled, enable "
|
||||
"with force_addr=0x%x\n", address);
|
||||
dev_warn(&dev->dev,
|
||||
"Sensors disabled, enable with force_addr=0x%x\n",
|
||||
address);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
|
@ -571,8 +571,9 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
|
|||
break;
|
||||
default:
|
||||
count = -EINVAL;
|
||||
dev_warn(dev, "fan div value %ld not supported. "
|
||||
"Choose one of 1, 2, 4, or 8.\n", val);
|
||||
dev_warn(dev,
|
||||
"fan div value %ld not supported. Choose one of 1, 2, 4, or 8.\n",
|
||||
val);
|
||||
goto EXIT;
|
||||
}
|
||||
vt1211_write8(data, VT1211_REG_FAN_DIV,
|
||||
|
@ -674,8 +675,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
|||
break;
|
||||
default:
|
||||
count = -EINVAL;
|
||||
dev_warn(dev, "pwm mode %ld not supported. "
|
||||
"Choose one of 0 or 2.\n", val);
|
||||
dev_warn(dev,
|
||||
"pwm mode %ld not supported. Choose one of 0 or 2.\n",
|
||||
val);
|
||||
goto EXIT;
|
||||
}
|
||||
vt1211_write8(data, VT1211_REG_PWM_CTL,
|
||||
|
@ -700,8 +702,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
|||
case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
|
||||
if (val < 1 || val > 7) {
|
||||
count = -EINVAL;
|
||||
dev_warn(dev, "temp channel %ld not supported. "
|
||||
"Choose a value between 1 and 7.\n", val);
|
||||
dev_warn(dev,
|
||||
"temp channel %ld not supported. Choose a value between 1 and 7.\n",
|
||||
val);
|
||||
goto EXIT;
|
||||
}
|
||||
if (!ISTEMP(val - 1, data->uch_config)) {
|
||||
|
@ -1325,15 +1328,15 @@ static int __init vt1211_init(void)
|
|||
|
||||
if ((uch_config < -1) || (uch_config > 31)) {
|
||||
err = -EINVAL;
|
||||
pr_warn("Invalid UCH configuration %d. "
|
||||
"Choose a value between 0 and 31.\n", uch_config);
|
||||
pr_warn("Invalid UCH configuration %d. Choose a value between 0 and 31.\n",
|
||||
uch_config);
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
if ((int_mode < -1) || (int_mode > 0)) {
|
||||
err = -EINVAL;
|
||||
pr_warn("Invalid interrupt mode %d. "
|
||||
"Only mode 0 is supported.\n", int_mode);
|
||||
pr_warn("Invalid interrupt mode %d. Only mode 0 is supported.\n",
|
||||
int_mode);
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
|
|
|
@ -573,8 +573,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
|||
data->fan_div[nr] = 3;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "fan_div value %ld not supported. "
|
||||
"Choose one of 1, 2, 4 or 8!\n", val);
|
||||
dev_err(dev,
|
||||
"fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
|
||||
val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -840,8 +840,8 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
|
|||
&& (reg >= 0xff || (sio_data->kind == nct6775
|
||||
&& reg == 0x00))
|
||||
&& data->fan_div[i] < 0x07) {
|
||||
dev_dbg(dev, "Increasing fan%d "
|
||||
"clock divider from %u to %u\n",
|
||||
dev_dbg(dev,
|
||||
"Increasing fan%d clock divider from %u to %u\n",
|
||||
i + 1, div_from_reg(data->fan_div[i]),
|
||||
div_from_reg(data->fan_div[i] + 1));
|
||||
data->fan_div[i]++;
|
||||
|
@ -1110,9 +1110,9 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
|
|||
*/
|
||||
data->fan_min[nr] = 254;
|
||||
new_div = 7; /* 128 == (1 << 7) */
|
||||
dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
|
||||
"minimum\n", nr + 1, val,
|
||||
data->fan_from_reg_min(254, 7));
|
||||
dev_warn(dev,
|
||||
"fan%u low limit %lu below minimum %u, set to minimum\n",
|
||||
nr + 1, val, data->fan_from_reg_min(254, 7));
|
||||
} else if (!reg) {
|
||||
/*
|
||||
* Speed above this value cannot possibly be represented,
|
||||
|
@ -1120,9 +1120,9 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
|
|||
*/
|
||||
data->fan_min[nr] = 1;
|
||||
new_div = 0; /* 1 == (1 << 0) */
|
||||
dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
|
||||
"maximum\n", nr + 1, val,
|
||||
data->fan_from_reg_min(1, 0));
|
||||
dev_warn(dev,
|
||||
"fan%u low limit %lu above maximum %u, set to maximum\n",
|
||||
nr + 1, val, data->fan_from_reg_min(1, 0));
|
||||
} else {
|
||||
/*
|
||||
* Automatically pick the best divider, i.e. the one such
|
||||
|
@ -2396,15 +2396,15 @@ static int w83627ehf_probe(struct platform_device *pdev)
|
|||
en_vrm10 = superio_inb(sio_data->sioreg,
|
||||
SIO_REG_EN_VRM10);
|
||||
if ((en_vrm10 & 0x08) && data->vrm == 90) {
|
||||
dev_warn(dev, "Setting VID input "
|
||||
"voltage to TTL\n");
|
||||
dev_warn(dev,
|
||||
"Setting VID input voltage to TTL\n");
|
||||
superio_outb(sio_data->sioreg,
|
||||
SIO_REG_EN_VRM10,
|
||||
en_vrm10 & ~0x08);
|
||||
} else if (!(en_vrm10 & 0x08)
|
||||
&& data->vrm == 100) {
|
||||
dev_warn(dev, "Setting VID input "
|
||||
"voltage to VRM10\n");
|
||||
dev_warn(dev,
|
||||
"Setting VID input voltage to VRM10\n");
|
||||
superio_outb(sio_data->sioreg,
|
||||
SIO_REG_EN_VRM10,
|
||||
en_vrm10 | 0x08);
|
||||
|
@ -2420,8 +2420,8 @@ static int w83627ehf_probe(struct platform_device *pdev)
|
|||
if (err)
|
||||
goto exit_release;
|
||||
} else {
|
||||
dev_info(dev, "VID pins in output mode, CPU VID not "
|
||||
"available\n");
|
||||
dev_info(dev,
|
||||
"VID pins in output mode, CPU VID not available\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2795,8 +2795,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
|
|||
/* Activate logical device if needed */
|
||||
val = superio_inb(sioaddr, SIO_REG_ENABLE);
|
||||
if (!(val & 0x01)) {
|
||||
pr_warn("Forcibly enabling Super-I/O. "
|
||||
"Sensor is probably unusable.\n");
|
||||
pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
|
||||
superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
|
||||
}
|
||||
|
||||
|
|
|
@ -64,8 +64,8 @@ enum chips { w83781d, w83782d, w83783s, as99127f };
|
|||
/* Insmod parameters */
|
||||
static unsigned short force_subclients[4];
|
||||
module_param_array(force_subclients, short, NULL, 0);
|
||||
MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
|
||||
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
|
||||
MODULE_PARM_DESC(force_subclients,
|
||||
"List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
|
||||
|
||||
static bool reset;
|
||||
module_param(reset, bool, 0);
|
||||
|
@ -826,8 +826,9 @@ store_sensor(struct device *dev, struct device_attribute *da,
|
|||
data->sens[nr] = val;
|
||||
break;
|
||||
case W83781D_DEFAULT_BETA:
|
||||
dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
|
||||
"instead\n", W83781D_DEFAULT_BETA);
|
||||
dev_warn(dev,
|
||||
"Sensor type %d is deprecated, please use 4 instead\n",
|
||||
W83781D_DEFAULT_BETA);
|
||||
/* fall through */
|
||||
case 4: /* thermistor */
|
||||
tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
|
||||
|
@ -874,8 +875,8 @@ w83781d_detect_subclients(struct i2c_client *new_client)
|
|||
for (i = 2; i <= 3; i++) {
|
||||
if (force_subclients[i] < 0x48 ||
|
||||
force_subclients[i] > 0x4f) {
|
||||
dev_err(&new_client->dev, "Invalid subclient "
|
||||
"address %d; must be 0x48-0x4f\n",
|
||||
dev_err(&new_client->dev,
|
||||
"Invalid subclient address %d; must be 0x48-0x4f\n",
|
||||
force_subclients[i]);
|
||||
err = -EINVAL;
|
||||
goto ERROR_SC_1;
|
||||
|
@ -910,9 +911,9 @@ w83781d_detect_subclients(struct i2c_client *new_client)
|
|||
for (i = 0; i < num_sc; i++) {
|
||||
data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
|
||||
if (!data->lm75[i]) {
|
||||
dev_err(&new_client->dev, "Subclient %d "
|
||||
"registration at address 0x%x "
|
||||
"failed.\n", i, sc_addr[i]);
|
||||
dev_err(&new_client->dev,
|
||||
"Subclient %d registration at address 0x%x failed.\n",
|
||||
i, sc_addr[i]);
|
||||
err = -ENOMEM;
|
||||
if (i == 1)
|
||||
goto ERROR_SC_3;
|
||||
|
@ -1176,8 +1177,9 @@ w83781d_detect(struct i2c_client *client, struct i2c_board_info *info)
|
|||
goto err_nodev;
|
||||
|
||||
if (val1 <= 0x30 && w83781d_alias_detect(client, val1)) {
|
||||
dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
|
||||
"be the same as ISA device\n", address);
|
||||
dev_dbg(&adapter->dev,
|
||||
"Device at 0x%02x appears to be the same as ISA device\n",
|
||||
address);
|
||||
goto err_nodev;
|
||||
}
|
||||
|
||||
|
@ -1367,8 +1369,8 @@ w83781d_init_device(struct device *dev)
|
|||
* as I see very little reason why this would be needed at
|
||||
* all.
|
||||
*/
|
||||
dev_info(dev, "If reset=1 solved a problem you were "
|
||||
"having, please report!\n");
|
||||
dev_info(dev,
|
||||
"If reset=1 solved a problem you were having, please report!\n");
|
||||
|
||||
/* save these registers */
|
||||
i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
|
||||
|
@ -1425,8 +1427,8 @@ w83781d_init_device(struct device *dev)
|
|||
/* Enable temp2 */
|
||||
tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
|
||||
if (tmp & 0x01) {
|
||||
dev_warn(dev, "Enabling temp2, readings "
|
||||
"might not make sense\n");
|
||||
dev_warn(dev,
|
||||
"Enabling temp2, readings might not make sense\n");
|
||||
w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
|
||||
tmp & 0xfe);
|
||||
}
|
||||
|
@ -1436,8 +1438,8 @@ w83781d_init_device(struct device *dev)
|
|||
tmp = w83781d_read_value(data,
|
||||
W83781D_REG_TEMP3_CONFIG);
|
||||
if (tmp & 0x01) {
|
||||
dev_warn(dev, "Enabling temp3, "
|
||||
"readings might not make sense\n");
|
||||
dev_warn(dev,
|
||||
"Enabling temp3, readings might not make sense\n");
|
||||
w83781d_write_value(data,
|
||||
W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
|
||||
}
|
||||
|
|
|
@ -56,8 +56,8 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
|
|||
|
||||
static unsigned short force_subclients[4];
|
||||
module_param_array(force_subclients, short, NULL, 0);
|
||||
MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
|
||||
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
|
||||
MODULE_PARM_DESC(force_subclients,
|
||||
"List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
|
||||
|
||||
static bool reset;
|
||||
module_param(reset, bool, 0);
|
||||
|
|
|
@ -54,8 +54,8 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
|
|||
|
||||
static unsigned short force_subclients[4];
|
||||
module_param_array(force_subclients, short, NULL, 0);
|
||||
MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
|
||||
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
|
||||
MODULE_PARM_DESC(force_subclients,
|
||||
"List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
|
||||
|
||||
static bool init;
|
||||
module_param(init, bool, 0);
|
||||
|
@ -951,8 +951,8 @@ w83792d_detect_subclients(struct i2c_client *new_client)
|
|||
for (i = 2; i <= 3; i++) {
|
||||
if (force_subclients[i] < 0x48 ||
|
||||
force_subclients[i] > 0x4f) {
|
||||
dev_err(&new_client->dev, "invalid subclient "
|
||||
"address %d; must be 0x48-0x4f\n",
|
||||
dev_err(&new_client->dev,
|
||||
"invalid subclient address %d; must be 0x48-0x4f\n",
|
||||
force_subclients[i]);
|
||||
err = -ENODEV;
|
||||
goto ERROR_SC_0;
|
||||
|
@ -969,8 +969,9 @@ w83792d_detect_subclients(struct i2c_client *new_client)
|
|||
if (!(val & 0x80)) {
|
||||
if ((data->lm75[0] != NULL) &&
|
||||
((val & 0x7) == ((val >> 4) & 0x7))) {
|
||||
dev_err(&new_client->dev, "duplicate addresses 0x%x, "
|
||||
"use force_subclient\n", data->lm75[0]->addr);
|
||||
dev_err(&new_client->dev,
|
||||
"duplicate addresses 0x%x, use force_subclient\n",
|
||||
data->lm75[0]->addr);
|
||||
err = -ENODEV;
|
||||
goto ERROR_SC_1;
|
||||
}
|
||||
|
|
|
@ -59,8 +59,8 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
|
|||
|
||||
static unsigned short force_subclients[4];
|
||||
module_param_array(force_subclients, short, NULL, 0);
|
||||
MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
|
||||
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
|
||||
MODULE_PARM_DESC(force_subclients,
|
||||
"List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
|
||||
|
||||
static bool reset;
|
||||
module_param(reset, bool, 0);
|
||||
|
@ -1921,8 +1921,8 @@ static int w83793_probe(struct i2c_client *client,
|
|||
}
|
||||
if (i == ARRAY_SIZE(watchdog_minors)) {
|
||||
data->watchdog_miscdev.minor = 0;
|
||||
dev_warn(&client->dev, "Couldn't register watchdog chardev "
|
||||
"(due to no free minor)\n");
|
||||
dev_warn(&client->dev,
|
||||
"Couldn't register watchdog chardev (due to no free minor)\n");
|
||||
}
|
||||
|
||||
mutex_unlock(&watchdog_data_mutex);
|
||||
|
|
|
@ -2120,11 +2120,12 @@ static void w83795_check_dynamic_in_limits(struct i2c_client *client)
|
|||
&w83795_in[i][3].dev_attr.attr,
|
||||
S_IRUGO);
|
||||
if (err_max || err_min)
|
||||
dev_warn(&client->dev, "Failed to set in%d limits "
|
||||
"read-only (%d, %d)\n", i, err_max, err_min);
|
||||
dev_warn(&client->dev,
|
||||
"Failed to set in%d limits read-only (%d, %d)\n",
|
||||
i, err_max, err_min);
|
||||
else
|
||||
dev_info(&client->dev, "in%d limits set dynamically "
|
||||
"from VID\n", i);
|
||||
dev_info(&client->dev,
|
||||
"in%d limits set dynamically from VID\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#ifndef _LINUX_NTC_H
|
||||
#define _LINUX_NTC_H
|
||||
|
||||
struct iio_channel;
|
||||
|
||||
enum ntc_thermistor_type {
|
||||
TYPE_NCPXXWB473,
|
||||
TYPE_NCPXXWL333,
|
||||
|
@ -39,13 +41,17 @@ struct ntc_thermistor_platform_data {
|
|||
* described at Documentation/hwmon/ntc_thermistor
|
||||
*
|
||||
* pullup/down_ohm: 0 for infinite / not-connected
|
||||
*
|
||||
* chan: iio_channel pointer to communicate with the ADC which the
|
||||
* thermistor is using for conversion of the analog values.
|
||||
*/
|
||||
int (*read_uV)(void);
|
||||
unsigned int pullup_uV;
|
||||
int (*read_uv)(struct ntc_thermistor_platform_data *);
|
||||
unsigned int pullup_uv;
|
||||
|
||||
unsigned int pullup_ohm;
|
||||
unsigned int pulldown_ohm;
|
||||
enum { NTC_CONNECTED_POSITIVE, NTC_CONNECTED_GROUND } connect;
|
||||
struct iio_channel *chan;
|
||||
|
||||
int (*read_ohm)(void);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue