Notable changes:
Heiko Schocher provided a driver for TI TMP103. Kamil Debski provided a driver for pwm-controlled fans. Neelesh Gupta provided a driver for power, fan rpm, voltage and temperature reporting on powerpc/powernv systems. Scott Kanowitz provided a driver supporting Lattice's POWR1220 power manager IC. Richard Zhu provided a pmbus front-end driver for TPS40422. Frans Klaver added support for TMP112 to the lm75 driver. Johannes Pointner added support for EPCOS B57330V2103 to the ntc_thermistor driver. Guenter Roeck added support for TMP441 and TMP442 to the tmp421 driver. Axel Lin converted several drivers to the new hwmon API (36 of them, if I counted correctly), and cleaned up many of the drivers along the way. There are also a number of patches fixing bugs discovered while testing Axel's changes. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJT4D5rAAoJEMsfJm/On5mB/skP/3VhhwIx+BikBSA0NH6Q6W/6 wKlC1GdYoGUhLZop0o1nFrYZUgj7YEo7L6odPCKkqUyO5eEalhumV3KXusH1IWcE tw+xffdHEihSi2B9XssPFQW1bYGEJECP6GWRma+M76KG1nHJMnuHMTThGuSiei6P zCb2ZYjR+10FlTPf+Rl/2o11501Lj5Rq8VYqqKSMNf1fW8OsTkbC2tZnvCS3UTlg emm1lzWIiHxMmDQkNZsGN1CM5n1U5P6Kwr4RZKZjP4Jtx5EbF3A8vK7uBflUXFHC NELIzaO25pXiEMpYB6YVFpDUMPcsQR/W+esQD/FmHRltLtw7/+ZW7A/42oejRt93 rvoabFj0q+DRvIUi1URfGaBgCp5V1z+8uEPQJu2QiUe/iGZyxpJIGNl90JjoV9xP UEkAaNCPvl3Voih7+UulIolehiO7mibF/+vp72uJ/kgBCaFXgiftpg+WVhwqkwk1 UbUcejDMZnSXUY99UD2ut5jWo8YYhEaqvCDhsrcmnVLr791mZfhor1XYn77o7a4a wI5h2S8r3xkBSSHLAR5Y/vb8peMHXSr6VmcKHM5m/oEU8OYi5xujQPWn2hos7AHp 2O436774VVVaULB7OZOETkvNtSCZFR/dHV8OcVTLc2ASh4UjJp4UD4Hy9p0iAx9h ExBE8supJWHBpX+walyc =9j+M -----END PGP SIGNATURE----- Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging Pull hwmon updates from Guenter Roeck: "Notable changes: - Heiko Schocher provided a driver for TI TMP103. - Kamil Debski provided a driver for pwm-controlled fans. - Neelesh Gupta provided a driver for power, fan rpm, voltage and temperature reporting on powerpc/powernv systems. - Scott Kanowitz provided a driver supporting Lattice's POWR1220 power manager IC. - Richard Zhu provided a pmbus front-end driver for TPS40422. - Frans Klaver added support for TMP112 to the lm75 driver. - Johannes Pointner added support for EPCOS B57330V2103 to the ntc_thermistor driver. - Guenter Roeck added support for TMP441 and TMP442 to the tmp421 driver. - Axel Lin converted several drivers to the new hwmon API (36 of them, if I counted correctly), and cleaned up many of the drivers along the way. There are also a number of patches fixing bugs discovered while testing Axel's changes" * tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (88 commits) hwmon: (g762) Use of_property_read_u32 at appropriate place hwmon: (sis5595) Prevent overflow problem when writing large limits hwmon: (gpio-fan) Prevent overflow problem when writing large limits hwmon: (ibmpowernv) Use of_property_read_u32 at appropriate place hwmon: (lm85) Convert to devm_hwmon_device_register_with_groups hwmon: (lm85) Avoid forward declaration hwmon: (lm78) Convert to devm_hwmon_device_register_with_groups hwmon: (max6697) Use of_property_read_bool at appropriate places hwmon: (pwm-fan) Make SENSORS_PWM_FAN depend on OF hwmon: (pwm-fan) Remove duplicate dev_set_drvdata call hwmon: (nct6775) Remove num_attr_groups from struct nct6775_data hwmon: (nct6775) Update module description and Kconfig for NCT6106D and NCT6791D hwmon: (adt7411) Convert to devm_hwmon_device_register_with_groups hwmon: (g762) Convert to hwmon_device_register_with_groups hwmon: (emc2103) Convert to devm_hwmon_device_register_with_groups hwmon: (smsc47m1) Avoid forward declaration hwmon: (smsc47m192) Convert to devm_hwmon_device_register_with_groups hwmon: (smsc47m192) Avoid forward declaration hwmon: (max1668) Make max1668_addr_list array const hwmon: (max6639) Make normal_i2c array const ...
This commit is contained in:
commit
161d2e0a19
|
@ -0,0 +1,23 @@
|
|||
IBM POWERNV platform sensors
|
||||
----------------------------
|
||||
|
||||
Required node properties:
|
||||
- compatible: must be one of
|
||||
"ibm,opal-sensor-cooling-fan"
|
||||
"ibm,opal-sensor-amb-temp"
|
||||
"ibm,opal-sensor-power-supply"
|
||||
"ibm,opal-sensor-power"
|
||||
- sensor-id: an opaque id provided by the firmware to the kernel, identifies a
|
||||
given sensor and its attribute data
|
||||
|
||||
Example sensors node:
|
||||
|
||||
cooling-fan#8-data {
|
||||
sensor-id = <0x7052107>;
|
||||
compatible = "ibm,opal-sensor-cooling-fan";
|
||||
};
|
||||
|
||||
amb-temp#1-thrs {
|
||||
sensor-id = <0x5096000>;
|
||||
compatible = "ibm,opal-sensor-amb-temp";
|
||||
};
|
|
@ -3,6 +3,7 @@ NTC Thermistor hwmon sensors
|
|||
|
||||
Requires node properties:
|
||||
- "compatible" value : one of
|
||||
"epcos,b57330v2103"
|
||||
"murata,ncp15wb473"
|
||||
"murata,ncp18wb473"
|
||||
"murata,ncp21wb473"
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
Bindings for a fan connected to the PWM lines
|
||||
|
||||
Required properties:
|
||||
- compatible : "pwm-fan"
|
||||
- pwms : the PWM that is used to control the PWM fan
|
||||
|
||||
Example:
|
||||
pwm-fan {
|
||||
compatible = "pwm-fan";
|
||||
status = "okay";
|
||||
pwms = <&pwm 0 10000 0>;
|
||||
};
|
|
@ -84,5 +84,6 @@ stm,m41t80 M41T80 - SERIAL ACCESS RTC WITH ALARMS
|
|||
taos,tsl2550 Ambient Light Sensor with SMBUS/Two Wire Serial Interface
|
||||
ti,tsc2003 I2C Touch-Screen Controller
|
||||
ti,tmp102 Low Power Digital Temperature Sensor with SMBUS/Two Wire Serial Interface
|
||||
ti,tmp103 Low Power Digital Temperature Sensor with SMBUS/Two Wire Serial Interface
|
||||
ti,tmp275 Digital Temperature Sensor
|
||||
winbond,wpct301 i2c trusted platform module (TPM)
|
||||
|
|
|
@ -42,6 +42,7 @@ dmo Data Modul AG
|
|||
ebv EBV Elektronik
|
||||
edt Emerging Display Technologies
|
||||
emmicro EM Microelectronic
|
||||
epcos EPCOS AG
|
||||
epfl Ecole Polytechnique Fédérale de Lausanne
|
||||
epson Seiko Epson Corp.
|
||||
est ESTeem Wireless Modems
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
Kernel Driver IBMPOWERNV
|
||||
========================
|
||||
|
||||
Supported systems:
|
||||
* Any recent IBM P servers based on POWERNV platform
|
||||
|
||||
Author: Neelesh Gupta
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements reading the platform sensors data like temperature/fan/
|
||||
voltage/power for 'POWERNV' platform.
|
||||
|
||||
The driver uses the platform device infrastructure. It probes the device tree
|
||||
for sensor devices during the __init phase and registers them with the 'hwmon'.
|
||||
'hwmon' populates the 'sysfs' tree having attribute files, each for a given
|
||||
sensor type and its attribute data.
|
||||
|
||||
All the nodes in the DT appear under "/ibm,opal/sensors" and each valid node in
|
||||
the DT maps to an attribute file in 'sysfs'. The node exports unique 'sensor-id'
|
||||
which the driver uses to make an OPAL call to the firmware.
|
||||
|
||||
Usage notes
|
||||
-----------
|
||||
The driver is built statically with the kernel by enabling the config
|
||||
CONFIG_SENSORS_IBMPOWERNV. It can also be built as module 'ibmpowernv'.
|
||||
|
||||
Sysfs attributes
|
||||
----------------
|
||||
|
||||
fanX_input Measured RPM value.
|
||||
fanX_min Threshold RPM for alert generation.
|
||||
fanX_fault 0: No fail condition
|
||||
1: Failing fan
|
||||
tempX_input Measured ambient temperature.
|
||||
tempX_max Threshold ambient temperature for alert generation.
|
||||
inX_input Measured power supply voltage
|
||||
inX_fault 0: No fail condition.
|
||||
1: Failing power supply.
|
||||
power1_input System power consumption (microWatt)
|
|
@ -42,13 +42,14 @@ Supported chips:
|
|||
Addresses scanned: none
|
||||
Datasheet: Publicly available at the ST website
|
||||
http://www.st.com/internet/analog/product/121769.jsp
|
||||
* Texas Instruments TMP100, TMP101, TMP105, TMP75, TMP175, TMP275
|
||||
Prefixes: 'tmp100', 'tmp101', 'tmp105', 'tmp175', 'tmp75', 'tmp275'
|
||||
* Texas Instruments TMP100, TMP101, TMP105, TMP112, TMP75, TMP175, TMP275
|
||||
Prefixes: 'tmp100', 'tmp101', 'tmp105', 'tmp112', 'tmp175', 'tmp75', 'tmp275'
|
||||
Addresses scanned: none
|
||||
Datasheet: Publicly available at the Texas Instruments website
|
||||
http://www.ti.com/product/tmp100
|
||||
http://www.ti.com/product/tmp101
|
||||
http://www.ti.com/product/tmp105
|
||||
http://www.ti.com/product/tmp112
|
||||
http://www.ti.com/product/tmp75
|
||||
http://www.ti.com/product/tmp175
|
||||
http://www.ti.com/product/tmp275
|
||||
|
|
|
@ -6,6 +6,11 @@ Supported thermistors from Murata:
|
|||
Prefixes: 'ncp15wb473', 'ncp18wb473', 'ncp21wb473', 'ncp03wb473', 'ncp15wl333'
|
||||
Datasheet: Publicly available at Murata
|
||||
|
||||
Supported thermistors from EPCOS:
|
||||
* EPCOS NTC Thermistors B57330V2103
|
||||
Prefixes: b57330v2103
|
||||
Datasheet: Publicly available at EPCOS
|
||||
|
||||
Other NTC thermistors can be supported simply by adding compensation
|
||||
tables; e.g., NCP15WL333 support is added by the table ncpXXwl333.
|
||||
|
||||
|
|
|
@ -23,12 +23,11 @@ Supported chips:
|
|||
http://www.lineagepower.com/oem/pdf/PDT012A0X.pdf
|
||||
http://www.lineagepower.com/oem/pdf/UDT020A0X.pdf
|
||||
http://www.lineagepower.com/oem/pdf/MDT040A0X.pdf
|
||||
* Texas Instruments TPS40400, TPS40422
|
||||
Prefixes: 'tps40400', 'tps40422'
|
||||
* Texas Instruments TPS40400
|
||||
Prefixes: 'tps40400'
|
||||
Addresses scanned: -
|
||||
Datasheets:
|
||||
http://www.ti.com/lit/gpn/tps40400
|
||||
http://www.ti.com/lit/gpn/tps40422
|
||||
* Generic PMBus devices
|
||||
Prefix: 'pmbus'
|
||||
Addresses scanned: -
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
Kernel driver powr1220
|
||||
==================
|
||||
|
||||
Supported chips:
|
||||
* Lattice POWR1220AT8
|
||||
Prefix: 'powr1220'
|
||||
Addresses scanned: none
|
||||
Datasheet: Publicly available at the Lattice website
|
||||
http://www.latticesemi.com/
|
||||
|
||||
Author: Scott Kanowitz <scott.kanowitz@gmail.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver supports the Lattice POWR1220AT8 chip. The POWR1220
|
||||
includes voltage monitoring for 14 inputs as well as trim settings
|
||||
for output voltages and GPIOs. This driver implements the voltage
|
||||
monitoring portion of the chip.
|
||||
|
||||
Voltages are sampled by a 12-bit ADC with a step size of 2 mV.
|
||||
An in-line attenuator allows measurements from 0 to 6 V. The
|
||||
attenuator is enabled or disabled depending on the setting of the
|
||||
input's max value. The driver will enable the attenuator for any
|
||||
value over the low measurement range maximum of 2 V.
|
||||
|
||||
The input naming convention is as follows:
|
||||
|
||||
driver name pin name
|
||||
in0 VMON1
|
||||
in1 VMON2
|
||||
in2 VMON3
|
||||
in2 VMON4
|
||||
in4 VMON5
|
||||
in5 VMON6
|
||||
in6 VMON7
|
||||
in7 VMON8
|
||||
in8 VMON9
|
||||
in9 VMON10
|
||||
in10 VMON11
|
||||
in11 VMON12
|
||||
in12 VCCA
|
||||
in13 VCCINP
|
||||
|
||||
The ADC readings are updated on request with a minimum period of 1s.
|
|
@ -0,0 +1,17 @@
|
|||
Kernel driver pwm-fan
|
||||
=====================
|
||||
|
||||
This driver enables the use of a PWM module to drive a fan. It uses the
|
||||
generic PWM interface thus it is hardware independent. It can be used on
|
||||
many SoCs, as long as the SoC supplies a PWM line driver that exposes
|
||||
the generic PWM API.
|
||||
|
||||
Author: Kamil Debski <k.debski@samsung.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The driver implements a simple interface for driving a fan connected to
|
||||
a PWM output. It uses the generic PWM interface, thus it can be used with
|
||||
a range of SoCs. The driver exposes the fan to the user space through
|
||||
the hwmon's sysfs interface.
|
|
@ -0,0 +1,28 @@
|
|||
Kernel driver tmp103
|
||||
====================
|
||||
|
||||
Supported chips:
|
||||
* Texas Instruments TMP103
|
||||
Prefix: 'tmp103'
|
||||
Addresses scanned: none
|
||||
Product info and datasheet: http://www.ti.com/product/tmp103
|
||||
|
||||
Author:
|
||||
Heiko Schocher <hs@denx.de>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The TMP103 is a digital output temperature sensor in a four-ball
|
||||
wafer chip-scale package (WCSP). The TMP103 is capable of reading
|
||||
temperatures to a resolution of 1°C. The TMP103 is specified for
|
||||
operation over a temperature range of –40°C to +125°C.
|
||||
|
||||
Resolution: 8 Bits
|
||||
Accuracy: ±1°C Typ (–10°C to +100°C)
|
||||
|
||||
The driver provides the common sysfs-interface for temperatures (see
|
||||
Documentation/hwmon/sysfs-interface under Temperatures).
|
||||
|
||||
Please refer how to instantiate this driver:
|
||||
Documentation/i2c/instantiating-devices
|
|
@ -8,12 +8,20 @@ Supported chips:
|
|||
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp421.html
|
||||
* Texas Instruments TMP422
|
||||
Prefix: 'tmp422'
|
||||
Addresses scanned: I2C 0x2a, 0x4c, 0x4d, 0x4e and 0x4f
|
||||
Addresses scanned: I2C 0x4c, 0x4d, 0x4e and 0x4f
|
||||
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp421.html
|
||||
* Texas Instruments TMP423
|
||||
Prefix: 'tmp423'
|
||||
Addresses scanned: I2C 0x2a, 0x4c, 0x4d, 0x4e and 0x4f
|
||||
Addresses scanned: I2C 0x4c and 0x4d
|
||||
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp421.html
|
||||
* Texas Instruments TMP441
|
||||
Prefix: 'tmp441'
|
||||
Addresses scanned: I2C 0x2a, 0x4c, 0x4d, 0x4e and 0x4f
|
||||
Datasheet: http://www.ti.com/product/tmp441
|
||||
* Texas Instruments TMP442
|
||||
Prefix: 'tmp442'
|
||||
Addresses scanned: I2C 0x4c and 0x4d
|
||||
Datasheet: http://www.ti.com/product/tmp442
|
||||
|
||||
Authors:
|
||||
Andre Prendel <andre.prendel@gmx.de>
|
||||
|
@ -21,13 +29,13 @@ Authors:
|
|||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for Texas Instruments TMP421, TMP422
|
||||
and TMP423 temperature sensor chips. These chips implement one local
|
||||
and up to one (TMP421), up to two (TMP422) or up to three (TMP423)
|
||||
remote sensors. Temperature is measured in degrees Celsius. The chips
|
||||
are wired over I2C/SMBus and specified over a temperature range of -40
|
||||
to +125 degrees Celsius. Resolution for both the local and remote
|
||||
channels is 0.0625 degree C.
|
||||
This driver implements support for Texas Instruments TMP421, TMP422,
|
||||
TMP423, TMP441, and TMP442 temperature sensor chips. These chips
|
||||
implement one local and up to one (TMP421, TMP441), up to two (TMP422,
|
||||
TMP442) or up to three (TMP423) remote sensors. Temperature is measured
|
||||
in degrees Celsius. The chips are wired over I2C/SMBus and specified
|
||||
over a temperature range of -40 to +125 degrees Celsius. Resolution
|
||||
for both the local and remote channels is 0.0625 degree C.
|
||||
|
||||
The chips support only temperature measurement. The driver exports
|
||||
the temperature values via the following sysfs files:
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
Kernel driver tps40422
|
||||
======================
|
||||
|
||||
Supported chips:
|
||||
* TI TPS40422
|
||||
Prefix: 'tps40422'
|
||||
Addresses scanned: -
|
||||
Datasheet: http://www.ti.com/lit/gpn/tps40422
|
||||
|
||||
Author: Zhu Laiwen <richard.zhu@nsn.com>
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver supports TI TPS40422 Dual-Output or Two-Phase Synchronous Buck
|
||||
Controller with PMBus
|
||||
|
||||
The driver is a client driver to the core PMBus driver.
|
||||
Please see Documentation/hwmon/pmbus for details on PMBus client drivers.
|
||||
|
||||
|
||||
Usage Notes
|
||||
-----------
|
||||
|
||||
This driver does not auto-detect devices. You will have to instantiate the
|
||||
devices explicitly. Please see Documentation/i2c/instantiating-devices for
|
||||
details.
|
||||
|
||||
|
||||
Platform data support
|
||||
---------------------
|
||||
|
||||
The driver supports standard PMBus driver platform data.
|
||||
|
||||
|
||||
Sysfs entries
|
||||
-------------
|
||||
|
||||
The following attributes are supported.
|
||||
|
||||
in[1-2]_label "vout[1-2]"
|
||||
in[1-2]_input Measured voltage. From READ_VOUT register.
|
||||
in[1-2]_alarm voltage alarm.
|
||||
|
||||
curr[1-2]_input Measured current. From READ_IOUT register.
|
||||
curr[1-2]_label "iout[1-2]"
|
||||
curr1_max Maximum current. From IOUT_OC_WARN_LIMIT register.
|
||||
curr1_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT register.
|
||||
curr1_max_alarm Current high alarm. From IOUT_OC_WARN_LIMIT status.
|
||||
curr1_crit_alarm Current critical high alarm. From IOUT_OC_FAULT status.
|
||||
curr2_alarm Current high alarm. From IOUT_OC_WARNING status.
|
||||
|
||||
temp1_input Measured temperature. From READ_TEMPERATURE_2 register on page 0.
|
||||
temp1_max Maximum temperature. From OT_WARN_LIMIT register.
|
||||
temp1_crit Critical high temperature. From OT_FAULT_LIMIT register.
|
||||
temp1_max_alarm Chip temperature high alarm. Set by comparing
|
||||
READ_TEMPERATURE_2 on page 0 with OT_WARN_LIMIT if TEMP_OT_WARNING
|
||||
status is set.
|
||||
temp1_crit_alarm Chip temperature critical high alarm. Set by comparing
|
||||
READ_TEMPERATURE_2 on page 0 with OT_FAULT_LIMIT if TEMP_OT_FAULT
|
||||
status is set.
|
||||
temp2_input Measured temperature. From READ_TEMPERATURE_2 register on page 1.
|
||||
temp2_alarm Chip temperature alarm on page 1.
|
|
@ -554,6 +554,17 @@ config SENSORS_IBMPEX
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called ibmpex.
|
||||
|
||||
config SENSORS_IBMPOWERNV
|
||||
tristate "IBM POWERNV platform sensors"
|
||||
depends on PPC_POWERNV
|
||||
default y
|
||||
help
|
||||
If you say yes here you get support for the temperature/fan/power
|
||||
sensors on your PowerNV platform.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ibmpowernv.
|
||||
|
||||
config SENSORS_IIO_HWMON
|
||||
tristate "Hwmon driver that uses channels specified via iio maps"
|
||||
depends on IIO
|
||||
|
@ -608,6 +619,18 @@ config SENSORS_JC42
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called jc42.
|
||||
|
||||
config SENSORS_POWR1220
|
||||
tristate "Lattice POWR1220 Power Monitoring"
|
||||
depends on I2C
|
||||
default n
|
||||
help
|
||||
If you say yes here you get access to the hardware monitoring
|
||||
functions of the Lattice POWR1220 isp Power Supply Monitoring,
|
||||
Sequencing and Margining Controller.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called powr1220.
|
||||
|
||||
config SENSORS_LINEAGE
|
||||
tristate "Lineage Compact Power Line Power Entry Module"
|
||||
depends on I2C
|
||||
|
@ -882,8 +905,8 @@ config SENSORS_LM75
|
|||
- NXP's LM75A
|
||||
- ST Microelectronics STDS75
|
||||
- TelCom (now Microchip) TCN75
|
||||
- Texas Instruments TMP100, TMP101, TMP105, TMP75, TMP175,
|
||||
TMP275
|
||||
- Texas Instruments TMP100, TMP101, TMP105, TMP112, TMP75,
|
||||
TMP175, TMP275
|
||||
|
||||
This driver supports driver model based binding through board
|
||||
specific I2C device tables.
|
||||
|
@ -1061,7 +1084,7 @@ config SENSORS_NTC_THERMISTOR
|
|||
|
||||
Currently, this driver supports
|
||||
NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, and NCP15WL333
|
||||
from Murata.
|
||||
from Murata and B57330V2103 from EPCOS.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ntc-thermistor.
|
||||
|
@ -1082,8 +1105,8 @@ config SENSORS_NCT6775
|
|||
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
|
||||
functionality of the Nuvoton NCT6106D, NCT6775F, NCT6776F, NCT6779D,
|
||||
NCT6791D 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
|
||||
|
@ -1105,6 +1128,17 @@ config SENSORS_PCF8591
|
|||
|
||||
source drivers/hwmon/pmbus/Kconfig
|
||||
|
||||
config SENSORS_PWM_FAN
|
||||
tristate "PWM fan"
|
||||
depends on (PWM && OF) || COMPILE_TEST
|
||||
help
|
||||
If you say yes here you get support for fans connected to PWM lines.
|
||||
The driver uses the generic PWM interface, thus it will work on a
|
||||
variety of SoCs.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called pwm-fan.
|
||||
|
||||
config SENSORS_SHT15
|
||||
tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
|
||||
depends on GPIOLIB
|
||||
|
@ -1393,6 +1427,17 @@ config SENSORS_TMP102
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called tmp102.
|
||||
|
||||
config SENSORS_TMP103
|
||||
tristate "Texas Instruments TMP103"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for Texas Instruments TMP103
|
||||
sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tmp103.
|
||||
|
||||
config SENSORS_TMP401
|
||||
tristate "Texas Instruments TMP401 and compatibles"
|
||||
depends on I2C
|
||||
|
@ -1408,7 +1453,7 @@ config SENSORS_TMP421
|
|||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for Texas Instruments TMP421,
|
||||
TMP422 and TMP423 temperature sensor chips.
|
||||
TMP422, TMP423, TMP441, and TMP442 temperature sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tmp421.
|
||||
|
|
|
@ -71,6 +71,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
|
|||
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
|
||||
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
|
||||
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
|
||||
obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o
|
||||
obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o
|
||||
obj-$(CONFIG_SENSORS_INA209) += ina209.o
|
||||
obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o
|
||||
|
@ -120,6 +121,8 @@ obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
|
|||
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
|
||||
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
|
||||
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
|
||||
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
|
||||
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
|
||||
obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
|
||||
obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o
|
||||
|
@ -135,6 +138,7 @@ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
|
|||
obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o
|
||||
obj-$(CONFIG_SENSORS_THMC50) += thmc50.o
|
||||
obj-$(CONFIG_SENSORS_TMP102) += tmp102.o
|
||||
obj-$(CONFIG_SENSORS_TMP103) += tmp103.o
|
||||
obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
|
||||
obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
|
||||
obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
static u8 AD7414_REG_LIMIT[] = { AD7414_REG_T_HIGH, AD7414_REG_T_LOW };
|
||||
|
||||
struct ad7414_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex lock; /* atomic read data updates */
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long next_update; /* In jiffies */
|
||||
|
@ -72,8 +72,8 @@ static inline int ad7414_write(struct i2c_client *client, u8 reg, u8 value)
|
|||
|
||||
static struct ad7414_data *ad7414_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ad7414_data *data = i2c_get_clientdata(client);
|
||||
struct ad7414_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
|
@ -127,8 +127,8 @@ static ssize_t set_max_min(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ad7414_data *data = i2c_get_clientdata(client);
|
||||
struct ad7414_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
u8 reg = AD7414_REG_LIMIT[index];
|
||||
long temp;
|
||||
|
@ -164,7 +164,7 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
|
|||
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 4);
|
||||
|
||||
static struct attribute *ad7414_attributes[] = {
|
||||
static struct attribute *ad7414_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
|
@ -173,27 +173,25 @@ static struct attribute *ad7414_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group ad7414_group = {
|
||||
.attrs = ad7414_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ad7414);
|
||||
|
||||
static int ad7414_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *dev_id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct ad7414_data *data;
|
||||
struct device *hwmon_dev;
|
||||
int conf;
|
||||
int err;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_READ_WORD_DATA))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct ad7414_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct ad7414_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
dev_info(&client->dev, "chip found\n");
|
||||
|
@ -201,38 +199,16 @@ static int ad7414_probe(struct i2c_client *client,
|
|||
/* Make sure the chip is powered up. */
|
||||
conf = i2c_smbus_read_byte_data(client, AD7414_REG_CONF);
|
||||
if (conf < 0)
|
||||
dev_warn(&client->dev,
|
||||
"ad7414_probe unable to read config register.\n");
|
||||
dev_warn(dev, "ad7414_probe unable to read config register.\n");
|
||||
else {
|
||||
conf &= ~(1 << 7);
|
||||
i2c_smbus_write_byte_data(client, AD7414_REG_CONF, conf);
|
||||
}
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &ad7414_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &ad7414_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ad7414_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ad7414_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &ad7414_group);
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev,
|
||||
client->name,
|
||||
data, ad7414_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ad7414_id[] = {
|
||||
|
@ -246,7 +222,6 @@ static struct i2c_driver ad7414_driver = {
|
|||
.name = "ad7414",
|
||||
},
|
||||
.probe = ad7414_probe,
|
||||
.remove = ad7414_remove,
|
||||
.id_table = ad7414_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -44,8 +44,7 @@ static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN,
|
|||
AD7418_REG_TEMP_OS };
|
||||
|
||||
struct ad7418_data {
|
||||
struct device *hwmon_dev;
|
||||
struct attribute_group attrs;
|
||||
struct i2c_client *client;
|
||||
enum chips type;
|
||||
struct mutex lock;
|
||||
int adc_max; /* number of ADC channels */
|
||||
|
@ -55,48 +54,10 @@ struct ad7418_data {
|
|||
u16 in[4];
|
||||
};
|
||||
|
||||
static int ad7418_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int ad7418_remove(struct i2c_client *client);
|
||||
|
||||
static const struct i2c_device_id ad7418_id[] = {
|
||||
{ "ad7416", ad7416 },
|
||||
{ "ad7417", ad7417 },
|
||||
{ "ad7418", ad7418 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ad7418_id);
|
||||
|
||||
static struct i2c_driver ad7418_driver = {
|
||||
.driver = {
|
||||
.name = "ad7418",
|
||||
},
|
||||
.probe = ad7418_probe,
|
||||
.remove = ad7418_remove,
|
||||
.id_table = ad7418_id,
|
||||
};
|
||||
|
||||
static void ad7418_init_client(struct i2c_client *client)
|
||||
{
|
||||
struct ad7418_data *data = i2c_get_clientdata(client);
|
||||
|
||||
int reg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF);
|
||||
if (reg < 0) {
|
||||
dev_err(&client->dev, "cannot read configuration register\n");
|
||||
} else {
|
||||
dev_info(&client->dev, "configuring for mode 1\n");
|
||||
i2c_smbus_write_byte_data(client, AD7418_REG_CONF, reg & 0xfe);
|
||||
|
||||
if (data->type == ad7417 || data->type == ad7418)
|
||||
i2c_smbus_write_byte_data(client,
|
||||
AD7418_REG_CONF2, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ad7418_data *ad7418_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ad7418_data *data = i2c_get_clientdata(client);
|
||||
struct ad7418_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
|
@ -165,8 +126,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ad7418_data *data = i2c_get_clientdata(client);
|
||||
struct ad7418_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
int ret = kstrtol(buf, 10, &temp);
|
||||
|
||||
|
@ -193,14 +154,15 @@ static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 1);
|
|||
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 3);
|
||||
|
||||
static struct attribute *ad7416_attributes[] = {
|
||||
static struct attribute *ad7416_attrs[] = {
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ad7416);
|
||||
|
||||
static struct attribute *ad7417_attributes[] = {
|
||||
static struct attribute *ad7417_attrs[] = {
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
|
@ -210,83 +172,100 @@ static struct attribute *ad7417_attributes[] = {
|
|||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ad7417);
|
||||
|
||||
static struct attribute *ad7418_attributes[] = {
|
||||
static struct attribute *ad7418_attrs[] = {
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ad7418);
|
||||
|
||||
static void ad7418_init_client(struct i2c_client *client)
|
||||
{
|
||||
struct ad7418_data *data = i2c_get_clientdata(client);
|
||||
|
||||
int reg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF);
|
||||
if (reg < 0) {
|
||||
dev_err(&client->dev, "cannot read configuration register\n");
|
||||
} else {
|
||||
dev_info(&client->dev, "configuring for mode 1\n");
|
||||
i2c_smbus_write_byte_data(client, AD7418_REG_CONF, reg & 0xfe);
|
||||
|
||||
if (data->type == ad7417 || data->type == ad7418)
|
||||
i2c_smbus_write_byte_data(client,
|
||||
AD7418_REG_CONF2, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
static int ad7418_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct ad7418_data *data;
|
||||
int err;
|
||||
struct device *hwmon_dev;
|
||||
const struct attribute_group **attr_groups = NULL;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct ad7418_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct ad7418_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
|
||||
mutex_init(&data->lock);
|
||||
data->client = client;
|
||||
data->type = id->driver_data;
|
||||
|
||||
switch (data->type) {
|
||||
case ad7416:
|
||||
data->adc_max = 0;
|
||||
data->attrs.attrs = ad7416_attributes;
|
||||
attr_groups = ad7416_groups;
|
||||
break;
|
||||
|
||||
case ad7417:
|
||||
data->adc_max = 4;
|
||||
data->attrs.attrs = ad7417_attributes;
|
||||
attr_groups = ad7417_groups;
|
||||
break;
|
||||
|
||||
case ad7418:
|
||||
data->adc_max = 1;
|
||||
data->attrs.attrs = ad7418_attributes;
|
||||
attr_groups = ad7418_groups;
|
||||
break;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "%s chip found\n", client->name);
|
||||
dev_info(dev, "%s chip found\n", client->name);
|
||||
|
||||
/* Initialize the AD7418 chip */
|
||||
ad7418_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &data->attrs);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||
return err;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev,
|
||||
client->name,
|
||||
data, attr_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static int ad7418_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ad7418_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||
return 0;
|
||||
}
|
||||
static const struct i2c_device_id ad7418_id[] = {
|
||||
{ "ad7416", ad7416 },
|
||||
{ "ad7417", ad7417 },
|
||||
{ "ad7418", ad7418 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ad7418_id);
|
||||
|
||||
static struct i2c_driver ad7418_driver = {
|
||||
.driver = {
|
||||
.name = "ad7418",
|
||||
},
|
||||
.probe = ad7418_probe,
|
||||
.id_table = ad7418_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(ad7418_driver);
|
||||
|
||||
|
|
|
@ -98,41 +98,63 @@ struct adm1021_data {
|
|||
u8 remote_temp_offset_prec;
|
||||
};
|
||||
|
||||
static int adm1021_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int adm1021_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info);
|
||||
static void adm1021_init_client(struct i2c_client *client);
|
||||
static struct adm1021_data *adm1021_update_device(struct device *dev);
|
||||
|
||||
/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
|
||||
static bool read_only;
|
||||
|
||||
static struct adm1021_data *adm1021_update_device(struct device *dev)
|
||||
{
|
||||
struct adm1021_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
static const struct i2c_device_id adm1021_id[] = {
|
||||
{ "adm1021", adm1021 },
|
||||
{ "adm1023", adm1023 },
|
||||
{ "max1617", max1617 },
|
||||
{ "max1617a", max1617a },
|
||||
{ "thmc10", thmc10 },
|
||||
{ "lm84", lm84 },
|
||||
{ "gl523sm", gl523sm },
|
||||
{ "mc1066", mc1066 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adm1021_id);
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
static struct i2c_driver adm1021_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adm1021",
|
||||
},
|
||||
.probe = adm1021_probe,
|
||||
.id_table = adm1021_id,
|
||||
.detect = adm1021_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
int i;
|
||||
|
||||
dev_dbg(dev, "Starting adm1021 update\n");
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->temp[i] = 1000 *
|
||||
(s8) i2c_smbus_read_byte_data(
|
||||
client, ADM1021_REG_TEMP(i));
|
||||
data->temp_max[i] = 1000 *
|
||||
(s8) i2c_smbus_read_byte_data(
|
||||
client, ADM1021_REG_TOS_R(i));
|
||||
if (data->type != lm84) {
|
||||
data->temp_min[i] = 1000 *
|
||||
(s8) i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_THYST_R(i));
|
||||
}
|
||||
}
|
||||
data->alarms = i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_STATUS) & 0x7c;
|
||||
if (data->type == adm1023) {
|
||||
/*
|
||||
* The ADM1023 provides 3 extra bits of precision for
|
||||
* the remote sensor in extra registers.
|
||||
*/
|
||||
data->temp[1] += 125 * (i2c_smbus_read_byte_data(
|
||||
client, ADM1023_REG_REM_TEMP_PREC) >> 5);
|
||||
data->temp_max[1] += 125 * (i2c_smbus_read_byte_data(
|
||||
client, ADM1023_REG_REM_TOS_PREC) >> 5);
|
||||
data->temp_min[1] += 125 * (i2c_smbus_read_byte_data(
|
||||
client, ADM1023_REG_REM_THYST_PREC) >> 5);
|
||||
data->remote_temp_offset =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1023_REG_REM_OFFSET);
|
||||
data->remote_temp_offset_prec =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1023_REG_REM_OFFSET_PREC);
|
||||
}
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static ssize_t show_temp(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
|
@ -411,6 +433,15 @@ static int adm1021_detect(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void adm1021_init_client(struct i2c_client *client)
|
||||
{
|
||||
/* Enable ADC and disable suspend mode */
|
||||
i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W,
|
||||
i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R) & 0xBF);
|
||||
/* Set Conversion rate to 1/sec (this can be tinkered with) */
|
||||
i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04);
|
||||
}
|
||||
|
||||
static int adm1021_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -440,69 +471,29 @@ static int adm1021_probe(struct i2c_client *client,
|
|||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static void adm1021_init_client(struct i2c_client *client)
|
||||
{
|
||||
/* Enable ADC and disable suspend mode */
|
||||
i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W,
|
||||
i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R) & 0xBF);
|
||||
/* Set Conversion rate to 1/sec (this can be tinkered with) */
|
||||
i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04);
|
||||
}
|
||||
static const struct i2c_device_id adm1021_id[] = {
|
||||
{ "adm1021", adm1021 },
|
||||
{ "adm1023", adm1023 },
|
||||
{ "max1617", max1617 },
|
||||
{ "max1617a", max1617a },
|
||||
{ "thmc10", thmc10 },
|
||||
{ "lm84", lm84 },
|
||||
{ "gl523sm", gl523sm },
|
||||
{ "mc1066", mc1066 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adm1021_id);
|
||||
|
||||
static struct adm1021_data *adm1021_update_device(struct device *dev)
|
||||
{
|
||||
struct adm1021_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
int i;
|
||||
|
||||
dev_dbg(dev, "Starting adm1021 update\n");
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->temp[i] = 1000 *
|
||||
(s8) i2c_smbus_read_byte_data(
|
||||
client, ADM1021_REG_TEMP(i));
|
||||
data->temp_max[i] = 1000 *
|
||||
(s8) i2c_smbus_read_byte_data(
|
||||
client, ADM1021_REG_TOS_R(i));
|
||||
if (data->type != lm84) {
|
||||
data->temp_min[i] = 1000 *
|
||||
(s8) i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_THYST_R(i));
|
||||
}
|
||||
}
|
||||
data->alarms = i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_STATUS) & 0x7c;
|
||||
if (data->type == adm1023) {
|
||||
/*
|
||||
* The ADM1023 provides 3 extra bits of precision for
|
||||
* the remote sensor in extra registers.
|
||||
*/
|
||||
data->temp[1] += 125 * (i2c_smbus_read_byte_data(
|
||||
client, ADM1023_REG_REM_TEMP_PREC) >> 5);
|
||||
data->temp_max[1] += 125 * (i2c_smbus_read_byte_data(
|
||||
client, ADM1023_REG_REM_TOS_PREC) >> 5);
|
||||
data->temp_min[1] += 125 * (i2c_smbus_read_byte_data(
|
||||
client, ADM1023_REG_REM_THYST_PREC) >> 5);
|
||||
data->remote_temp_offset =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1023_REG_REM_OFFSET);
|
||||
data->remote_temp_offset_prec =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1023_REG_REM_OFFSET_PREC);
|
||||
}
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
static struct i2c_driver adm1021_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adm1021",
|
||||
},
|
||||
.probe = adm1021_probe,
|
||||
.id_table = adm1021_id,
|
||||
.detect = adm1021_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(adm1021_driver);
|
||||
|
||||
|
|
|
@ -102,47 +102,13 @@ static const int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 };
|
|||
(((val) < 0 ? (val) - 500 : \
|
||||
(val) + 500) / 1000))
|
||||
|
||||
/*
|
||||
* Functions declaration
|
||||
*/
|
||||
|
||||
static int adm1025_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int adm1025_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info);
|
||||
static void adm1025_init_client(struct i2c_client *client);
|
||||
static int adm1025_remove(struct i2c_client *client);
|
||||
static struct adm1025_data *adm1025_update_device(struct device *dev);
|
||||
|
||||
/*
|
||||
* Driver data (common to all clients)
|
||||
*/
|
||||
|
||||
static const struct i2c_device_id adm1025_id[] = {
|
||||
{ "adm1025", adm1025 },
|
||||
{ "ne1619", ne1619 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adm1025_id);
|
||||
|
||||
static struct i2c_driver adm1025_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adm1025",
|
||||
},
|
||||
.probe = adm1025_probe,
|
||||
.remove = adm1025_remove,
|
||||
.id_table = adm1025_id,
|
||||
.detect = adm1025_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
/*
|
||||
* Client data (each client gets its own)
|
||||
*/
|
||||
|
||||
struct adm1025_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
const struct attribute_group *groups[3];
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
|
@ -158,6 +124,51 @@ struct adm1025_data {
|
|||
u8 vrm;
|
||||
};
|
||||
|
||||
static struct adm1025_data *adm1025_update_device(struct device *dev)
|
||||
{
|
||||
struct adm1025_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
|
||||
int i;
|
||||
|
||||
dev_dbg(&client->dev, "Updating data.\n");
|
||||
for (i = 0; i < 6; i++) {
|
||||
data->in[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_IN(i));
|
||||
data->in_min[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_IN_MIN(i));
|
||||
data->in_max[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_IN_MAX(i));
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->temp[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_TEMP(i));
|
||||
data->temp_min[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_TEMP_LOW(i));
|
||||
data->temp_max[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_TEMP_HIGH(i));
|
||||
}
|
||||
data->alarms = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_STATUS1)
|
||||
| (i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_STATUS2) << 8);
|
||||
data->vid = (i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_VID) & 0x0f)
|
||||
| ((i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_VID4) & 0x01) << 4);
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sysfs stuff
|
||||
*/
|
||||
|
@ -217,8 +228,8 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1025_data *data = i2c_get_clientdata(client);
|
||||
struct adm1025_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -238,8 +249,8 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1025_data *data = i2c_get_clientdata(client);
|
||||
struct adm1025_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -273,8 +284,8 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1025_data *data = i2c_get_clientdata(client);
|
||||
struct adm1025_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -294,8 +305,8 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1025_data *data = i2c_get_clientdata(client);
|
||||
struct adm1025_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -470,51 +481,6 @@ static int adm1025_detect(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int adm1025_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adm1025_data *data;
|
||||
int err;
|
||||
u8 config;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct adm1025_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the ADM1025 chip */
|
||||
adm1025_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &adm1025_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Pin 11 is either in4 (+12V) or VID4 */
|
||||
config = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
|
||||
if (!(config & 0x20)) {
|
||||
err = sysfs_create_group(&client->dev.kobj, &adm1025_group_in4);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1025_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void adm1025_init_client(struct i2c_client *client)
|
||||
{
|
||||
u8 reg;
|
||||
|
@ -557,61 +523,54 @@ static void adm1025_init_client(struct i2c_client *client)
|
|||
(reg&0x7E)|0x01);
|
||||
}
|
||||
|
||||
static int adm1025_remove(struct i2c_client *client)
|
||||
static int adm1025_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adm1025_data *data = i2c_get_clientdata(client);
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct adm1025_data *data;
|
||||
u8 config;
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1025_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4);
|
||||
data = devm_kzalloc(dev, sizeof(struct adm1025_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the ADM1025 chip */
|
||||
adm1025_init_client(client);
|
||||
|
||||
/* sysfs hooks */
|
||||
data->groups[0] = &adm1025_group;
|
||||
/* Pin 11 is either in4 (+12V) or VID4 */
|
||||
config = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
|
||||
if (!(config & 0x20))
|
||||
data->groups[1] = &adm1025_group_in4;
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, data->groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static struct adm1025_data *adm1025_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1025_data *data = i2c_get_clientdata(client);
|
||||
static const struct i2c_device_id adm1025_id[] = {
|
||||
{ "adm1025", adm1025 },
|
||||
{ "ne1619", ne1619 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adm1025_id);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
|
||||
int i;
|
||||
|
||||
dev_dbg(&client->dev, "Updating data.\n");
|
||||
for (i = 0; i < 6; i++) {
|
||||
data->in[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_IN(i));
|
||||
data->in_min[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_IN_MIN(i));
|
||||
data->in_max[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_IN_MAX(i));
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->temp[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_TEMP(i));
|
||||
data->temp_min[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_TEMP_LOW(i));
|
||||
data->temp_max[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_TEMP_HIGH(i));
|
||||
}
|
||||
data->alarms = i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_STATUS1)
|
||||
| (i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_STATUS2) << 8);
|
||||
data->vid = (i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_VID) & 0x0f)
|
||||
| ((i2c_smbus_read_byte_data(client,
|
||||
ADM1025_REG_VID4) & 0x01) << 4);
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
static struct i2c_driver adm1025_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adm1025",
|
||||
},
|
||||
.probe = adm1025_probe,
|
||||
.id_table = adm1025_id,
|
||||
.detect = adm1025_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(adm1025_driver);
|
||||
|
||||
|
|
|
@ -266,7 +266,8 @@ struct pwm_data {
|
|||
};
|
||||
|
||||
struct adm1026_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
const struct attribute_group *groups[3];
|
||||
|
||||
struct mutex update_lock;
|
||||
int valid; /* !=0 if following fields are valid */
|
||||
|
@ -298,37 +299,6 @@ struct adm1026_data {
|
|||
u8 config3; /* Register value */
|
||||
};
|
||||
|
||||
static int adm1026_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int adm1026_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info);
|
||||
static int adm1026_remove(struct i2c_client *client);
|
||||
static int adm1026_read_value(struct i2c_client *client, u8 reg);
|
||||
static int adm1026_write_value(struct i2c_client *client, u8 reg, int value);
|
||||
static void adm1026_print_gpio(struct i2c_client *client);
|
||||
static void adm1026_fixup_gpio(struct i2c_client *client);
|
||||
static struct adm1026_data *adm1026_update_device(struct device *dev);
|
||||
static void adm1026_init_client(struct i2c_client *client);
|
||||
|
||||
|
||||
static const struct i2c_device_id adm1026_id[] = {
|
||||
{ "adm1026", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adm1026_id);
|
||||
|
||||
static struct i2c_driver adm1026_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adm1026",
|
||||
},
|
||||
.probe = adm1026_probe,
|
||||
.remove = adm1026_remove,
|
||||
.id_table = adm1026_id,
|
||||
.detect = adm1026_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int adm1026_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
int res;
|
||||
|
@ -357,212 +327,10 @@ static int adm1026_write_value(struct i2c_client *client, u8 reg, int value)
|
|||
return res;
|
||||
}
|
||||
|
||||
static void adm1026_init_client(struct i2c_client *client)
|
||||
{
|
||||
int value, i;
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
|
||||
dev_dbg(&client->dev, "Initializing device\n");
|
||||
/* Read chip config */
|
||||
data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1);
|
||||
data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2);
|
||||
data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3);
|
||||
|
||||
/* Inform user of chip config */
|
||||
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");
|
||||
}
|
||||
if (data->config1 & CFG1_INT_ENABLE) {
|
||||
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");
|
||||
} else {
|
||||
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");
|
||||
}
|
||||
|
||||
if (data->config3 & CFG3_GPIO16_ENABLE) {
|
||||
dev_dbg(&client->dev,
|
||||
"GPIO16 enabled. THERM pin disabled.\n");
|
||||
} else {
|
||||
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");
|
||||
else
|
||||
dev_dbg(&client->dev, "Vref is 1.82 Volts.\n");
|
||||
/* Read and pick apart the existing GPIO configuration */
|
||||
value = 0;
|
||||
for (i = 0; i <= 15; ++i) {
|
||||
if ((i & 0x03) == 0) {
|
||||
value = adm1026_read_value(client,
|
||||
ADM1026_REG_GPIO_CFG_0_3 + i / 4);
|
||||
}
|
||||
data->gpio_config[i] = value & 0x03;
|
||||
value >>= 2;
|
||||
}
|
||||
data->gpio_config[16] = (data->config3 >> 6) & 0x03;
|
||||
|
||||
/* ... and then print it */
|
||||
adm1026_print_gpio(client);
|
||||
|
||||
/*
|
||||
* If the user asks us to reprogram the GPIO config, then
|
||||
* do it now.
|
||||
*/
|
||||
if (gpio_input[0] != -1 || gpio_output[0] != -1
|
||||
|| gpio_inverted[0] != -1 || gpio_normal[0] != -1
|
||||
|| gpio_fan[0] != -1) {
|
||||
adm1026_fixup_gpio(client);
|
||||
}
|
||||
|
||||
/*
|
||||
* WE INTENTIONALLY make no changes to the limits,
|
||||
* offsets, pwms, fans and zones. If they were
|
||||
* configured, we don't want to mess with them.
|
||||
* If they weren't, the default is 100% PWM, no
|
||||
* control and will suffice until 'sensors -s'
|
||||
* can be run by the user. We DO set the default
|
||||
* value for pwm1.auto_pwm_min to its maximum
|
||||
* so that enabling automatic pwm fan control
|
||||
* without first setting a value for pwm1.auto_pwm_min
|
||||
* will not result in potentially dangerous fan speed decrease.
|
||||
*/
|
||||
data->pwm1.auto_pwm_min = 255;
|
||||
/* Start monitoring */
|
||||
value = adm1026_read_value(client, ADM1026_REG_CONFIG1);
|
||||
/* Set MONITOR, clear interrupt acknowledge and s/w reset */
|
||||
value = (value | CFG1_MONITOR) & (~CFG1_INT_CLEAR & ~CFG1_RESET);
|
||||
dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value);
|
||||
data->config1 = value;
|
||||
adm1026_write_value(client, ADM1026_REG_CONFIG1, value);
|
||||
|
||||
/* initialize fan_div[] to hardware defaults */
|
||||
value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) |
|
||||
(adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8);
|
||||
for (i = 0; i <= 7; ++i) {
|
||||
data->fan_div[i] = DIV_FROM_REG(value & 0x03);
|
||||
value >>= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void adm1026_print_gpio(struct i2c_client *client)
|
||||
{
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int i;
|
||||
|
||||
dev_dbg(&client->dev, "GPIO config is:\n");
|
||||
for (i = 0; i <= 7; ++i) {
|
||||
if (data->config2 & (1 << i)) {
|
||||
dev_dbg(&client->dev, "\t%sGP%s%d\n",
|
||||
data->gpio_config[i] & 0x02 ? "" : "!",
|
||||
data->gpio_config[i] & 0x01 ? "OUT" : "IN",
|
||||
i);
|
||||
} else {
|
||||
dev_dbg(&client->dev, "\tFAN%d\n", i);
|
||||
}
|
||||
}
|
||||
for (i = 8; i <= 15; ++i) {
|
||||
dev_dbg(&client->dev, "\t%sGP%s%d\n",
|
||||
data->gpio_config[i] & 0x02 ? "" : "!",
|
||||
data->gpio_config[i] & 0x01 ? "OUT" : "IN",
|
||||
i);
|
||||
}
|
||||
if (data->config3 & CFG3_GPIO16_ENABLE) {
|
||||
dev_dbg(&client->dev, "\t%sGP%s16\n",
|
||||
data->gpio_config[16] & 0x02 ? "" : "!",
|
||||
data->gpio_config[16] & 0x01 ? "OUT" : "IN");
|
||||
} else {
|
||||
/* GPIO16 is THERM */
|
||||
dev_dbg(&client->dev, "\tTHERM\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void adm1026_fixup_gpio(struct i2c_client *client)
|
||||
{
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int i;
|
||||
int value;
|
||||
|
||||
/* Make the changes requested. */
|
||||
/*
|
||||
* We may need to unlock/stop monitoring or soft-reset the
|
||||
* chip before we can make changes. This hasn't been
|
||||
* tested much. FIXME
|
||||
*/
|
||||
|
||||
/* Make outputs */
|
||||
for (i = 0; i <= 16; ++i) {
|
||||
if (gpio_output[i] >= 0 && gpio_output[i] <= 16)
|
||||
data->gpio_config[gpio_output[i]] |= 0x01;
|
||||
/* if GPIO0-7 is output, it isn't a FAN tach */
|
||||
if (gpio_output[i] >= 0 && gpio_output[i] <= 7)
|
||||
data->config2 |= 1 << gpio_output[i];
|
||||
}
|
||||
|
||||
/* Input overrides output */
|
||||
for (i = 0; i <= 16; ++i) {
|
||||
if (gpio_input[i] >= 0 && gpio_input[i] <= 16)
|
||||
data->gpio_config[gpio_input[i]] &= ~0x01;
|
||||
/* if GPIO0-7 is input, it isn't a FAN tach */
|
||||
if (gpio_input[i] >= 0 && gpio_input[i] <= 7)
|
||||
data->config2 |= 1 << gpio_input[i];
|
||||
}
|
||||
|
||||
/* Inverted */
|
||||
for (i = 0; i <= 16; ++i) {
|
||||
if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16)
|
||||
data->gpio_config[gpio_inverted[i]] &= ~0x02;
|
||||
}
|
||||
|
||||
/* Normal overrides inverted */
|
||||
for (i = 0; i <= 16; ++i) {
|
||||
if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16)
|
||||
data->gpio_config[gpio_normal[i]] |= 0x02;
|
||||
}
|
||||
|
||||
/* Fan overrides input and output */
|
||||
for (i = 0; i <= 7; ++i) {
|
||||
if (gpio_fan[i] >= 0 && gpio_fan[i] <= 7)
|
||||
data->config2 &= ~(1 << gpio_fan[i]);
|
||||
}
|
||||
|
||||
/* Write new configs to registers */
|
||||
adm1026_write_value(client, ADM1026_REG_CONFIG2, data->config2);
|
||||
data->config3 = (data->config3 & 0x3f)
|
||||
| ((data->gpio_config[16] & 0x03) << 6);
|
||||
adm1026_write_value(client, ADM1026_REG_CONFIG3, data->config3);
|
||||
for (i = 15, value = 0; i >= 0; --i) {
|
||||
value <<= 2;
|
||||
value |= data->gpio_config[i] & 0x03;
|
||||
if ((i & 0x03) == 0) {
|
||||
adm1026_write_value(client,
|
||||
ADM1026_REG_GPIO_CFG_0_3 + i/4,
|
||||
value);
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the new config */
|
||||
adm1026_print_gpio(client);
|
||||
}
|
||||
|
||||
|
||||
static struct adm1026_data *adm1026_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int i;
|
||||
long value, alarms, gpio;
|
||||
|
||||
|
@ -728,8 +496,8 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -756,8 +524,8 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -815,8 +583,8 @@ static ssize_t show_in16_min(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -840,8 +608,8 @@ static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -888,8 +656,8 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -923,8 +691,8 @@ fan_offset(8);
|
|||
/* Adjust fan_min to account for new fan divisor */
|
||||
static void fixup_fan_min(struct device *dev, int fan, int old_div)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int new_min;
|
||||
int new_div = data->fan_div[fan];
|
||||
|
||||
|
@ -952,8 +720,8 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int orig_div, new_div;
|
||||
int err;
|
||||
|
@ -1024,8 +792,8 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -1053,8 +821,8 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -1097,8 +865,8 @@ static ssize_t set_temp_offset(struct device *dev,
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -1153,8 +921,8 @@ static ssize_t set_temp_auto_point1_temp(struct device *dev,
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -1192,8 +960,8 @@ static ssize_t show_temp_crit_enable(struct device *dev,
|
|||
static ssize_t set_temp_crit_enable(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -1233,8 +1001,8 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -1268,8 +1036,8 @@ static ssize_t set_analog_out_reg(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -1378,8 +1146,8 @@ static ssize_t show_alarm_mask(struct device *dev,
|
|||
static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long mask;
|
||||
long val;
|
||||
int err;
|
||||
|
@ -1420,8 +1188,8 @@ static ssize_t show_gpio(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_gpio(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long gpio;
|
||||
long val;
|
||||
int err;
|
||||
|
@ -1453,8 +1221,8 @@ static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long mask;
|
||||
long val;
|
||||
int err;
|
||||
|
@ -1487,8 +1255,8 @@ static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
if (data->pwm1.enable == 1) {
|
||||
long val;
|
||||
|
@ -1517,8 +1285,8 @@ static ssize_t set_auto_pwm_min(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -1553,8 +1321,8 @@ static ssize_t show_pwm_enable(struct device *dev,
|
|||
static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int old_enable;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -1829,18 +1597,220 @@ static int adm1026_detect(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void adm1026_print_gpio(struct i2c_client *client)
|
||||
{
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int i;
|
||||
|
||||
dev_dbg(&client->dev, "GPIO config is:\n");
|
||||
for (i = 0; i <= 7; ++i) {
|
||||
if (data->config2 & (1 << i)) {
|
||||
dev_dbg(&client->dev, "\t%sGP%s%d\n",
|
||||
data->gpio_config[i] & 0x02 ? "" : "!",
|
||||
data->gpio_config[i] & 0x01 ? "OUT" : "IN",
|
||||
i);
|
||||
} else {
|
||||
dev_dbg(&client->dev, "\tFAN%d\n", i);
|
||||
}
|
||||
}
|
||||
for (i = 8; i <= 15; ++i) {
|
||||
dev_dbg(&client->dev, "\t%sGP%s%d\n",
|
||||
data->gpio_config[i] & 0x02 ? "" : "!",
|
||||
data->gpio_config[i] & 0x01 ? "OUT" : "IN",
|
||||
i);
|
||||
}
|
||||
if (data->config3 & CFG3_GPIO16_ENABLE) {
|
||||
dev_dbg(&client->dev, "\t%sGP%s16\n",
|
||||
data->gpio_config[16] & 0x02 ? "" : "!",
|
||||
data->gpio_config[16] & 0x01 ? "OUT" : "IN");
|
||||
} else {
|
||||
/* GPIO16 is THERM */
|
||||
dev_dbg(&client->dev, "\tTHERM\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void adm1026_fixup_gpio(struct i2c_client *client)
|
||||
{
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
int i;
|
||||
int value;
|
||||
|
||||
/* Make the changes requested. */
|
||||
/*
|
||||
* We may need to unlock/stop monitoring or soft-reset the
|
||||
* chip before we can make changes. This hasn't been
|
||||
* tested much. FIXME
|
||||
*/
|
||||
|
||||
/* Make outputs */
|
||||
for (i = 0; i <= 16; ++i) {
|
||||
if (gpio_output[i] >= 0 && gpio_output[i] <= 16)
|
||||
data->gpio_config[gpio_output[i]] |= 0x01;
|
||||
/* if GPIO0-7 is output, it isn't a FAN tach */
|
||||
if (gpio_output[i] >= 0 && gpio_output[i] <= 7)
|
||||
data->config2 |= 1 << gpio_output[i];
|
||||
}
|
||||
|
||||
/* Input overrides output */
|
||||
for (i = 0; i <= 16; ++i) {
|
||||
if (gpio_input[i] >= 0 && gpio_input[i] <= 16)
|
||||
data->gpio_config[gpio_input[i]] &= ~0x01;
|
||||
/* if GPIO0-7 is input, it isn't a FAN tach */
|
||||
if (gpio_input[i] >= 0 && gpio_input[i] <= 7)
|
||||
data->config2 |= 1 << gpio_input[i];
|
||||
}
|
||||
|
||||
/* Inverted */
|
||||
for (i = 0; i <= 16; ++i) {
|
||||
if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16)
|
||||
data->gpio_config[gpio_inverted[i]] &= ~0x02;
|
||||
}
|
||||
|
||||
/* Normal overrides inverted */
|
||||
for (i = 0; i <= 16; ++i) {
|
||||
if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16)
|
||||
data->gpio_config[gpio_normal[i]] |= 0x02;
|
||||
}
|
||||
|
||||
/* Fan overrides input and output */
|
||||
for (i = 0; i <= 7; ++i) {
|
||||
if (gpio_fan[i] >= 0 && gpio_fan[i] <= 7)
|
||||
data->config2 &= ~(1 << gpio_fan[i]);
|
||||
}
|
||||
|
||||
/* Write new configs to registers */
|
||||
adm1026_write_value(client, ADM1026_REG_CONFIG2, data->config2);
|
||||
data->config3 = (data->config3 & 0x3f)
|
||||
| ((data->gpio_config[16] & 0x03) << 6);
|
||||
adm1026_write_value(client, ADM1026_REG_CONFIG3, data->config3);
|
||||
for (i = 15, value = 0; i >= 0; --i) {
|
||||
value <<= 2;
|
||||
value |= data->gpio_config[i] & 0x03;
|
||||
if ((i & 0x03) == 0) {
|
||||
adm1026_write_value(client,
|
||||
ADM1026_REG_GPIO_CFG_0_3 + i/4,
|
||||
value);
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the new config */
|
||||
adm1026_print_gpio(client);
|
||||
}
|
||||
|
||||
static void adm1026_init_client(struct i2c_client *client)
|
||||
{
|
||||
int value, i;
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
|
||||
dev_dbg(&client->dev, "Initializing device\n");
|
||||
/* Read chip config */
|
||||
data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1);
|
||||
data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2);
|
||||
data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3);
|
||||
|
||||
/* Inform user of chip config */
|
||||
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");
|
||||
}
|
||||
if (data->config1 & CFG1_INT_ENABLE) {
|
||||
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");
|
||||
} else {
|
||||
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");
|
||||
}
|
||||
|
||||
if (data->config3 & CFG3_GPIO16_ENABLE) {
|
||||
dev_dbg(&client->dev,
|
||||
"GPIO16 enabled. THERM pin disabled.\n");
|
||||
} else {
|
||||
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");
|
||||
else
|
||||
dev_dbg(&client->dev, "Vref is 1.82 Volts.\n");
|
||||
/* Read and pick apart the existing GPIO configuration */
|
||||
value = 0;
|
||||
for (i = 0; i <= 15; ++i) {
|
||||
if ((i & 0x03) == 0) {
|
||||
value = adm1026_read_value(client,
|
||||
ADM1026_REG_GPIO_CFG_0_3 + i / 4);
|
||||
}
|
||||
data->gpio_config[i] = value & 0x03;
|
||||
value >>= 2;
|
||||
}
|
||||
data->gpio_config[16] = (data->config3 >> 6) & 0x03;
|
||||
|
||||
/* ... and then print it */
|
||||
adm1026_print_gpio(client);
|
||||
|
||||
/*
|
||||
* If the user asks us to reprogram the GPIO config, then
|
||||
* do it now.
|
||||
*/
|
||||
if (gpio_input[0] != -1 || gpio_output[0] != -1
|
||||
|| gpio_inverted[0] != -1 || gpio_normal[0] != -1
|
||||
|| gpio_fan[0] != -1) {
|
||||
adm1026_fixup_gpio(client);
|
||||
}
|
||||
|
||||
/*
|
||||
* WE INTENTIONALLY make no changes to the limits,
|
||||
* offsets, pwms, fans and zones. If they were
|
||||
* configured, we don't want to mess with them.
|
||||
* If they weren't, the default is 100% PWM, no
|
||||
* control and will suffice until 'sensors -s'
|
||||
* can be run by the user. We DO set the default
|
||||
* value for pwm1.auto_pwm_min to its maximum
|
||||
* so that enabling automatic pwm fan control
|
||||
* without first setting a value for pwm1.auto_pwm_min
|
||||
* will not result in potentially dangerous fan speed decrease.
|
||||
*/
|
||||
data->pwm1.auto_pwm_min = 255;
|
||||
/* Start monitoring */
|
||||
value = adm1026_read_value(client, ADM1026_REG_CONFIG1);
|
||||
/* Set MONITOR, clear interrupt acknowledge and s/w reset */
|
||||
value = (value | CFG1_MONITOR) & (~CFG1_INT_CLEAR & ~CFG1_RESET);
|
||||
dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value);
|
||||
data->config1 = value;
|
||||
adm1026_write_value(client, ADM1026_REG_CONFIG1, value);
|
||||
|
||||
/* initialize fan_div[] to hardware defaults */
|
||||
value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) |
|
||||
(adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8);
|
||||
for (i = 0; i <= 7; ++i) {
|
||||
data->fan_div[i] = DIV_FROM_REG(value & 0x03);
|
||||
value >>= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int adm1026_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct adm1026_data *data;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct adm1026_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct adm1026_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Set the VRM version */
|
||||
|
@ -1849,48 +1819,34 @@ static int adm1026_probe(struct i2c_client *client,
|
|||
/* Initialize the ADM1026 chip */
|
||||
adm1026_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &adm1026_group);
|
||||
if (err)
|
||||
return err;
|
||||
/* sysfs hooks */
|
||||
data->groups[0] = &adm1026_group;
|
||||
if (data->config1 & CFG1_AIN8_9)
|
||||
err = sysfs_create_group(&client->dev.kobj,
|
||||
&adm1026_group_in8_9);
|
||||
data->groups[1] = &adm1026_group_in8_9;
|
||||
else
|
||||
err = sysfs_create_group(&client->dev.kobj,
|
||||
&adm1026_group_temp3);
|
||||
if (err)
|
||||
goto exitremove;
|
||||
data->groups[1] = &adm1026_group_temp3;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exitremove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
/* Error out and cleanup code */
|
||||
exitremove:
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1026_group);
|
||||
if (data->config1 & CFG1_AIN8_9)
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9);
|
||||
else
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3);
|
||||
return err;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, data->groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static int adm1026_remove(struct i2c_client *client)
|
||||
{
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1026_group);
|
||||
if (data->config1 & CFG1_AIN8_9)
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9);
|
||||
else
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3);
|
||||
return 0;
|
||||
}
|
||||
static const struct i2c_device_id adm1026_id[] = {
|
||||
{ "adm1026", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adm1026_id);
|
||||
|
||||
static struct i2c_driver adm1026_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adm1026",
|
||||
},
|
||||
.probe = adm1026_probe,
|
||||
.id_table = adm1026_id,
|
||||
.detect = adm1026_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(adm1026_driver);
|
||||
|
||||
|
|
|
@ -105,46 +105,12 @@ static const u8 ADM1029_REG_FAN_DIV[] = {
|
|||
ADM1029_REG_FAN2_CONFIG,
|
||||
};
|
||||
|
||||
/*
|
||||
* Functions declaration
|
||||
*/
|
||||
|
||||
static int adm1029_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int adm1029_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info);
|
||||
static int adm1029_remove(struct i2c_client *client);
|
||||
static struct adm1029_data *adm1029_update_device(struct device *dev);
|
||||
static int adm1029_init_client(struct i2c_client *client);
|
||||
|
||||
/*
|
||||
* Driver data (common to all clients)
|
||||
*/
|
||||
|
||||
static const struct i2c_device_id adm1029_id[] = {
|
||||
{ "adm1029", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adm1029_id);
|
||||
|
||||
static struct i2c_driver adm1029_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adm1029",
|
||||
},
|
||||
.probe = adm1029_probe,
|
||||
.remove = adm1029_remove,
|
||||
.id_table = adm1029_id,
|
||||
.detect = adm1029_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
/*
|
||||
* Client data (each client gets its own)
|
||||
*/
|
||||
|
||||
struct adm1029_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
|
@ -155,6 +121,50 @@ struct adm1029_data {
|
|||
u8 fan_div[ARRAY_SIZE(ADM1029_REG_FAN_DIV)];
|
||||
};
|
||||
|
||||
/*
|
||||
* function that update the status of the chips (temperature for example)
|
||||
*/
|
||||
static struct adm1029_data *adm1029_update_device(struct device *dev)
|
||||
{
|
||||
struct adm1029_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
/*
|
||||
* Use the "cache" Luke, don't recheck values
|
||||
* if there are already checked not a long time later
|
||||
*/
|
||||
if (time_after(jiffies, data->last_updated + HZ * 2)
|
||||
|| !data->valid) {
|
||||
int nr;
|
||||
|
||||
dev_dbg(&client->dev, "Updating adm1029 data\n");
|
||||
|
||||
for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_TEMP); nr++) {
|
||||
data->temp[nr] =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1029_REG_TEMP[nr]);
|
||||
}
|
||||
for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN); nr++) {
|
||||
data->fan[nr] =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1029_REG_FAN[nr]);
|
||||
}
|
||||
for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN_DIV); nr++) {
|
||||
data->fan_div[nr] =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1029_REG_FAN_DIV[nr]);
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sysfs stuff
|
||||
*/
|
||||
|
@ -197,8 +207,8 @@ show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
|
|||
static ssize_t set_fan_div(struct device *dev,
|
||||
struct device_attribute *devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1029_data *data = i2c_get_clientdata(client);
|
||||
struct adm1029_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
u8 reg;
|
||||
long val;
|
||||
|
@ -270,7 +280,7 @@ static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
|
|||
static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
|
||||
show_fan_div, set_fan_div, 1);
|
||||
|
||||
static struct attribute *adm1029_attributes[] = {
|
||||
static struct attribute *adm1029_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
|
@ -289,9 +299,7 @@ static struct attribute *adm1029_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adm1029_group = {
|
||||
.attrs = adm1029_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(adm1029);
|
||||
|
||||
/*
|
||||
* Real code
|
||||
|
@ -340,48 +348,10 @@ static int adm1029_detect(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int adm1029_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adm1029_data *data;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct adm1029_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/*
|
||||
* Initialize the ADM1029 chip
|
||||
* Check config register
|
||||
*/
|
||||
if (adm1029_init_client(client) == 0)
|
||||
return -ENODEV;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &adm1029_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->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(&client->dev.kobj, &adm1029_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adm1029_init_client(struct i2c_client *client)
|
||||
{
|
||||
u8 config;
|
||||
|
||||
config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG);
|
||||
if ((config & 0x10) == 0) {
|
||||
i2c_smbus_write_byte_data(client, ADM1029_REG_CONFIG,
|
||||
|
@ -396,60 +366,50 @@ static int adm1029_init_client(struct i2c_client *client)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int adm1029_remove(struct i2c_client *client)
|
||||
static int adm1029_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adm1029_data *data = i2c_get_clientdata(client);
|
||||
struct device *dev = &client->dev;
|
||||
struct adm1029_data *data;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1029_group);
|
||||
data = devm_kzalloc(dev, sizeof(struct adm1029_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/*
|
||||
* function that update the status of the chips (temperature for example)
|
||||
*/
|
||||
static struct adm1029_data *adm1029_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1029_data *data = i2c_get_clientdata(client);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
/*
|
||||
* Use the "cache" Luke, don't recheck values
|
||||
* if there are already checked not a long time later
|
||||
* Initialize the ADM1029 chip
|
||||
* Check config register
|
||||
*/
|
||||
if (time_after(jiffies, data->last_updated + HZ * 2)
|
||||
|| !data->valid) {
|
||||
int nr;
|
||||
if (adm1029_init_client(client) == 0)
|
||||
return -ENODEV;
|
||||
|
||||
dev_dbg(&client->dev, "Updating adm1029 data\n");
|
||||
|
||||
for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_TEMP); nr++) {
|
||||
data->temp[nr] =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1029_REG_TEMP[nr]);
|
||||
}
|
||||
for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN); nr++) {
|
||||
data->fan[nr] =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1029_REG_FAN[nr]);
|
||||
}
|
||||
for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN_DIV); nr++) {
|
||||
data->fan_div[nr] =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1029_REG_FAN_DIV[nr]);
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
adm1029_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adm1029_id[] = {
|
||||
{ "adm1029", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adm1029_id);
|
||||
|
||||
static struct i2c_driver adm1029_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adm1029",
|
||||
},
|
||||
.probe = adm1029_probe,
|
||||
.id_table = adm1029_id,
|
||||
.detect = adm1029_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(adm1029_driver);
|
||||
|
||||
MODULE_AUTHOR("Corentin LABBE <clabbe.montjoie@gmail.com>");
|
||||
|
|
|
@ -74,7 +74,8 @@ typedef u8 auto_chan_table_t[8][2];
|
|||
|
||||
/* Each client has this additional data */
|
||||
struct adm1031_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
const struct attribute_group *groups[3];
|
||||
struct mutex update_lock;
|
||||
int chip_type;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
|
@ -105,34 +106,6 @@ struct adm1031_data {
|
|||
s8 temp_crit[3];
|
||||
};
|
||||
|
||||
static int adm1031_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int adm1031_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info);
|
||||
static void adm1031_init_client(struct i2c_client *client);
|
||||
static int adm1031_remove(struct i2c_client *client);
|
||||
static struct adm1031_data *adm1031_update_device(struct device *dev);
|
||||
|
||||
static const struct i2c_device_id adm1031_id[] = {
|
||||
{ "adm1030", adm1030 },
|
||||
{ "adm1031", adm1031 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adm1031_id);
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
static struct i2c_driver adm1031_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adm1031",
|
||||
},
|
||||
.probe = adm1031_probe,
|
||||
.remove = adm1031_remove,
|
||||
.id_table = adm1031_id,
|
||||
.detect = adm1031_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
|
@ -144,6 +117,96 @@ adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value)
|
|||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static struct adm1031_data *adm1031_update_device(struct device *dev)
|
||||
{
|
||||
struct adm1031_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long next_update;
|
||||
int chan;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
next_update = data->last_updated
|
||||
+ msecs_to_jiffies(data->update_interval);
|
||||
if (time_after(jiffies, next_update) || !data->valid) {
|
||||
|
||||
dev_dbg(&client->dev, "Starting adm1031 update\n");
|
||||
for (chan = 0;
|
||||
chan < ((data->chip_type == adm1031) ? 3 : 2); chan++) {
|
||||
u8 oldh, newh;
|
||||
|
||||
oldh =
|
||||
adm1031_read_value(client, ADM1031_REG_TEMP(chan));
|
||||
data->ext_temp[chan] =
|
||||
adm1031_read_value(client, ADM1031_REG_EXT_TEMP);
|
||||
newh =
|
||||
adm1031_read_value(client, ADM1031_REG_TEMP(chan));
|
||||
if (newh != oldh) {
|
||||
data->ext_temp[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_EXT_TEMP);
|
||||
#ifdef DEBUG
|
||||
oldh =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_TEMP(chan));
|
||||
|
||||
/* oldh is actually newer */
|
||||
if (newh != oldh)
|
||||
dev_warn(&client->dev,
|
||||
"Remote temperature may be wrong.\n");
|
||||
#endif
|
||||
}
|
||||
data->temp[chan] = newh;
|
||||
|
||||
data->temp_offset[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_TEMP_OFFSET(chan));
|
||||
data->temp_min[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_TEMP_MIN(chan));
|
||||
data->temp_max[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_TEMP_MAX(chan));
|
||||
data->temp_crit[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_TEMP_CRIT(chan));
|
||||
data->auto_temp[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_AUTO_TEMP(chan));
|
||||
|
||||
}
|
||||
|
||||
data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1);
|
||||
data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2);
|
||||
|
||||
data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0))
|
||||
| (adm1031_read_value(client, ADM1031_REG_STATUS(1)) << 8);
|
||||
if (data->chip_type == adm1030)
|
||||
data->alarm &= 0xc0ff;
|
||||
|
||||
for (chan = 0; chan < (data->chip_type == adm1030 ? 1 : 2);
|
||||
chan++) {
|
||||
data->fan_div[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_FAN_DIV(chan));
|
||||
data->fan_min[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_FAN_MIN(chan));
|
||||
data->fan[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_FAN_SPEED(chan));
|
||||
data->pwm[chan] =
|
||||
(adm1031_read_value(client,
|
||||
ADM1031_REG_PWM) >> (4 * chan)) & 0x0f;
|
||||
}
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
#define TEMP_TO_REG(val) (((val) < 0 ? ((val - 500) / 1000) : \
|
||||
((val + 500) / 1000)))
|
||||
|
@ -280,8 +343,8 @@ static ssize_t
|
|||
set_fan_auto_channel(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
struct adm1031_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
u8 reg;
|
||||
|
@ -355,8 +418,8 @@ static ssize_t
|
|||
set_auto_temp_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
struct adm1031_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
int ret;
|
||||
|
@ -385,8 +448,8 @@ static ssize_t
|
|||
set_auto_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
struct adm1031_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
int ret;
|
||||
|
@ -428,8 +491,8 @@ static ssize_t show_pwm(struct device *dev,
|
|||
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
struct adm1031_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
int ret, reg;
|
||||
|
@ -541,8 +604,8 @@ static ssize_t show_fan_min(struct device *dev,
|
|||
static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
struct adm1031_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
int ret;
|
||||
|
@ -565,8 +628,8 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
struct adm1031_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
u8 tmp;
|
||||
|
@ -667,8 +730,8 @@ static ssize_t set_temp_offset(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
struct adm1031_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
int ret;
|
||||
|
@ -688,8 +751,8 @@ static ssize_t set_temp_offset(struct device *dev,
|
|||
static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
struct adm1031_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
int ret;
|
||||
|
@ -709,8 +772,8 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
struct adm1031_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
int ret;
|
||||
|
@ -730,8 +793,8 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
struct adm1031_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
long val;
|
||||
int ret;
|
||||
|
@ -807,8 +870,7 @@ static const unsigned int update_intervals[] = {
|
|||
static ssize_t show_update_interval(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
struct adm1031_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", data->update_interval);
|
||||
}
|
||||
|
@ -817,8 +879,8 @@ 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 adm1031_data *data = i2c_get_clientdata(client);
|
||||
struct adm1031_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int i, err;
|
||||
u8 reg;
|
||||
|
@ -950,64 +1012,6 @@ static int adm1031_detect(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int adm1031_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adm1031_data *data;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct adm1031_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->chip_type = id->driver_data;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
if (data->chip_type == adm1030)
|
||||
data->chan_select_table = &auto_channel_select_table_adm1030;
|
||||
else
|
||||
data->chan_select_table = &auto_channel_select_table_adm1031;
|
||||
|
||||
/* Initialize the ADM1031 chip */
|
||||
adm1031_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &adm1031_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (data->chip_type == adm1031) {
|
||||
err = sysfs_create_group(&client->dev.kobj, &adm1031_group_opt);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1031_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adm1031_remove(struct i2c_client *client)
|
||||
{
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1031_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adm1031_init_client(struct i2c_client *client)
|
||||
{
|
||||
unsigned int read_val;
|
||||
|
@ -1039,97 +1043,58 @@ static void adm1031_init_client(struct i2c_client *client)
|
|||
data->update_interval = update_intervals[i];
|
||||
}
|
||||
|
||||
static struct adm1031_data *adm1031_update_device(struct device *dev)
|
||||
static int adm1031_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
unsigned long next_update;
|
||||
int chan;
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct adm1031_data *data;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data = devm_kzalloc(dev, sizeof(struct adm1031_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
next_update = data->last_updated
|
||||
+ msecs_to_jiffies(data->update_interval);
|
||||
if (time_after(jiffies, next_update) || !data->valid) {
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
data->chip_type = id->driver_data;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
dev_dbg(&client->dev, "Starting adm1031 update\n");
|
||||
for (chan = 0;
|
||||
chan < ((data->chip_type == adm1031) ? 3 : 2); chan++) {
|
||||
u8 oldh, newh;
|
||||
if (data->chip_type == adm1030)
|
||||
data->chan_select_table = &auto_channel_select_table_adm1030;
|
||||
else
|
||||
data->chan_select_table = &auto_channel_select_table_adm1031;
|
||||
|
||||
oldh =
|
||||
adm1031_read_value(client, ADM1031_REG_TEMP(chan));
|
||||
data->ext_temp[chan] =
|
||||
adm1031_read_value(client, ADM1031_REG_EXT_TEMP);
|
||||
newh =
|
||||
adm1031_read_value(client, ADM1031_REG_TEMP(chan));
|
||||
if (newh != oldh) {
|
||||
data->ext_temp[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_EXT_TEMP);
|
||||
#ifdef DEBUG
|
||||
oldh =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_TEMP(chan));
|
||||
/* Initialize the ADM1031 chip */
|
||||
adm1031_init_client(client);
|
||||
|
||||
/* oldh is actually newer */
|
||||
if (newh != oldh)
|
||||
dev_warn(&client->dev,
|
||||
"Remote temperature may be wrong.\n");
|
||||
#endif
|
||||
}
|
||||
data->temp[chan] = newh;
|
||||
/* sysfs hooks */
|
||||
data->groups[0] = &adm1031_group;
|
||||
if (data->chip_type == adm1031)
|
||||
data->groups[1] = &adm1031_group_opt;
|
||||
|
||||
data->temp_offset[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_TEMP_OFFSET(chan));
|
||||
data->temp_min[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_TEMP_MIN(chan));
|
||||
data->temp_max[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_TEMP_MAX(chan));
|
||||
data->temp_crit[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_TEMP_CRIT(chan));
|
||||
data->auto_temp[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_AUTO_TEMP(chan));
|
||||
|
||||
}
|
||||
|
||||
data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1);
|
||||
data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2);
|
||||
|
||||
data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0))
|
||||
| (adm1031_read_value(client, ADM1031_REG_STATUS(1)) << 8);
|
||||
if (data->chip_type == adm1030)
|
||||
data->alarm &= 0xc0ff;
|
||||
|
||||
for (chan = 0; chan < (data->chip_type == adm1030 ? 1 : 2);
|
||||
chan++) {
|
||||
data->fan_div[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_FAN_DIV(chan));
|
||||
data->fan_min[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_FAN_MIN(chan));
|
||||
data->fan[chan] =
|
||||
adm1031_read_value(client,
|
||||
ADM1031_REG_FAN_SPEED(chan));
|
||||
data->pwm[chan] =
|
||||
(adm1031_read_value(client,
|
||||
ADM1031_REG_PWM) >> (4 * chan)) & 0x0f;
|
||||
}
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, data->groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adm1031_id[] = {
|
||||
{ "adm1030", adm1030 },
|
||||
{ "adm1031", adm1031 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adm1031_id);
|
||||
|
||||
static struct i2c_driver adm1031_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adm1031",
|
||||
},
|
||||
.probe = adm1031_probe,
|
||||
.id_table = adm1031_id,
|
||||
.detect = adm1031_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(adm1031_driver);
|
||||
|
||||
MODULE_AUTHOR("Alexandre d'Alton <alex@alexdalton.org>");
|
||||
|
|
|
@ -130,38 +130,9 @@ static inline unsigned int AOUT_FROM_REG(u8 reg)
|
|||
return SCALE(reg, 1250, 255);
|
||||
}
|
||||
|
||||
static int adm9240_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int adm9240_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info);
|
||||
static void adm9240_init_client(struct i2c_client *client);
|
||||
static int adm9240_remove(struct i2c_client *client);
|
||||
static struct adm9240_data *adm9240_update_device(struct device *dev);
|
||||
|
||||
/* driver data */
|
||||
static const struct i2c_device_id adm9240_id[] = {
|
||||
{ "adm9240", adm9240 },
|
||||
{ "ds1780", ds1780 },
|
||||
{ "lm81", lm81 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adm9240_id);
|
||||
|
||||
static struct i2c_driver adm9240_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adm9240",
|
||||
},
|
||||
.probe = adm9240_probe,
|
||||
.remove = adm9240_remove,
|
||||
.id_table = adm9240_id,
|
||||
.detect = adm9240_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
/* per client data */
|
||||
struct adm9240_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
char valid;
|
||||
unsigned long last_updated_measure;
|
||||
|
@ -181,6 +152,110 @@ struct adm9240_data {
|
|||
u8 vrm; /* -- vrm set on startup, no accessor */
|
||||
};
|
||||
|
||||
/* write new fan div, callers must hold data->update_lock */
|
||||
static void adm9240_write_fan_div(struct i2c_client *client, int nr,
|
||||
u8 fan_div)
|
||||
{
|
||||
u8 reg, old, shift = (nr + 2) * 2;
|
||||
|
||||
reg = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV);
|
||||
old = (reg >> shift) & 3;
|
||||
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);
|
||||
}
|
||||
|
||||
static struct adm9240_data *adm9240_update_device(struct device *dev)
|
||||
{
|
||||
struct adm9240_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int i;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
/* minimum measurement cycle: 1.75 seconds */
|
||||
if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4))
|
||||
|| !data->valid) {
|
||||
|
||||
for (i = 0; i < 6; i++) { /* read voltages */
|
||||
data->in[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_IN(i));
|
||||
}
|
||||
data->alarms = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_INT(0)) |
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_INT(1)) << 8;
|
||||
|
||||
/*
|
||||
* read temperature: assume temperature changes less than
|
||||
* 0.5'C per two measurement cycles thus ignore possible
|
||||
* but unlikely aliasing error on lsb reading. --Grant
|
||||
*/
|
||||
data->temp = ((i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_TEMP) << 8) |
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_TEMP_CONF)) / 128;
|
||||
|
||||
for (i = 0; i < 2; i++) { /* read fans */
|
||||
data->fan[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_FAN(i));
|
||||
|
||||
/* adjust fan clock divider on overflow */
|
||||
if (data->valid && data->fan[i] == 255 &&
|
||||
data->fan_div[i] < 3) {
|
||||
|
||||
adm9240_write_fan_div(client, i,
|
||||
++data->fan_div[i]);
|
||||
|
||||
/* adjust fan_min if active, but not to 0 */
|
||||
if (data->fan_min[i] < 255 &&
|
||||
data->fan_min[i] >= 2)
|
||||
data->fan_min[i] /= 2;
|
||||
}
|
||||
}
|
||||
data->last_updated_measure = jiffies;
|
||||
}
|
||||
|
||||
/* minimum config reading cycle: 300 seconds */
|
||||
if (time_after(jiffies, data->last_updated_config + (HZ * 300))
|
||||
|| !data->valid) {
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
data->in_min[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_IN_MIN(i));
|
||||
data->in_max[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_IN_MAX(i));
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->fan_min[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_FAN_MIN(i));
|
||||
}
|
||||
data->temp_max[0] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_TEMP_MAX(0));
|
||||
data->temp_max[1] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_TEMP_MAX(1));
|
||||
|
||||
/* read fan divs and 5-bit VID */
|
||||
i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV);
|
||||
data->fan_div[0] = (i >> 4) & 3;
|
||||
data->fan_div[1] = (i >> 6) & 3;
|
||||
data->vid = i & 0x0f;
|
||||
data->vid |= (i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_VID4) & 1) << 4;
|
||||
/* read analog out */
|
||||
data->aout = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_ANALOG_OUT);
|
||||
|
||||
data->last_updated_config = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
/*** sysfs accessors ***/
|
||||
|
||||
/* temperature */
|
||||
|
@ -203,8 +278,8 @@ static ssize_t set_max(struct device *dev, struct device_attribute *devattr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
struct adm9240_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -259,8 +334,8 @@ static ssize_t set_in_min(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
struct adm9240_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -281,8 +356,8 @@ static ssize_t set_in_max(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
struct adm9240_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -340,22 +415,6 @@ static ssize_t show_fan_div(struct device *dev,
|
|||
return sprintf(buf, "%d\n", 1 << data->fan_div[attr->index]);
|
||||
}
|
||||
|
||||
/* write new fan div, callers must hold data->update_lock */
|
||||
static void adm9240_write_fan_div(struct i2c_client *client, int nr,
|
||||
u8 fan_div)
|
||||
{
|
||||
u8 reg, old, shift = (nr + 2) * 2;
|
||||
|
||||
reg = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV);
|
||||
old = (reg >> shift) & 3;
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* set fan speed low limit:
|
||||
*
|
||||
|
@ -372,8 +431,8 @@ static ssize_t set_fan_min(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
struct adm9240_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr = attr->index;
|
||||
u8 new_div;
|
||||
unsigned long val;
|
||||
|
@ -485,8 +544,8 @@ static ssize_t set_aout(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
struct adm9240_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -506,8 +565,8 @@ static ssize_t chassis_clear(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
struct adm9240_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
|
||||
if (kstrtoul(buf, 10, &val) || val != 0)
|
||||
|
@ -524,7 +583,7 @@ static ssize_t chassis_clear(struct device *dev,
|
|||
static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR, show_alarm,
|
||||
chassis_clear, 12);
|
||||
|
||||
static struct attribute *adm9240_attributes[] = {
|
||||
static struct attribute *adm9240_attrs[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_max.dev_attr.attr,
|
||||
|
@ -568,9 +627,7 @@ static struct attribute *adm9240_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adm9240_group = {
|
||||
.attrs = adm9240_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(adm9240);
|
||||
|
||||
|
||||
/*** sensor chip detect and driver install ***/
|
||||
|
@ -620,49 +677,6 @@ static int adm9240_detect(struct i2c_client *new_client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int adm9240_probe(struct i2c_client *new_client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adm9240_data *data;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&new_client->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(new_client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
adm9240_init_client(new_client);
|
||||
|
||||
/* populate sysfs filesystem */
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &adm9240_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adm9240_remove(struct i2c_client *client)
|
||||
{
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm9240_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adm9240_init_client(struct i2c_client *client)
|
||||
{
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
|
@ -705,94 +719,49 @@ static void adm9240_init_client(struct i2c_client *client)
|
|||
}
|
||||
}
|
||||
|
||||
static struct adm9240_data *adm9240_update_device(struct device *dev)
|
||||
static int adm9240_probe(struct i2c_client *new_client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
int i;
|
||||
struct device *dev = &new_client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct adm9240_data *data;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
/* minimum measurement cycle: 1.75 seconds */
|
||||
if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4))
|
||||
|| !data->valid) {
|
||||
i2c_set_clientdata(new_client, data);
|
||||
data->client = new_client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
for (i = 0; i < 6; i++) { /* read voltages */
|
||||
data->in[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_IN(i));
|
||||
}
|
||||
data->alarms = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_INT(0)) |
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_INT(1)) << 8;
|
||||
adm9240_init_client(new_client);
|
||||
|
||||
/*
|
||||
* read temperature: assume temperature changes less than
|
||||
* 0.5'C per two measurement cycles thus ignore possible
|
||||
* but unlikely aliasing error on lsb reading. --Grant
|
||||
*/
|
||||
data->temp = ((i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_TEMP) << 8) |
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_TEMP_CONF)) / 128;
|
||||
|
||||
for (i = 0; i < 2; i++) { /* read fans */
|
||||
data->fan[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_FAN(i));
|
||||
|
||||
/* adjust fan clock divider on overflow */
|
||||
if (data->valid && data->fan[i] == 255 &&
|
||||
data->fan_div[i] < 3) {
|
||||
|
||||
adm9240_write_fan_div(client, i,
|
||||
++data->fan_div[i]);
|
||||
|
||||
/* adjust fan_min if active, but not to 0 */
|
||||
if (data->fan_min[i] < 255 &&
|
||||
data->fan_min[i] >= 2)
|
||||
data->fan_min[i] /= 2;
|
||||
}
|
||||
}
|
||||
data->last_updated_measure = jiffies;
|
||||
}
|
||||
|
||||
/* minimum config reading cycle: 300 seconds */
|
||||
if (time_after(jiffies, data->last_updated_config + (HZ * 300))
|
||||
|| !data->valid) {
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
data->in_min[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_IN_MIN(i));
|
||||
data->in_max[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_IN_MAX(i));
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->fan_min[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_FAN_MIN(i));
|
||||
}
|
||||
data->temp_max[0] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_TEMP_MAX(0));
|
||||
data->temp_max[1] = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_TEMP_MAX(1));
|
||||
|
||||
/* read fan divs and 5-bit VID */
|
||||
i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV);
|
||||
data->fan_div[0] = (i >> 4) & 3;
|
||||
data->fan_div[1] = (i >> 6) & 3;
|
||||
data->vid = i & 0x0f;
|
||||
data->vid |= (i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_VID4) & 1) << 4;
|
||||
/* read analog out */
|
||||
data->aout = i2c_smbus_read_byte_data(client,
|
||||
ADM9240_REG_ANALOG_OUT);
|
||||
|
||||
data->last_updated_config = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
return data;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev,
|
||||
new_client->name,
|
||||
data,
|
||||
adm9240_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adm9240_id[] = {
|
||||
{ "adm9240", adm9240 },
|
||||
{ "ds1780", ds1780 },
|
||||
{ "lm81", lm81 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adm9240_id);
|
||||
|
||||
static struct i2c_driver adm9240_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adm9240",
|
||||
},
|
||||
.probe = adm9240_probe,
|
||||
.id_table = adm9240_id,
|
||||
.detect = adm9240_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(adm9240_driver);
|
||||
|
||||
MODULE_AUTHOR("Michiel Rook <michiel@grendelproject.nl>, "
|
||||
|
|
|
@ -198,7 +198,7 @@ static int ads1015_get_channels_config_of(struct i2c_client *client)
|
|||
}
|
||||
|
||||
channel = be32_to_cpup(property);
|
||||
if (channel > ADS1015_CHANNELS) {
|
||||
if (channel >= ADS1015_CHANNELS) {
|
||||
dev_err(&client->dev,
|
||||
"invalid channel index %d on %s\n",
|
||||
channel, node->full_name);
|
||||
|
|
|
@ -50,7 +50,7 @@ enum ads7828_chips { ads7828, ads7830 };
|
|||
|
||||
/* Client specific data */
|
||||
struct ads7828_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock; /* Mutex protecting updates */
|
||||
unsigned long last_updated; /* Last updated time (in jiffies) */
|
||||
u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH samples */
|
||||
|
@ -72,8 +72,8 @@ static inline u8 ads7828_cmd_byte(u8 cmd, int ch)
|
|||
/* Update data for the device (all 8 channels) */
|
||||
static struct ads7828_data *ads7828_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ads7828_data *data = i2c_get_clientdata(client);
|
||||
struct ads7828_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
|
@ -116,7 +116,7 @@ static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ads7828_show_in, NULL, 5);
|
|||
static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ads7828_show_in, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ads7828_show_in, NULL, 7);
|
||||
|
||||
static struct attribute *ads7828_attributes[] = {
|
||||
static struct attribute *ads7828_attrs[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
|
@ -128,29 +128,17 @@ static struct attribute *ads7828_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group ads7828_group = {
|
||||
.attrs = ads7828_attributes,
|
||||
};
|
||||
|
||||
static int ads7828_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ads7828_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
ATTRIBUTE_GROUPS(ads7828);
|
||||
|
||||
static int ads7828_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct ads7828_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
struct device *dev = &client->dev;
|
||||
struct ads7828_platform_data *pdata = dev_get_platdata(dev);
|
||||
struct ads7828_data *data;
|
||||
int err;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct ads7828_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -182,24 +170,13 @@ static int ads7828_probe(struct i2c_client *client,
|
|||
if (!data->diff_input)
|
||||
data->cmd_byte |= ADS7828_CMD_SD_SE;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
|
||||
return err;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
ads7828_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ads7828_device_ids[] = {
|
||||
|
@ -216,7 +193,6 @@ static struct i2c_driver ads7828_driver = {
|
|||
|
||||
.id_table = ads7828_device_ids,
|
||||
.probe = ads7828_probe,
|
||||
.remove = ads7828_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(ads7828_driver);
|
||||
|
|
|
@ -51,7 +51,7 @@ struct adt7411_data {
|
|||
struct mutex update_lock;
|
||||
unsigned long next_update;
|
||||
int vref_cached;
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -111,7 +111,8 @@ static int adt7411_modify_bit(struct i2c_client *client, u8 reg, u8 bit,
|
|||
static ssize_t adt7411_show_vdd(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7411_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int ret = adt7411_read_10_bit(client, ADT7411_REG_INT_TEMP_VDD_LSB,
|
||||
ADT7411_REG_VDD_MSB, 2);
|
||||
|
||||
|
@ -121,7 +122,8 @@ static ssize_t adt7411_show_vdd(struct device *dev,
|
|||
static ssize_t adt7411_show_temp(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7411_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int val = adt7411_read_10_bit(client, ADT7411_REG_INT_TEMP_VDD_LSB,
|
||||
ADT7411_REG_INT_TEMP_MSB, 0);
|
||||
|
||||
|
@ -137,8 +139,8 @@ static ssize_t adt7411_show_input(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7411_data *data = i2c_get_clientdata(client);
|
||||
struct adt7411_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int val;
|
||||
u8 lsb_reg, lsb_shift;
|
||||
|
||||
|
@ -180,7 +182,8 @@ static ssize_t adt7411_show_bit(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7411_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int ret = i2c_smbus_read_byte_data(client, attr2->index);
|
||||
|
||||
return ret < 0 ? ret : sprintf(buf, "%u\n", !!(ret & attr2->nr));
|
||||
|
@ -191,8 +194,8 @@ static ssize_t adt7411_set_bit(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute_2 *s_attr2 = to_sensor_dev_attr_2(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7411_data *data = i2c_get_clientdata(client);
|
||||
struct adt7411_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int ret;
|
||||
unsigned long flag;
|
||||
|
||||
|
@ -245,9 +248,7 @@ static struct attribute *adt7411_attrs[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adt7411_attr_grp = {
|
||||
.attrs = adt7411_attrs,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(adt7411);
|
||||
|
||||
static int adt7411_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info)
|
||||
|
@ -281,14 +282,17 @@ static int adt7411_detect(struct i2c_client *client,
|
|||
static int adt7411_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct adt7411_data *data;
|
||||
struct device *hwmon_dev;
|
||||
int ret;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->device_lock);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
|
@ -300,32 +304,10 @@ static int adt7411_probe(struct i2c_client *client,
|
|||
/* force update on first occasion */
|
||||
data->next_update = jiffies;
|
||||
|
||||
ret = sysfs_create_group(&client->dev.kobj, &adt7411_attr_grp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
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, "successfully registered\n");
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adt7411_remove(struct i2c_client *client)
|
||||
{
|
||||
struct adt7411_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
adt7411_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adt7411_id[] = {
|
||||
|
@ -339,7 +321,6 @@ static struct i2c_driver adt7411_driver = {
|
|||
.name = "adt7411",
|
||||
},
|
||||
.probe = adt7411_probe,
|
||||
.remove = adt7411_remove,
|
||||
.id_table = adt7411_id,
|
||||
.detect = adt7411_detect,
|
||||
.address_list = normal_i2c,
|
||||
|
|
|
@ -202,8 +202,7 @@ static const unsigned short normal_i2c[] = { 0x58, 0x5C, I2C_CLIENT_END };
|
|||
(((value) & prefix##_MASK) >> prefix##_SHIFT)
|
||||
|
||||
struct adt7462_data {
|
||||
struct device *hwmon_dev;
|
||||
struct attribute_group attrs;
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
char sensors_valid;
|
||||
char limits_valid;
|
||||
|
@ -232,30 +231,6 @@ struct adt7462_data {
|
|||
u8 alarms[ADT7462_ALARM_REG_COUNT];
|
||||
};
|
||||
|
||||
static int adt7462_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int adt7462_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info);
|
||||
static int adt7462_remove(struct i2c_client *client);
|
||||
|
||||
static const struct i2c_device_id adt7462_id[] = {
|
||||
{ "adt7462", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adt7462_id);
|
||||
|
||||
static struct i2c_driver adt7462_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adt7462",
|
||||
},
|
||||
.probe = adt7462_probe,
|
||||
.remove = adt7462_remove,
|
||||
.id_table = adt7462_id,
|
||||
.detect = adt7462_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
/*
|
||||
* 16-bit registers on the ADT7462 are low-byte first. The data sheet says
|
||||
* that the low byte must be read before the high byte.
|
||||
|
@ -705,8 +680,8 @@ static int find_trange_value(int trange)
|
|||
|
||||
static struct adt7462_data *adt7462_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long local_jiffies = jiffies;
|
||||
int i;
|
||||
|
||||
|
@ -828,8 +803,8 @@ static ssize_t set_temp_min(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp) || !temp_enabled(data, attr->index))
|
||||
|
@ -866,8 +841,8 @@ static ssize_t set_temp_max(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp) || !temp_enabled(data, attr->index))
|
||||
|
@ -929,8 +904,8 @@ static ssize_t set_volt_max(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int x = voltage_multiplier(data, attr->index);
|
||||
long temp;
|
||||
|
||||
|
@ -971,8 +946,8 @@ static ssize_t set_volt_min(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int x = voltage_multiplier(data, attr->index);
|
||||
long temp;
|
||||
|
||||
|
@ -1061,8 +1036,8 @@ static ssize_t set_fan_min(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp) || !temp ||
|
||||
|
@ -1109,8 +1084,8 @@ static ssize_t set_force_pwm_max(struct device *dev,
|
|||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
u8 reg;
|
||||
|
||||
|
@ -1142,8 +1117,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -1172,8 +1147,8 @@ static ssize_t set_pwm_max(struct device *dev,
|
|||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -1204,8 +1179,8 @@ static ssize_t set_pwm_min(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -1238,8 +1213,8 @@ static ssize_t set_pwm_hyst(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -1283,8 +1258,8 @@ static ssize_t set_pwm_tmax(struct device *dev,
|
|||
{
|
||||
int temp;
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int tmin, trange_value;
|
||||
long trange;
|
||||
|
||||
|
@ -1324,8 +1299,8 @@ static ssize_t set_pwm_tmin(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -1381,8 +1356,8 @@ static ssize_t set_pwm_auto(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -1440,8 +1415,8 @@ static ssize_t set_pwm_auto_temp(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
struct adt7462_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -1725,7 +1700,7 @@ static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO,
|
|||
static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO,
|
||||
show_pwm_auto_temp, set_pwm_auto_temp, 3);
|
||||
|
||||
static struct attribute *adt7462_attr[] = {
|
||||
static struct attribute *adt7462_attrs[] = {
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
|
@ -1896,6 +1871,8 @@ static struct attribute *adt7462_attr[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(adt7462);
|
||||
|
||||
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||
static int adt7462_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info)
|
||||
|
@ -1926,46 +1903,41 @@ static int adt7462_detect(struct i2c_client *client,
|
|||
static int adt7462_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct adt7462_data *data;
|
||||
int err;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct adt7462_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct adt7462_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
dev_info(&client->dev, "%s chip found\n", client->name);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
data->attrs.attrs = adt7462_attr;
|
||||
err = sysfs_create_group(&client->dev.kobj, &data->attrs);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||
return err;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
adt7462_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static int adt7462_remove(struct i2c_client *client)
|
||||
{
|
||||
struct adt7462_data *data = i2c_get_clientdata(client);
|
||||
static const struct i2c_device_id adt7462_id[] = {
|
||||
{ "adt7462", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adt7462_id);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||
return 0;
|
||||
}
|
||||
static struct i2c_driver adt7462_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adt7462",
|
||||
},
|
||||
.probe = adt7462_probe,
|
||||
.id_table = adt7462_id,
|
||||
.detect = adt7462_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(adt7462_driver);
|
||||
|
||||
|
|
|
@ -143,8 +143,7 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
|
|||
#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
|
||||
|
||||
struct adt7470_data {
|
||||
struct device *hwmon_dev;
|
||||
struct attribute_group attrs;
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
char sensors_valid;
|
||||
char limits_valid;
|
||||
|
@ -175,30 +174,6 @@ struct adt7470_data {
|
|||
unsigned int auto_update_interval;
|
||||
};
|
||||
|
||||
static int adt7470_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int adt7470_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info);
|
||||
static int adt7470_remove(struct i2c_client *client);
|
||||
|
||||
static const struct i2c_device_id adt7470_id[] = {
|
||||
{ "adt7470", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adt7470_id);
|
||||
|
||||
static struct i2c_driver adt7470_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adt7470",
|
||||
},
|
||||
.probe = adt7470_probe,
|
||||
.remove = adt7470_remove,
|
||||
.id_table = adt7470_id,
|
||||
.detect = adt7470_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
/*
|
||||
* 16-bit registers on the ADT7470 are low-byte first. The data sheet says
|
||||
* that the low byte must be read before the high byte.
|
||||
|
@ -218,18 +193,6 @@ static inline int adt7470_write_word_data(struct i2c_client *client, u8 reg,
|
|||
|| i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
|
||||
}
|
||||
|
||||
static void adt7470_init_client(struct i2c_client *client)
|
||||
{
|
||||
int reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
|
||||
|
||||
if (reg < 0) {
|
||||
dev_err(&client->dev, "cannot read configuration register\n");
|
||||
} else {
|
||||
/* start monitoring (and do a self-test) */
|
||||
i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg | 3);
|
||||
}
|
||||
}
|
||||
|
||||
/* Probe for temperature sensors. Assumes lock is held */
|
||||
static int adt7470_read_temperatures(struct i2c_client *client,
|
||||
struct adt7470_data *data)
|
||||
|
@ -314,8 +277,8 @@ static int adt7470_update_thread(void *p)
|
|||
|
||||
static struct adt7470_data *adt7470_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long local_jiffies = jiffies;
|
||||
u8 cfg;
|
||||
int i;
|
||||
|
@ -445,8 +408,7 @@ static ssize_t set_auto_update_interval(struct device *dev,
|
|||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -474,8 +436,7 @@ static ssize_t set_num_temp_sensors(struct device *dev,
|
|||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -507,8 +468,8 @@ static ssize_t set_temp_min(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -541,8 +502,8 @@ static ssize_t set_temp_max(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -596,8 +557,8 @@ static ssize_t set_fan_max(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp) || !temp)
|
||||
|
@ -633,8 +594,8 @@ static ssize_t set_fan_min(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp) || !temp)
|
||||
|
@ -677,8 +638,8 @@ static ssize_t set_force_pwm_max(struct device *dev,
|
|||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
u8 reg;
|
||||
|
||||
|
@ -710,8 +671,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -742,8 +703,8 @@ static ssize_t set_pwm_max(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -775,8 +736,8 @@ static ssize_t set_pwm_min(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -818,8 +779,8 @@ static ssize_t set_pwm_tmin(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
|
||||
if (kstrtol(buf, 10, &temp))
|
||||
|
@ -852,8 +813,8 @@ static ssize_t set_pwm_auto(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int pwm_auto_reg = ADT7470_REG_PWM_CFG(attr->index);
|
||||
int pwm_auto_reg_mask;
|
||||
long temp;
|
||||
|
@ -913,8 +874,8 @@ static ssize_t set_pwm_auto_temp(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int pwm_auto_reg = ADT7470_REG_PWM_AUTO_TEMP(attr->index);
|
||||
long temp;
|
||||
u8 reg;
|
||||
|
@ -1131,7 +1092,7 @@ static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO,
|
|||
static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO,
|
||||
show_pwm_auto_temp, set_pwm_auto_temp, 3);
|
||||
|
||||
static struct attribute *adt7470_attr[] = {
|
||||
static struct attribute *adt7470_attrs[] = {
|
||||
&dev_attr_alarm_mask.attr,
|
||||
&dev_attr_num_temp_sensors.attr,
|
||||
&dev_attr_auto_update_interval.attr,
|
||||
|
@ -1223,6 +1184,8 @@ static struct attribute *adt7470_attr[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(adt7470);
|
||||
|
||||
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||
static int adt7470_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info)
|
||||
|
@ -1250,14 +1213,26 @@ static int adt7470_detect(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void adt7470_init_client(struct i2c_client *client)
|
||||
{
|
||||
int reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
|
||||
|
||||
if (reg < 0) {
|
||||
dev_err(&client->dev, "cannot read configuration register\n");
|
||||
} else {
|
||||
/* start monitoring (and do a self-test) */
|
||||
i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg | 3);
|
||||
}
|
||||
}
|
||||
|
||||
static int adt7470_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct adt7470_data *data;
|
||||
int err;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct adt7470_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct adt7470_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1265,6 +1240,7 @@ static int adt7470_probe(struct i2c_client *client,
|
|||
data->auto_update_interval = AUTO_UPDATE_INTERVAL;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
dev_info(&client->dev, "%s chip found\n", client->name);
|
||||
|
@ -1273,32 +1249,21 @@ static int adt7470_probe(struct i2c_client *client,
|
|||
adt7470_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
data->attrs.attrs = adt7470_attr;
|
||||
err = sysfs_create_group(&client->dev.kobj, &data->attrs);
|
||||
if (err)
|
||||
return err;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
adt7470_groups);
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
if (IS_ERR(hwmon_dev))
|
||||
return PTR_ERR(hwmon_dev);
|
||||
|
||||
init_completion(&data->auto_update_stop);
|
||||
data->auto_update = kthread_run(adt7470_update_thread, client, "%s",
|
||||
dev_name(data->hwmon_dev));
|
||||
dev_name(hwmon_dev));
|
||||
if (IS_ERR(data->auto_update)) {
|
||||
err = PTR_ERR(data->auto_update);
|
||||
goto exit_unregister;
|
||||
return PTR_ERR(data->auto_update);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_unregister:
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adt7470_remove(struct i2c_client *client)
|
||||
|
@ -1307,11 +1272,27 @@ static int adt7470_remove(struct i2c_client *client)
|
|||
|
||||
kthread_stop(data->auto_update);
|
||||
wait_for_completion(&data->auto_update_stop);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adt7470_id[] = {
|
||||
{ "adt7470", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adt7470_id);
|
||||
|
||||
static struct i2c_driver adt7470_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adt7470",
|
||||
},
|
||||
.probe = adt7470_probe,
|
||||
.remove = adt7470_remove,
|
||||
.id_table = adt7470_id,
|
||||
.detect = adt7470_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(adt7470_driver);
|
||||
|
||||
MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -300,7 +300,7 @@ static ssize_t store_fan16(struct device *dev,
|
|||
* respectively. That doesn't mean that's what the motherboard provides. :)
|
||||
*/
|
||||
|
||||
static int asc7621_in_scaling[] = {
|
||||
static const int asc7621_in_scaling[] = {
|
||||
2500, 2250, 3300, 5000, 12000
|
||||
};
|
||||
|
||||
|
@ -451,7 +451,7 @@ static ssize_t store_temp62(struct device *dev,
|
|||
* hwmon specs, we synthesize the auto_point_2 from them.
|
||||
*/
|
||||
|
||||
static u32 asc7621_range_map[] = {
|
||||
static const u32 asc7621_range_map[] = {
|
||||
2000, 2500, 3330, 4000, 5000, 6670, 8000, 10000,
|
||||
13330, 16000, 20000, 26670, 32000, 40000, 53330, 80000,
|
||||
};
|
||||
|
@ -512,7 +512,7 @@ static ssize_t show_pwm_ac(struct device *dev,
|
|||
{
|
||||
SETUP_SHOW_DATA_PARAM(dev, attr);
|
||||
u8 config, altbit, regval;
|
||||
u8 map[] = {
|
||||
const u8 map[] = {
|
||||
0x01, 0x02, 0x04, 0x1f, 0x00, 0x06, 0x07, 0x10,
|
||||
0x08, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
|
||||
};
|
||||
|
@ -533,7 +533,7 @@ static ssize_t store_pwm_ac(struct device *dev,
|
|||
SETUP_STORE_DATA_PARAM(dev, attr);
|
||||
unsigned long reqval;
|
||||
u8 currval, config, altbit, newval;
|
||||
u16 map[] = {
|
||||
const u16 map[] = {
|
||||
0x04, 0x00, 0x01, 0xff, 0x02, 0xff, 0x05, 0x06,
|
||||
0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
|
||||
0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
|
@ -651,7 +651,7 @@ static ssize_t store_pwm_enable(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static u32 asc7621_pwm_freq_map[] = {
|
||||
static const u32 asc7621_pwm_freq_map[] = {
|
||||
10, 15, 23, 30, 38, 47, 62, 94,
|
||||
23000, 24000, 25000, 26000, 27000, 28000, 29000, 30000
|
||||
};
|
||||
|
@ -700,7 +700,7 @@ static ssize_t store_pwm_freq(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static u32 asc7621_pwm_auto_spinup_map[] = {
|
||||
static const u32 asc7621_pwm_auto_spinup_map[] = {
|
||||
0, 100, 250, 400, 700, 1000, 2000, 4000
|
||||
};
|
||||
|
||||
|
@ -749,7 +749,7 @@ static ssize_t store_pwm_ast(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static u32 asc7621_temp_smoothing_time_map[] = {
|
||||
static const u32 asc7621_temp_smoothing_time_map[] = {
|
||||
35000, 17600, 11800, 7000, 4400, 3000, 1600, 800
|
||||
};
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
|
|||
static const unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END };
|
||||
|
||||
struct atxp1_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
unsigned long last_updated;
|
||||
u8 valid;
|
||||
|
@ -61,11 +61,8 @@ struct atxp1_data {
|
|||
|
||||
static struct atxp1_data *atxp1_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct atxp1_data *data;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = i2c_get_clientdata(client);
|
||||
struct atxp1_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
|
@ -105,15 +102,12 @@ static ssize_t atxp1_storevcore(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct atxp1_data *data;
|
||||
struct i2c_client *client;
|
||||
struct atxp1_data *data = atxp1_update_device(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int vid, cvid;
|
||||
unsigned long vcore;
|
||||
int err;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
err = kstrtoul(buf, 10, &vcore);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -184,14 +178,11 @@ static ssize_t atxp1_storegpio1(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct atxp1_data *data;
|
||||
struct i2c_client *client;
|
||||
struct atxp1_data *data = atxp1_update_device(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long value;
|
||||
int err;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
err = kstrtoul(buf, 16, &value);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -234,7 +225,7 @@ static ssize_t atxp1_storegpio2(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct atxp1_data *data = atxp1_update_device(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long value;
|
||||
int err;
|
||||
|
||||
|
@ -260,17 +251,13 @@ static ssize_t atxp1_storegpio2(struct device *dev,
|
|||
*/
|
||||
static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
|
||||
|
||||
static struct attribute *atxp1_attributes[] = {
|
||||
static struct attribute *atxp1_attrs[] = {
|
||||
&dev_attr_gpio1.attr,
|
||||
&dev_attr_gpio2.attr,
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group atxp1_group = {
|
||||
.attrs = atxp1_attributes,
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(atxp1);
|
||||
|
||||
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||
static int atxp1_detect(struct i2c_client *new_client,
|
||||
|
@ -314,50 +301,30 @@ static int atxp1_detect(struct i2c_client *new_client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int atxp1_probe(struct i2c_client *new_client,
|
||||
static int atxp1_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct atxp1_data *data;
|
||||
int err;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
data = devm_kzalloc(&new_client->dev, sizeof(struct atxp1_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct atxp1_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Get VRM */
|
||||
data->vrm = vid_which_vrm();
|
||||
|
||||
i2c_set_clientdata(new_client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group);
|
||||
if (err)
|
||||
return err;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
atxp1_groups);
|
||||
if (IS_ERR(hwmon_dev))
|
||||
return PTR_ERR(hwmon_dev);
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
dev_info(&new_client->dev, "Using VRM: %d.%d\n",
|
||||
data->vrm / 10, data->vrm % 10);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &atxp1_group);
|
||||
return err;
|
||||
};
|
||||
|
||||
static int atxp1_remove(struct i2c_client *client)
|
||||
{
|
||||
struct atxp1_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &atxp1_group);
|
||||
dev_info(dev, "Using VRM: %d.%d\n", data->vrm / 10, data->vrm % 10);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
@ -374,7 +341,6 @@ static struct i2c_driver atxp1_driver = {
|
|||
.name = "atxp1",
|
||||
},
|
||||
.probe = atxp1_probe,
|
||||
.remove = atxp1_remove,
|
||||
.id_table = atxp1_id,
|
||||
.detect = atxp1_detect,
|
||||
.address_list = normal_i2c,
|
||||
|
|
|
@ -67,7 +67,7 @@ static const u8 DS620_REG_TEMP[3] = {
|
|||
|
||||
/* Each client has this additional data */
|
||||
struct ds620_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
@ -106,8 +106,8 @@ static void ds620_init_client(struct i2c_client *client)
|
|||
|
||||
static struct ds620_data *ds620_update_client(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ds620_data *data = i2c_get_clientdata(client);
|
||||
struct ds620_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
struct ds620_data *ret = data;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
@ -158,8 +158,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
|
|||
long val;
|
||||
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ds620_data *data = i2c_get_clientdata(client);
|
||||
struct ds620_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
res = kstrtol(buf, 10, &val);
|
||||
|
||||
|
@ -181,13 +181,15 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
|
|||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct ds620_data *data = ds620_update_client(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_client *client;
|
||||
u16 conf, new_conf;
|
||||
int res;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
client = data->client;
|
||||
|
||||
/* reset alarms if necessary */
|
||||
res = i2c_smbus_read_word_swapped(client, DS620_REG_CONF);
|
||||
if (res < 0)
|
||||
|
@ -213,7 +215,7 @@ static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
|
|||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
|
||||
DS620_REG_CONFIG_THF);
|
||||
|
||||
static struct attribute *ds620_attributes[] = {
|
||||
static struct attribute *ds620_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
|
@ -222,55 +224,28 @@ static struct attribute *ds620_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group ds620_group = {
|
||||
.attrs = ds620_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ds620);
|
||||
|
||||
static int ds620_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct ds620_data *data;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct ds620_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct ds620_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the DS620 chip */
|
||||
ds620_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &ds620_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "temperature sensor found\n");
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&client->dev.kobj, &ds620_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ds620_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ds620_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &ds620_group);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, ds620_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ds620_id[] = {
|
||||
|
@ -287,7 +262,6 @@ static struct i2c_driver ds620_driver = {
|
|||
.name = "ds620",
|
||||
},
|
||||
.probe = ds620_probe,
|
||||
.remove = ds620_remove,
|
||||
.id_table = ds620_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -416,7 +416,7 @@ static bool emc1403_regmap_is_volatile(struct device *dev, unsigned int reg)
|
|||
}
|
||||
}
|
||||
|
||||
static struct regmap_config emc1403_regmap_config = {
|
||||
static const struct regmap_config emc1403_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
|
|
@ -66,7 +66,8 @@ struct temperature {
|
|||
};
|
||||
|
||||
struct emc2103_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
const struct attribute_group *groups[4];
|
||||
struct mutex update_lock;
|
||||
bool valid; /* registers are valid */
|
||||
bool fan_rpm_control;
|
||||
|
@ -146,8 +147,8 @@ static void read_fan_config_from_i2c(struct i2c_client *client)
|
|||
|
||||
static struct emc2103_data *emc2103_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct emc2103_data *data = i2c_get_clientdata(client);
|
||||
struct emc2103_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
|
@ -242,8 +243,8 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *da,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(da)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct emc2103_data *data = i2c_get_clientdata(client);
|
||||
struct emc2103_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
|
||||
int result = kstrtol(buf, 10, &val);
|
||||
|
@ -264,8 +265,8 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *da,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(da)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct emc2103_data *data = i2c_get_clientdata(client);
|
||||
struct emc2103_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
|
||||
int result = kstrtol(buf, 10, &val);
|
||||
|
@ -310,7 +311,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct emc2103_data *data = emc2103_update_device(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int new_range_bits, old_div = 8 / data->fan_multiplier;
|
||||
long new_div;
|
||||
|
||||
|
@ -385,7 +386,7 @@ static ssize_t set_fan_target(struct device *dev, struct device_attribute *da,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct emc2103_data *data = emc2103_update_device(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long rpm_target;
|
||||
|
||||
int result = kstrtoul(buf, 10, &rpm_target);
|
||||
|
@ -428,8 +429,8 @@ show_pwm_enable(struct device *dev, struct device_attribute *da, char *buf)
|
|||
static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct emc2103_data *data = i2c_get_clientdata(client);
|
||||
struct emc2103_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long new_value;
|
||||
u8 conf_reg;
|
||||
|
||||
|
@ -580,7 +581,8 @@ static int
|
|||
emc2103_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct emc2103_data *data;
|
||||
int status;
|
||||
struct device *hwmon_dev;
|
||||
int status, idx = 0;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EIO;
|
||||
|
@ -591,6 +593,7 @@ emc2103_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* 2103-2 and 2103-4 have 3 external diodes, 2103-1 has 1 */
|
||||
|
@ -624,60 +627,21 @@ emc2103_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
}
|
||||
}
|
||||
|
||||
/* Register sysfs hooks */
|
||||
status = sysfs_create_group(&client->dev.kobj, &emc2103_group);
|
||||
if (status)
|
||||
return status;
|
||||
/* sysfs hooks */
|
||||
data->groups[idx++] = &emc2103_group;
|
||||
if (data->temp_count >= 3)
|
||||
data->groups[idx++] = &emc2103_temp3_group;
|
||||
if (data->temp_count == 4)
|
||||
data->groups[idx++] = &emc2103_temp4_group;
|
||||
|
||||
if (data->temp_count >= 3) {
|
||||
status = sysfs_create_group(&client->dev.kobj,
|
||||
&emc2103_temp3_group);
|
||||
if (status)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
if (data->temp_count == 4) {
|
||||
status = sysfs_create_group(&client->dev.kobj,
|
||||
&emc2103_temp4_group);
|
||||
if (status)
|
||||
goto exit_remove_temp3;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
status = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_temp4;
|
||||
}
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
|
||||
client->name, data,
|
||||
data->groups);
|
||||
if (IS_ERR(hwmon_dev))
|
||||
return PTR_ERR(hwmon_dev);
|
||||
|
||||
dev_info(&client->dev, "%s: sensor '%s'\n",
|
||||
dev_name(data->hwmon_dev), client->name);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_temp4:
|
||||
if (data->temp_count == 4)
|
||||
sysfs_remove_group(&client->dev.kobj, &emc2103_temp4_group);
|
||||
exit_remove_temp3:
|
||||
if (data->temp_count >= 3)
|
||||
sysfs_remove_group(&client->dev.kobj, &emc2103_temp3_group);
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &emc2103_group);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int emc2103_remove(struct i2c_client *client)
|
||||
{
|
||||
struct emc2103_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
|
||||
if (data->temp_count == 4)
|
||||
sysfs_remove_group(&client->dev.kobj, &emc2103_temp4_group);
|
||||
|
||||
if (data->temp_count >= 3)
|
||||
sysfs_remove_group(&client->dev.kobj, &emc2103_temp3_group);
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &emc2103_group);
|
||||
dev_name(hwmon_dev), client->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -717,7 +681,6 @@ static struct i2c_driver emc2103_driver = {
|
|||
.name = "emc2103",
|
||||
},
|
||||
.probe = emc2103_probe,
|
||||
.remove = emc2103_remove,
|
||||
.id_table = emc2103_ids,
|
||||
.detect = emc2103_detect,
|
||||
.address_list = normal_i2c,
|
||||
|
|
|
@ -56,7 +56,7 @@ enum subfeature { input, min, max };
|
|||
*/
|
||||
|
||||
struct emc6w201_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
|
@ -134,8 +134,8 @@ static int emc6w201_write8(struct i2c_client *client, u8 reg, u8 val)
|
|||
|
||||
static struct emc6w201_data *emc6w201_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct emc6w201_data *data = i2c_get_clientdata(client);
|
||||
struct emc6w201_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
@ -203,8 +203,8 @@ static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
|
|||
static ssize_t set_in(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct emc6w201_data *data = i2c_get_clientdata(client);
|
||||
struct emc6w201_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int sf = to_sensor_dev_attr_2(devattr)->index;
|
||||
int nr = to_sensor_dev_attr_2(devattr)->nr;
|
||||
int err;
|
||||
|
@ -240,8 +240,8 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
|
|||
static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct emc6w201_data *data = i2c_get_clientdata(client);
|
||||
struct emc6w201_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int sf = to_sensor_dev_attr_2(devattr)->index;
|
||||
int nr = to_sensor_dev_attr_2(devattr)->nr;
|
||||
int err;
|
||||
|
@ -283,8 +283,8 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
|
|||
static ssize_t set_fan(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct emc6w201_data *data = i2c_get_clientdata(client);
|
||||
struct emc6w201_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int sf = to_sensor_dev_attr_2(devattr)->index;
|
||||
int nr = to_sensor_dev_attr_2(devattr)->nr;
|
||||
int err;
|
||||
|
@ -388,7 +388,7 @@ static SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, input);
|
|||
static SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
|
||||
4, min);
|
||||
|
||||
static struct attribute *emc6w201_attributes[] = {
|
||||
static struct attribute *emc6w201_attrs[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_max.dev_attr.attr,
|
||||
|
@ -440,9 +440,7 @@ static struct attribute *emc6w201_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group emc6w201_group = {
|
||||
.attrs = emc6w201_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(emc6w201);
|
||||
|
||||
/*
|
||||
* Driver interface
|
||||
|
@ -488,44 +486,21 @@ static int emc6w201_detect(struct i2c_client *client,
|
|||
static int emc6w201_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct emc6w201_data *data;
|
||||
int err;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct emc6w201_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct emc6w201_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Create sysfs attribute */
|
||||
err = sysfs_create_group(&client->dev.kobj, &emc6w201_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Expose as a hwmon device */
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &emc6w201_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int emc6w201_remove(struct i2c_client *client)
|
||||
{
|
||||
struct emc6w201_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &emc6w201_group);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
emc6w201_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id emc6w201_id[] = {
|
||||
|
@ -540,7 +515,6 @@ static struct i2c_driver emc6w201_driver = {
|
|||
.name = "emc6w201",
|
||||
},
|
||||
.probe = emc6w201_probe,
|
||||
.remove = emc6w201_remove,
|
||||
.id_table = emc6w201_id,
|
||||
.detect = emc6w201_detect,
|
||||
.address_list = normal_i2c,
|
||||
|
|
|
@ -31,9 +31,6 @@ MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor");
|
|||
MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Family 16h Northbridge's function 4 PCI ID */
|
||||
#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534
|
||||
|
||||
/* D18F3 */
|
||||
#define REG_NORTHBRIDGE_CAP 0xe8
|
||||
|
||||
|
@ -45,7 +42,7 @@ MODULE_LICENSE("GPL");
|
|||
#define REG_TDP_LIMIT3 0xe8
|
||||
|
||||
struct fam15h_power_data {
|
||||
struct device *hwmon_dev;
|
||||
struct pci_dev *pdev;
|
||||
unsigned int tdp_to_watts;
|
||||
unsigned int base_tdp;
|
||||
unsigned int processor_pwr_watts;
|
||||
|
@ -57,8 +54,8 @@ static ssize_t show_power(struct device *dev,
|
|||
u32 val, tdp_limit, running_avg_range;
|
||||
s32 running_avg_capture;
|
||||
u64 curr_pwr_watts;
|
||||
struct pci_dev *f4 = to_pci_dev(dev);
|
||||
struct fam15h_power_data *data = dev_get_drvdata(dev);
|
||||
struct pci_dev *f4 = data->pdev;
|
||||
|
||||
pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
|
||||
REG_TDP_RUNNING_AVERAGE, &val);
|
||||
|
@ -96,23 +93,13 @@ static ssize_t show_power_crit(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR(power1_crit, S_IRUGO, show_power_crit, NULL);
|
||||
|
||||
static ssize_t show_name(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "fam15h_power\n");
|
||||
}
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
static struct attribute *fam15h_power_attrs[] = {
|
||||
&dev_attr_power1_input.attr,
|
||||
&dev_attr_power1_crit.attr,
|
||||
&dev_attr_name.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group fam15h_power_attr_group = {
|
||||
.attrs = fam15h_power_attrs,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(fam15h_power);
|
||||
|
||||
static bool fam15h_power_is_internal_node0(struct pci_dev *f4)
|
||||
{
|
||||
|
@ -202,7 +189,7 @@ static int fam15h_power_probe(struct pci_dev *pdev,
|
|||
{
|
||||
struct fam15h_power_data *data;
|
||||
struct device *dev = &pdev->dev;
|
||||
int err;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
/*
|
||||
* though we ignore every other northbridge, we still have to
|
||||
|
@ -219,34 +206,12 @@ static int fam15h_power_probe(struct pci_dev *pdev,
|
|||
return -ENOMEM;
|
||||
|
||||
fam15h_power_init_data(pdev, data);
|
||||
data->pdev = pdev;
|
||||
|
||||
dev_set_drvdata(dev, data);
|
||||
err = sysfs_create_group(&dev->kobj, &fam15h_power_attr_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_group;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_group:
|
||||
sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void fam15h_power_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct device *dev;
|
||||
struct fam15h_power_data *data;
|
||||
|
||||
dev = &pdev->dev;
|
||||
data = dev_get_drvdata(dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, "fam15h_power",
|
||||
data,
|
||||
fam15h_power_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct pci_device_id fam15h_power_id_table[] = {
|
||||
|
@ -260,7 +225,6 @@ static struct pci_driver fam15h_power_driver = {
|
|||
.name = "fam15h_power",
|
||||
.id_table = fam15h_power_id_table,
|
||||
.probe = fam15h_power_probe,
|
||||
.remove = fam15h_power_remove,
|
||||
.resume = fam15h_power_resume,
|
||||
};
|
||||
|
||||
|
|
|
@ -24,12 +24,6 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
static const struct i2c_device_id g760a_id[] = {
|
||||
{ "g760a", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, g760a_id);
|
||||
|
||||
enum g760a_regs {
|
||||
G760A_REG_SET_CNT = 0x00,
|
||||
G760A_REG_ACT_CNT = 0x01,
|
||||
|
@ -44,7 +38,6 @@ enum g760a_regs {
|
|||
|
||||
struct g760a_data {
|
||||
struct i2c_client *client;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
|
||||
/* board specific parameters */
|
||||
|
@ -74,20 +67,6 @@ static inline unsigned int rpm_from_cnt(u8 val, u32 clk, u16 div)
|
|||
return ((val == 0x00) ? 0 : ((clk*30)/(val*div)));
|
||||
}
|
||||
|
||||
/* new-style driver model */
|
||||
static int g760a_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int g760a_remove(struct i2c_client *client);
|
||||
|
||||
static struct i2c_driver g760a_driver = {
|
||||
.driver = {
|
||||
.name = "g760a",
|
||||
},
|
||||
.probe = g760a_probe,
|
||||
.remove = g760a_remove,
|
||||
.id_table = g760a_id,
|
||||
};
|
||||
|
||||
/* read/write wrappers */
|
||||
static int g760a_read_value(struct i2c_client *client, enum g760a_regs reg)
|
||||
{
|
||||
|
@ -106,8 +85,8 @@ static int g760a_write_value(struct i2c_client *client, enum g760a_regs reg,
|
|||
|
||||
static struct g760a_data *g760a_update_client(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g760a_data *data = i2c_get_clientdata(client);
|
||||
struct g760a_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
|
@ -163,8 +142,8 @@ static ssize_t get_pwm(struct device *dev, struct device_attribute *da,
|
|||
static ssize_t set_pwm(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g760a_data *data = g760a_update_client(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
|
||||
if (kstrtoul(buf, 10, &val))
|
||||
|
@ -182,16 +161,14 @@ static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm);
|
|||
static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL);
|
||||
static DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL);
|
||||
|
||||
static struct attribute *g760a_attributes[] = {
|
||||
static struct attribute *g760a_attrs[] = {
|
||||
&dev_attr_pwm1.attr,
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan1_alarm.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group g760a_group = {
|
||||
.attrs = g760a_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(g760a);
|
||||
|
||||
/*
|
||||
* new-style driver model code
|
||||
|
@ -200,20 +177,17 @@ static const struct attribute_group g760a_group = {
|
|||
static int g760a_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct g760a_data *data;
|
||||
int err;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EIO;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct g760a_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct g760a_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
|
@ -221,31 +195,25 @@ static int g760a_probe(struct i2c_client *client,
|
|||
data->fan_div = G760A_DEFAULT_FAN_DIV;
|
||||
data->clk = G760A_DEFAULT_CLK;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &g760a_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto error_hwmon_device_register;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_hwmon_device_register:
|
||||
sysfs_remove_group(&client->dev.kobj, &g760a_group);
|
||||
return err;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
g760a_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static int g760a_remove(struct i2c_client *client)
|
||||
{
|
||||
struct g760a_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &g760a_group);
|
||||
return 0;
|
||||
}
|
||||
static const struct i2c_device_id g760a_id[] = {
|
||||
{ "g760a", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, g760a_id);
|
||||
|
||||
static struct i2c_driver g760a_driver = {
|
||||
.driver = {
|
||||
.name = "g760a",
|
||||
},
|
||||
.probe = g760a_probe,
|
||||
.id_table = g760a_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(g760a_driver);
|
||||
|
||||
|
|
|
@ -128,8 +128,8 @@ enum g762_regs {
|
|||
G762_REG_FAN_CMD2_GEAR_MODE_1)) >> 2))
|
||||
|
||||
struct g762_data {
|
||||
struct i2c_client *client;
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct clk *clk;
|
||||
|
||||
/* update mutex */
|
||||
|
@ -206,8 +206,8 @@ static inline unsigned char cnt_from_rpm(u32 rpm, u32 clk_freq, u16 p,
|
|||
/* helper to grab and cache data, at most one time per second */
|
||||
static struct g762_data *g762_update_client(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g762_data *data = i2c_get_clientdata(client);
|
||||
struct g762_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
@ -266,8 +266,7 @@ static struct g762_data *g762_update_client(struct device *dev)
|
|||
*/
|
||||
static int do_set_clk_freq(struct device *dev, unsigned long val)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g762_data *data = i2c_get_clientdata(client);
|
||||
struct g762_data *data = dev_get_drvdata(dev);
|
||||
|
||||
if (val > 0xffffff)
|
||||
return -EINVAL;
|
||||
|
@ -282,7 +281,6 @@ static int do_set_clk_freq(struct device *dev, unsigned long val)
|
|||
/* Set pwm mode. Accepts either 0 (PWM mode) or 1 (DC mode) */
|
||||
static int do_set_pwm_mode(struct device *dev, unsigned long val)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g762_data *data = g762_update_client(dev);
|
||||
int ret;
|
||||
|
||||
|
@ -301,7 +299,7 @@ static int do_set_pwm_mode(struct device *dev, unsigned long val)
|
|||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
|
||||
ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
|
||||
data->fan_cmd1);
|
||||
data->valid = false;
|
||||
out:
|
||||
|
@ -313,7 +311,6 @@ static int do_set_pwm_mode(struct device *dev, unsigned long val)
|
|||
/* Set fan clock divisor. Accepts either 1, 2, 4 or 8. */
|
||||
static int do_set_fan_div(struct device *dev, unsigned long val)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g762_data *data = g762_update_client(dev);
|
||||
int ret;
|
||||
|
||||
|
@ -342,7 +339,7 @@ static int do_set_fan_div(struct device *dev, unsigned long val)
|
|||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
|
||||
ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
|
||||
data->fan_cmd1);
|
||||
data->valid = false;
|
||||
out:
|
||||
|
@ -354,7 +351,6 @@ static int do_set_fan_div(struct device *dev, unsigned long val)
|
|||
/* Set fan gear mode. Accepts either 0, 1 or 2. */
|
||||
static int do_set_fan_gear_mode(struct device *dev, unsigned long val)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g762_data *data = g762_update_client(dev);
|
||||
int ret;
|
||||
|
||||
|
@ -379,7 +375,7 @@ static int do_set_fan_gear_mode(struct device *dev, unsigned long val)
|
|||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD2,
|
||||
ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD2,
|
||||
data->fan_cmd2);
|
||||
data->valid = false;
|
||||
out:
|
||||
|
@ -391,7 +387,6 @@ static int do_set_fan_gear_mode(struct device *dev, unsigned long val)
|
|||
/* Set number of fan pulses per revolution. Accepts either 2 or 4. */
|
||||
static int do_set_fan_pulses(struct device *dev, unsigned long val)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g762_data *data = g762_update_client(dev);
|
||||
int ret;
|
||||
|
||||
|
@ -410,7 +405,7 @@ static int do_set_fan_pulses(struct device *dev, unsigned long val)
|
|||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
|
||||
ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
|
||||
data->fan_cmd1);
|
||||
data->valid = false;
|
||||
out:
|
||||
|
@ -422,7 +417,6 @@ static int do_set_fan_pulses(struct device *dev, unsigned long val)
|
|||
/* Set fan mode. Accepts either 1 (open-loop) or 2 (closed-loop). */
|
||||
static int do_set_pwm_enable(struct device *dev, unsigned long val)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g762_data *data = g762_update_client(dev);
|
||||
int ret;
|
||||
|
||||
|
@ -444,15 +438,15 @@ static int do_set_pwm_enable(struct device *dev, unsigned long val)
|
|||
* value of 254 if it is 255 when switching to open-loop.
|
||||
*/
|
||||
if (data->set_cnt == 0xff)
|
||||
i2c_smbus_write_byte_data(client, G762_REG_SET_CNT,
|
||||
254);
|
||||
i2c_smbus_write_byte_data(data->client,
|
||||
G762_REG_SET_CNT, 254);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
|
||||
ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
|
||||
data->fan_cmd1);
|
||||
data->valid = false;
|
||||
out:
|
||||
|
@ -464,7 +458,6 @@ static int do_set_pwm_enable(struct device *dev, unsigned long val)
|
|||
/* Set PWM polarity. Accepts either 0 (positive duty) or 1 (negative duty) */
|
||||
static int do_set_pwm_polarity(struct device *dev, unsigned long val)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g762_data *data = g762_update_client(dev);
|
||||
int ret;
|
||||
|
||||
|
@ -483,7 +476,7 @@ static int do_set_pwm_polarity(struct device *dev, unsigned long val)
|
|||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
|
||||
ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
|
||||
data->fan_cmd1);
|
||||
data->valid = false;
|
||||
out:
|
||||
|
@ -498,8 +491,8 @@ static int do_set_pwm_polarity(struct device *dev, unsigned long val)
|
|||
*/
|
||||
static int do_set_pwm(struct device *dev, unsigned long val)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g762_data *data = i2c_get_clientdata(client);
|
||||
struct g762_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int ret;
|
||||
|
||||
if (val > 255)
|
||||
|
@ -519,7 +512,6 @@ static int do_set_pwm(struct device *dev, unsigned long val)
|
|||
*/
|
||||
static int do_set_fan_target(struct device *dev, unsigned long val)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g762_data *data = g762_update_client(dev);
|
||||
int ret;
|
||||
|
||||
|
@ -531,7 +523,7 @@ static int do_set_fan_target(struct device *dev, unsigned long val)
|
|||
G762_PULSE_FROM_REG(data->fan_cmd1),
|
||||
G762_CLKDIV_FROM_REG(data->fan_cmd1),
|
||||
G762_GEARMULT_FROM_REG(data->fan_cmd2));
|
||||
ret = i2c_smbus_write_byte_data(client, G762_REG_SET_CNT,
|
||||
ret = i2c_smbus_write_byte_data(data->client, G762_REG_SET_CNT,
|
||||
data->set_cnt);
|
||||
data->valid = false;
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
@ -542,7 +534,6 @@ static int do_set_fan_target(struct device *dev, unsigned long val)
|
|||
/* Set fan startup voltage. Accepted values are either 0, 1, 2 or 3. */
|
||||
static int do_set_fan_startv(struct device *dev, unsigned long val)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g762_data *data = g762_update_client(dev);
|
||||
int ret;
|
||||
|
||||
|
@ -571,7 +562,7 @@ static int do_set_fan_startv(struct device *dev, unsigned long val)
|
|||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD2,
|
||||
ret = i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD2,
|
||||
data->fan_cmd2);
|
||||
data->valid = false;
|
||||
out:
|
||||
|
@ -658,15 +649,12 @@ static int g762_of_prop_import_one(struct i2c_client *client,
|
|||
int (*psetter)(struct device *dev,
|
||||
unsigned long val))
|
||||
{
|
||||
const __be32 *prop;
|
||||
int len, ret;
|
||||
int ret;
|
||||
u32 pval;
|
||||
|
||||
prop = of_get_property(client->dev.of_node, pname, &len);
|
||||
if (!prop || len != sizeof(u32))
|
||||
if (of_property_read_u32(client->dev.of_node, pname, &pval))
|
||||
return 0;
|
||||
|
||||
pval = be32_to_cpu(prop[0]);
|
||||
dev_dbg(&client->dev, "found %s (%d)\n", pname, pval);
|
||||
ret = (*psetter)(&client->dev, pval);
|
||||
if (ret)
|
||||
|
@ -1026,7 +1014,7 @@ static DEVICE_ATTR(fan1_pulses, S_IWUSR | S_IRUGO,
|
|||
get_fan_pulses, set_fan_pulses);
|
||||
|
||||
/* Driver data */
|
||||
static struct attribute *g762_attributes[] = {
|
||||
static struct attribute *g762_attrs[] = {
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan1_alarm.attr,
|
||||
&dev_attr_fan1_fault.attr,
|
||||
|
@ -1039,9 +1027,7 @@ static struct attribute *g762_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group g762_group = {
|
||||
.attrs = g762_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(g762);
|
||||
|
||||
/*
|
||||
* Enable both fan failure detection and fan out of control protection. The
|
||||
|
@ -1050,7 +1036,6 @@ static const struct attribute_group g762_group = {
|
|||
*/
|
||||
static inline int g762_fan_init(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct g762_data *data = g762_update_client(dev);
|
||||
|
||||
if (IS_ERR(data))
|
||||
|
@ -1060,12 +1045,13 @@ static inline int g762_fan_init(struct device *dev)
|
|||
data->fan_cmd1 |= G762_REG_FAN_CMD1_DET_FAN_OOC;
|
||||
data->valid = false;
|
||||
|
||||
return i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
|
||||
return i2c_smbus_write_byte_data(data->client, G762_REG_FAN_CMD1,
|
||||
data->fan_cmd1);
|
||||
}
|
||||
|
||||
static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct g762_data *data;
|
||||
int ret;
|
||||
|
||||
|
@ -1073,7 +1059,7 @@ static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct g762_data), GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct g762_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1082,7 +1068,7 @@ static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Enable fan failure detection and fan out of control protection */
|
||||
ret = g762_fan_init(&client->dev);
|
||||
ret = g762_fan_init(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1098,22 +1084,17 @@ static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
if (ret)
|
||||
goto clock_dis;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
ret = sysfs_create_group(&client->dev.kobj, &g762_group);
|
||||
if (ret)
|
||||
goto clock_dis;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
data->hwmon_dev = devm_hwmon_device_register_with_groups(dev,
|
||||
client->name,
|
||||
data,
|
||||
g762_groups);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
ret = PTR_ERR(data->hwmon_dev);
|
||||
goto sysfs_rem;
|
||||
goto clock_dis;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
sysfs_rem:
|
||||
sysfs_remove_group(&client->dev.kobj, &g762_group);
|
||||
|
||||
clock_dis:
|
||||
g762_of_clock_disable(client);
|
||||
|
||||
|
@ -1125,7 +1106,6 @@ static int g762_remove(struct i2c_client *client)
|
|||
struct g762_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &g762_group);
|
||||
g762_of_clock_disable(client);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -114,7 +114,8 @@ static inline u8 FAN_TO_REG(long rpm, int div)
|
|||
|
||||
/* Each client has this additional data */
|
||||
struct gl518_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
const struct attribute_group *groups[3];
|
||||
enum chips type;
|
||||
|
||||
struct mutex update_lock;
|
||||
|
@ -137,33 +138,98 @@ struct gl518_data {
|
|||
u8 beep_enable; /* Boolean */
|
||||
};
|
||||
|
||||
static int gl518_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int gl518_detect(struct i2c_client *client, struct i2c_board_info *info);
|
||||
static void gl518_init_client(struct i2c_client *client);
|
||||
static int gl518_remove(struct i2c_client *client);
|
||||
static int gl518_read_value(struct i2c_client *client, u8 reg);
|
||||
static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value);
|
||||
static struct gl518_data *gl518_update_device(struct device *dev);
|
||||
/*
|
||||
* Registers 0x07 to 0x0c are word-sized, others are byte-sized
|
||||
* GL518 uses a high-byte first convention, which is exactly opposite to
|
||||
* the SMBus standard.
|
||||
*/
|
||||
static int gl518_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
if ((reg >= 0x07) && (reg <= 0x0c))
|
||||
return i2c_smbus_read_word_swapped(client, reg);
|
||||
else
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id gl518_id[] = {
|
||||
{ "gl518sm", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, gl518_id);
|
||||
static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value)
|
||||
{
|
||||
if ((reg >= 0x07) && (reg <= 0x0c))
|
||||
return i2c_smbus_write_word_swapped(client, reg, value);
|
||||
else
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
static struct i2c_driver gl518_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "gl518sm",
|
||||
},
|
||||
.probe = gl518_probe,
|
||||
.remove = gl518_remove,
|
||||
.id_table = gl518_id,
|
||||
.detect = gl518_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
static struct gl518_data *gl518_update_device(struct device *dev)
|
||||
{
|
||||
struct gl518_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int val;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
dev_dbg(&client->dev, "Starting gl518 update\n");
|
||||
|
||||
data->alarms = gl518_read_value(client, GL518_REG_INT);
|
||||
data->beep_mask = gl518_read_value(client, GL518_REG_ALARM);
|
||||
|
||||
val = gl518_read_value(client, GL518_REG_VDD_LIMIT);
|
||||
data->voltage_min[0] = val & 0xff;
|
||||
data->voltage_max[0] = (val >> 8) & 0xff;
|
||||
val = gl518_read_value(client, GL518_REG_VIN1_LIMIT);
|
||||
data->voltage_min[1] = val & 0xff;
|
||||
data->voltage_max[1] = (val >> 8) & 0xff;
|
||||
val = gl518_read_value(client, GL518_REG_VIN2_LIMIT);
|
||||
data->voltage_min[2] = val & 0xff;
|
||||
data->voltage_max[2] = (val >> 8) & 0xff;
|
||||
val = gl518_read_value(client, GL518_REG_VIN3_LIMIT);
|
||||
data->voltage_min[3] = val & 0xff;
|
||||
data->voltage_max[3] = (val >> 8) & 0xff;
|
||||
|
||||
val = gl518_read_value(client, GL518_REG_FAN_COUNT);
|
||||
data->fan_in[0] = (val >> 8) & 0xff;
|
||||
data->fan_in[1] = val & 0xff;
|
||||
|
||||
val = gl518_read_value(client, GL518_REG_FAN_LIMIT);
|
||||
data->fan_min[0] = (val >> 8) & 0xff;
|
||||
data->fan_min[1] = val & 0xff;
|
||||
|
||||
data->temp_in = gl518_read_value(client, GL518_REG_TEMP_IN);
|
||||
data->temp_max =
|
||||
gl518_read_value(client, GL518_REG_TEMP_MAX);
|
||||
data->temp_hyst =
|
||||
gl518_read_value(client, GL518_REG_TEMP_HYST);
|
||||
|
||||
val = gl518_read_value(client, GL518_REG_MISC);
|
||||
data->fan_div[0] = (val >> 6) & 0x03;
|
||||
data->fan_div[1] = (val >> 4) & 0x03;
|
||||
data->fan_auto1 = (val >> 3) & 0x01;
|
||||
|
||||
data->alarms &= data->alarm_mask;
|
||||
|
||||
val = gl518_read_value(client, GL518_REG_CONF);
|
||||
data->beep_enable = (val >> 2) & 1;
|
||||
|
||||
if (data->type != gl518sm_r00) {
|
||||
data->voltage_in[0] =
|
||||
gl518_read_value(client, GL518_REG_VDD);
|
||||
data->voltage_in[1] =
|
||||
gl518_read_value(client, GL518_REG_VIN1);
|
||||
data->voltage_in[2] =
|
||||
gl518_read_value(client, GL518_REG_VIN2);
|
||||
}
|
||||
data->voltage_in[3] =
|
||||
gl518_read_value(client, GL518_REG_VIN3);
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sysfs stuff
|
||||
|
@ -228,8 +294,8 @@ static ssize_t set_##suffix(struct device *dev, \
|
|||
struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct gl518_data *data = i2c_get_clientdata(client); \
|
||||
struct gl518_data *data = dev_get_drvdata(dev); \
|
||||
struct i2c_client *client = data->client; \
|
||||
long val; \
|
||||
int err = kstrtol(buf, 10, &val); \
|
||||
if (err) \
|
||||
|
@ -247,8 +313,8 @@ static ssize_t set_##suffix(struct device *dev, \
|
|||
struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct gl518_data *data = i2c_get_clientdata(client); \
|
||||
struct gl518_data *data = dev_get_drvdata(dev); \
|
||||
struct i2c_client *client = data->client; \
|
||||
int regvalue; \
|
||||
unsigned long val; \
|
||||
int err = kstrtoul(buf, 10, &val); \
|
||||
|
@ -286,8 +352,8 @@ set(BEEP_MASK, beep_mask, beep_mask, GL518_REG_ALARM);
|
|||
static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl518_data *data = i2c_get_clientdata(client);
|
||||
struct gl518_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
int regvalue;
|
||||
unsigned long val;
|
||||
|
@ -319,8 +385,8 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl518_data *data = i2c_get_clientdata(client);
|
||||
struct gl518_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
int regvalue;
|
||||
unsigned long val;
|
||||
|
@ -420,8 +486,8 @@ static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl518_data *data = i2c_get_clientdata(client);
|
||||
struct gl518_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int bitnr = to_sensor_dev_attr(attr)->index;
|
||||
unsigned long bit;
|
||||
int err;
|
||||
|
@ -539,52 +605,6 @@ static int gl518_detect(struct i2c_client *client, struct i2c_board_info *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int gl518_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct gl518_data *data;
|
||||
int err, revision;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct gl518_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
revision = gl518_read_value(client, GL518_REG_REVISION);
|
||||
data->type = revision == 0x80 ? gl518sm_r80 : gl518sm_r00;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the GL518SM chip */
|
||||
data->alarm_mask = 0xff;
|
||||
gl518_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &gl518_group);
|
||||
if (err)
|
||||
return err;
|
||||
if (data->type == gl518sm_r80) {
|
||||
err = sysfs_create_group(&client->dev.kobj, &gl518_group_r80);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->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(&client->dev.kobj, &gl518_group);
|
||||
if (data->type == gl518sm_r80)
|
||||
sysfs_remove_group(&client->dev.kobj, &gl518_group_r80);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called when we have found a new GL518SM.
|
||||
* Note that we preserve D4:NoFan2 and D2:beep_enable.
|
||||
|
@ -605,110 +625,53 @@ static void gl518_init_client(struct i2c_client *client)
|
|||
gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue);
|
||||
}
|
||||
|
||||
static int gl518_remove(struct i2c_client *client)
|
||||
static int gl518_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct gl518_data *data = i2c_get_clientdata(client);
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct gl518_data *data;
|
||||
int revision;
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl518_group);
|
||||
data = devm_kzalloc(dev, sizeof(struct gl518_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->client = client;
|
||||
revision = gl518_read_value(client, GL518_REG_REVISION);
|
||||
data->type = revision == 0x80 ? gl518sm_r80 : gl518sm_r00;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the GL518SM chip */
|
||||
data->alarm_mask = 0xff;
|
||||
gl518_init_client(client);
|
||||
|
||||
/* sysfs hooks */
|
||||
data->groups[0] = &gl518_group;
|
||||
if (data->type == gl518sm_r80)
|
||||
sysfs_remove_group(&client->dev.kobj, &gl518_group_r80);
|
||||
data->groups[1] = &gl518_group_r80;
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, data->groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Registers 0x07 to 0x0c are word-sized, others are byte-sized
|
||||
* GL518 uses a high-byte first convention, which is exactly opposite to
|
||||
* the SMBus standard.
|
||||
*/
|
||||
static int gl518_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
if ((reg >= 0x07) && (reg <= 0x0c))
|
||||
return i2c_smbus_read_word_swapped(client, reg);
|
||||
else
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
static const struct i2c_device_id gl518_id[] = {
|
||||
{ "gl518sm", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, gl518_id);
|
||||
|
||||
static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value)
|
||||
{
|
||||
if ((reg >= 0x07) && (reg <= 0x0c))
|
||||
return i2c_smbus_write_word_swapped(client, reg, value);
|
||||
else
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static struct gl518_data *gl518_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl518_data *data = i2c_get_clientdata(client);
|
||||
int val;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
dev_dbg(&client->dev, "Starting gl518 update\n");
|
||||
|
||||
data->alarms = gl518_read_value(client, GL518_REG_INT);
|
||||
data->beep_mask = gl518_read_value(client, GL518_REG_ALARM);
|
||||
|
||||
val = gl518_read_value(client, GL518_REG_VDD_LIMIT);
|
||||
data->voltage_min[0] = val & 0xff;
|
||||
data->voltage_max[0] = (val >> 8) & 0xff;
|
||||
val = gl518_read_value(client, GL518_REG_VIN1_LIMIT);
|
||||
data->voltage_min[1] = val & 0xff;
|
||||
data->voltage_max[1] = (val >> 8) & 0xff;
|
||||
val = gl518_read_value(client, GL518_REG_VIN2_LIMIT);
|
||||
data->voltage_min[2] = val & 0xff;
|
||||
data->voltage_max[2] = (val >> 8) & 0xff;
|
||||
val = gl518_read_value(client, GL518_REG_VIN3_LIMIT);
|
||||
data->voltage_min[3] = val & 0xff;
|
||||
data->voltage_max[3] = (val >> 8) & 0xff;
|
||||
|
||||
val = gl518_read_value(client, GL518_REG_FAN_COUNT);
|
||||
data->fan_in[0] = (val >> 8) & 0xff;
|
||||
data->fan_in[1] = val & 0xff;
|
||||
|
||||
val = gl518_read_value(client, GL518_REG_FAN_LIMIT);
|
||||
data->fan_min[0] = (val >> 8) & 0xff;
|
||||
data->fan_min[1] = val & 0xff;
|
||||
|
||||
data->temp_in = gl518_read_value(client, GL518_REG_TEMP_IN);
|
||||
data->temp_max =
|
||||
gl518_read_value(client, GL518_REG_TEMP_MAX);
|
||||
data->temp_hyst =
|
||||
gl518_read_value(client, GL518_REG_TEMP_HYST);
|
||||
|
||||
val = gl518_read_value(client, GL518_REG_MISC);
|
||||
data->fan_div[0] = (val >> 6) & 0x03;
|
||||
data->fan_div[1] = (val >> 4) & 0x03;
|
||||
data->fan_auto1 = (val >> 3) & 0x01;
|
||||
|
||||
data->alarms &= data->alarm_mask;
|
||||
|
||||
val = gl518_read_value(client, GL518_REG_CONF);
|
||||
data->beep_enable = (val >> 2) & 1;
|
||||
|
||||
if (data->type != gl518sm_r00) {
|
||||
data->voltage_in[0] =
|
||||
gl518_read_value(client, GL518_REG_VDD);
|
||||
data->voltage_in[1] =
|
||||
gl518_read_value(client, GL518_REG_VIN1);
|
||||
data->voltage_in[2] =
|
||||
gl518_read_value(client, GL518_REG_VIN2);
|
||||
}
|
||||
data->voltage_in[3] =
|
||||
gl518_read_value(client, GL518_REG_VIN3);
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
static struct i2c_driver gl518_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "gl518sm",
|
||||
},
|
||||
.probe = gl518_probe,
|
||||
.id_table = gl518_id,
|
||||
.detect = gl518_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(gl518_driver);
|
||||
|
||||
|
|
|
@ -73,41 +73,10 @@ static const u8 GL520_REG_TEMP_MAX_HYST[] = { 0x06, 0x18 };
|
|||
#define GL520_REG_BEEP_MASK 0x10
|
||||
#define GL520_REG_BEEP_ENABLE GL520_REG_CONF
|
||||
|
||||
/*
|
||||
* Function declarations
|
||||
*/
|
||||
|
||||
static int gl520_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int gl520_detect(struct i2c_client *client, struct i2c_board_info *info);
|
||||
static void gl520_init_client(struct i2c_client *client);
|
||||
static int gl520_remove(struct i2c_client *client);
|
||||
static int gl520_read_value(struct i2c_client *client, u8 reg);
|
||||
static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value);
|
||||
static struct gl520_data *gl520_update_device(struct device *dev);
|
||||
|
||||
/* Driver data */
|
||||
static const struct i2c_device_id gl520_id[] = {
|
||||
{ "gl520sm", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, gl520_id);
|
||||
|
||||
static struct i2c_driver gl520_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "gl520sm",
|
||||
},
|
||||
.probe = gl520_probe,
|
||||
.remove = gl520_remove,
|
||||
.id_table = gl520_id,
|
||||
.detect = gl520_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
/* Client data */
|
||||
struct gl520_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
const struct attribute_group *groups[3];
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until the following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
|
@ -131,6 +100,102 @@ struct gl520_data {
|
|||
u8 two_temps;
|
||||
};
|
||||
|
||||
/*
|
||||
* Registers 0x07 to 0x0c are word-sized, others are byte-sized
|
||||
* GL520 uses a high-byte first convention
|
||||
*/
|
||||
static int gl520_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
if ((reg >= 0x07) && (reg <= 0x0c))
|
||||
return i2c_smbus_read_word_swapped(client, reg);
|
||||
else
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value)
|
||||
{
|
||||
if ((reg >= 0x07) && (reg <= 0x0c))
|
||||
return i2c_smbus_write_word_swapped(client, reg, value);
|
||||
else
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static struct gl520_data *gl520_update_device(struct device *dev)
|
||||
{
|
||||
struct gl520_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int val, i;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
|
||||
|
||||
dev_dbg(&client->dev, "Starting gl520sm update\n");
|
||||
|
||||
data->alarms = gl520_read_value(client, GL520_REG_ALARMS);
|
||||
data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
|
||||
data->vid = gl520_read_value(client,
|
||||
GL520_REG_VID_INPUT) & 0x1f;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
data->in_input[i] = gl520_read_value(client,
|
||||
GL520_REG_IN_INPUT[i]);
|
||||
val = gl520_read_value(client, GL520_REG_IN_LIMIT[i]);
|
||||
data->in_min[i] = val & 0xff;
|
||||
data->in_max[i] = (val >> 8) & 0xff;
|
||||
}
|
||||
|
||||
val = gl520_read_value(client, GL520_REG_FAN_INPUT);
|
||||
data->fan_input[0] = (val >> 8) & 0xff;
|
||||
data->fan_input[1] = val & 0xff;
|
||||
|
||||
val = gl520_read_value(client, GL520_REG_FAN_MIN);
|
||||
data->fan_min[0] = (val >> 8) & 0xff;
|
||||
data->fan_min[1] = val & 0xff;
|
||||
|
||||
data->temp_input[0] = gl520_read_value(client,
|
||||
GL520_REG_TEMP_INPUT[0]);
|
||||
data->temp_max[0] = gl520_read_value(client,
|
||||
GL520_REG_TEMP_MAX[0]);
|
||||
data->temp_max_hyst[0] = gl520_read_value(client,
|
||||
GL520_REG_TEMP_MAX_HYST[0]);
|
||||
|
||||
val = gl520_read_value(client, GL520_REG_FAN_DIV);
|
||||
data->fan_div[0] = (val >> 6) & 0x03;
|
||||
data->fan_div[1] = (val >> 4) & 0x03;
|
||||
data->fan_off = (val >> 2) & 0x01;
|
||||
|
||||
data->alarms &= data->alarm_mask;
|
||||
|
||||
val = gl520_read_value(client, GL520_REG_CONF);
|
||||
data->beep_enable = !((val >> 2) & 1);
|
||||
|
||||
/* Temp1 and Vin4 are the same input */
|
||||
if (data->two_temps) {
|
||||
data->temp_input[1] = gl520_read_value(client,
|
||||
GL520_REG_TEMP_INPUT[1]);
|
||||
data->temp_max[1] = gl520_read_value(client,
|
||||
GL520_REG_TEMP_MAX[1]);
|
||||
data->temp_max_hyst[1] = gl520_read_value(client,
|
||||
GL520_REG_TEMP_MAX_HYST[1]);
|
||||
} else {
|
||||
data->in_input[4] = gl520_read_value(client,
|
||||
GL520_REG_IN_INPUT[4]);
|
||||
data->in_min[4] = gl520_read_value(client,
|
||||
GL520_REG_IN_MIN[4]);
|
||||
data->in_max[4] = gl520_read_value(client,
|
||||
GL520_REG_IN_MAX[4]);
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sysfs stuff
|
||||
*/
|
||||
|
@ -191,8 +256,8 @@ static ssize_t get_in_max(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
struct gl520_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int n = to_sensor_dev_attr(attr)->index;
|
||||
u8 r;
|
||||
long v;
|
||||
|
@ -225,8 +290,8 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
struct gl520_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int n = to_sensor_dev_attr(attr)->index;
|
||||
u8 r;
|
||||
long v;
|
||||
|
@ -326,8 +391,8 @@ static ssize_t get_fan_off(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
struct gl520_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int n = to_sensor_dev_attr(attr)->index;
|
||||
u8 r;
|
||||
unsigned long v;
|
||||
|
@ -365,8 +430,8 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
struct gl520_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int n = to_sensor_dev_attr(attr)->index;
|
||||
u8 r;
|
||||
unsigned long v;
|
||||
|
@ -414,8 +479,8 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_fan_off(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
struct gl520_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 r;
|
||||
unsigned long v;
|
||||
int err;
|
||||
|
@ -482,8 +547,8 @@ static ssize_t get_temp_max_hyst(struct device *dev,
|
|||
static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
struct gl520_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int n = to_sensor_dev_attr(attr)->index;
|
||||
long v;
|
||||
int err;
|
||||
|
@ -502,8 +567,8 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_temp_max_hyst(struct device *dev, struct device_attribute
|
||||
*attr, const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
struct gl520_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int n = to_sensor_dev_attr(attr)->index;
|
||||
long v;
|
||||
int err;
|
||||
|
@ -555,8 +620,8 @@ static ssize_t get_beep_mask(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_beep_enable(struct device *dev, struct device_attribute
|
||||
*attr, const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
struct gl520_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 r;
|
||||
unsigned long v;
|
||||
int err;
|
||||
|
@ -579,8 +644,8 @@ static ssize_t set_beep_enable(struct device *dev, struct device_attribute
|
|||
static ssize_t set_beep_mask(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
struct gl520_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long r;
|
||||
int err;
|
||||
|
||||
|
@ -633,8 +698,8 @@ static ssize_t get_beep(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
struct gl520_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int bitnr = to_sensor_dev_attr(attr)->index;
|
||||
unsigned long bit;
|
||||
|
||||
|
@ -772,52 +837,6 @@ static int gl520_detect(struct i2c_client *client, struct i2c_board_info *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int gl520_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct gl520_data *data;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct gl520_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the GL520SM chip */
|
||||
gl520_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &gl520_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (data->two_temps)
|
||||
err = sysfs_create_group(&client->dev.kobj, &gl520_group_temp2);
|
||||
else
|
||||
err = sysfs_create_group(&client->dev.kobj, &gl520_group_in4);
|
||||
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->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(&client->dev.kobj, &gl520_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_in4);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_temp2);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Called when we have found a new GL520SM. */
|
||||
static void gl520_init_client(struct i2c_client *client)
|
||||
{
|
||||
|
@ -856,115 +875,53 @@ static void gl520_init_client(struct i2c_client *client)
|
|||
gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
|
||||
}
|
||||
|
||||
static int gl520_remove(struct i2c_client *client)
|
||||
static int gl520_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct gl520_data *data;
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_in4);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_temp2);
|
||||
data = devm_kzalloc(dev, sizeof(struct gl520_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
data->client = client;
|
||||
|
||||
/* Initialize the GL520SM chip */
|
||||
gl520_init_client(client);
|
||||
|
||||
/*
|
||||
* Registers 0x07 to 0x0c are word-sized, others are byte-sized
|
||||
* GL520 uses a high-byte first convention
|
||||
*/
|
||||
static int gl520_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
if ((reg >= 0x07) && (reg <= 0x0c))
|
||||
return i2c_smbus_read_word_swapped(client, reg);
|
||||
/* sysfs hooks */
|
||||
data->groups[0] = &gl520_group;
|
||||
|
||||
if (data->two_temps)
|
||||
data->groups[1] = &gl520_group_temp2;
|
||||
else
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
data->groups[1] = &gl520_group_in4;
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, data->groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value)
|
||||
{
|
||||
if ((reg >= 0x07) && (reg <= 0x0c))
|
||||
return i2c_smbus_write_word_swapped(client, reg, value);
|
||||
else
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
static const struct i2c_device_id gl520_id[] = {
|
||||
{ "gl520sm", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, gl520_id);
|
||||
|
||||
|
||||
static struct gl520_data *gl520_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
int val, i;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
|
||||
|
||||
dev_dbg(&client->dev, "Starting gl520sm update\n");
|
||||
|
||||
data->alarms = gl520_read_value(client, GL520_REG_ALARMS);
|
||||
data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK);
|
||||
data->vid = gl520_read_value(client,
|
||||
GL520_REG_VID_INPUT) & 0x1f;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
data->in_input[i] = gl520_read_value(client,
|
||||
GL520_REG_IN_INPUT[i]);
|
||||
val = gl520_read_value(client, GL520_REG_IN_LIMIT[i]);
|
||||
data->in_min[i] = val & 0xff;
|
||||
data->in_max[i] = (val >> 8) & 0xff;
|
||||
}
|
||||
|
||||
val = gl520_read_value(client, GL520_REG_FAN_INPUT);
|
||||
data->fan_input[0] = (val >> 8) & 0xff;
|
||||
data->fan_input[1] = val & 0xff;
|
||||
|
||||
val = gl520_read_value(client, GL520_REG_FAN_MIN);
|
||||
data->fan_min[0] = (val >> 8) & 0xff;
|
||||
data->fan_min[1] = val & 0xff;
|
||||
|
||||
data->temp_input[0] = gl520_read_value(client,
|
||||
GL520_REG_TEMP_INPUT[0]);
|
||||
data->temp_max[0] = gl520_read_value(client,
|
||||
GL520_REG_TEMP_MAX[0]);
|
||||
data->temp_max_hyst[0] = gl520_read_value(client,
|
||||
GL520_REG_TEMP_MAX_HYST[0]);
|
||||
|
||||
val = gl520_read_value(client, GL520_REG_FAN_DIV);
|
||||
data->fan_div[0] = (val >> 6) & 0x03;
|
||||
data->fan_div[1] = (val >> 4) & 0x03;
|
||||
data->fan_off = (val >> 2) & 0x01;
|
||||
|
||||
data->alarms &= data->alarm_mask;
|
||||
|
||||
val = gl520_read_value(client, GL520_REG_CONF);
|
||||
data->beep_enable = !((val >> 2) & 1);
|
||||
|
||||
/* Temp1 and Vin4 are the same input */
|
||||
if (data->two_temps) {
|
||||
data->temp_input[1] = gl520_read_value(client,
|
||||
GL520_REG_TEMP_INPUT[1]);
|
||||
data->temp_max[1] = gl520_read_value(client,
|
||||
GL520_REG_TEMP_MAX[1]);
|
||||
data->temp_max_hyst[1] = gl520_read_value(client,
|
||||
GL520_REG_TEMP_MAX_HYST[1]);
|
||||
} else {
|
||||
data->in_input[4] = gl520_read_value(client,
|
||||
GL520_REG_IN_INPUT[4]);
|
||||
data->in_min[4] = gl520_read_value(client,
|
||||
GL520_REG_IN_MIN[4]);
|
||||
data->in_max[4] = gl520_read_value(client,
|
||||
GL520_REG_IN_MAX[4]);
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
static struct i2c_driver gl520_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "gl520sm",
|
||||
},
|
||||
.probe = gl520_probe,
|
||||
.id_table = gl520_id,
|
||||
.detect = gl520_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(gl520_driver);
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ static int get_fan_speed_index(struct gpio_fan_data *fan_data)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int rpm_to_speed_index(struct gpio_fan_data *fan_data, int rpm)
|
||||
static int rpm_to_speed_index(struct gpio_fan_data *fan_data, unsigned long rpm)
|
||||
{
|
||||
struct gpio_fan_speed *speed = fan_data->speed;
|
||||
int i;
|
||||
|
@ -537,9 +537,10 @@ static int gpio_fan_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* Make this driver part of hwmon class. */
|
||||
fan_data->hwmon_dev = hwmon_device_register_with_groups(&pdev->dev,
|
||||
"gpio_fan", fan_data,
|
||||
gpio_fan_groups);
|
||||
fan_data->hwmon_dev =
|
||||
devm_hwmon_device_register_with_groups(&pdev->dev,
|
||||
"gpio_fan", fan_data,
|
||||
gpio_fan_groups);
|
||||
if (IS_ERR(fan_data->hwmon_dev))
|
||||
return PTR_ERR(fan_data->hwmon_dev);
|
||||
|
||||
|
@ -548,15 +549,6 @@ static int gpio_fan_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int gpio_fan_suspend(struct device *dev)
|
||||
{
|
||||
|
@ -588,7 +580,6 @@ static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
|
|||
|
||||
static struct platform_driver gpio_fan_driver = {
|
||||
.probe = gpio_fan_probe,
|
||||
.remove = gpio_fan_remove,
|
||||
.driver = {
|
||||
.name = "gpio-fan",
|
||||
.pm = GPIO_FAN_PM,
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
* @write_length: length for I2C measurement request
|
||||
*/
|
||||
struct hih6130 {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
bool valid;
|
||||
unsigned long last_update;
|
||||
|
@ -62,7 +62,6 @@ struct hih6130 {
|
|||
*/
|
||||
static inline int hih6130_temp_ticks_to_millicelsius(int ticks)
|
||||
{
|
||||
|
||||
ticks = ticks >> 2;
|
||||
/*
|
||||
* from data sheet section 5.0
|
||||
|
@ -78,7 +77,6 @@ static inline int hih6130_temp_ticks_to_millicelsius(int ticks)
|
|||
*/
|
||||
static inline int hih6130_rh_ticks_to_per_cent_mille(int ticks)
|
||||
{
|
||||
|
||||
ticks &= ~0xC000; /* clear status bits */
|
||||
/*
|
||||
* from data sheet section 4.0
|
||||
|
@ -89,15 +87,16 @@ static inline int hih6130_rh_ticks_to_per_cent_mille(int ticks)
|
|||
|
||||
/**
|
||||
* hih6130_update_measurements() - get updated measurements from device
|
||||
* @client: I2C client device
|
||||
* @dev: device
|
||||
*
|
||||
* Returns 0 on success, else negative errno.
|
||||
*/
|
||||
static int hih6130_update_measurements(struct i2c_client *client)
|
||||
static int hih6130_update_measurements(struct device *dev)
|
||||
{
|
||||
struct hih6130 *hih6130 = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = hih6130->client;
|
||||
int ret = 0;
|
||||
int t;
|
||||
struct hih6130 *hih6130 = i2c_get_clientdata(client);
|
||||
unsigned char tmp[4];
|
||||
struct i2c_msg msgs[1] = {
|
||||
{
|
||||
|
@ -176,9 +175,10 @@ static ssize_t hih6130_show_temperature(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct hih6130 *hih6130 = i2c_get_clientdata(client);
|
||||
int ret = hih6130_update_measurements(client);
|
||||
struct hih6130 *hih6130 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = hih6130_update_measurements(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", hih6130->temperature);
|
||||
|
@ -196,9 +196,10 @@ static ssize_t hih6130_show_temperature(struct device *dev,
|
|||
static ssize_t hih6130_show_humidity(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct hih6130 *hih6130 = i2c_get_clientdata(client);
|
||||
int ret = hih6130_update_measurements(client);
|
||||
struct hih6130 *hih6130 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = hih6130_update_measurements(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", hih6130->humidity);
|
||||
|
@ -210,79 +211,37 @@ static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, hih6130_show_temperature,
|
|||
static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, hih6130_show_humidity,
|
||||
NULL, 0);
|
||||
|
||||
static struct attribute *hih6130_attributes[] = {
|
||||
static struct attribute *hih6130_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_humidity1_input.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group hih6130_attr_group = {
|
||||
.attrs = hih6130_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(hih6130);
|
||||
|
||||
/**
|
||||
* hih6130_probe() - probe device
|
||||
* @client: I2C client device
|
||||
* @id: device ID
|
||||
*
|
||||
* Called by the I2C core when an entry in the ID table matches a
|
||||
* device's name.
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
static int hih6130_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct hih6130 *hih6130;
|
||||
int err;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
dev_err(&client->dev, "adapter does not support true I2C\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hih6130 = devm_kzalloc(&client->dev, sizeof(*hih6130), GFP_KERNEL);
|
||||
hih6130 = devm_kzalloc(dev, sizeof(*hih6130), GFP_KERNEL);
|
||||
if (!hih6130)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, hih6130);
|
||||
|
||||
hih6130->client = client;
|
||||
mutex_init(&hih6130->lock);
|
||||
|
||||
err = sysfs_create_group(&client->dev.kobj, &hih6130_attr_group);
|
||||
if (err) {
|
||||
dev_dbg(&client->dev, "could not create sysfs files\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
hih6130->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(hih6130->hwmon_dev)) {
|
||||
dev_dbg(&client->dev, "unable to register hwmon device\n");
|
||||
err = PTR_ERR(hih6130->hwmon_dev);
|
||||
goto fail_remove_sysfs;
|
||||
}
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_QUICK))
|
||||
hih6130->write_length = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_remove_sysfs:
|
||||
sysfs_remove_group(&client->dev.kobj, &hih6130_attr_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* hih6130_remove() - remove device
|
||||
* @client: I2C client device
|
||||
*/
|
||||
static int hih6130_remove(struct i2c_client *client)
|
||||
{
|
||||
struct hih6130 *hih6130 = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(hih6130->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &hih6130_attr_group);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
hih6130,
|
||||
hih6130_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
/* Device ID table */
|
||||
|
@ -295,7 +254,6 @@ MODULE_DEVICE_TABLE(i2c, hih6130_id);
|
|||
static struct i2c_driver hih6130_driver = {
|
||||
.driver.name = "hih6130",
|
||||
.probe = hih6130_probe,
|
||||
.remove = hih6130_remove,
|
||||
.id_table = hih6130_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#define HTU21_RH_MEASUREMENT_HM 0xE5
|
||||
|
||||
struct htu21 {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
bool valid;
|
||||
unsigned long last_update;
|
||||
|
@ -59,10 +59,11 @@ static inline int htu21_rh_ticks_to_per_cent_mille(int ticks)
|
|||
return ((15625 * ticks) >> 13) - 6000;
|
||||
}
|
||||
|
||||
static int htu21_update_measurements(struct i2c_client *client)
|
||||
static int htu21_update_measurements(struct device *dev)
|
||||
{
|
||||
struct htu21 *htu21 = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = htu21->client;
|
||||
int ret = 0;
|
||||
struct htu21 *htu21 = i2c_get_clientdata(client);
|
||||
|
||||
mutex_lock(&htu21->lock);
|
||||
|
||||
|
@ -90,9 +91,10 @@ out:
|
|||
static ssize_t htu21_show_temperature(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct htu21 *htu21 = i2c_get_clientdata(client);
|
||||
int ret = htu21_update_measurements(client);
|
||||
struct htu21 *htu21 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = htu21_update_measurements(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", htu21->temperature);
|
||||
|
@ -101,9 +103,10 @@ static ssize_t htu21_show_temperature(struct device *dev,
|
|||
static ssize_t htu21_show_humidity(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct htu21 *htu21 = i2c_get_clientdata(client);
|
||||
int ret = htu21_update_measurements(client);
|
||||
struct htu21 *htu21 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = htu21_update_measurements(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", htu21->humidity);
|
||||
|
@ -114,21 +117,20 @@ static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
|
|||
static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO,
|
||||
htu21_show_humidity, NULL, 0);
|
||||
|
||||
static struct attribute *htu21_attributes[] = {
|
||||
static struct attribute *htu21_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_humidity1_input.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group htu21_group = {
|
||||
.attrs = htu21_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(htu21);
|
||||
|
||||
static int htu21_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct htu21 *htu21;
|
||||
int err;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_READ_WORD_DATA)) {
|
||||
|
@ -137,43 +139,17 @@ static int htu21_probe(struct i2c_client *client,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
htu21 = devm_kzalloc(&client->dev, sizeof(*htu21), GFP_KERNEL);
|
||||
htu21 = devm_kzalloc(dev, sizeof(*htu21), GFP_KERNEL);
|
||||
if (!htu21)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, htu21);
|
||||
|
||||
htu21->client = client;
|
||||
mutex_init(&htu21->lock);
|
||||
|
||||
err = sysfs_create_group(&client->dev.kobj, &htu21_group);
|
||||
if (err) {
|
||||
dev_dbg(&client->dev, "could not create sysfs files\n");
|
||||
return err;
|
||||
}
|
||||
htu21->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(htu21->hwmon_dev)) {
|
||||
dev_dbg(&client->dev, "unable to register hwmon device\n");
|
||||
err = PTR_ERR(htu21->hwmon_dev);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "initialized\n");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
sysfs_remove_group(&client->dev.kobj, &htu21_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int htu21_remove(struct i2c_client *client)
|
||||
{
|
||||
struct htu21 *htu21 = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(htu21->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &htu21_group);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
htu21,
|
||||
htu21_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id htu21_id[] = {
|
||||
|
@ -188,7 +164,6 @@ static struct i2c_driver htu21_driver = {
|
|||
.name = "htu21",
|
||||
},
|
||||
.probe = htu21_probe,
|
||||
.remove = htu21_remove,
|
||||
.id_table = htu21_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* IBM PowerNV platform sensors for temperature/fan/voltage/power
|
||||
* Copyright (C) 2014 IBM
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define DRVNAME "ibmpowernv"
|
||||
#define pr_fmt(fmt) DRVNAME ": " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/opal.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#define MAX_ATTR_LEN 32
|
||||
|
||||
/* Sensor suffix name from DT */
|
||||
#define DT_FAULT_ATTR_SUFFIX "faulted"
|
||||
#define DT_DATA_ATTR_SUFFIX "data"
|
||||
#define DT_THRESHOLD_ATTR_SUFFIX "thrs"
|
||||
|
||||
/*
|
||||
* Enumerates all the types of sensors in the POWERNV platform and does index
|
||||
* into 'struct sensor_group'
|
||||
*/
|
||||
enum sensors {
|
||||
FAN,
|
||||
AMBIENT_TEMP,
|
||||
POWER_SUPPLY,
|
||||
POWER_INPUT,
|
||||
MAX_SENSOR_TYPE,
|
||||
};
|
||||
|
||||
static struct sensor_group {
|
||||
const char *name;
|
||||
const char *compatible;
|
||||
struct attribute_group group;
|
||||
u32 attr_count;
|
||||
} sensor_groups[] = {
|
||||
{"fan", "ibm,opal-sensor-cooling-fan"},
|
||||
{"temp", "ibm,opal-sensor-amb-temp"},
|
||||
{"in", "ibm,opal-sensor-power-supply"},
|
||||
{"power", "ibm,opal-sensor-power"}
|
||||
};
|
||||
|
||||
struct sensor_data {
|
||||
u32 id; /* An opaque id of the firmware for each sensor */
|
||||
enum sensors type;
|
||||
char name[MAX_ATTR_LEN];
|
||||
struct device_attribute dev_attr;
|
||||
};
|
||||
|
||||
struct platform_data {
|
||||
const struct attribute_group *attr_groups[MAX_SENSOR_TYPE + 1];
|
||||
u32 sensors_count; /* Total count of sensors from each group */
|
||||
};
|
||||
|
||||
/* Platform device representing all the ibmpowernv sensors */
|
||||
static struct platform_device *pdevice;
|
||||
|
||||
static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_data *sdata = container_of(devattr, struct sensor_data,
|
||||
dev_attr);
|
||||
ssize_t ret;
|
||||
u32 x;
|
||||
|
||||
ret = opal_get_sensor_data(sdata->id, &x);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Convert temperature to milli-degrees */
|
||||
if (sdata->type == AMBIENT_TEMP)
|
||||
x *= 1000;
|
||||
/* Convert power to micro-watts */
|
||||
else if (sdata->type == POWER_INPUT)
|
||||
x *= 1000000;
|
||||
|
||||
return sprintf(buf, "%u\n", x);
|
||||
}
|
||||
|
||||
static int __init get_sensor_index_attr(const char *name, u32 *index,
|
||||
char *attr)
|
||||
{
|
||||
char *hash_pos = strchr(name, '#');
|
||||
char buf[8] = { 0 };
|
||||
char *dash_pos;
|
||||
u32 copy_len;
|
||||
int err;
|
||||
|
||||
if (!hash_pos)
|
||||
return -EINVAL;
|
||||
|
||||
dash_pos = strchr(hash_pos, '-');
|
||||
if (!dash_pos)
|
||||
return -EINVAL;
|
||||
|
||||
copy_len = dash_pos - hash_pos - 1;
|
||||
if (copy_len >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
||||
strncpy(buf, hash_pos + 1, copy_len);
|
||||
|
||||
err = kstrtou32(buf, 10, index);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
strncpy(attr, dash_pos + 1, MAX_ATTR_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function translates the DT node name into the 'hwmon' attribute name.
|
||||
* IBMPOWERNV device node appear like cooling-fan#2-data, amb-temp#1-thrs etc.
|
||||
* which need to be mapped as fan2_input, temp1_max respectively before
|
||||
* populating them inside hwmon device class.
|
||||
*/
|
||||
static int __init create_hwmon_attr_name(struct device *dev, enum sensors type,
|
||||
const char *node_name,
|
||||
char *hwmon_attr_name)
|
||||
{
|
||||
char attr_suffix[MAX_ATTR_LEN];
|
||||
char *attr_name;
|
||||
u32 index;
|
||||
int err;
|
||||
|
||||
err = get_sensor_index_attr(node_name, &index, attr_suffix);
|
||||
if (err) {
|
||||
dev_err(dev, "Sensor device node name '%s' is invalid\n",
|
||||
node_name);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!strcmp(attr_suffix, DT_FAULT_ATTR_SUFFIX)) {
|
||||
attr_name = "fault";
|
||||
} else if (!strcmp(attr_suffix, DT_DATA_ATTR_SUFFIX)) {
|
||||
attr_name = "input";
|
||||
} else if (!strcmp(attr_suffix, DT_THRESHOLD_ATTR_SUFFIX)) {
|
||||
if (type == AMBIENT_TEMP)
|
||||
attr_name = "max";
|
||||
else if (type == FAN)
|
||||
attr_name = "min";
|
||||
else
|
||||
return -ENOENT;
|
||||
} else {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
snprintf(hwmon_attr_name, MAX_ATTR_LEN, "%s%d_%s",
|
||||
sensor_groups[type].name, index, attr_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init populate_attr_groups(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_data *pdata = platform_get_drvdata(pdev);
|
||||
const struct attribute_group **pgroups = pdata->attr_groups;
|
||||
struct device_node *opal, *np;
|
||||
enum sensors type;
|
||||
|
||||
opal = of_find_node_by_path("/ibm,opal/sensors");
|
||||
if (!opal) {
|
||||
dev_err(&pdev->dev, "Opal node 'sensors' not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for_each_child_of_node(opal, np) {
|
||||
if (np->name == NULL)
|
||||
continue;
|
||||
|
||||
for (type = 0; type < MAX_SENSOR_TYPE; type++)
|
||||
if (of_device_is_compatible(np,
|
||||
sensor_groups[type].compatible)) {
|
||||
sensor_groups[type].attr_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
of_node_put(opal);
|
||||
|
||||
for (type = 0; type < MAX_SENSOR_TYPE; type++) {
|
||||
sensor_groups[type].group.attrs = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct attribute *) *
|
||||
(sensor_groups[type].attr_count + 1),
|
||||
GFP_KERNEL);
|
||||
if (!sensor_groups[type].group.attrs)
|
||||
return -ENOMEM;
|
||||
|
||||
pgroups[type] = &sensor_groups[type].group;
|
||||
pdata->sensors_count += sensor_groups[type].attr_count;
|
||||
sensor_groups[type].attr_count = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate through the device tree for each child of 'sensors' node, create
|
||||
* a sysfs attribute file, the file is named by translating the DT node name
|
||||
* to the name required by the higher 'hwmon' driver like fan1_input, temp1_max
|
||||
* etc..
|
||||
*/
|
||||
static int __init create_device_attrs(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_data *pdata = platform_get_drvdata(pdev);
|
||||
const struct attribute_group **pgroups = pdata->attr_groups;
|
||||
struct device_node *opal, *np;
|
||||
struct sensor_data *sdata;
|
||||
u32 sensor_id;
|
||||
enum sensors type;
|
||||
u32 count = 0;
|
||||
int err = 0;
|
||||
|
||||
opal = of_find_node_by_path("/ibm,opal/sensors");
|
||||
sdata = devm_kzalloc(&pdev->dev, pdata->sensors_count * sizeof(*sdata),
|
||||
GFP_KERNEL);
|
||||
if (!sdata) {
|
||||
err = -ENOMEM;
|
||||
goto exit_put_node;
|
||||
}
|
||||
|
||||
for_each_child_of_node(opal, np) {
|
||||
if (np->name == NULL)
|
||||
continue;
|
||||
|
||||
for (type = 0; type < MAX_SENSOR_TYPE; type++)
|
||||
if (of_device_is_compatible(np,
|
||||
sensor_groups[type].compatible))
|
||||
break;
|
||||
|
||||
if (type == MAX_SENSOR_TYPE)
|
||||
continue;
|
||||
|
||||
if (of_property_read_u32(np, "sensor-id", &sensor_id)) {
|
||||
dev_info(&pdev->dev,
|
||||
"'sensor-id' missing in the node '%s'\n",
|
||||
np->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
sdata[count].id = sensor_id;
|
||||
sdata[count].type = type;
|
||||
err = create_hwmon_attr_name(&pdev->dev, type, np->name,
|
||||
sdata[count].name);
|
||||
if (err)
|
||||
goto exit_put_node;
|
||||
|
||||
sysfs_attr_init(&sdata[count].dev_attr.attr);
|
||||
sdata[count].dev_attr.attr.name = sdata[count].name;
|
||||
sdata[count].dev_attr.attr.mode = S_IRUGO;
|
||||
sdata[count].dev_attr.show = show_sensor;
|
||||
|
||||
pgroups[type]->attrs[sensor_groups[type].attr_count++] =
|
||||
&sdata[count++].dev_attr.attr;
|
||||
}
|
||||
|
||||
exit_put_node:
|
||||
of_node_put(opal);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init ibmpowernv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_data *pdata;
|
||||
struct device *hwmon_dev;
|
||||
int err;
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
pdata->sensors_count = 0;
|
||||
err = populate_attr_groups(pdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Create sysfs attribute data for each sensor found in the DT */
|
||||
err = create_device_attrs(pdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Finally, register with hwmon */
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, DRVNAME,
|
||||
pdata,
|
||||
pdata->attr_groups);
|
||||
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static struct platform_driver ibmpowernv_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRVNAME,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ibmpowernv_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
pdevice = platform_device_alloc(DRVNAME, 0);
|
||||
if (!pdevice) {
|
||||
pr_err("Device allocation failed\n");
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = platform_device_add(pdevice);
|
||||
if (err) {
|
||||
pr_err("Device addition failed (%d)\n", err);
|
||||
goto exit_device_put;
|
||||
}
|
||||
|
||||
err = platform_driver_probe(&ibmpowernv_driver, ibmpowernv_probe);
|
||||
if (err) {
|
||||
pr_err("Platfrom driver probe failed\n");
|
||||
goto exit_device_del;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_device_del:
|
||||
platform_device_del(pdevice);
|
||||
exit_device_put:
|
||||
platform_device_put(pdevice);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit ibmpowernv_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ibmpowernv_driver);
|
||||
platform_device_unregister(pdevice);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
|
||||
MODULE_DESCRIPTION("IBM POWERNV platform sensors");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(ibmpowernv_init);
|
||||
module_exit(ibmpowernv_exit);
|
|
@ -125,7 +125,8 @@
|
|||
#define FAN_SPEED_LEN 5
|
||||
|
||||
struct pem_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
const struct attribute_group *groups[4];
|
||||
|
||||
struct mutex update_lock;
|
||||
bool valid;
|
||||
|
@ -160,8 +161,8 @@ abort:
|
|||
|
||||
static struct pem_data *pem_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pem_data *data = i2c_get_clientdata(client);
|
||||
struct pem_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
struct pem_data *ret = data;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
@ -444,18 +445,20 @@ static int pem_probe(struct i2c_client *client,
|
|||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct pem_data *data;
|
||||
int ret;
|
||||
int ret, idx = 0;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BLOCK_DATA
|
||||
| I2C_FUNC_SMBUS_WRITE_BYTE))
|
||||
return -ENODEV;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/*
|
||||
|
@ -471,14 +474,12 @@ static int pem_probe(struct i2c_client *client,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_info(&client->dev, "Firmware revision %d.%d.%d\n",
|
||||
dev_info(dev, "Firmware revision %d.%d.%d\n",
|
||||
data->firmware_rev[0], data->firmware_rev[1],
|
||||
data->firmware_rev[2]);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
ret = sysfs_create_group(&client->dev.kobj, &pem_group);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* sysfs hooks */
|
||||
data->groups[idx++] = &pem_group;
|
||||
|
||||
/*
|
||||
* Check if input readings are supported.
|
||||
|
@ -501,12 +502,9 @@ static int pem_probe(struct i2c_client *client,
|
|||
data->input_string[2] || data->input_string[3]))
|
||||
data->input_length = sizeof(data->input_string);
|
||||
}
|
||||
ret = 0;
|
||||
if (data->input_length) {
|
||||
ret = sysfs_create_group(&client->dev.kobj, &pem_input_group);
|
||||
if (ret)
|
||||
goto out_remove_groups;
|
||||
}
|
||||
|
||||
if (data->input_length)
|
||||
data->groups[idx++] = &pem_input_group;
|
||||
|
||||
/*
|
||||
* Check if fan speed readings are supported.
|
||||
|
@ -520,37 +518,12 @@ static int pem_probe(struct i2c_client *client,
|
|||
if (!ret && (data->fan_speed[0] || data->fan_speed[1] ||
|
||||
data->fan_speed[2] || data->fan_speed[3])) {
|
||||
data->fans_supported = true;
|
||||
ret = sysfs_create_group(&client->dev.kobj, &pem_fan_group);
|
||||
if (ret)
|
||||
goto out_remove_groups;
|
||||
data->groups[idx++] = &pem_fan_group;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
ret = PTR_ERR(data->hwmon_dev);
|
||||
goto out_remove_groups;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_remove_groups:
|
||||
sysfs_remove_group(&client->dev.kobj, &pem_input_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pem_fan_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pem_group);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pem_remove(struct i2c_client *client)
|
||||
{
|
||||
struct pem_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &pem_input_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pem_fan_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pem_group);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, data->groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id pem_id[] = {
|
||||
|
@ -564,7 +537,6 @@ static struct i2c_driver pem_driver = {
|
|||
.name = "lineage_pem",
|
||||
},
|
||||
.probe = pem_probe,
|
||||
.remove = pem_remove,
|
||||
.id_table = pem_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -126,24 +126,17 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
|
|||
#define FAN_TO_REG(val) ((val) <= 82 ? 0xFFFC : \
|
||||
(5400000 / (val)) & 0xFFFC)
|
||||
#define TEMP8_FROM_REG(reg) ((reg) * 1000)
|
||||
#define TEMP8_TO_REG(val) ((val) <= -128000 ? -128 : \
|
||||
(val) >= 127000 ? 127 : \
|
||||
(val) < 0 ? ((val) - 500) / 1000 : \
|
||||
((val) + 500) / 1000)
|
||||
#define TEMP8U_TO_REG(val) ((val) <= 0 ? 0 : \
|
||||
(val) >= 255000 ? 255 : \
|
||||
((val) + 500) / 1000)
|
||||
#define TEMP8_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val((val), -128000, \
|
||||
127000), 1000)
|
||||
#define TEMP8U_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val((val), 0, \
|
||||
255000), 1000)
|
||||
#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125)
|
||||
#define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \
|
||||
(val) >= 127875 ? 0x7FE0 : \
|
||||
(val) < 0 ? ((val) - 62) / 125 * 32 : \
|
||||
((val) + 62) / 125 * 32)
|
||||
#define TEMP11U_TO_REG(val) ((val) <= 0 ? 0 : \
|
||||
(val) >= 255875 ? 0xFFE0 : \
|
||||
((val) + 62) / 125 * 32)
|
||||
#define HYST_TO_REG(val) ((val) <= 0 ? 0 : \
|
||||
(val) >= 127000 ? 127 : \
|
||||
((val) + 500) / 1000)
|
||||
#define TEMP11_TO_REG(val) (DIV_ROUND_CLOSEST(clamp_val((val), -128000, \
|
||||
127875), 125) * 32)
|
||||
#define TEMP11U_TO_REG(val) (DIV_ROUND_CLOSEST(clamp_val((val), 0, \
|
||||
255875), 125) * 32)
|
||||
#define HYST_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val((val), 0, 127000), \
|
||||
1000)
|
||||
|
||||
#define UPDATE_INTERVAL(max, rate) \
|
||||
((1000 << (LM63_MAX_CONVRATE - (rate))) / (max))
|
||||
|
|
|
@ -52,6 +52,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
|
|||
tmp100,
|
||||
tmp101,
|
||||
tmp105,
|
||||
tmp112,
|
||||
tmp175,
|
||||
tmp275,
|
||||
tmp75,
|
||||
|
@ -255,6 +256,12 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
data->sample_time = HZ;
|
||||
clr_mask |= 1 << 7; /* not one-shot mode */
|
||||
break;
|
||||
case tmp112:
|
||||
set_mask |= 3 << 5; /* 12-bit mode */
|
||||
clr_mask |= 1 << 7; /* not one-shot mode */
|
||||
data->resolution = 12;
|
||||
data->sample_time = HZ / 4;
|
||||
break;
|
||||
case tmp105:
|
||||
case tmp175:
|
||||
case tmp275:
|
||||
|
@ -323,6 +330,7 @@ static const struct i2c_device_id lm75_ids[] = {
|
|||
{ "tmp100", tmp100, },
|
||||
{ "tmp101", tmp101, },
|
||||
{ "tmp105", tmp105, },
|
||||
{ "tmp112", tmp112, },
|
||||
{ "tmp175", tmp175, },
|
||||
{ "tmp275", tmp275, },
|
||||
{ "tmp75", tmp75, },
|
||||
|
|
|
@ -80,8 +80,7 @@ struct lm77_data {
|
|||
*/
|
||||
static inline s16 LM77_TEMP_TO_REG(int temp)
|
||||
{
|
||||
int ntemp = clamp_val(temp, LM77_TEMP_MIN, LM77_TEMP_MAX);
|
||||
return (ntemp / 500) * 8;
|
||||
return (temp / 500) * 8;
|
||||
}
|
||||
|
||||
static inline int LM77_TEMP_FROM_REG(s16 reg)
|
||||
|
@ -175,6 +174,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
val = clamp_val(val, LM77_TEMP_MIN, LM77_TEMP_MAX);
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp[nr] = val;
|
||||
lm77_write_value(client, temp_regs[nr], LM77_TEMP_TO_REG(val));
|
||||
|
@ -192,15 +192,16 @@ static ssize_t set_temp_hyst(struct device *dev,
|
|||
{
|
||||
struct lm77_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
err = kstrtol(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp[t_hyst] = data->temp[t_crit] - val;
|
||||
val = clamp_val(data->temp[t_crit] - val, LM77_TEMP_MIN, LM77_TEMP_MAX);
|
||||
data->temp[t_hyst] = val;
|
||||
lm77_write_value(client, LM77_REG_TEMP_HYST,
|
||||
LM77_TEMP_TO_REG(data->temp[t_hyst]));
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
|
|
@ -108,7 +108,7 @@ static inline int FAN_FROM_REG(u8 val, int div)
|
|||
* TEMP: mC (-128C to +127C)
|
||||
* REG: 1C/bit, two's complement
|
||||
*/
|
||||
static inline s8 TEMP_TO_REG(int val)
|
||||
static inline s8 TEMP_TO_REG(long val)
|
||||
{
|
||||
int nval = clamp_val(val, -128000, 127000) ;
|
||||
return nval < 0 ? (nval - 500) / 1000 : (nval + 500) / 1000;
|
||||
|
@ -123,7 +123,6 @@ static inline int TEMP_FROM_REG(s8 val)
|
|||
|
||||
struct lm78_data {
|
||||
struct i2c_client *client;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex lock;
|
||||
enum chips type;
|
||||
|
||||
|
@ -468,7 +467,7 @@ static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
|
|||
static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
|
||||
static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
|
||||
|
||||
static struct attribute *lm78_attributes[] = {
|
||||
static struct attribute *lm78_attrs[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_max.dev_attr.attr,
|
||||
|
@ -519,9 +518,7 @@ static struct attribute *lm78_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm78_group = {
|
||||
.attrs = lm78_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(lm78);
|
||||
|
||||
/*
|
||||
* ISA related code
|
||||
|
@ -533,19 +530,6 @@ static struct platform_device *pdev;
|
|||
|
||||
static unsigned short isa_address = 0x290;
|
||||
|
||||
/*
|
||||
* I2C devices get this name attribute automatically, but for ISA devices
|
||||
* we must create it by ourselves.
|
||||
*/
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct lm78_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", data->name);
|
||||
}
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
static struct lm78_data *lm78_data_if_isa(void)
|
||||
{
|
||||
return pdev ? platform_get_drvdata(pdev) : NULL;
|
||||
|
@ -661,46 +645,23 @@ static int lm78_i2c_detect(struct i2c_client *client,
|
|||
static int lm78_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct lm78_data *data;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct lm78_data), GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct lm78_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
data->type = id->driver_data;
|
||||
|
||||
/* Initialize the LM78 chip */
|
||||
lm78_init_device(data);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &lm78_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
sysfs_remove_group(&client->dev.kobj, &lm78_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lm78_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct lm78_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm78_group);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, lm78_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id lm78_i2c_id[] = {
|
||||
|
@ -716,7 +677,6 @@ static struct i2c_driver lm78_driver = {
|
|||
.name = "lm78",
|
||||
},
|
||||
.probe = lm78_i2c_probe,
|
||||
.remove = lm78_i2c_remove,
|
||||
.id_table = lm78_i2c_id,
|
||||
.detect = lm78_i2c_detect,
|
||||
.address_list = normal_i2c,
|
||||
|
@ -839,17 +799,18 @@ static struct lm78_data *lm78_update_device(struct device *dev)
|
|||
#ifdef CONFIG_ISA
|
||||
static int lm78_isa_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct lm78_data *data;
|
||||
struct resource *res;
|
||||
|
||||
/* Reserve the ISA region */
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (!devm_request_region(&pdev->dev, res->start + LM78_ADDR_REG_OFFSET,
|
||||
if (!devm_request_region(dev, res->start + LM78_ADDR_REG_OFFSET,
|
||||
2, "lm78"))
|
||||
return -EBUSY;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(struct lm78_data), GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct lm78_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -868,37 +829,9 @@ static int lm78_isa_probe(struct platform_device *pdev)
|
|||
/* Initialize the LM78 chip */
|
||||
lm78_init_device(data);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&pdev->dev.kobj, &lm78_group);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
err = device_create_file(&pdev->dev, &dev_attr_name);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->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(&pdev->dev.kobj, &lm78_group);
|
||||
device_remove_file(&pdev->dev, &dev_attr_name);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lm78_isa_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lm78_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &lm78_group);
|
||||
device_remove_file(&pdev->dev, &dev_attr_name);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
|
||||
data, lm78_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static struct platform_driver lm78_isa_driver = {
|
||||
|
@ -907,7 +840,6 @@ static struct platform_driver lm78_isa_driver = {
|
|||
.name = "lm78",
|
||||
},
|
||||
.probe = lm78_isa_probe,
|
||||
.remove = lm78_isa_remove,
|
||||
};
|
||||
|
||||
/* return 1 if a supported chip is found, 0 otherwise */
|
||||
|
|
|
@ -121,7 +121,6 @@ enum chips {
|
|||
#define EMC6D102_REG_EXTEND_ADC3 0x87
|
||||
#define EMC6D102_REG_EXTEND_ADC4 0x88
|
||||
|
||||
|
||||
/*
|
||||
* Conversions. Rounding and limit checking is only done on the TO_REG
|
||||
* variants. Note that you should be a bit careful with which arguments
|
||||
|
@ -155,7 +154,7 @@ static inline u16 FAN_TO_REG(unsigned long val)
|
|||
|
||||
/* Temperature is reported in .001 degC increments */
|
||||
#define TEMP_TO_REG(val) \
|
||||
clamp_val(SCALE(val, 1000, 1), -127, 127)
|
||||
DIV_ROUND_CLOSEST(clamp_val((val), -127000, 127000), 1000)
|
||||
#define TEMPEXT_FROM_REG(val, ext) \
|
||||
SCALE(((val) << 4) + (ext), 16, 1000)
|
||||
#define TEMP_FROM_REG(val) ((val) * 1000)
|
||||
|
@ -189,7 +188,7 @@ static const int lm85_range_map[] = {
|
|||
13300, 16000, 20000, 26600, 32000, 40000, 53300, 80000
|
||||
};
|
||||
|
||||
static int RANGE_TO_REG(int range)
|
||||
static int RANGE_TO_REG(long range)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -211,7 +210,7 @@ static const int adm1027_freq_map[8] = { /* 1 Hz */
|
|||
11, 15, 22, 29, 35, 44, 59, 88
|
||||
};
|
||||
|
||||
static int FREQ_TO_REG(const int *map, int freq)
|
||||
static int FREQ_TO_REG(const int *map, unsigned long freq)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -303,7 +302,8 @@ struct lm85_autofan {
|
|||
* The structure is dynamically allocated.
|
||||
*/
|
||||
struct lm85_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
const struct attribute_group *groups[6];
|
||||
const int *freq_map;
|
||||
enum chips type;
|
||||
|
||||
|
@ -334,44 +334,235 @@ struct lm85_data {
|
|||
struct lm85_zone zone[3];
|
||||
};
|
||||
|
||||
static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info);
|
||||
static int lm85_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int lm85_remove(struct i2c_client *client);
|
||||
static int lm85_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
int res;
|
||||
|
||||
static int lm85_read_value(struct i2c_client *client, u8 reg);
|
||||
static void lm85_write_value(struct i2c_client *client, u8 reg, int value);
|
||||
static struct lm85_data *lm85_update_device(struct device *dev);
|
||||
/* What size location is it? */
|
||||
switch (reg) {
|
||||
case LM85_REG_FAN(0): /* Read WORD data */
|
||||
case LM85_REG_FAN(1):
|
||||
case LM85_REG_FAN(2):
|
||||
case LM85_REG_FAN(3):
|
||||
case LM85_REG_FAN_MIN(0):
|
||||
case LM85_REG_FAN_MIN(1):
|
||||
case LM85_REG_FAN_MIN(2):
|
||||
case LM85_REG_FAN_MIN(3):
|
||||
case LM85_REG_ALARM1: /* Read both bytes at once */
|
||||
res = i2c_smbus_read_byte_data(client, reg) & 0xff;
|
||||
res |= i2c_smbus_read_byte_data(client, reg + 1) << 8;
|
||||
break;
|
||||
default: /* Read BYTE data */
|
||||
res = i2c_smbus_read_byte_data(client, reg);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id lm85_id[] = {
|
||||
{ "adm1027", adm1027 },
|
||||
{ "adt7463", adt7463 },
|
||||
{ "adt7468", adt7468 },
|
||||
{ "lm85", lm85 },
|
||||
{ "lm85b", lm85 },
|
||||
{ "lm85c", lm85 },
|
||||
{ "emc6d100", emc6d100 },
|
||||
{ "emc6d101", emc6d100 },
|
||||
{ "emc6d102", emc6d102 },
|
||||
{ "emc6d103", emc6d103 },
|
||||
{ "emc6d103s", emc6d103s },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lm85_id);
|
||||
static void lm85_write_value(struct i2c_client *client, u8 reg, int value)
|
||||
{
|
||||
switch (reg) {
|
||||
case LM85_REG_FAN(0): /* Write WORD data */
|
||||
case LM85_REG_FAN(1):
|
||||
case LM85_REG_FAN(2):
|
||||
case LM85_REG_FAN(3):
|
||||
case LM85_REG_FAN_MIN(0):
|
||||
case LM85_REG_FAN_MIN(1):
|
||||
case LM85_REG_FAN_MIN(2):
|
||||
case LM85_REG_FAN_MIN(3):
|
||||
/* NOTE: ALARM is read only, so not included here */
|
||||
i2c_smbus_write_byte_data(client, reg, value & 0xff);
|
||||
i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
|
||||
break;
|
||||
default: /* Write BYTE data */
|
||||
i2c_smbus_write_byte_data(client, reg, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct i2c_driver lm85_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "lm85",
|
||||
},
|
||||
.probe = lm85_probe,
|
||||
.remove = lm85_remove,
|
||||
.id_table = lm85_id,
|
||||
.detect = lm85_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
static struct lm85_data *lm85_update_device(struct device *dev)
|
||||
{
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int i;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (!data->valid ||
|
||||
time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL)) {
|
||||
/* Things that change quickly */
|
||||
dev_dbg(&client->dev, "Reading sensor values\n");
|
||||
|
||||
/*
|
||||
* Have to read extended bits first to "freeze" the
|
||||
* more significant bits that are read later.
|
||||
* There are 2 additional resolution bits per channel and we
|
||||
* have room for 4, so we shift them to the left.
|
||||
*/
|
||||
if (data->type == adm1027 || data->type == adt7463 ||
|
||||
data->type == adt7468) {
|
||||
int ext1 = lm85_read_value(client,
|
||||
ADM1027_REG_EXTEND_ADC1);
|
||||
int ext2 = lm85_read_value(client,
|
||||
ADM1027_REG_EXTEND_ADC2);
|
||||
int val = (ext1 << 8) + ext2;
|
||||
|
||||
for (i = 0; i <= 4; i++)
|
||||
data->in_ext[i] =
|
||||
((val >> (i * 2)) & 0x03) << 2;
|
||||
|
||||
for (i = 0; i <= 2; i++)
|
||||
data->temp_ext[i] =
|
||||
(val >> ((i + 4) * 2)) & 0x0c;
|
||||
}
|
||||
|
||||
data->vid = lm85_read_value(client, LM85_REG_VID);
|
||||
|
||||
for (i = 0; i <= 3; ++i) {
|
||||
data->in[i] =
|
||||
lm85_read_value(client, LM85_REG_IN(i));
|
||||
data->fan[i] =
|
||||
lm85_read_value(client, LM85_REG_FAN(i));
|
||||
}
|
||||
|
||||
if (!data->has_vid5)
|
||||
data->in[4] = lm85_read_value(client, LM85_REG_IN(4));
|
||||
|
||||
if (data->type == adt7468)
|
||||
data->cfg5 = lm85_read_value(client, ADT7468_REG_CFG5);
|
||||
|
||||
for (i = 0; i <= 2; ++i) {
|
||||
data->temp[i] =
|
||||
lm85_read_value(client, LM85_REG_TEMP(i));
|
||||
data->pwm[i] =
|
||||
lm85_read_value(client, LM85_REG_PWM(i));
|
||||
|
||||
if (IS_ADT7468_OFF64(data))
|
||||
data->temp[i] -= 64;
|
||||
}
|
||||
|
||||
data->alarms = lm85_read_value(client, LM85_REG_ALARM1);
|
||||
|
||||
if (data->type == emc6d100) {
|
||||
/* Three more voltage sensors */
|
||||
for (i = 5; i <= 7; ++i) {
|
||||
data->in[i] = lm85_read_value(client,
|
||||
EMC6D100_REG_IN(i));
|
||||
}
|
||||
/* More alarm bits */
|
||||
data->alarms |= lm85_read_value(client,
|
||||
EMC6D100_REG_ALARM3) << 16;
|
||||
} else if (data->type == emc6d102 || data->type == emc6d103 ||
|
||||
data->type == emc6d103s) {
|
||||
/*
|
||||
* Have to read LSB bits after the MSB ones because
|
||||
* the reading of the MSB bits has frozen the
|
||||
* LSBs (backward from the ADM1027).
|
||||
*/
|
||||
int ext1 = lm85_read_value(client,
|
||||
EMC6D102_REG_EXTEND_ADC1);
|
||||
int ext2 = lm85_read_value(client,
|
||||
EMC6D102_REG_EXTEND_ADC2);
|
||||
int ext3 = lm85_read_value(client,
|
||||
EMC6D102_REG_EXTEND_ADC3);
|
||||
int ext4 = lm85_read_value(client,
|
||||
EMC6D102_REG_EXTEND_ADC4);
|
||||
data->in_ext[0] = ext3 & 0x0f;
|
||||
data->in_ext[1] = ext4 & 0x0f;
|
||||
data->in_ext[2] = ext4 >> 4;
|
||||
data->in_ext[3] = ext3 >> 4;
|
||||
data->in_ext[4] = ext2 >> 4;
|
||||
|
||||
data->temp_ext[0] = ext1 & 0x0f;
|
||||
data->temp_ext[1] = ext2 & 0x0f;
|
||||
data->temp_ext[2] = ext1 >> 4;
|
||||
}
|
||||
|
||||
data->last_reading = jiffies;
|
||||
} /* last_reading */
|
||||
|
||||
if (!data->valid ||
|
||||
time_after(jiffies, data->last_config + LM85_CONFIG_INTERVAL)) {
|
||||
/* Things that don't change often */
|
||||
dev_dbg(&client->dev, "Reading config values\n");
|
||||
|
||||
for (i = 0; i <= 3; ++i) {
|
||||
data->in_min[i] =
|
||||
lm85_read_value(client, LM85_REG_IN_MIN(i));
|
||||
data->in_max[i] =
|
||||
lm85_read_value(client, LM85_REG_IN_MAX(i));
|
||||
data->fan_min[i] =
|
||||
lm85_read_value(client, LM85_REG_FAN_MIN(i));
|
||||
}
|
||||
|
||||
if (!data->has_vid5) {
|
||||
data->in_min[4] = lm85_read_value(client,
|
||||
LM85_REG_IN_MIN(4));
|
||||
data->in_max[4] = lm85_read_value(client,
|
||||
LM85_REG_IN_MAX(4));
|
||||
}
|
||||
|
||||
if (data->type == emc6d100) {
|
||||
for (i = 5; i <= 7; ++i) {
|
||||
data->in_min[i] = lm85_read_value(client,
|
||||
EMC6D100_REG_IN_MIN(i));
|
||||
data->in_max[i] = lm85_read_value(client,
|
||||
EMC6D100_REG_IN_MAX(i));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i <= 2; ++i) {
|
||||
int val;
|
||||
|
||||
data->temp_min[i] =
|
||||
lm85_read_value(client, LM85_REG_TEMP_MIN(i));
|
||||
data->temp_max[i] =
|
||||
lm85_read_value(client, LM85_REG_TEMP_MAX(i));
|
||||
|
||||
data->autofan[i].config =
|
||||
lm85_read_value(client, LM85_REG_AFAN_CONFIG(i));
|
||||
val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i));
|
||||
data->pwm_freq[i] = val & 0x07;
|
||||
data->zone[i].range = val >> 4;
|
||||
data->autofan[i].min_pwm =
|
||||
lm85_read_value(client, LM85_REG_AFAN_MINPWM(i));
|
||||
data->zone[i].limit =
|
||||
lm85_read_value(client, LM85_REG_AFAN_LIMIT(i));
|
||||
data->zone[i].critical =
|
||||
lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i));
|
||||
|
||||
if (IS_ADT7468_OFF64(data)) {
|
||||
data->temp_min[i] -= 64;
|
||||
data->temp_max[i] -= 64;
|
||||
data->zone[i].limit -= 64;
|
||||
data->zone[i].critical -= 64;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->type != emc6d103s) {
|
||||
i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
|
||||
data->autofan[0].min_off = (i & 0x20) != 0;
|
||||
data->autofan[1].min_off = (i & 0x40) != 0;
|
||||
data->autofan[2].min_off = (i & 0x80) != 0;
|
||||
|
||||
i = lm85_read_value(client, LM85_REG_AFAN_HYST1);
|
||||
data->zone[0].hyst = i >> 4;
|
||||
data->zone[1].hyst = i & 0x0f;
|
||||
|
||||
i = lm85_read_value(client, LM85_REG_AFAN_HYST2);
|
||||
data->zone[2].hyst = i >> 4;
|
||||
}
|
||||
|
||||
data->last_config = jiffies;
|
||||
} /* last_config */
|
||||
|
||||
data->valid = 1;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/* 4 Fans */
|
||||
static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
|
||||
|
@ -394,8 +585,8 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -460,6 +651,9 @@ static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (val > 255)
|
||||
return -EINVAL;
|
||||
|
||||
data->vrm = val;
|
||||
return count;
|
||||
}
|
||||
|
@ -515,8 +709,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -557,8 +751,8 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute
|
|||
*attr, const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 config;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -615,8 +809,8 @@ static ssize_t set_pwm_freq(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -682,8 +876,8 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -710,8 +904,8 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -766,8 +960,8 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -797,8 +991,8 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -843,8 +1037,8 @@ static ssize_t set_pwm_auto_channels(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -873,8 +1067,8 @@ static ssize_t set_pwm_auto_pwm_min(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -902,8 +1096,8 @@ static ssize_t set_pwm_auto_pwm_minctl(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 tmp;
|
||||
long val;
|
||||
int err;
|
||||
|
@ -953,8 +1147,8 @@ static ssize_t set_temp_auto_temp_off(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int min;
|
||||
long val;
|
||||
int err;
|
||||
|
@ -990,8 +1184,8 @@ static ssize_t set_temp_auto_temp_min(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -1029,8 +1223,8 @@ static ssize_t set_temp_auto_temp_max(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int min;
|
||||
long val;
|
||||
int err;
|
||||
|
@ -1063,8 +1257,8 @@ static ssize_t set_temp_auto_temp_crit(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
struct lm85_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -1355,30 +1549,18 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void lm85_remove_files(struct i2c_client *client, struct lm85_data *data)
|
||||
{
|
||||
sysfs_remove_group(&client->dev.kobj, &lm85_group);
|
||||
if (data->type != emc6d103s) {
|
||||
sysfs_remove_group(&client->dev.kobj, &lm85_group_minctl);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm85_group_temp_off);
|
||||
}
|
||||
if (!data->has_vid5)
|
||||
sysfs_remove_group(&client->dev.kobj, &lm85_group_in4);
|
||||
if (data->type == emc6d100)
|
||||
sysfs_remove_group(&client->dev.kobj, &lm85_group_in567);
|
||||
}
|
||||
|
||||
static int lm85_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static int lm85_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct lm85_data *data;
|
||||
int err;
|
||||
int idx = 0;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct lm85_data), GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct lm85_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
data->type = id->driver_data;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
|
@ -1403,20 +1585,13 @@ static int lm85_probe(struct i2c_client *client,
|
|||
/* Initialize the LM85 chip */
|
||||
lm85_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &lm85_group);
|
||||
if (err)
|
||||
return err;
|
||||
/* sysfs hooks */
|
||||
data->groups[idx++] = &lm85_group;
|
||||
|
||||
/* minctl and temp_off exist on all chips except emc6d103s */
|
||||
if (data->type != emc6d103s) {
|
||||
err = sysfs_create_group(&client->dev.kobj, &lm85_group_minctl);
|
||||
if (err)
|
||||
goto err_remove_files;
|
||||
err = sysfs_create_group(&client->dev.kobj,
|
||||
&lm85_group_temp_off);
|
||||
if (err)
|
||||
goto err_remove_files;
|
||||
data->groups[idx++] = &lm85_group_minctl;
|
||||
data->groups[idx++] = &lm85_group_temp_off;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1429,271 +1604,44 @@ static int lm85_probe(struct i2c_client *client,
|
|||
data->has_vid5 = true;
|
||||
}
|
||||
|
||||
if (!data->has_vid5) {
|
||||
err = sysfs_create_group(&client->dev.kobj, &lm85_group_in4);
|
||||
if (err)
|
||||
goto err_remove_files;
|
||||
}
|
||||
if (!data->has_vid5)
|
||||
data->groups[idx++] = &lm85_group_in4;
|
||||
|
||||
/* The EMC6D100 has 3 additional voltage inputs */
|
||||
if (data->type == emc6d100) {
|
||||
err = sysfs_create_group(&client->dev.kobj, &lm85_group_in567);
|
||||
if (err)
|
||||
goto err_remove_files;
|
||||
}
|
||||
if (data->type == emc6d100)
|
||||
data->groups[idx++] = &lm85_group_in567;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto err_remove_files;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
/* Error out and cleanup code */
|
||||
err_remove_files:
|
||||
lm85_remove_files(client, data);
|
||||
return err;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, data->groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static int lm85_remove(struct i2c_client *client)
|
||||
{
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
lm85_remove_files(client, data);
|
||||
return 0;
|
||||
}
|
||||
static const struct i2c_device_id lm85_id[] = {
|
||||
{ "adm1027", adm1027 },
|
||||
{ "adt7463", adt7463 },
|
||||
{ "adt7468", adt7468 },
|
||||
{ "lm85", lm85 },
|
||||
{ "lm85b", lm85 },
|
||||
{ "lm85c", lm85 },
|
||||
{ "emc6d100", emc6d100 },
|
||||
{ "emc6d101", emc6d100 },
|
||||
{ "emc6d102", emc6d102 },
|
||||
{ "emc6d103", emc6d103 },
|
||||
{ "emc6d103s", emc6d103s },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lm85_id);
|
||||
|
||||
|
||||
static int lm85_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* What size location is it? */
|
||||
switch (reg) {
|
||||
case LM85_REG_FAN(0): /* Read WORD data */
|
||||
case LM85_REG_FAN(1):
|
||||
case LM85_REG_FAN(2):
|
||||
case LM85_REG_FAN(3):
|
||||
case LM85_REG_FAN_MIN(0):
|
||||
case LM85_REG_FAN_MIN(1):
|
||||
case LM85_REG_FAN_MIN(2):
|
||||
case LM85_REG_FAN_MIN(3):
|
||||
case LM85_REG_ALARM1: /* Read both bytes at once */
|
||||
res = i2c_smbus_read_byte_data(client, reg) & 0xff;
|
||||
res |= i2c_smbus_read_byte_data(client, reg + 1) << 8;
|
||||
break;
|
||||
default: /* Read BYTE data */
|
||||
res = i2c_smbus_read_byte_data(client, reg);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void lm85_write_value(struct i2c_client *client, u8 reg, int value)
|
||||
{
|
||||
switch (reg) {
|
||||
case LM85_REG_FAN(0): /* Write WORD data */
|
||||
case LM85_REG_FAN(1):
|
||||
case LM85_REG_FAN(2):
|
||||
case LM85_REG_FAN(3):
|
||||
case LM85_REG_FAN_MIN(0):
|
||||
case LM85_REG_FAN_MIN(1):
|
||||
case LM85_REG_FAN_MIN(2):
|
||||
case LM85_REG_FAN_MIN(3):
|
||||
/* NOTE: ALARM is read only, so not included here */
|
||||
i2c_smbus_write_byte_data(client, reg, value & 0xff);
|
||||
i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
|
||||
break;
|
||||
default: /* Write BYTE data */
|
||||
i2c_smbus_write_byte_data(client, reg, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct lm85_data *lm85_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
int i;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (!data->valid ||
|
||||
time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL)) {
|
||||
/* Things that change quickly */
|
||||
dev_dbg(&client->dev, "Reading sensor values\n");
|
||||
|
||||
/*
|
||||
* Have to read extended bits first to "freeze" the
|
||||
* more significant bits that are read later.
|
||||
* There are 2 additional resolution bits per channel and we
|
||||
* have room for 4, so we shift them to the left.
|
||||
*/
|
||||
if (data->type == adm1027 || data->type == adt7463 ||
|
||||
data->type == adt7468) {
|
||||
int ext1 = lm85_read_value(client,
|
||||
ADM1027_REG_EXTEND_ADC1);
|
||||
int ext2 = lm85_read_value(client,
|
||||
ADM1027_REG_EXTEND_ADC2);
|
||||
int val = (ext1 << 8) + ext2;
|
||||
|
||||
for (i = 0; i <= 4; i++)
|
||||
data->in_ext[i] =
|
||||
((val >> (i * 2)) & 0x03) << 2;
|
||||
|
||||
for (i = 0; i <= 2; i++)
|
||||
data->temp_ext[i] =
|
||||
(val >> ((i + 4) * 2)) & 0x0c;
|
||||
}
|
||||
|
||||
data->vid = lm85_read_value(client, LM85_REG_VID);
|
||||
|
||||
for (i = 0; i <= 3; ++i) {
|
||||
data->in[i] =
|
||||
lm85_read_value(client, LM85_REG_IN(i));
|
||||
data->fan[i] =
|
||||
lm85_read_value(client, LM85_REG_FAN(i));
|
||||
}
|
||||
|
||||
if (!data->has_vid5)
|
||||
data->in[4] = lm85_read_value(client, LM85_REG_IN(4));
|
||||
|
||||
if (data->type == adt7468)
|
||||
data->cfg5 = lm85_read_value(client, ADT7468_REG_CFG5);
|
||||
|
||||
for (i = 0; i <= 2; ++i) {
|
||||
data->temp[i] =
|
||||
lm85_read_value(client, LM85_REG_TEMP(i));
|
||||
data->pwm[i] =
|
||||
lm85_read_value(client, LM85_REG_PWM(i));
|
||||
|
||||
if (IS_ADT7468_OFF64(data))
|
||||
data->temp[i] -= 64;
|
||||
}
|
||||
|
||||
data->alarms = lm85_read_value(client, LM85_REG_ALARM1);
|
||||
|
||||
if (data->type == emc6d100) {
|
||||
/* Three more voltage sensors */
|
||||
for (i = 5; i <= 7; ++i) {
|
||||
data->in[i] = lm85_read_value(client,
|
||||
EMC6D100_REG_IN(i));
|
||||
}
|
||||
/* More alarm bits */
|
||||
data->alarms |= lm85_read_value(client,
|
||||
EMC6D100_REG_ALARM3) << 16;
|
||||
} else if (data->type == emc6d102 || data->type == emc6d103 ||
|
||||
data->type == emc6d103s) {
|
||||
/*
|
||||
* Have to read LSB bits after the MSB ones because
|
||||
* the reading of the MSB bits has frozen the
|
||||
* LSBs (backward from the ADM1027).
|
||||
*/
|
||||
int ext1 = lm85_read_value(client,
|
||||
EMC6D102_REG_EXTEND_ADC1);
|
||||
int ext2 = lm85_read_value(client,
|
||||
EMC6D102_REG_EXTEND_ADC2);
|
||||
int ext3 = lm85_read_value(client,
|
||||
EMC6D102_REG_EXTEND_ADC3);
|
||||
int ext4 = lm85_read_value(client,
|
||||
EMC6D102_REG_EXTEND_ADC4);
|
||||
data->in_ext[0] = ext3 & 0x0f;
|
||||
data->in_ext[1] = ext4 & 0x0f;
|
||||
data->in_ext[2] = ext4 >> 4;
|
||||
data->in_ext[3] = ext3 >> 4;
|
||||
data->in_ext[4] = ext2 >> 4;
|
||||
|
||||
data->temp_ext[0] = ext1 & 0x0f;
|
||||
data->temp_ext[1] = ext2 & 0x0f;
|
||||
data->temp_ext[2] = ext1 >> 4;
|
||||
}
|
||||
|
||||
data->last_reading = jiffies;
|
||||
} /* last_reading */
|
||||
|
||||
if (!data->valid ||
|
||||
time_after(jiffies, data->last_config + LM85_CONFIG_INTERVAL)) {
|
||||
/* Things that don't change often */
|
||||
dev_dbg(&client->dev, "Reading config values\n");
|
||||
|
||||
for (i = 0; i <= 3; ++i) {
|
||||
data->in_min[i] =
|
||||
lm85_read_value(client, LM85_REG_IN_MIN(i));
|
||||
data->in_max[i] =
|
||||
lm85_read_value(client, LM85_REG_IN_MAX(i));
|
||||
data->fan_min[i] =
|
||||
lm85_read_value(client, LM85_REG_FAN_MIN(i));
|
||||
}
|
||||
|
||||
if (!data->has_vid5) {
|
||||
data->in_min[4] = lm85_read_value(client,
|
||||
LM85_REG_IN_MIN(4));
|
||||
data->in_max[4] = lm85_read_value(client,
|
||||
LM85_REG_IN_MAX(4));
|
||||
}
|
||||
|
||||
if (data->type == emc6d100) {
|
||||
for (i = 5; i <= 7; ++i) {
|
||||
data->in_min[i] = lm85_read_value(client,
|
||||
EMC6D100_REG_IN_MIN(i));
|
||||
data->in_max[i] = lm85_read_value(client,
|
||||
EMC6D100_REG_IN_MAX(i));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i <= 2; ++i) {
|
||||
int val;
|
||||
|
||||
data->temp_min[i] =
|
||||
lm85_read_value(client, LM85_REG_TEMP_MIN(i));
|
||||
data->temp_max[i] =
|
||||
lm85_read_value(client, LM85_REG_TEMP_MAX(i));
|
||||
|
||||
data->autofan[i].config =
|
||||
lm85_read_value(client, LM85_REG_AFAN_CONFIG(i));
|
||||
val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i));
|
||||
data->pwm_freq[i] = val & 0x07;
|
||||
data->zone[i].range = val >> 4;
|
||||
data->autofan[i].min_pwm =
|
||||
lm85_read_value(client, LM85_REG_AFAN_MINPWM(i));
|
||||
data->zone[i].limit =
|
||||
lm85_read_value(client, LM85_REG_AFAN_LIMIT(i));
|
||||
data->zone[i].critical =
|
||||
lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i));
|
||||
|
||||
if (IS_ADT7468_OFF64(data)) {
|
||||
data->temp_min[i] -= 64;
|
||||
data->temp_max[i] -= 64;
|
||||
data->zone[i].limit -= 64;
|
||||
data->zone[i].critical -= 64;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->type != emc6d103s) {
|
||||
i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
|
||||
data->autofan[0].min_off = (i & 0x20) != 0;
|
||||
data->autofan[1].min_off = (i & 0x40) != 0;
|
||||
data->autofan[2].min_off = (i & 0x80) != 0;
|
||||
|
||||
i = lm85_read_value(client, LM85_REG_AFAN_HYST1);
|
||||
data->zone[0].hyst = i >> 4;
|
||||
data->zone[1].hyst = i & 0x0f;
|
||||
|
||||
i = lm85_read_value(client, LM85_REG_AFAN_HYST2);
|
||||
data->zone[2].hyst = i >> 4;
|
||||
}
|
||||
|
||||
data->last_config = jiffies;
|
||||
} /* last_config */
|
||||
|
||||
data->valid = 1;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
static struct i2c_driver lm85_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "lm85",
|
||||
},
|
||||
.probe = lm85_probe,
|
||||
.id_table = lm85_id,
|
||||
.detect = lm85_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(lm85_driver);
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ struct block1_t {
|
|||
* Client-specific data
|
||||
*/
|
||||
struct lm93_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
|
||||
struct mutex update_lock;
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
@ -919,8 +919,8 @@ static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values)
|
|||
|
||||
static struct lm93_data *lm93_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
const unsigned long interval = HZ + (HZ / 2);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
@ -1158,8 +1158,8 @@ static ssize_t store_in_min(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int vccp = nr - 6;
|
||||
long vid;
|
||||
unsigned long val;
|
||||
|
@ -1239,8 +1239,8 @@ static ssize_t store_in_max(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int vccp = nr - 6;
|
||||
long vid;
|
||||
unsigned long val;
|
||||
|
@ -1323,8 +1323,8 @@ static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -1358,8 +1358,8 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -1394,8 +1394,8 @@ static ssize_t store_temp_auto_base(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -1430,8 +1430,8 @@ static ssize_t store_temp_auto_boost(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -1469,8 +1469,8 @@ static ssize_t store_temp_auto_boost_hyst(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -1520,8 +1520,8 @@ static ssize_t store_temp_auto_offset(struct device *dev,
|
|||
struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
|
||||
int nr = s_attr->index;
|
||||
int ofs = s_attr->nr;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -1632,8 +1632,8 @@ static ssize_t store_temp_auto_pwm_min(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 reg, ctl4;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -1680,8 +1680,8 @@ static ssize_t store_temp_auto_offset_hyst(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 reg;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -1741,8 +1741,8 @@ static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -1824,8 +1824,8 @@ static ssize_t store_fan_smart_tach(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -1880,8 +1880,8 @@ static ssize_t store_pwm(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 ctl2, ctl4;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -1928,8 +1928,8 @@ static ssize_t store_pwm_enable(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 ctl2;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -2006,8 +2006,8 @@ static ssize_t store_pwm_freq(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 ctl4;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -2046,8 +2046,8 @@ static ssize_t store_pwm_auto_channels(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -2087,8 +2087,8 @@ static ssize_t store_pwm_auto_spinup_min(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 ctl3, ctl4;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -2130,8 +2130,8 @@ static ssize_t store_pwm_auto_spinup_time(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 ctl3;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -2168,8 +2168,8 @@ static ssize_t store_pwm_auto_prochot_ramp(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 ramp;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -2202,8 +2202,8 @@ static ssize_t store_pwm_auto_vrdhot_ramp(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 ramp;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -2270,8 +2270,8 @@ static ssize_t store_prochot_max(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -2308,8 +2308,8 @@ static ssize_t store_prochot_override(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -2351,8 +2351,8 @@ static ssize_t store_prochot_interval(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 tmp;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -2390,8 +2390,8 @@ static ssize_t store_prochot_override_duty_cycle(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -2423,8 +2423,8 @@ static ssize_t store_prochot_short(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
struct lm93_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -2631,9 +2631,7 @@ static struct attribute *lm93_attrs[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group lm93_attr_grp = {
|
||||
.attrs = lm93_attrs,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(lm93);
|
||||
|
||||
static void lm93_init_client(struct i2c_client *client)
|
||||
{
|
||||
|
@ -2726,61 +2724,42 @@ static int lm93_detect(struct i2c_client *client, struct i2c_board_info *info)
|
|||
static int lm93_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct lm93_data *data;
|
||||
int err, func;
|
||||
struct device *hwmon_dev;
|
||||
int func;
|
||||
void (*update)(struct lm93_data *, struct i2c_client *);
|
||||
|
||||
/* choose update routine based on bus capabilities */
|
||||
func = i2c_get_functionality(client->adapter);
|
||||
if (((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) &&
|
||||
(!disable_block)) {
|
||||
dev_dbg(&client->dev, "using SMBus block data transactions\n");
|
||||
dev_dbg(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(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(dev, "detect failed, smbus byte and/or word data not supported!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct lm93_data), GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct lm93_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
i2c_set_clientdata(client, data);
|
||||
|
||||
/* housekeeping */
|
||||
data->client = client;
|
||||
data->update = update;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* initialize the chip */
|
||||
lm93_init_client(client);
|
||||
|
||||
err = sysfs_create_group(&client->dev.kobj, &lm93_attr_grp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Register hwmon driver class */
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (!IS_ERR(data->hwmon_dev))
|
||||
return 0;
|
||||
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
dev_err(&client->dev, "error registering hwmon device.\n");
|
||||
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lm93_remove(struct i2c_client *client)
|
||||
{
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
lm93_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id lm93_id[] = {
|
||||
|
@ -2796,7 +2775,6 @@ static struct i2c_driver lm93_driver = {
|
|||
.name = "lm93",
|
||||
},
|
||||
.probe = lm93_probe,
|
||||
.remove = lm93_remove,
|
||||
.id_table = lm93_id,
|
||||
.detect = lm93_detect,
|
||||
.address_list = normal_i2c,
|
||||
|
|
|
@ -469,7 +469,7 @@ static struct attribute *ltc2945_attrs[] = {
|
|||
};
|
||||
ATTRIBUTE_GROUPS(ltc2945);
|
||||
|
||||
static struct regmap_config ltc2945_regmap_config = {
|
||||
static const struct regmap_config ltc2945_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = LTC2945_MIN_ADIN_THRES_L,
|
||||
|
|
|
@ -186,7 +186,7 @@ static struct attribute *ltc4222_attrs[] = {
|
|||
};
|
||||
ATTRIBUTE_GROUPS(ltc4222);
|
||||
|
||||
static struct regmap_config ltc4222_regmap_config = {
|
||||
static const struct regmap_config ltc4222_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = LTC4222_ADC_CONTROL,
|
||||
|
|
|
@ -150,7 +150,7 @@ static struct attribute *ltc4260_attrs[] = {
|
|||
};
|
||||
ATTRIBUTE_GROUPS(ltc4260);
|
||||
|
||||
static struct regmap_config ltc4260_regmap_config = {
|
||||
static const struct regmap_config ltc4260_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = LTC4260_ADIN,
|
||||
|
|
|
@ -642,10 +642,7 @@ static int max16065_probe(struct i2c_client *client,
|
|||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, data->groups);
|
||||
if (unlikely(IS_ERR(hwmon_dev)))
|
||||
return PTR_ERR(hwmon_dev);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max16065_id[] = {
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include <linux/mutex.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short max1668_addr_list[] = {
|
||||
static const unsigned short max1668_addr_list[] = {
|
||||
0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
|
||||
|
||||
/* max1668 registers */
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include <linux/i2c/max6639.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END };
|
||||
static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END };
|
||||
|
||||
/* The MAX6639 registers, valid channel numbers: 0, 1 */
|
||||
#define MAX6639_REG_TEMP(ch) (0x00 + (ch))
|
||||
|
|
|
@ -495,15 +495,13 @@ static void max6697_get_config_of(struct device_node *node,
|
|||
int len;
|
||||
const __be32 *prop;
|
||||
|
||||
prop = of_get_property(node, "smbus-timeout-disable", &len);
|
||||
if (prop)
|
||||
pdata->smbus_timeout_disable = true;
|
||||
prop = of_get_property(node, "extended-range-enable", &len);
|
||||
if (prop)
|
||||
pdata->extended_range_enable = true;
|
||||
prop = of_get_property(node, "beta-compensation-enable", &len);
|
||||
if (prop)
|
||||
pdata->beta_compensation = true;
|
||||
pdata->smbus_timeout_disable =
|
||||
of_property_read_bool(node, "smbus-timeout-disable");
|
||||
pdata->extended_range_enable =
|
||||
of_property_read_bool(node, "extended-range-enable");
|
||||
pdata->beta_compensation =
|
||||
of_property_read_bool(node, "beta-compensation-enable");
|
||||
|
||||
prop = of_get_property(node, "alert-mask", &len);
|
||||
if (prop && len == sizeof(u32))
|
||||
pdata->alert_mask = be32_to_cpu(prop[0]);
|
||||
|
|
|
@ -735,7 +735,6 @@ struct nct6775_data {
|
|||
enum kinds kind;
|
||||
const char *name;
|
||||
|
||||
int num_attr_groups;
|
||||
const struct attribute_group *groups[6];
|
||||
|
||||
u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
|
||||
|
@ -3276,6 +3275,7 @@ static int nct6775_probe(struct platform_device *pdev)
|
|||
u8 cr2a;
|
||||
struct attribute_group *group;
|
||||
struct device *hwmon_dev;
|
||||
int num_attr_groups = 0;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
|
||||
|
@ -3907,29 +3907,29 @@ static int nct6775_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(group))
|
||||
return PTR_ERR(group);
|
||||
|
||||
data->groups[data->num_attr_groups++] = group;
|
||||
data->groups[num_attr_groups++] = group;
|
||||
|
||||
group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
|
||||
fls(data->have_in));
|
||||
if (IS_ERR(group))
|
||||
return PTR_ERR(group);
|
||||
|
||||
data->groups[data->num_attr_groups++] = group;
|
||||
data->groups[num_attr_groups++] = group;
|
||||
|
||||
group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
|
||||
fls(data->has_fan));
|
||||
if (IS_ERR(group))
|
||||
return PTR_ERR(group);
|
||||
|
||||
data->groups[data->num_attr_groups++] = group;
|
||||
data->groups[num_attr_groups++] = group;
|
||||
|
||||
group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
|
||||
fls(data->have_temp));
|
||||
if (IS_ERR(group))
|
||||
return PTR_ERR(group);
|
||||
|
||||
data->groups[data->num_attr_groups++] = group;
|
||||
data->groups[data->num_attr_groups++] = &nct6775_group_other;
|
||||
data->groups[num_attr_groups++] = group;
|
||||
data->groups[num_attr_groups++] = &nct6775_group_other;
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name,
|
||||
data, data->groups);
|
||||
|
@ -4221,7 +4221,7 @@ static void __exit sensors_nct6775_exit(void)
|
|||
}
|
||||
|
||||
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
|
||||
MODULE_DESCRIPTION("NCT6775F/NCT6776F/NCT6779D driver");
|
||||
MODULE_DESCRIPTION("NCT6106D/NCT6775F/NCT6776F/NCT6779D/NCT6791D driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_nct6775_init);
|
||||
|
|
|
@ -51,6 +51,7 @@ static const struct platform_device_id ntc_thermistor_id[] = {
|
|||
{ "ncp21wb473", TYPE_NCPXXWB473 },
|
||||
{ "ncp03wb473", TYPE_NCPXXWB473 },
|
||||
{ "ncp15wl333", TYPE_NCPXXWL333 },
|
||||
{ "b57330v2103", TYPE_B57330V2103},
|
||||
{ },
|
||||
};
|
||||
|
||||
|
@ -133,6 +134,47 @@ static const struct ntc_compensation ncpXXwl333[] = {
|
|||
{ .temp_c = 125, .ohm = 707 },
|
||||
};
|
||||
|
||||
/*
|
||||
* The following compensation table is from the specification of EPCOS NTC
|
||||
* Thermistors Datasheet
|
||||
*/
|
||||
static const struct ntc_compensation b57330v2103[] = {
|
||||
{ .temp_c = -40, .ohm = 190030 },
|
||||
{ .temp_c = -35, .ohm = 145360 },
|
||||
{ .temp_c = -30, .ohm = 112060 },
|
||||
{ .temp_c = -25, .ohm = 87041 },
|
||||
{ .temp_c = -20, .ohm = 68104 },
|
||||
{ .temp_c = -15, .ohm = 53665 },
|
||||
{ .temp_c = -10, .ohm = 42576 },
|
||||
{ .temp_c = -5, .ohm = 34001 },
|
||||
{ .temp_c = 0, .ohm = 27326 },
|
||||
{ .temp_c = 5, .ohm = 22096 },
|
||||
{ .temp_c = 10, .ohm = 17973 },
|
||||
{ .temp_c = 15, .ohm = 14703 },
|
||||
{ .temp_c = 20, .ohm = 12090 },
|
||||
{ .temp_c = 25, .ohm = 10000 },
|
||||
{ .temp_c = 30, .ohm = 8311 },
|
||||
{ .temp_c = 35, .ohm = 6941 },
|
||||
{ .temp_c = 40, .ohm = 5825 },
|
||||
{ .temp_c = 45, .ohm = 4911 },
|
||||
{ .temp_c = 50, .ohm = 4158 },
|
||||
{ .temp_c = 55, .ohm = 3536 },
|
||||
{ .temp_c = 60, .ohm = 3019 },
|
||||
{ .temp_c = 65, .ohm = 2588 },
|
||||
{ .temp_c = 70, .ohm = 2227 },
|
||||
{ .temp_c = 75, .ohm = 1924 },
|
||||
{ .temp_c = 80, .ohm = 1668 },
|
||||
{ .temp_c = 85, .ohm = 1451 },
|
||||
{ .temp_c = 90, .ohm = 1266 },
|
||||
{ .temp_c = 95, .ohm = 1108 },
|
||||
{ .temp_c = 100, .ohm = 973 },
|
||||
{ .temp_c = 105, .ohm = 857 },
|
||||
{ .temp_c = 110, .ohm = 757 },
|
||||
{ .temp_c = 115, .ohm = 671 },
|
||||
{ .temp_c = 120, .ohm = 596 },
|
||||
{ .temp_c = 125, .ohm = 531 },
|
||||
};
|
||||
|
||||
struct ntc_data {
|
||||
struct device *hwmon_dev;
|
||||
struct ntc_thermistor_platform_data *pdata;
|
||||
|
@ -173,6 +215,8 @@ static const struct of_device_id ntc_match[] = {
|
|||
.data = &ntc_thermistor_id[3] },
|
||||
{ .compatible = "murata,ncp15wl333",
|
||||
.data = &ntc_thermistor_id[4] },
|
||||
{ .compatible = "epcos,b57330v2103",
|
||||
.data = &ntc_thermistor_id[5]},
|
||||
|
||||
/* Usage of vendor name "ntc" is deprecated */
|
||||
{ .compatible = "ntc,ncp15wb473",
|
||||
|
@ -490,6 +534,10 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
|
|||
data->comp = ncpXXwl333;
|
||||
data->n_comp = ARRAY_SIZE(ncpXXwl333);
|
||||
break;
|
||||
case TYPE_B57330V2103:
|
||||
data->comp = b57330v2103;
|
||||
data->n_comp = ARRAY_SIZE(b57330v2103);
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
|
||||
pdev_id->driver_data, pdev_id->name);
|
||||
|
@ -546,7 +594,7 @@ static struct platform_driver ntc_thermistor_driver = {
|
|||
|
||||
module_platform_driver(ntc_thermistor_driver);
|
||||
|
||||
MODULE_DESCRIPTION("NTC Thermistor Driver from Murata");
|
||||
MODULE_DESCRIPTION("NTC Thermistor Driver");
|
||||
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:ntc-thermistor");
|
||||
|
|
|
@ -20,8 +20,7 @@ config SENSORS_PMBUS
|
|||
help
|
||||
If you say yes here you get hardware monitoring support for generic
|
||||
PMBus devices, including but not limited to ADP4000, BMR453, BMR454,
|
||||
MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, UDT020, TPS40400,
|
||||
and TPS40422.
|
||||
MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, UDT020, and TPS40400.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called pmbus.
|
||||
|
@ -87,6 +86,16 @@ config SENSORS_MAX8688
|
|||
This driver can also be built as a module. If so, the module will
|
||||
be called max8688.
|
||||
|
||||
config SENSORS_TPS40422
|
||||
tristate "TI TPS40422"
|
||||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for TI
|
||||
TPS40422.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called tps40422.
|
||||
|
||||
config SENSORS_UCD9000
|
||||
tristate "TI UCD90120, UCD90124, UCD9090, UCD90910"
|
||||
default n
|
||||
|
|
|
@ -10,6 +10,7 @@ obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
|
|||
obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
|
||||
obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
|
||||
obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
|
||||
obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
|
||||
obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o
|
||||
obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o
|
||||
obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o
|
||||
|
|
|
@ -193,7 +193,6 @@ static const struct i2c_device_id pmbus_id[] = {
|
|||
{"pdt012", 1},
|
||||
{"pmbus", 0},
|
||||
{"tps40400", 1},
|
||||
{"tps40422", 2},
|
||||
{"udt020", 1},
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Hardware monitoring driver for TI TPS40422
|
||||
*
|
||||
* Copyright (c) 2014 Nokia Solutions and Networks.
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
static struct pmbus_driver_info tps40422_info = {
|
||||
.pages = 2,
|
||||
.format[PSC_VOLTAGE_IN] = linear,
|
||||
.format[PSC_VOLTAGE_OUT] = linear,
|
||||
.format[PSC_TEMPERATURE] = linear,
|
||||
.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_TEMP2
|
||||
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_TEMP
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
|
||||
.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_TEMP2
|
||||
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_TEMP
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
|
||||
};
|
||||
|
||||
static int tps40422_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
return pmbus_do_probe(client, id, &tps40422_info);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tps40422_id[] = {
|
||||
{"tps40422", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, tps40422_id);
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
static struct i2c_driver tps40422_driver = {
|
||||
.driver = {
|
||||
.name = "tps40422",
|
||||
},
|
||||
.probe = tps40422_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = tps40422_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(tps40422_driver);
|
||||
|
||||
MODULE_AUTHOR("Zhu Laiwen <richard.zhu@nsn.com>");
|
||||
MODULE_DESCRIPTION("PMBus driver for TI TPS40422");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,391 @@
|
|||
/*
|
||||
* powr1220.c - Driver for the Lattice POWR1220 programmable power supply
|
||||
* and monitor. Users can read all ADC inputs along with their labels
|
||||
* using the sysfs nodes.
|
||||
*
|
||||
* Copyright (c) 2014 Echo360 http://www.echo360.com
|
||||
* Scott Kanowitz <skanowitz@echo360.com> <scott.kanowitz@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/delay.h>
|
||||
|
||||
#define ADC_STEP_MV 2
|
||||
#define ADC_MAX_LOW_MEASUREMENT_MV 2000
|
||||
|
||||
enum powr1220_regs {
|
||||
VMON_STATUS0,
|
||||
VMON_STATUS1,
|
||||
VMON_STATUS2,
|
||||
OUTPUT_STATUS0,
|
||||
OUTPUT_STATUS1,
|
||||
OUTPUT_STATUS2,
|
||||
INPUT_STATUS,
|
||||
ADC_VALUE_LOW,
|
||||
ADC_VALUE_HIGH,
|
||||
ADC_MUX,
|
||||
UES_BYTE0,
|
||||
UES_BYTE1,
|
||||
UES_BYTE2,
|
||||
UES_BYTE3,
|
||||
GP_OUTPUT1,
|
||||
GP_OUTPUT2,
|
||||
GP_OUTPUT3,
|
||||
INPUT_VALUE,
|
||||
RESET,
|
||||
TRIM1_TRIM,
|
||||
TRIM2_TRIM,
|
||||
TRIM3_TRIM,
|
||||
TRIM4_TRIM,
|
||||
TRIM5_TRIM,
|
||||
TRIM6_TRIM,
|
||||
TRIM7_TRIM,
|
||||
TRIM8_TRIM,
|
||||
MAX_POWR1220_REGS
|
||||
};
|
||||
|
||||
enum powr1220_adc_values {
|
||||
VMON1,
|
||||
VMON2,
|
||||
VMON3,
|
||||
VMON4,
|
||||
VMON5,
|
||||
VMON6,
|
||||
VMON7,
|
||||
VMON8,
|
||||
VMON9,
|
||||
VMON10,
|
||||
VMON11,
|
||||
VMON12,
|
||||
VCCA,
|
||||
VCCINP,
|
||||
MAX_POWR1220_ADC_VALUES
|
||||
};
|
||||
|
||||
struct powr1220_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
bool adc_valid[MAX_POWR1220_ADC_VALUES];
|
||||
/* the next value is in jiffies */
|
||||
unsigned long adc_last_updated[MAX_POWR1220_ADC_VALUES];
|
||||
|
||||
/* values */
|
||||
int adc_maxes[MAX_POWR1220_ADC_VALUES];
|
||||
int adc_values[MAX_POWR1220_ADC_VALUES];
|
||||
};
|
||||
|
||||
static const char * const input_names[] = {
|
||||
[VMON1] = "vmon1",
|
||||
[VMON2] = "vmon2",
|
||||
[VMON3] = "vmon3",
|
||||
[VMON4] = "vmon4",
|
||||
[VMON5] = "vmon5",
|
||||
[VMON6] = "vmon6",
|
||||
[VMON7] = "vmon7",
|
||||
[VMON8] = "vmon8",
|
||||
[VMON9] = "vmon9",
|
||||
[VMON10] = "vmon10",
|
||||
[VMON11] = "vmon11",
|
||||
[VMON12] = "vmon12",
|
||||
[VCCA] = "vcca",
|
||||
[VCCINP] = "vccinp",
|
||||
};
|
||||
|
||||
/* Reads the specified ADC channel */
|
||||
static int powr1220_read_adc(struct device *dev, int ch_num)
|
||||
{
|
||||
struct powr1220_data *data = dev_get_drvdata(dev);
|
||||
int reading;
|
||||
int result;
|
||||
int adc_range = 0;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->adc_last_updated[ch_num] + HZ) ||
|
||||
!data->adc_valid[ch_num]) {
|
||||
/*
|
||||
* figure out if we need to use the attenuator for
|
||||
* high inputs or inputs that we don't yet have a measurement
|
||||
* for. We dynamically set the attenuator depending on the
|
||||
* max reading.
|
||||
*/
|
||||
if (data->adc_maxes[ch_num] > ADC_MAX_LOW_MEASUREMENT_MV ||
|
||||
data->adc_maxes[ch_num] == 0)
|
||||
adc_range = 1 << 4;
|
||||
|
||||
/* set the attenuator and mux */
|
||||
result = i2c_smbus_write_byte_data(data->client, ADC_MUX,
|
||||
adc_range | ch_num);
|
||||
if (result)
|
||||
goto exit;
|
||||
|
||||
/*
|
||||
* wait at least Tconvert time (200 us) for the
|
||||
* conversion to complete
|
||||
*/
|
||||
udelay(200);
|
||||
|
||||
/* get the ADC reading */
|
||||
result = i2c_smbus_read_byte_data(data->client, ADC_VALUE_LOW);
|
||||
if (result < 0)
|
||||
goto exit;
|
||||
|
||||
reading = result >> 4;
|
||||
|
||||
/* get the upper half of the reading */
|
||||
result = i2c_smbus_read_byte_data(data->client, ADC_VALUE_HIGH);
|
||||
if (result < 0)
|
||||
goto exit;
|
||||
|
||||
reading |= result << 4;
|
||||
|
||||
/* now convert the reading to a voltage */
|
||||
reading *= ADC_STEP_MV;
|
||||
data->adc_values[ch_num] = reading;
|
||||
data->adc_valid[ch_num] = true;
|
||||
data->adc_last_updated[ch_num] = jiffies;
|
||||
result = reading;
|
||||
|
||||
if (reading > data->adc_maxes[ch_num])
|
||||
data->adc_maxes[ch_num] = reading;
|
||||
} else {
|
||||
result = data->adc_values[ch_num];
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Shows the voltage associated with the specified ADC channel */
|
||||
static ssize_t powr1220_show_voltage(struct device *dev,
|
||||
struct device_attribute *dev_attr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
|
||||
int adc_val = powr1220_read_adc(dev, attr->index);
|
||||
|
||||
if (adc_val < 0)
|
||||
return adc_val;
|
||||
|
||||
return sprintf(buf, "%d\n", adc_val);
|
||||
}
|
||||
|
||||
/* Shows the maximum setting associated with the specified ADC channel */
|
||||
static ssize_t powr1220_show_max(struct device *dev,
|
||||
struct device_attribute *dev_attr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
|
||||
struct powr1220_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", data->adc_maxes[attr->index]);
|
||||
}
|
||||
|
||||
/* Shows the label associated with the specified ADC channel */
|
||||
static ssize_t powr1220_show_label(struct device *dev,
|
||||
struct device_attribute *dev_attr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
|
||||
|
||||
return sprintf(buf, "%s\n", input_names[attr->index]);
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VMON1);
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VMON2);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VMON3);
|
||||
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VMON4);
|
||||
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VMON5);
|
||||
static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VMON6);
|
||||
static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VMON7);
|
||||
static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VMON8);
|
||||
static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VMON9);
|
||||
static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VMON10);
|
||||
static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VMON11);
|
||||
static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VMON12);
|
||||
static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VCCA);
|
||||
static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, powr1220_show_voltage, NULL,
|
||||
VCCINP);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in0_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VMON1);
|
||||
static SENSOR_DEVICE_ATTR(in1_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VMON2);
|
||||
static SENSOR_DEVICE_ATTR(in2_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VMON3);
|
||||
static SENSOR_DEVICE_ATTR(in3_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VMON4);
|
||||
static SENSOR_DEVICE_ATTR(in4_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VMON5);
|
||||
static SENSOR_DEVICE_ATTR(in5_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VMON6);
|
||||
static SENSOR_DEVICE_ATTR(in6_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VMON7);
|
||||
static SENSOR_DEVICE_ATTR(in7_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VMON8);
|
||||
static SENSOR_DEVICE_ATTR(in8_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VMON9);
|
||||
static SENSOR_DEVICE_ATTR(in9_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VMON10);
|
||||
static SENSOR_DEVICE_ATTR(in10_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VMON11);
|
||||
static SENSOR_DEVICE_ATTR(in11_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VMON12);
|
||||
static SENSOR_DEVICE_ATTR(in12_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VCCA);
|
||||
static SENSOR_DEVICE_ATTR(in13_highest, S_IRUGO, powr1220_show_max, NULL,
|
||||
VCCINP);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VMON1);
|
||||
static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VMON2);
|
||||
static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VMON3);
|
||||
static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VMON4);
|
||||
static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VMON5);
|
||||
static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VMON6);
|
||||
static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VMON7);
|
||||
static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VMON8);
|
||||
static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VMON9);
|
||||
static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VMON10);
|
||||
static SENSOR_DEVICE_ATTR(in10_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VMON11);
|
||||
static SENSOR_DEVICE_ATTR(in11_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VMON12);
|
||||
static SENSOR_DEVICE_ATTR(in12_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VCCA);
|
||||
static SENSOR_DEVICE_ATTR(in13_label, S_IRUGO, powr1220_show_label, NULL,
|
||||
VCCINP);
|
||||
|
||||
static struct attribute *powr1220_attrs[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in9_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in10_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in11_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in12_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in13_input.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_in0_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in9_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in10_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in11_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in12_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_in13_highest.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_in0_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in9_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in10_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in11_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in12_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in13_label.dev_attr.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(powr1220);
|
||||
|
||||
static int powr1220_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct powr1220_data *data;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&data->update_lock);
|
||||
data->client = client;
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
|
||||
client->name, data, powr1220_groups);
|
||||
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id powr1220_ids[] = {
|
||||
{ "powr1220", 0, },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, powr1220_ids);
|
||||
|
||||
static struct i2c_driver powr1220_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "powr1220",
|
||||
},
|
||||
.probe = powr1220_probe,
|
||||
.id_table = powr1220_ids,
|
||||
};
|
||||
|
||||
module_i2c_driver(powr1220_driver);
|
||||
|
||||
MODULE_AUTHOR("Scott Kanowitz");
|
||||
MODULE_DESCRIPTION("POWR1220 driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* pwm-fan.c - Hwmon driver for fans connected to PWM lines.
|
||||
*
|
||||
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* Author: Kamil Debski <k.debski@samsung.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/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#define MAX_PWM 255
|
||||
|
||||
struct pwm_fan_ctx {
|
||||
struct mutex lock;
|
||||
struct pwm_device *pwm;
|
||||
unsigned char pwm_value;
|
||||
};
|
||||
|
||||
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
|
||||
unsigned long pwm, duty;
|
||||
ssize_t ret;
|
||||
|
||||
if (kstrtoul(buf, 10, &pwm) || pwm > MAX_PWM)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ctx->lock);
|
||||
|
||||
if (ctx->pwm_value == pwm)
|
||||
goto exit_set_pwm_no_change;
|
||||
|
||||
if (pwm == 0) {
|
||||
pwm_disable(ctx->pwm);
|
||||
goto exit_set_pwm;
|
||||
}
|
||||
|
||||
duty = DIV_ROUND_UP(pwm * (ctx->pwm->period - 1), MAX_PWM);
|
||||
ret = pwm_config(ctx->pwm, duty, ctx->pwm->period);
|
||||
if (ret)
|
||||
goto exit_set_pwm_err;
|
||||
|
||||
if (ctx->pwm_value == 0) {
|
||||
ret = pwm_enable(ctx->pwm);
|
||||
if (ret)
|
||||
goto exit_set_pwm_err;
|
||||
}
|
||||
|
||||
exit_set_pwm:
|
||||
ctx->pwm_value = pwm;
|
||||
exit_set_pwm_no_change:
|
||||
ret = count;
|
||||
exit_set_pwm_err:
|
||||
mutex_unlock(&ctx->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t show_pwm(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", ctx->pwm_value);
|
||||
}
|
||||
|
||||
|
||||
static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
|
||||
|
||||
static struct attribute *pwm_fan_attrs[] = {
|
||||
&sensor_dev_attr_pwm1.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(pwm_fan);
|
||||
|
||||
static int pwm_fan_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *hwmon;
|
||||
struct pwm_fan_ctx *ctx;
|
||||
int duty_cycle;
|
||||
int ret;
|
||||
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&ctx->lock);
|
||||
|
||||
ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL);
|
||||
if (IS_ERR(ctx->pwm)) {
|
||||
dev_err(&pdev->dev, "Could not get PWM\n");
|
||||
return PTR_ERR(ctx->pwm);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
/* Set duty cycle to maximum allowed */
|
||||
duty_cycle = ctx->pwm->period - 1;
|
||||
ctx->pwm_value = MAX_PWM;
|
||||
|
||||
ret = pwm_config(ctx->pwm, duty_cycle, ctx->pwm->period);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to configure PWM\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enbale PWM output */
|
||||
ret = pwm_enable(ctx->pwm);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to enable PWM\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "pwmfan",
|
||||
ctx, pwm_fan_groups);
|
||||
if (IS_ERR(hwmon)) {
|
||||
dev_err(&pdev->dev, "Failed to register hwmon device\n");
|
||||
pwm_disable(ctx->pwm);
|
||||
return PTR_ERR(hwmon);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pwm_fan_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev);
|
||||
|
||||
if (ctx->pwm_value)
|
||||
pwm_disable(ctx->pwm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pwm_fan_suspend(struct device *dev)
|
||||
{
|
||||
struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
|
||||
|
||||
if (ctx->pwm_value)
|
||||
pwm_disable(ctx->pwm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pwm_fan_resume(struct device *dev)
|
||||
{
|
||||
struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
|
||||
|
||||
if (ctx->pwm_value)
|
||||
return pwm_enable(ctx->pwm);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pwm_fan_pm, pwm_fan_suspend, pwm_fan_resume);
|
||||
|
||||
static struct of_device_id of_pwm_fan_match[] = {
|
||||
{ .compatible = "pwm-fan", },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver pwm_fan_driver = {
|
||||
.probe = pwm_fan_probe,
|
||||
.remove = pwm_fan_remove,
|
||||
.driver = {
|
||||
.name = "pwm-fan",
|
||||
.pm = &pwm_fan_pm,
|
||||
.of_match_table = of_pwm_fan_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(pwm_fan_driver);
|
||||
|
||||
MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
|
||||
MODULE_ALIAS("platform:pwm-fan");
|
||||
MODULE_DESCRIPTION("PWM FAN driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -45,7 +45,7 @@
|
|||
* @humidity: cached humidity measurement value
|
||||
*/
|
||||
struct sht21 {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
char valid;
|
||||
unsigned long last_update;
|
||||
|
@ -85,14 +85,15 @@ static inline int sht21_rh_ticks_to_per_cent_mille(int ticks)
|
|||
|
||||
/**
|
||||
* sht21_update_measurements() - get updated measurements from device
|
||||
* @client: I2C client device
|
||||
* @dev: device
|
||||
*
|
||||
* Returns 0 on success, else negative errno.
|
||||
*/
|
||||
static int sht21_update_measurements(struct i2c_client *client)
|
||||
static int sht21_update_measurements(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sht21 *sht21 = i2c_get_clientdata(client);
|
||||
struct sht21 *sht21 = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = sht21->client;
|
||||
|
||||
mutex_lock(&sht21->lock);
|
||||
/*
|
||||
|
@ -133,9 +134,10 @@ static ssize_t sht21_show_temperature(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct sht21 *sht21 = i2c_get_clientdata(client);
|
||||
int ret = sht21_update_measurements(client);
|
||||
struct sht21 *sht21 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = sht21_update_measurements(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", sht21->temperature);
|
||||
|
@ -154,9 +156,10 @@ static ssize_t sht21_show_humidity(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct sht21 *sht21 = i2c_get_clientdata(client);
|
||||
int ret = sht21_update_measurements(client);
|
||||
struct sht21 *sht21 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = sht21_update_measurements(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", sht21->humidity);
|
||||
|
@ -168,30 +171,20 @@ static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sht21_show_temperature,
|
|||
static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, sht21_show_humidity,
|
||||
NULL, 0);
|
||||
|
||||
static struct attribute *sht21_attributes[] = {
|
||||
static struct attribute *sht21_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_humidity1_input.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group sht21_attr_group = {
|
||||
.attrs = sht21_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(sht21);
|
||||
|
||||
/**
|
||||
* sht21_probe() - probe device
|
||||
* @client: I2C client device
|
||||
* @id: device ID
|
||||
*
|
||||
* Called by the I2C core when an entry in the ID table matches a
|
||||
* device's name.
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
static int sht21_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct sht21 *sht21;
|
||||
int err;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_WORD_DATA)) {
|
||||
|
@ -200,47 +193,17 @@ static int sht21_probe(struct i2c_client *client,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
sht21 = devm_kzalloc(&client->dev, sizeof(*sht21), GFP_KERNEL);
|
||||
sht21 = devm_kzalloc(dev, sizeof(*sht21), GFP_KERNEL);
|
||||
if (!sht21)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, sht21);
|
||||
sht21->client = client;
|
||||
|
||||
mutex_init(&sht21->lock);
|
||||
|
||||
err = sysfs_create_group(&client->dev.kobj, &sht21_attr_group);
|
||||
if (err) {
|
||||
dev_dbg(&client->dev, "could not create sysfs files\n");
|
||||
return err;
|
||||
}
|
||||
sht21->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(sht21->hwmon_dev)) {
|
||||
dev_dbg(&client->dev, "unable to register hwmon device\n");
|
||||
err = PTR_ERR(sht21->hwmon_dev);
|
||||
goto fail_remove_sysfs;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "initialized\n");
|
||||
|
||||
return 0;
|
||||
|
||||
fail_remove_sysfs:
|
||||
sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* sht21_remove() - remove device
|
||||
* @client: I2C client device
|
||||
*/
|
||||
static int sht21_remove(struct i2c_client *client)
|
||||
{
|
||||
struct sht21 *sht21 = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(sht21->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
sht21, sht21_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
/* Device ID table */
|
||||
|
@ -253,7 +216,6 @@ MODULE_DEVICE_TABLE(i2c, sht21_id);
|
|||
static struct i2c_driver sht21_driver = {
|
||||
.driver.name = "sht21",
|
||||
.probe = sht21_probe,
|
||||
.remove = sht21_remove,
|
||||
.id_table = sht21_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ static inline int TEMP_FROM_REG(s8 val)
|
|||
{
|
||||
return val * 830 + 52120;
|
||||
}
|
||||
static inline s8 TEMP_TO_REG(int val)
|
||||
static inline s8 TEMP_TO_REG(long val)
|
||||
{
|
||||
int nval = clamp_val(val, -54120, 157530) ;
|
||||
return nval < 0 ? (nval - 5212 - 415) / 830 : (nval - 5212 + 415) / 830;
|
||||
|
|
|
@ -140,7 +140,7 @@ enum chips { smm465, smm665, smm665c, smm764, smm766 };
|
|||
struct smm665_data {
|
||||
enum chips type;
|
||||
int conversion_time; /* ADC conversion time */
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
bool valid;
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
|
@ -239,8 +239,8 @@ static int smm665_read_adc(struct smm665_data *data, int adc)
|
|||
|
||||
static struct smm665_data *smm665_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct smm665_data *data = i2c_get_clientdata(client);
|
||||
struct smm665_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
struct smm665_data *ret = data;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
@ -315,32 +315,28 @@ static int smm665_convert(u16 adcval, int index)
|
|||
|
||||
static int smm665_get_min(struct device *dev, int index)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct smm665_data *data = i2c_get_clientdata(client);
|
||||
struct smm665_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return data->alarm_min_limit[index];
|
||||
}
|
||||
|
||||
static int smm665_get_max(struct device *dev, int index)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct smm665_data *data = i2c_get_clientdata(client);
|
||||
struct smm665_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return data->alarm_max_limit[index];
|
||||
}
|
||||
|
||||
static int smm665_get_lcrit(struct device *dev, int index)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct smm665_data *data = i2c_get_clientdata(client);
|
||||
struct smm665_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return data->critical_min_limit[index];
|
||||
}
|
||||
|
||||
static int smm665_get_crit(struct device *dev, int index)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct smm665_data *data = i2c_get_clientdata(client);
|
||||
struct smm665_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return data->critical_max_limit[index];
|
||||
}
|
||||
|
@ -486,7 +482,7 @@ SMM665_ATTR(temp1, crit_alarm, SMM665_FAULT_TEMP);
|
|||
* Finally, construct an array of pointers to members of the above objects,
|
||||
* as required for sysfs_create_group()
|
||||
*/
|
||||
static struct attribute *smm665_attributes[] = {
|
||||
static struct attribute *smm665_attrs[] = {
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_max.dev_attr.attr,
|
||||
|
@ -567,15 +563,14 @@ static struct attribute *smm665_attributes[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group smm665_group = {
|
||||
.attrs = smm665_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(smm665);
|
||||
|
||||
static int smm665_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct smm665_data *data;
|
||||
struct device *hwmon_dev;
|
||||
int i, ret;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
|
||||
|
@ -592,6 +587,7 @@ static int smm665_probe(struct i2c_client *client,
|
|||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
data->client = client;
|
||||
data->type = id->driver_data;
|
||||
data->cmdreg = i2c_new_dummy(adapter, (client->addr & ~SMM665_REGMASK)
|
||||
| SMM665_CMDREG_BASE);
|
||||
|
@ -662,21 +658,16 @@ static int smm665_probe(struct i2c_client *client,
|
|||
data->alarm_max_limit[i] = smm665_convert(val, i);
|
||||
}
|
||||
|
||||
/* Register sysfs hooks */
|
||||
ret = sysfs_create_group(&client->dev.kobj, &smm665_group);
|
||||
if (ret)
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
|
||||
client->name, data,
|
||||
smm665_groups);
|
||||
if (IS_ERR(hwmon_dev)) {
|
||||
ret = PTR_ERR(hwmon_dev);
|
||||
goto out_unregister;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
ret = PTR_ERR(data->hwmon_dev);
|
||||
goto out_remove_group;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_remove_group:
|
||||
sysfs_remove_group(&client->dev.kobj, &smm665_group);
|
||||
out_unregister:
|
||||
i2c_unregister_device(data->cmdreg);
|
||||
return ret;
|
||||
|
@ -687,9 +678,6 @@ static int smm665_remove(struct i2c_client *client)
|
|||
struct smm665_data *data = i2c_get_clientdata(client);
|
||||
|
||||
i2c_unregister_device(data->cmdreg);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &smm665_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -142,11 +142,6 @@ struct smsc47m1_sio_data {
|
|||
u8 activate; /* Remember initial device state */
|
||||
};
|
||||
|
||||
|
||||
static int __exit smsc47m1_remove(struct platform_device *pdev);
|
||||
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
|
||||
int init);
|
||||
|
||||
static inline int smsc47m1_read_value(struct smsc47m1_data *data, u8 reg)
|
||||
{
|
||||
return inb_p(data->addr + reg);
|
||||
|
@ -158,13 +153,54 @@ static inline void smsc47m1_write_value(struct smsc47m1_data *data, u8 reg,
|
|||
outb_p(value, data->addr + reg);
|
||||
}
|
||||
|
||||
static struct platform_driver smsc47m1_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRVNAME,
|
||||
},
|
||||
.remove = __exit_p(smsc47m1_remove),
|
||||
};
|
||||
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
|
||||
int init)
|
||||
{
|
||||
struct smsc47m1_data *data = dev_get_drvdata(dev);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
|
||||
int i, fan_nr;
|
||||
fan_nr = data->type == smsc47m2 ? 3 : 2;
|
||||
|
||||
for (i = 0; i < fan_nr; i++) {
|
||||
data->fan[i] = smsc47m1_read_value(data,
|
||||
SMSC47M1_REG_FAN[i]);
|
||||
data->fan_preload[i] = smsc47m1_read_value(data,
|
||||
SMSC47M1_REG_FAN_PRELOAD[i]);
|
||||
data->pwm[i] = smsc47m1_read_value(data,
|
||||
SMSC47M1_REG_PWM[i]);
|
||||
}
|
||||
|
||||
i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV);
|
||||
data->fan_div[0] = (i >> 4) & 0x03;
|
||||
data->fan_div[1] = i >> 6;
|
||||
|
||||
data->alarms = smsc47m1_read_value(data,
|
||||
SMSC47M1_REG_ALARM) >> 6;
|
||||
/* Clear alarms if needed */
|
||||
if (data->alarms)
|
||||
smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0);
|
||||
|
||||
if (fan_nr >= 3) {
|
||||
data->fan_div[2] = (smsc47m1_read_value(data,
|
||||
SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
|
||||
data->alarms |= (smsc47m1_read_value(data,
|
||||
SMSC47M2_REG_ALARM6) & 0x40) >> 4;
|
||||
/* Clear alarm if needed */
|
||||
if (data->alarms & 0x04)
|
||||
smsc47m1_write_value(data,
|
||||
SMSC47M2_REG_ALARM6,
|
||||
0x40);
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
static ssize_t get_fan(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
|
@ -811,54 +847,13 @@ static int __exit smsc47m1_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
|
||||
int init)
|
||||
{
|
||||
struct smsc47m1_data *data = dev_get_drvdata(dev);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
|
||||
int i, fan_nr;
|
||||
fan_nr = data->type == smsc47m2 ? 3 : 2;
|
||||
|
||||
for (i = 0; i < fan_nr; i++) {
|
||||
data->fan[i] = smsc47m1_read_value(data,
|
||||
SMSC47M1_REG_FAN[i]);
|
||||
data->fan_preload[i] = smsc47m1_read_value(data,
|
||||
SMSC47M1_REG_FAN_PRELOAD[i]);
|
||||
data->pwm[i] = smsc47m1_read_value(data,
|
||||
SMSC47M1_REG_PWM[i]);
|
||||
}
|
||||
|
||||
i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV);
|
||||
data->fan_div[0] = (i >> 4) & 0x03;
|
||||
data->fan_div[1] = i >> 6;
|
||||
|
||||
data->alarms = smsc47m1_read_value(data,
|
||||
SMSC47M1_REG_ALARM) >> 6;
|
||||
/* Clear alarms if needed */
|
||||
if (data->alarms)
|
||||
smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0);
|
||||
|
||||
if (fan_nr >= 3) {
|
||||
data->fan_div[2] = (smsc47m1_read_value(data,
|
||||
SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
|
||||
data->alarms |= (smsc47m1_read_value(data,
|
||||
SMSC47M2_REG_ALARM6) & 0x40) >> 4;
|
||||
/* Clear alarm if needed */
|
||||
if (data->alarms & 0x04)
|
||||
smsc47m1_write_value(data,
|
||||
SMSC47M2_REG_ALARM6,
|
||||
0x40);
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return data;
|
||||
}
|
||||
static struct platform_driver smsc47m1_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRVNAME,
|
||||
},
|
||||
.remove = __exit_p(smsc47m1_remove),
|
||||
};
|
||||
|
||||
static int __init smsc47m1_device_add(unsigned short address,
|
||||
const struct smsc47m1_sio_data *sio_data)
|
||||
|
|
|
@ -95,7 +95,8 @@ static inline int TEMP_FROM_REG(s8 val)
|
|||
}
|
||||
|
||||
struct smsc47m192_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
const struct attribute_group *groups[3];
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
@ -112,30 +113,69 @@ struct smsc47m192_data {
|
|||
u8 vrm;
|
||||
};
|
||||
|
||||
static int smsc47m192_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int smsc47m192_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info);
|
||||
static int smsc47m192_remove(struct i2c_client *client);
|
||||
static struct smsc47m192_data *smsc47m192_update_device(struct device *dev);
|
||||
static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
|
||||
{
|
||||
struct smsc47m192_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int i, config;
|
||||
|
||||
static const struct i2c_device_id smsc47m192_id[] = {
|
||||
{ "smsc47m192", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, smsc47m192_id);
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
static struct i2c_driver smsc47m192_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "smsc47m192",
|
||||
},
|
||||
.probe = smsc47m192_probe,
|
||||
.remove = smsc47m192_remove,
|
||||
.id_table = smsc47m192_id,
|
||||
.detect = smsc47m192_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
|
||||
|
||||
dev_dbg(&client->dev, "Starting smsc47m192 update\n");
|
||||
|
||||
for (i = 0; i <= 7; i++) {
|
||||
data->in[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_IN(i));
|
||||
data->in_min[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_IN_MIN(i));
|
||||
data->in_max[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_IN_MAX(i));
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
data->temp[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_TEMP[i]);
|
||||
data->temp_max[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_TEMP_MAX[i]);
|
||||
data->temp_min[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_TEMP_MIN[i]);
|
||||
}
|
||||
for (i = 1; i < 3; i++)
|
||||
data->temp_offset[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_TEMP_OFFSET(i));
|
||||
/*
|
||||
* first offset is temp_offset[0] if SFR bit 4 is set,
|
||||
* temp_offset[1] otherwise
|
||||
*/
|
||||
if (sfr & 0x10) {
|
||||
data->temp_offset[0] = data->temp_offset[1];
|
||||
data->temp_offset[1] = 0;
|
||||
} else
|
||||
data->temp_offset[0] = 0;
|
||||
|
||||
data->vid = i2c_smbus_read_byte_data(client, SMSC47M192_REG_VID)
|
||||
& 0x0f;
|
||||
config = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_CONFIG);
|
||||
if (config & 0x20)
|
||||
data->vid |= (i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_VID4) & 0x01) << 4;
|
||||
data->alarms = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_ALARM1) |
|
||||
(i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_ALARM2) << 8);
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Voltages */
|
||||
static ssize_t show_in(struct device *dev, struct device_attribute *attr,
|
||||
|
@ -170,8 +210,8 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct smsc47m192_data *data = i2c_get_clientdata(client);
|
||||
struct smsc47m192_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -192,8 +232,8 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct smsc47m192_data *data = i2c_get_clientdata(client);
|
||||
struct smsc47m192_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -259,8 +299,8 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct smsc47m192_data *data = i2c_get_clientdata(client);
|
||||
struct smsc47m192_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -281,8 +321,8 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct smsc47m192_data *data = i2c_get_clientdata(client);
|
||||
struct smsc47m192_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -312,8 +352,8 @@ static ssize_t set_temp_offset(struct device *dev, struct device_attribute
|
|||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct smsc47m192_data *data = i2c_get_clientdata(client);
|
||||
struct smsc47m192_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
|
||||
long val;
|
||||
int err;
|
||||
|
@ -552,124 +592,50 @@ static int smsc47m192_detect(struct i2c_client *client,
|
|||
static int smsc47m192_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct smsc47m192_data *data;
|
||||
int config;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct smsc47m192_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct smsc47m192_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
data->vrm = vid_which_vrm();
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the SMSC47M192 chip */
|
||||
smsc47m192_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &smsc47m192_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* sysfs hooks */
|
||||
data->groups[0] = &smsc47m192_group;
|
||||
/* Pin 110 is either in4 (+12V) or VID4 */
|
||||
config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
|
||||
if (!(config & 0x20)) {
|
||||
err = sysfs_create_group(&client->dev.kobj,
|
||||
&smsc47m192_group_in4);
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
}
|
||||
if (!(config & 0x20))
|
||||
data->groups[1] = &smsc47m192_group_in4;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->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(&client->dev.kobj, &smsc47m192_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
|
||||
return err;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, data->groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static int smsc47m192_remove(struct i2c_client *client)
|
||||
{
|
||||
struct smsc47m192_data *data = i2c_get_clientdata(client);
|
||||
static const struct i2c_device_id smsc47m192_id[] = {
|
||||
{ "smsc47m192", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, smsc47m192_id);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct smsc47m192_data *data = i2c_get_clientdata(client);
|
||||
int i, config;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
|
||||
|
||||
dev_dbg(&client->dev, "Starting smsc47m192 update\n");
|
||||
|
||||
for (i = 0; i <= 7; i++) {
|
||||
data->in[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_IN(i));
|
||||
data->in_min[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_IN_MIN(i));
|
||||
data->in_max[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_IN_MAX(i));
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
data->temp[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_TEMP[i]);
|
||||
data->temp_max[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_TEMP_MAX[i]);
|
||||
data->temp_min[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_TEMP_MIN[i]);
|
||||
}
|
||||
for (i = 1; i < 3; i++)
|
||||
data->temp_offset[i] = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_TEMP_OFFSET(i));
|
||||
/*
|
||||
* first offset is temp_offset[0] if SFR bit 4 is set,
|
||||
* temp_offset[1] otherwise
|
||||
*/
|
||||
if (sfr & 0x10) {
|
||||
data->temp_offset[0] = data->temp_offset[1];
|
||||
data->temp_offset[1] = 0;
|
||||
} else
|
||||
data->temp_offset[0] = 0;
|
||||
|
||||
data->vid = i2c_smbus_read_byte_data(client, SMSC47M192_REG_VID)
|
||||
& 0x0f;
|
||||
config = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_CONFIG);
|
||||
if (config & 0x20)
|
||||
data->vid |= (i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_VID4) & 0x01) << 4;
|
||||
data->alarms = i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_ALARM1) |
|
||||
(i2c_smbus_read_byte_data(client,
|
||||
SMSC47M192_REG_ALARM2) << 8);
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
static struct i2c_driver smsc47m192_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "smsc47m192",
|
||||
},
|
||||
.probe = smsc47m192_probe,
|
||||
.id_table = smsc47m192_id,
|
||||
.detect = smsc47m192_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(smsc47m192_driver);
|
||||
|
||||
|
|
|
@ -68,7 +68,8 @@ static const u8 THMC50_REG_TEMP_DEFAULT[] = { 0x17, 0x18, 0x18 };
|
|||
|
||||
/* Each client has this additional data */
|
||||
struct thmc50_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
const struct attribute_group *groups[3];
|
||||
|
||||
struct mutex update_lock;
|
||||
enum chips type;
|
||||
|
@ -85,32 +86,47 @@ struct thmc50_data {
|
|||
u8 alarms;
|
||||
};
|
||||
|
||||
static int thmc50_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info);
|
||||
static int thmc50_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int thmc50_remove(struct i2c_client *client);
|
||||
static void thmc50_init_client(struct i2c_client *client);
|
||||
static struct thmc50_data *thmc50_update_device(struct device *dev);
|
||||
static struct thmc50_data *thmc50_update_device(struct device *dev)
|
||||
{
|
||||
struct thmc50_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int timeout = HZ / 5 + (data->type == thmc50 ? HZ : 0);
|
||||
|
||||
static const struct i2c_device_id thmc50_id[] = {
|
||||
{ "adm1022", adm1022 },
|
||||
{ "thmc50", thmc50 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, thmc50_id);
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
static struct i2c_driver thmc50_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "thmc50",
|
||||
},
|
||||
.probe = thmc50_probe,
|
||||
.remove = thmc50_remove,
|
||||
.id_table = thmc50_id,
|
||||
.detect = thmc50_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
if (time_after(jiffies, data->last_updated + timeout)
|
||||
|| !data->valid) {
|
||||
|
||||
int temps = data->has_temp3 ? 3 : 2;
|
||||
int i;
|
||||
int prog = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
|
||||
|
||||
prog &= THMC50_REG_CONF_PROGRAMMED;
|
||||
|
||||
for (i = 0; i < temps; i++) {
|
||||
data->temp_input[i] = i2c_smbus_read_byte_data(client,
|
||||
THMC50_REG_TEMP[i]);
|
||||
data->temp_max[i] = i2c_smbus_read_byte_data(client,
|
||||
THMC50_REG_TEMP_MAX[i]);
|
||||
data->temp_min[i] = i2c_smbus_read_byte_data(client,
|
||||
THMC50_REG_TEMP_MIN[i]);
|
||||
data->temp_critical[i] =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
prog ? THMC50_REG_TEMP_CRITICAL[i]
|
||||
: THMC50_REG_TEMP_DEFAULT[i]);
|
||||
}
|
||||
data->analog_out =
|
||||
i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
|
||||
data->alarms =
|
||||
i2c_smbus_read_byte_data(client, THMC50_REG_INTR);
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static ssize_t show_analog_out(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
|
@ -123,8 +139,8 @@ static ssize_t set_analog_out(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct thmc50_data *data = i2c_get_clientdata(client);
|
||||
struct thmc50_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int config;
|
||||
unsigned long tmp;
|
||||
int err;
|
||||
|
@ -177,8 +193,8 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct thmc50_data *data = i2c_get_clientdata(client);
|
||||
struct thmc50_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -206,8 +222,8 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct thmc50_data *data = i2c_get_clientdata(client);
|
||||
struct thmc50_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -355,67 +371,9 @@ static int thmc50_detect(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int thmc50_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static void thmc50_init_client(struct thmc50_data *data)
|
||||
{
|
||||
struct thmc50_data *data;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct thmc50_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->type = id->driver_data;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
thmc50_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &thmc50_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Register ADM1022 sysfs hooks */
|
||||
if (data->has_temp3) {
|
||||
err = sysfs_create_group(&client->dev.kobj, &temp3_group);
|
||||
if (err)
|
||||
goto exit_remove_sysfs_thmc50;
|
||||
}
|
||||
|
||||
/* Register a new directory entry with module sensors */
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_sysfs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_sysfs:
|
||||
if (data->has_temp3)
|
||||
sysfs_remove_group(&client->dev.kobj, &temp3_group);
|
||||
exit_remove_sysfs_thmc50:
|
||||
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int thmc50_remove(struct i2c_client *client)
|
||||
{
|
||||
struct thmc50_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
|
||||
if (data->has_temp3)
|
||||
sysfs_remove_group(&client->dev.kobj, &temp3_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void thmc50_init_client(struct i2c_client *client)
|
||||
{
|
||||
struct thmc50_data *data = i2c_get_clientdata(client);
|
||||
struct i2c_client *client = data->client;
|
||||
int config;
|
||||
|
||||
data->analog_out = i2c_smbus_read_byte_data(client,
|
||||
|
@ -433,48 +391,54 @@ static void thmc50_init_client(struct i2c_client *client)
|
|||
i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
|
||||
}
|
||||
|
||||
static struct thmc50_data *thmc50_update_device(struct device *dev)
|
||||
static int thmc50_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct thmc50_data *data = i2c_get_clientdata(client);
|
||||
int timeout = HZ / 5 + (data->type == thmc50 ? HZ : 0);
|
||||
struct device *dev = &client->dev;
|
||||
struct thmc50_data *data;
|
||||
struct device *hwmon_dev;
|
||||
int idx = 0;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data = devm_kzalloc(dev, sizeof(struct thmc50_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (time_after(jiffies, data->last_updated + timeout)
|
||||
|| !data->valid) {
|
||||
data->client = client;
|
||||
data->type = id->driver_data;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
int temps = data->has_temp3 ? 3 : 2;
|
||||
int i;
|
||||
int prog = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
|
||||
thmc50_init_client(data);
|
||||
|
||||
prog &= THMC50_REG_CONF_PROGRAMMED;
|
||||
/* sysfs hooks */
|
||||
data->groups[idx++] = &thmc50_group;
|
||||
|
||||
for (i = 0; i < temps; i++) {
|
||||
data->temp_input[i] = i2c_smbus_read_byte_data(client,
|
||||
THMC50_REG_TEMP[i]);
|
||||
data->temp_max[i] = i2c_smbus_read_byte_data(client,
|
||||
THMC50_REG_TEMP_MAX[i]);
|
||||
data->temp_min[i] = i2c_smbus_read_byte_data(client,
|
||||
THMC50_REG_TEMP_MIN[i]);
|
||||
data->temp_critical[i] =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
prog ? THMC50_REG_TEMP_CRITICAL[i]
|
||||
: THMC50_REG_TEMP_DEFAULT[i]);
|
||||
}
|
||||
data->analog_out =
|
||||
i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
|
||||
data->alarms =
|
||||
i2c_smbus_read_byte_data(client, THMC50_REG_INTR);
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
/* Register additional ADM1022 sysfs hooks */
|
||||
if (data->has_temp3)
|
||||
data->groups[idx++] = &temp3_group;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, data->groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id thmc50_id[] = {
|
||||
{ "adm1022", adm1022 },
|
||||
{ "thmc50", thmc50 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, thmc50_id);
|
||||
|
||||
static struct i2c_driver thmc50_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "thmc50",
|
||||
},
|
||||
.probe = thmc50_probe,
|
||||
.id_table = thmc50_id,
|
||||
.detect = thmc50_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(thmc50_driver);
|
||||
|
||||
MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Texas Instruments TMP103 SMBus temperature sensor driver
|
||||
* Copyright (C) 2014 Heiko Schocher <hs@denx.de>
|
||||
*
|
||||
* Based on:
|
||||
* Texas Instruments TMP102 SMBus temperature sensor driver
|
||||
*
|
||||
* Copyright (C) 2010 Steven King <sfking@fdwdc.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/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define TMP103_TEMP_REG 0x00
|
||||
#define TMP103_CONF_REG 0x01
|
||||
#define TMP103_TLOW_REG 0x02
|
||||
#define TMP103_THIGH_REG 0x03
|
||||
|
||||
#define TMP103_CONF_M0 0x01
|
||||
#define TMP103_CONF_M1 0x02
|
||||
#define TMP103_CONF_LC 0x04
|
||||
#define TMP103_CONF_FL 0x08
|
||||
#define TMP103_CONF_FH 0x10
|
||||
#define TMP103_CONF_CR0 0x20
|
||||
#define TMP103_CONF_CR1 0x40
|
||||
#define TMP103_CONF_ID 0x80
|
||||
#define TMP103_CONF_SD (TMP103_CONF_M1)
|
||||
#define TMP103_CONF_SD_MASK (TMP103_CONF_M0 | TMP103_CONF_M1)
|
||||
|
||||
#define TMP103_CONFIG (TMP103_CONF_CR1 | TMP103_CONF_M1)
|
||||
#define TMP103_CONFIG_MASK (TMP103_CONF_CR0 | TMP103_CONF_CR1 | \
|
||||
TMP103_CONF_M0 | TMP103_CONF_M1)
|
||||
|
||||
static inline int tmp103_reg_to_mc(s8 val)
|
||||
{
|
||||
return val * 1000;
|
||||
}
|
||||
|
||||
static inline u8 tmp103_mc_to_reg(int val)
|
||||
{
|
||||
return DIV_ROUND_CLOSEST(val, 1000);
|
||||
}
|
||||
|
||||
static ssize_t tmp103_show_temp(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
unsigned int regval;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(regmap, sda->index, ®val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", tmp103_reg_to_mc(regval));
|
||||
}
|
||||
|
||||
static ssize_t tmp103_set_temp(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
long val;
|
||||
int ret;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
val = clamp_val(val, -55000, 127000);
|
||||
ret = regmap_write(regmap, sda->index, tmp103_mc_to_reg(val));
|
||||
return ret ? ret : count;
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tmp103_show_temp, NULL ,
|
||||
TMP103_TEMP_REG);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, tmp103_show_temp,
|
||||
tmp103_set_temp, TMP103_TLOW_REG);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp103_show_temp,
|
||||
tmp103_set_temp, TMP103_THIGH_REG);
|
||||
|
||||
static struct attribute *tmp103_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(tmp103);
|
||||
|
||||
static bool tmp103_regmap_is_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return reg == TMP103_TEMP_REG;
|
||||
}
|
||||
|
||||
static const struct regmap_config tmp103_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = TMP103_THIGH_REG,
|
||||
.volatile_reg = tmp103_regmap_is_volatile,
|
||||
};
|
||||
|
||||
static int tmp103_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct regmap *regmap;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
dev_err(&client->dev,
|
||||
"adapter doesn't support SMBus byte transactions\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &tmp103_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(dev, "failed to allocate register map\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(regmap, TMP103_CONF_REG, TMP103_CONFIG_MASK,
|
||||
TMP103_CONFIG);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "error writing config register\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, regmap);
|
||||
hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
|
||||
regmap, tmp103_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int tmp103_suspend(struct device *dev)
|
||||
{
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
|
||||
return regmap_update_bits(regmap, TMP103_CONF_REG,
|
||||
TMP103_CONF_SD_MASK, 0);
|
||||
}
|
||||
|
||||
static int tmp103_resume(struct device *dev)
|
||||
{
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
|
||||
return regmap_update_bits(regmap, TMP103_CONF_REG,
|
||||
TMP103_CONF_SD_MASK, TMP103_CONF_SD);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops tmp103_dev_pm_ops = {
|
||||
.suspend = tmp103_suspend,
|
||||
.resume = tmp103_resume,
|
||||
};
|
||||
|
||||
#define TMP103_DEV_PM_OPS (&tmp103_dev_pm_ops)
|
||||
#else
|
||||
#define TMP103_DEV_PM_OPS NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct i2c_device_id tmp103_id[] = {
|
||||
{ "tmp103", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tmp103_id);
|
||||
|
||||
static struct i2c_driver tmp103_driver = {
|
||||
.driver = {
|
||||
.name = "tmp103",
|
||||
.pm = TMP103_DEV_PM_OPS,
|
||||
},
|
||||
.probe = tmp103_probe,
|
||||
.id_table = tmp103_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(tmp103_driver);
|
||||
|
||||
MODULE_AUTHOR("Heiko Schocher <hs@denx.de>");
|
||||
MODULE_DESCRIPTION("Texas Instruments TMP103 temperature sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -13,15 +13,11 @@
|
|||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Driver for the Texas Instruments TMP421 SMBus temperature sensor IC.
|
||||
* Supported models: TMP421, TMP422, TMP423
|
||||
* Supported models: TMP421, TMP422, TMP423, TMP441, TMP442
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -39,9 +35,10 @@
|
|||
static const unsigned short normal_i2c[] = { 0x2a, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
I2C_CLIENT_END };
|
||||
|
||||
enum chips { tmp421, tmp422, tmp423 };
|
||||
enum chips { tmp421, tmp422, tmp423, tmp441, tmp442 };
|
||||
|
||||
/* The TMP421 registers */
|
||||
#define TMP421_STATUS_REG 0x08
|
||||
#define TMP421_CONFIG_REG_1 0x09
|
||||
#define TMP421_CONVERSION_RATE_REG 0x0B
|
||||
#define TMP421_MANUFACTURER_ID_REG 0xFE
|
||||
|
@ -59,11 +56,15 @@ static const u8 TMP421_TEMP_LSB[4] = { 0x10, 0x11, 0x12, 0x13 };
|
|||
#define TMP421_DEVICE_ID 0x21
|
||||
#define TMP422_DEVICE_ID 0x22
|
||||
#define TMP423_DEVICE_ID 0x23
|
||||
#define TMP441_DEVICE_ID 0x41
|
||||
#define TMP442_DEVICE_ID 0x42
|
||||
|
||||
static const struct i2c_device_id tmp421_id[] = {
|
||||
{ "tmp421", 2 },
|
||||
{ "tmp422", 3 },
|
||||
{ "tmp423", 4 },
|
||||
{ "tmp441", 2 },
|
||||
{ "tmp442", 3 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tmp421_id);
|
||||
|
@ -234,7 +235,9 @@ static int tmp421_detect(struct i2c_client *client,
|
|||
{
|
||||
enum chips kind;
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
const char *names[] = { "TMP421", "TMP422", "TMP423" };
|
||||
const char * const names[] = { "TMP421", "TMP422", "TMP423",
|
||||
"TMP441", "TMP442" };
|
||||
int addr = client->addr;
|
||||
u8 reg;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
|
@ -244,17 +247,37 @@ static int tmp421_detect(struct i2c_client *client,
|
|||
if (reg != TMP421_MANUFACTURER_ID)
|
||||
return -ENODEV;
|
||||
|
||||
reg = i2c_smbus_read_byte_data(client, TMP421_CONVERSION_RATE_REG);
|
||||
if (reg & 0xf8)
|
||||
return -ENODEV;
|
||||
|
||||
reg = i2c_smbus_read_byte_data(client, TMP421_STATUS_REG);
|
||||
if (reg & 0x7f)
|
||||
return -ENODEV;
|
||||
|
||||
reg = i2c_smbus_read_byte_data(client, TMP421_DEVICE_ID_REG);
|
||||
switch (reg) {
|
||||
case TMP421_DEVICE_ID:
|
||||
kind = tmp421;
|
||||
break;
|
||||
case TMP422_DEVICE_ID:
|
||||
if (addr == 0x2a)
|
||||
return -ENODEV;
|
||||
kind = tmp422;
|
||||
break;
|
||||
case TMP423_DEVICE_ID:
|
||||
if (addr != 0x4c && addr != 0x4d)
|
||||
return -ENODEV;
|
||||
kind = tmp423;
|
||||
break;
|
||||
case TMP441_DEVICE_ID:
|
||||
kind = tmp441;
|
||||
break;
|
||||
case TMP442_DEVICE_ID:
|
||||
if (addr != 0x4c && addr != 0x4d)
|
||||
return -ENODEV;
|
||||
kind = tmp442;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -305,5 +328,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/441/442 temperature sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -74,7 +74,7 @@ static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, madc_read, NULL, 11);
|
|||
static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, madc_read, NULL, 12);
|
||||
static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, madc_read, NULL, 15);
|
||||
|
||||
static struct attribute *twl4030_madc_attributes[] = {
|
||||
static struct attribute *twl4030_madc_attrs[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
|
@ -91,46 +91,20 @@ static struct attribute *twl4030_madc_attributes[] = {
|
|||
&sensor_dev_attr_in15_input.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group twl4030_madc_group = {
|
||||
.attrs = twl4030_madc_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(twl4030_madc);
|
||||
|
||||
static int twl4030_madc_hwmon_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct device *hwmon;
|
||||
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &twl4030_madc_group);
|
||||
if (ret)
|
||||
goto err_sysfs;
|
||||
hwmon = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(hwmon)) {
|
||||
dev_err(&pdev->dev, "hwmon_device_register failed.\n");
|
||||
ret = PTR_ERR(hwmon);
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &twl4030_madc_group);
|
||||
err_sysfs:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int twl4030_madc_hwmon_remove(struct platform_device *pdev)
|
||||
{
|
||||
hwmon_device_unregister(&pdev->dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &twl4030_madc_group);
|
||||
|
||||
return 0;
|
||||
hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
|
||||
"twl4030_madc", NULL,
|
||||
twl4030_madc_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon);
|
||||
}
|
||||
|
||||
static struct platform_driver twl4030_madc_hwmon_driver = {
|
||||
.probe = twl4030_madc_hwmon_probe,
|
||||
.remove = twl4030_madc_hwmon_remove,
|
||||
.driver = {
|
||||
.name = "twl4030_madc_hwmon",
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -249,19 +249,16 @@ static u8 fan_to_reg(long rpm, int div)
|
|||
* the bottom 7 bits will always be zero
|
||||
*/
|
||||
#define TEMP23_FROM_REG(val) ((val) / 128 * 500)
|
||||
#define TEMP23_TO_REG(val) ((val) <= -128000 ? 0x8000 : \
|
||||
(val) >= 127500 ? 0x7F80 : \
|
||||
(val) < 0 ? ((val) - 250) / 500 * 128 : \
|
||||
((val) + 250) / 500 * 128)
|
||||
#define TEMP23_TO_REG(val) (DIV_ROUND_CLOSEST(clamp_val((val), -128000, \
|
||||
127500), 500) * 128)
|
||||
|
||||
/* for thermal cruise target temp, 7-bits, LSB = 1 degree Celsius */
|
||||
#define TARGET_TEMP_TO_REG(val) ((val) < 0 ? 0 : \
|
||||
(val) >= 127000 ? 127 : \
|
||||
((val) + 500) / 1000)
|
||||
#define TARGET_TEMP_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val((val), 0, 127000), \
|
||||
1000)
|
||||
|
||||
/* for thermal cruise temp tolerance, 4-bits, LSB = 1 degree Celsius */
|
||||
#define TOL_TEMP_TO_REG(val) ((val) >= 15000 ? 15 : \
|
||||
((val) + 500) / 1000)
|
||||
#define TOL_TEMP_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val((val), 0, 15000), \
|
||||
1000)
|
||||
|
||||
#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff)
|
||||
#define BEEP_MASK_FROM_REG(val) ((val) & 0xffffff)
|
||||
|
|
|
@ -124,7 +124,7 @@ DIV_TO_REG(long val)
|
|||
}
|
||||
|
||||
struct w83l786ng_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
@ -148,32 +148,6 @@ struct w83l786ng_data {
|
|||
u8 tolerance[2];
|
||||
};
|
||||
|
||||
static int w83l786ng_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
static int w83l786ng_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info);
|
||||
static int w83l786ng_remove(struct i2c_client *client);
|
||||
static void w83l786ng_init_client(struct i2c_client *client);
|
||||
static struct w83l786ng_data *w83l786ng_update_device(struct device *dev);
|
||||
|
||||
static const struct i2c_device_id w83l786ng_id[] = {
|
||||
{ "w83l786ng", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, w83l786ng_id);
|
||||
|
||||
static struct i2c_driver w83l786ng_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "w83l786ng",
|
||||
},
|
||||
.probe = w83l786ng_probe,
|
||||
.remove = w83l786ng_remove,
|
||||
.id_table = w83l786ng_id,
|
||||
.detect = w83l786ng_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static u8
|
||||
w83l786ng_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
|
@ -186,6 +160,77 @@ w83l786ng_write_value(struct i2c_client *client, u8 reg, u8 value)
|
|||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static struct w83l786ng_data *w83l786ng_update_device(struct device *dev)
|
||||
{
|
||||
struct w83l786ng_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int i, j;
|
||||
u8 reg_tmp, pwmcfg;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
dev_dbg(&client->dev, "Updating w83l786ng data.\n");
|
||||
|
||||
/* Update the voltages measured value and limits */
|
||||
for (i = 0; i < 3; i++) {
|
||||
data->in[i] = w83l786ng_read_value(client,
|
||||
W83L786NG_REG_IN(i));
|
||||
data->in_min[i] = w83l786ng_read_value(client,
|
||||
W83L786NG_REG_IN_MIN(i));
|
||||
data->in_max[i] = w83l786ng_read_value(client,
|
||||
W83L786NG_REG_IN_MAX(i));
|
||||
}
|
||||
|
||||
/* Update the fan counts and limits */
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->fan[i] = w83l786ng_read_value(client,
|
||||
W83L786NG_REG_FAN(i));
|
||||
data->fan_min[i] = w83l786ng_read_value(client,
|
||||
W83L786NG_REG_FAN_MIN(i));
|
||||
}
|
||||
|
||||
/* Update the fan divisor */
|
||||
reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV);
|
||||
data->fan_div[0] = reg_tmp & 0x07;
|
||||
data->fan_div[1] = (reg_tmp >> 4) & 0x07;
|
||||
|
||||
pwmcfg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG);
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->pwm_mode[i] =
|
||||
((pwmcfg >> W83L786NG_PWM_MODE_SHIFT[i]) & 1)
|
||||
? 0 : 1;
|
||||
data->pwm_enable[i] =
|
||||
((pwmcfg >> W83L786NG_PWM_ENABLE_SHIFT[i]) & 3) + 1;
|
||||
data->pwm[i] =
|
||||
(w83l786ng_read_value(client, W83L786NG_REG_PWM[i])
|
||||
& 0x0f) * 0x11;
|
||||
}
|
||||
|
||||
|
||||
/* Update the temperature sensors */
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
data->temp[i][j] = w83l786ng_read_value(client,
|
||||
W83L786NG_REG_TEMP[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update Smart Fan I/II tolerance */
|
||||
reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_TOLERANCE);
|
||||
data->tolerance[0] = reg_tmp & 0x0f;
|
||||
data->tolerance[1] = (reg_tmp >> 4) & 0x0f;
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/* following are the sysfs callback functions */
|
||||
#define show_in_reg(reg) \
|
||||
static ssize_t \
|
||||
|
@ -207,8 +252,8 @@ store_in_##reg(struct device *dev, struct device_attribute *attr, \
|
|||
const char *buf, size_t count) \
|
||||
{ \
|
||||
int nr = to_sensor_dev_attr(attr)->index; \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct w83l786ng_data *data = i2c_get_clientdata(client); \
|
||||
struct w83l786ng_data *data = dev_get_drvdata(dev); \
|
||||
struct i2c_client *client = data->client; \
|
||||
unsigned long val; \
|
||||
int err = kstrtoul(buf, 10, &val); \
|
||||
if (err) \
|
||||
|
@ -260,8 +305,8 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83l786ng_data *data = i2c_get_clientdata(client);
|
||||
struct w83l786ng_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -298,8 +343,8 @@ store_fan_div(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83l786ng_data *data = i2c_get_clientdata(client);
|
||||
struct w83l786ng_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
unsigned long min;
|
||||
u8 tmp_fan_div;
|
||||
|
@ -389,8 +434,8 @@ store_temp(struct device *dev, struct device_attribute *attr,
|
|||
to_sensor_dev_attr_2(attr);
|
||||
int nr = sensor_attr->nr;
|
||||
int index = sensor_attr->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83l786ng_data *data = i2c_get_clientdata(client);
|
||||
struct w83l786ng_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
|
@ -444,8 +489,8 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83l786ng_data *data = i2c_get_clientdata(client);
|
||||
struct w83l786ng_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 reg;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -472,8 +517,8 @@ store_pwm(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83l786ng_data *data = i2c_get_clientdata(client);
|
||||
struct w83l786ng_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
|
@ -496,8 +541,8 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83l786ng_data *data = i2c_get_clientdata(client);
|
||||
struct w83l786ng_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 reg;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -552,8 +597,8 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83l786ng_data *data = i2c_get_clientdata(client);
|
||||
struct w83l786ng_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u8 tol_tmp, tol_mask;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
@ -608,7 +653,7 @@ static struct sensor_device_attribute sda_tolerance[] = {
|
|||
#define TOLERANCE_UNIT_ATTRS(X) \
|
||||
&sda_tolerance[X].dev_attr.attr
|
||||
|
||||
static struct attribute *w83l786ng_attributes[] = {
|
||||
static struct attribute *w83l786ng_attrs[] = {
|
||||
IN_UNIT_ATTRS(0),
|
||||
IN_UNIT_ATTRS(1),
|
||||
IN_UNIT_ATTRS(2),
|
||||
|
@ -623,9 +668,7 @@ static struct attribute *w83l786ng_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group w83l786ng_group = {
|
||||
.attrs = w83l786ng_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(w83l786ng);
|
||||
|
||||
static int
|
||||
w83l786ng_detect(struct i2c_client *client, struct i2c_board_info *info)
|
||||
|
@ -662,20 +705,33 @@ w83l786ng_detect(struct i2c_client *client, struct i2c_board_info *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void w83l786ng_init_client(struct i2c_client *client)
|
||||
{
|
||||
u8 tmp;
|
||||
|
||||
if (reset)
|
||||
w83l786ng_write_value(client, W83L786NG_REG_CONFIG, 0x80);
|
||||
|
||||
/* Start monitoring */
|
||||
tmp = w83l786ng_read_value(client, W83L786NG_REG_CONFIG);
|
||||
if (!(tmp & 0x01))
|
||||
w83l786ng_write_value(client, W83L786NG_REG_CONFIG, tmp | 0x01);
|
||||
}
|
||||
|
||||
static int
|
||||
w83l786ng_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct w83l786ng_data *data;
|
||||
int i, err = 0;
|
||||
struct device *hwmon_dev;
|
||||
int i;
|
||||
u8 reg_tmp;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct w83l786ng_data),
|
||||
GFP_KERNEL);
|
||||
data = devm_kzalloc(dev, sizeof(struct w83l786ng_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the chip */
|
||||
|
@ -692,121 +748,28 @@ w83l786ng_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
data->fan_div[0] = reg_tmp & 0x07;
|
||||
data->fan_div[1] = (reg_tmp >> 4) & 0x07;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &w83l786ng_group);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
/* Unregister sysfs hooks */
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
|
||||
return err;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
w83l786ng_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static int
|
||||
w83l786ng_remove(struct i2c_client *client)
|
||||
{
|
||||
struct w83l786ng_data *data = i2c_get_clientdata(client);
|
||||
static const struct i2c_device_id w83l786ng_id[] = {
|
||||
{ "w83l786ng", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, w83l786ng_id);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
w83l786ng_init_client(struct i2c_client *client)
|
||||
{
|
||||
u8 tmp;
|
||||
|
||||
if (reset)
|
||||
w83l786ng_write_value(client, W83L786NG_REG_CONFIG, 0x80);
|
||||
|
||||
/* Start monitoring */
|
||||
tmp = w83l786ng_read_value(client, W83L786NG_REG_CONFIG);
|
||||
if (!(tmp & 0x01))
|
||||
w83l786ng_write_value(client, W83L786NG_REG_CONFIG, tmp | 0x01);
|
||||
}
|
||||
|
||||
static struct w83l786ng_data *w83l786ng_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83l786ng_data *data = i2c_get_clientdata(client);
|
||||
int i, j;
|
||||
u8 reg_tmp, pwmcfg;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
dev_dbg(&client->dev, "Updating w83l786ng data.\n");
|
||||
|
||||
/* Update the voltages measured value and limits */
|
||||
for (i = 0; i < 3; i++) {
|
||||
data->in[i] = w83l786ng_read_value(client,
|
||||
W83L786NG_REG_IN(i));
|
||||
data->in_min[i] = w83l786ng_read_value(client,
|
||||
W83L786NG_REG_IN_MIN(i));
|
||||
data->in_max[i] = w83l786ng_read_value(client,
|
||||
W83L786NG_REG_IN_MAX(i));
|
||||
}
|
||||
|
||||
/* Update the fan counts and limits */
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->fan[i] = w83l786ng_read_value(client,
|
||||
W83L786NG_REG_FAN(i));
|
||||
data->fan_min[i] = w83l786ng_read_value(client,
|
||||
W83L786NG_REG_FAN_MIN(i));
|
||||
}
|
||||
|
||||
/* Update the fan divisor */
|
||||
reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV);
|
||||
data->fan_div[0] = reg_tmp & 0x07;
|
||||
data->fan_div[1] = (reg_tmp >> 4) & 0x07;
|
||||
|
||||
pwmcfg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG);
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->pwm_mode[i] =
|
||||
((pwmcfg >> W83L786NG_PWM_MODE_SHIFT[i]) & 1)
|
||||
? 0 : 1;
|
||||
data->pwm_enable[i] =
|
||||
((pwmcfg >> W83L786NG_PWM_ENABLE_SHIFT[i]) & 3) + 1;
|
||||
data->pwm[i] =
|
||||
(w83l786ng_read_value(client, W83L786NG_REG_PWM[i])
|
||||
& 0x0f) * 0x11;
|
||||
}
|
||||
|
||||
|
||||
/* Update the temperature sensors */
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
data->temp[i][j] = w83l786ng_read_value(client,
|
||||
W83L786NG_REG_TEMP[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update Smart Fan I/II tolerance */
|
||||
reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_TOLERANCE);
|
||||
data->tolerance[0] = reg_tmp & 0x0f;
|
||||
data->tolerance[1] = (reg_tmp >> 4) & 0x0f;
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
static struct i2c_driver w83l786ng_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "w83l786ng",
|
||||
},
|
||||
.probe = w83l786ng_probe,
|
||||
.id_table = w83l786ng_id,
|
||||
.detect = w83l786ng_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(w83l786ng_driver);
|
||||
|
||||
|
|
|
@ -29,17 +29,6 @@
|
|||
#include <linux/mfd/wm831x/core.h>
|
||||
#include <linux/mfd/wm831x/auxadc.h>
|
||||
|
||||
struct wm831x_hwmon {
|
||||
struct wm831x *wm831x;
|
||||
struct device *classdev;
|
||||
};
|
||||
|
||||
static ssize_t show_name(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "wm831x\n");
|
||||
}
|
||||
|
||||
static const char * const input_names[] = {
|
||||
[WM831X_AUX_SYSVDD] = "SYSVDD",
|
||||
[WM831X_AUX_USB] = "USB",
|
||||
|
@ -50,15 +39,14 @@ static const char * const input_names[] = {
|
|||
[WM831X_AUX_BATT_TEMP] = "Battery",
|
||||
};
|
||||
|
||||
|
||||
static ssize_t show_voltage(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct wm831x_hwmon *hwmon = dev_get_drvdata(dev);
|
||||
struct wm831x *wm831x = dev_get_drvdata(dev);
|
||||
int channel = to_sensor_dev_attr(attr)->index;
|
||||
int ret;
|
||||
|
||||
ret = wm831x_auxadc_read_uv(hwmon->wm831x, channel);
|
||||
ret = wm831x_auxadc_read_uv(wm831x, channel);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -68,11 +56,11 @@ static ssize_t show_voltage(struct device *dev,
|
|||
static ssize_t show_chip_temp(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct wm831x_hwmon *hwmon = dev_get_drvdata(dev);
|
||||
struct wm831x *wm831x = dev_get_drvdata(dev);
|
||||
int channel = to_sensor_dev_attr(attr)->index;
|
||||
int ret;
|
||||
|
||||
ret = wm831x_auxadc_read(hwmon->wm831x, channel);
|
||||
ret = wm831x_auxadc_read(wm831x, channel);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -100,8 +88,6 @@ static ssize_t show_label(struct device *dev,
|
|||
static SENSOR_DEVICE_ATTR(in##id##_label, S_IRUGO, show_label, \
|
||||
NULL, name)
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
WM831X_VOLTAGE(0, WM831X_AUX_AUX1);
|
||||
WM831X_VOLTAGE(1, WM831X_AUX_AUX2);
|
||||
WM831X_VOLTAGE(2, WM831X_AUX_AUX3);
|
||||
|
@ -126,9 +112,7 @@ static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_voltage, NULL,
|
|||
static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_label, NULL,
|
||||
WM831X_AUX_BATT_TEMP);
|
||||
|
||||
static struct attribute *wm831x_attributes[] = {
|
||||
&dev_attr_name.attr,
|
||||
|
||||
static struct attribute *wm831x_attrs[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
|
@ -153,55 +137,21 @@ static struct attribute *wm831x_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group wm831x_attr_group = {
|
||||
.attrs = wm831x_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(wm831x);
|
||||
|
||||
static int wm831x_hwmon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
|
||||
struct wm831x_hwmon *hwmon;
|
||||
int ret;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
hwmon = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_hwmon),
|
||||
GFP_KERNEL);
|
||||
if (!hwmon)
|
||||
return -ENOMEM;
|
||||
|
||||
hwmon->wm831x = wm831x;
|
||||
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &wm831x_attr_group);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hwmon->classdev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(hwmon->classdev)) {
|
||||
ret = PTR_ERR(hwmon->classdev);
|
||||
goto err_sysfs;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, hwmon);
|
||||
|
||||
return 0;
|
||||
|
||||
err_sysfs:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &wm831x_attr_group);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm831x_hwmon_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm831x_hwmon *hwmon = platform_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(hwmon->classdev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &wm831x_attr_group);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, "wm831x",
|
||||
wm831x,
|
||||
wm831x_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static struct platform_driver wm831x_hwmon_driver = {
|
||||
.probe = wm831x_hwmon_probe,
|
||||
.remove = wm831x_hwmon_remove,
|
||||
.driver = {
|
||||
.name = "wm831x-hwmon",
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -28,19 +28,12 @@
|
|||
#include <linux/mfd/wm8350/core.h>
|
||||
#include <linux/mfd/wm8350/comparator.h>
|
||||
|
||||
static ssize_t show_name(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "wm8350\n");
|
||||
}
|
||||
|
||||
static const char * const input_names[] = {
|
||||
[WM8350_AUXADC_USB] = "USB",
|
||||
[WM8350_AUXADC_LINE] = "Line",
|
||||
[WM8350_AUXADC_BATT] = "Battery",
|
||||
};
|
||||
|
||||
|
||||
static ssize_t show_voltage(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
@ -68,15 +61,11 @@ static ssize_t show_label(struct device *dev,
|
|||
static SENSOR_DEVICE_ATTR(in##id##_label, S_IRUGO, show_label, \
|
||||
NULL, name)
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
WM8350_NAMED_VOLTAGE(0, WM8350_AUXADC_USB);
|
||||
WM8350_NAMED_VOLTAGE(1, WM8350_AUXADC_BATT);
|
||||
WM8350_NAMED_VOLTAGE(2, WM8350_AUXADC_LINE);
|
||||
|
||||
static struct attribute *wm8350_attributes[] = {
|
||||
&dev_attr_name.attr,
|
||||
|
||||
static struct attribute *wm8350_attrs[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
|
@ -87,46 +76,21 @@ static struct attribute *wm8350_attributes[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group wm8350_attr_group = {
|
||||
.attrs = wm8350_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(wm8350);
|
||||
|
||||
static int wm8350_hwmon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct wm8350 *wm8350 = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &wm8350_attr_group);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
wm8350->hwmon.classdev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(wm8350->hwmon.classdev)) {
|
||||
ret = PTR_ERR(wm8350->hwmon.classdev);
|
||||
goto err_group;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_group:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &wm8350_attr_group);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm8350_hwmon_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm8350 *wm8350 = platform_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(wm8350->hwmon.classdev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &wm8350_attr_group);
|
||||
|
||||
return 0;
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, "wm8350",
|
||||
wm8350,
|
||||
wm8350_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static struct platform_driver wm8350_hwmon_driver = {
|
||||
.probe = wm8350_hwmon_probe,
|
||||
.remove = wm8350_hwmon_remove,
|
||||
.driver = {
|
||||
.name = "wm8350-hwmon",
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -26,6 +26,7 @@ struct iio_channel;
|
|||
enum ntc_thermistor_type {
|
||||
TYPE_NCPXXWB473,
|
||||
TYPE_NCPXXWL333,
|
||||
TYPE_B57330V2103,
|
||||
};
|
||||
|
||||
struct ntc_thermistor_platform_data {
|
||||
|
|
Loading…
Reference in New Issue