forked from Minki/linux
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/hwmon-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/hwmon-2.6: (39 commits) hwmon: Remove Yuan Mu's address hwmon: Fix unchecked return status, SMSC chips hwmon: Fix unchecked return status, batch 6 w83792d: Fix unchecked return status w83l785ts: Fix unchecked return status w83781d: Fix unchecked return status vt8231: Fix unchecked return status Fix unchecked return status, batch 5 hwmon: Fix unchecked return status, batch 4 hwmon: Fix unchecked return status, batch 3 hwmon: Fix unchecked return status, batch 2 w83627ehf: Fix unchecked return status pc87360: Check for error on sysfs files creation pc87360: Delete sysfs files on device deletion pc87360: Move some code around hwmon: Fix unchecked return status, batch 1 vt1211: Document module parameters vt1211: Add documentation hwmon: New driver for the VIA VT1211 w83791d: Documentation update ...
This commit is contained in:
commit
2ff712585a
@ -13,12 +13,25 @@ Supported chips:
|
||||
from Super I/O config space (8 I/O ports)
|
||||
Datasheet: Publicly available at the ITE website
|
||||
http://www.ite.com.tw/
|
||||
* IT8716F
|
||||
Prefix: 'it8716'
|
||||
Addresses scanned: from Super I/O config space (8 I/O ports)
|
||||
Datasheet: Publicly available at the ITE website
|
||||
http://www.ite.com.tw/product_info/file/pc/IT8716F_V0.3.ZIP
|
||||
* IT8718F
|
||||
Prefix: 'it8718'
|
||||
Addresses scanned: from Super I/O config space (8 I/O ports)
|
||||
Datasheet: Publicly available at the ITE website
|
||||
http://www.ite.com.tw/product_info/file/pc/IT8718F_V0.2.zip
|
||||
http://www.ite.com.tw/product_info/file/pc/IT8718F_V0%203_(for%20C%20version).zip
|
||||
* SiS950 [clone of IT8705F]
|
||||
Prefix: 'it87'
|
||||
Addresses scanned: from Super I/O config space (8 I/O ports)
|
||||
Datasheet: No longer be available
|
||||
|
||||
Author: Christophe Gauthron <chrisg@0-in.com>
|
||||
Authors:
|
||||
Christophe Gauthron <chrisg@0-in.com>
|
||||
Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
|
||||
Module Parameters
|
||||
@ -43,26 +56,46 @@ Module Parameters
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the IT8705F, IT8712F and SiS950 chips.
|
||||
|
||||
This driver also supports IT8712F, which adds SMBus access, and a VID
|
||||
input, used to report the Vcore voltage of the Pentium processor.
|
||||
The IT8712F additionally features VID inputs.
|
||||
This driver implements support for the IT8705F, IT8712F, IT8716F,
|
||||
IT8718F and SiS950 chips.
|
||||
|
||||
These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
|
||||
joysticks and other miscellaneous stuff. For hardware monitoring, they
|
||||
include an 'environment controller' with 3 temperature sensors, 3 fan
|
||||
rotation speed sensors, 8 voltage sensors, and associated alarms.
|
||||
|
||||
The IT8712F and IT8716F additionally feature VID inputs, used to report
|
||||
the Vcore voltage of the processor. The early IT8712F have 5 VID pins,
|
||||
the IT8716F and late IT8712F have 6. They are shared with other functions
|
||||
though, so the functionality may not be available on a given system.
|
||||
The driver dumbly assume it is there.
|
||||
|
||||
The IT8718F also features VID inputs (up to 8 pins) but the value is
|
||||
stored in the Super-I/O configuration space. Due to technical limitations,
|
||||
this value can currently only be read once at initialization time, so
|
||||
the driver won't notice and report changes in the VID value. The two
|
||||
upper VID bits share their pins with voltage inputs (in5 and in6) so you
|
||||
can't have both on a given board.
|
||||
|
||||
The IT8716F, IT8718F and later IT8712F revisions have support for
|
||||
2 additional fans. They are not yet supported by the driver.
|
||||
|
||||
The IT8716F and IT8718F, and late IT8712F and IT8705F also have optional
|
||||
16-bit tachometer counters for fans 1 to 3. This is better (no more fan
|
||||
clock divider mess) but not compatible with the older chips and
|
||||
revisions. For now, the driver only uses the 16-bit mode on the
|
||||
IT8716F and IT8718F.
|
||||
|
||||
Temperatures are measured in degrees Celsius. An alarm is triggered once
|
||||
when the Overtemperature Shutdown limit is crossed.
|
||||
|
||||
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||
triggered if the rotation speed has dropped below a programmable limit. Fan
|
||||
readings can be divided by a programmable divider (1, 2, 4 or 8) to give the
|
||||
readings more range or accuracy. Not all RPM values can accurately be
|
||||
represented, so some rounding is done. With a divider of 2, the lowest
|
||||
representable value is around 2600 RPM.
|
||||
triggered if the rotation speed has dropped below a programmable limit. When
|
||||
16-bit tachometer counters aren't used, fan readings can be divided by
|
||||
a programmable divider (1, 2, 4 or 8) to give the readings more range or
|
||||
accuracy. With a divider of 2, the lowest representable value is around
|
||||
2600 RPM. Not all RPM values can accurately be represented, so some rounding
|
||||
is done.
|
||||
|
||||
Voltage sensors (also known as IN sensors) report their values in volts. An
|
||||
alarm is triggered if the voltage has crossed a programmable minimum or
|
||||
@ -71,9 +104,9 @@ zero'; this is important for negative voltage measurements. All voltage
|
||||
inputs can measure voltages between 0 and 4.08 volts, with a resolution of
|
||||
0.016 volt. The battery voltage in8 does not have limit registers.
|
||||
|
||||
The VID lines (IT8712F only) encode the core voltage value: the voltage
|
||||
level your processor should work with. This is hardcoded by the mainboard
|
||||
and/or processor itself. It is a value in volts.
|
||||
The VID lines (IT8712F/IT8716F/IT8718F) encode the core voltage value:
|
||||
the voltage level your processor should work with. This is hardcoded by
|
||||
the mainboard and/or processor itself. It is a value in volts.
|
||||
|
||||
If an alarm triggers, it will remain triggered until the hardware register
|
||||
is read at least once. This means that the cause for the alarm may already
|
||||
|
52
Documentation/hwmon/k8temp
Normal file
52
Documentation/hwmon/k8temp
Normal file
@ -0,0 +1,52 @@
|
||||
Kernel driver k8temp
|
||||
====================
|
||||
|
||||
Supported chips:
|
||||
* AMD K8 CPU
|
||||
Prefix: 'k8temp'
|
||||
Addresses scanned: PCI space
|
||||
Datasheet: http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf
|
||||
|
||||
Author: Rudolf Marek
|
||||
Contact: Rudolf Marek <r.marek@sh.cvut.cz>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver permits reading temperature sensor(s) embedded inside AMD K8 CPUs.
|
||||
Official documentation says that it works from revision F of K8 core, but
|
||||
in fact it seems to be implemented for all revisions of K8 except the first
|
||||
two revisions (SH-B0 and SH-B3).
|
||||
|
||||
There can be up to four temperature sensors inside single CPU. The driver
|
||||
will auto-detect the sensors and will display only temperatures from
|
||||
implemented sensors.
|
||||
|
||||
Mapping of /sys files is as follows:
|
||||
|
||||
temp1_input - temperature of Core 0 and "place" 0
|
||||
temp2_input - temperature of Core 0 and "place" 1
|
||||
temp3_input - temperature of Core 1 and "place" 0
|
||||
temp4_input - temperature of Core 1 and "place" 1
|
||||
|
||||
Temperatures are measured in degrees Celsius and measurement resolution is
|
||||
1 degree C. It is expected that future CPU will have better resolution. The
|
||||
temperature is updated once a second. Valid temperatures are from -49 to
|
||||
206 degrees C.
|
||||
|
||||
Temperature known as TCaseMax was specified for processors up to revision E.
|
||||
This temperature is defined as temperature between heat-spreader and CPU
|
||||
case, so the internal CPU temperature supplied by this driver can be higher.
|
||||
There is no easy way how to measure the temperature which will correlate
|
||||
with TCaseMax temperature.
|
||||
|
||||
For newer revisions of CPU (rev F, socket AM2) there is a mathematically
|
||||
computed temperature called TControl, which must be lower than TControlMax.
|
||||
|
||||
The relationship is following:
|
||||
|
||||
temp1_input - TjOffset*2 < TControlMax,
|
||||
|
||||
TjOffset is not yet exported by the driver, TControlMax is usually
|
||||
70 degrees C. The rule of the thumb -> CPU temperature should not cross
|
||||
60 degrees C too much.
|
206
Documentation/hwmon/vt1211
Normal file
206
Documentation/hwmon/vt1211
Normal file
@ -0,0 +1,206 @@
|
||||
Kernel driver vt1211
|
||||
====================
|
||||
|
||||
Supported chips:
|
||||
* VIA VT1211
|
||||
Prefix: 'vt1211'
|
||||
Addresses scanned: none, address read from Super-I/O config space
|
||||
Datasheet: Provided by VIA upon request and under NDA
|
||||
|
||||
Authors: Juerg Haefliger <juergh@gmail.com>
|
||||
|
||||
This driver is based on the driver for kernel 2.4 by Mark D. Studebaker and
|
||||
its port to kernel 2.6 by Lars Ekman.
|
||||
|
||||
Thanks to Joseph Chan and Fiona Gatt from VIA for providing documentation and
|
||||
technical support.
|
||||
|
||||
|
||||
Module Parameters
|
||||
-----------------
|
||||
|
||||
* uch_config: int Override the BIOS default universal channel (UCH)
|
||||
configuration for channels 1-5.
|
||||
Legal values are in the range of 0-31. Bit 0 maps to
|
||||
UCH1, bit 1 maps to UCH2 and so on. Setting a bit to 1
|
||||
enables the thermal input of that particular UCH and
|
||||
setting a bit to 0 enables the voltage input.
|
||||
|
||||
* int_mode: int Override the BIOS default temperature interrupt mode.
|
||||
The only possible value is 0 which forces interrupt
|
||||
mode 0. In this mode, any pending interrupt is cleared
|
||||
when the status register is read but is regenerated as
|
||||
long as the temperature stays above the hysteresis
|
||||
limit.
|
||||
|
||||
Be aware that overriding BIOS defaults might cause some unwanted side effects!
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The VIA VT1211 Super-I/O chip includes complete hardware monitoring
|
||||
capabilities. It monitors 2 dedicated temperature sensor inputs (temp1 and
|
||||
temp2), 1 dedicated voltage (in5) and 2 fans. Additionally, the chip
|
||||
implements 5 universal input channels (UCH1-5) that can be individually
|
||||
programmed to either monitor a voltage or a temperature.
|
||||
|
||||
This chip also provides manual and automatic control of fan speeds (according
|
||||
to the datasheet). The driver only supports automatic control since the manual
|
||||
mode doesn't seem to work as advertised in the datasheet. In fact I couldn't
|
||||
get manual mode to work at all! Be aware that automatic mode hasn't been
|
||||
tested very well (due to the fact that my EPIA M10000 doesn't have the fans
|
||||
connected to the PWM outputs of the VT1211 :-().
|
||||
|
||||
The following table shows the relationship between the vt1211 inputs and the
|
||||
sysfs nodes.
|
||||
|
||||
Sensor Voltage Mode Temp Mode Default Use (from the datasheet)
|
||||
------ ------------ --------- --------------------------------
|
||||
Reading 1 temp1 Intel thermal diode
|
||||
Reading 3 temp2 Internal thermal diode
|
||||
UCH1/Reading2 in0 temp3 NTC type thermistor
|
||||
UCH2 in1 temp4 +2.5V
|
||||
UCH3 in2 temp5 VccP (processor core)
|
||||
UCH4 in3 temp6 +5V
|
||||
UCH5 in4 temp7 +12V
|
||||
+3.3V in5 Internal VCC (+3.3V)
|
||||
|
||||
|
||||
Voltage Monitoring
|
||||
------------------
|
||||
|
||||
Voltages are sampled by an 8-bit ADC with a LSB of ~10mV. The supported input
|
||||
range is thus from 0 to 2.60V. Voltage values outside of this range need
|
||||
external scaling resistors. This external scaling needs to be compensated for
|
||||
via compute lines in sensors.conf, like:
|
||||
|
||||
compute inx @*(1+R1/R2), @/(1+R1/R2)
|
||||
|
||||
The board level scaling resistors according to VIA's recommendation are as
|
||||
follows. And this is of course totally dependent on the actual board
|
||||
implementation :-) You will have to find documentation for your own
|
||||
motherboard and edit sensors.conf accordingly.
|
||||
|
||||
Expected
|
||||
Voltage R1 R2 Divider Raw Value
|
||||
-----------------------------------------------
|
||||
+2.5V 2K 10K 1.2 2083 mV
|
||||
VccP --- --- 1.0 1400 mV (1)
|
||||
+5V 14K 10K 2.4 2083 mV
|
||||
+12V 47K 10K 5.7 2105 mV
|
||||
+3.3V (int) 2K 3.4K 1.588 3300 mV (2)
|
||||
+3.3V (ext) 6.8K 10K 1.68 1964 mV
|
||||
|
||||
(1) Depending on the CPU (1.4V is for a VIA C3 Nehemiah).
|
||||
(2) R1 and R2 for 3.3V (int) are internal to the VT1211 chip and the driver
|
||||
performs the scaling and returns the properly scaled voltage value.
|
||||
|
||||
Each measured voltage has an associated low and high limit which triggers an
|
||||
alarm when crossed.
|
||||
|
||||
|
||||
Temperature Monitoring
|
||||
----------------------
|
||||
|
||||
Temperatures are reported in millidegree Celsius. Each measured temperature
|
||||
has a high limit which triggers an alarm if crossed. There is an associated
|
||||
hysteresis value with each temperature below which the temperature has to drop
|
||||
before the alarm is cleared (this is only true for interrupt mode 0). The
|
||||
interrupt mode can be forced to 0 in case the BIOS doesn't do it
|
||||
automatically. See the 'Module Parameters' section for details.
|
||||
|
||||
All temperature channels except temp2 are external. Temp2 is the VT1211
|
||||
internal thermal diode and the driver does all the scaling for temp2 and
|
||||
returns the temperature in millidegree Celsius. For the external channels
|
||||
temp1 and temp3-temp7, scaling depends on the board implementation and needs
|
||||
to be performed in userspace via sensors.conf.
|
||||
|
||||
Temp1 is an Intel-type thermal diode which requires the following formula to
|
||||
convert between sysfs readings and real temperatures:
|
||||
|
||||
compute temp1 (@-Offset)/Gain, (@*Gain)+Offset
|
||||
|
||||
According to the VIA VT1211 BIOS porting guide, the following gain and offset
|
||||
values should be used:
|
||||
|
||||
Diode Type Offset Gain
|
||||
---------- ------ ----
|
||||
Intel CPU 88.638 0.9528
|
||||
65.000 0.9686 *)
|
||||
VIA C3 Ezra 83.869 0.9528
|
||||
VIA C3 Ezra-T 73.869 0.9528
|
||||
|
||||
*) This is the formula from the lm_sensors 2.10.0 sensors.conf file. I don't
|
||||
know where it comes from or how it was derived, it's just listed here for
|
||||
completeness.
|
||||
|
||||
Temp3-temp7 support NTC thermistors. For these channels, the driver returns
|
||||
the voltages as seen at the individual pins of UCH1-UCH5. The voltage at the
|
||||
pin (Vpin) is formed by a voltage divider made of the thermistor (Rth) and a
|
||||
scaling resistor (Rs):
|
||||
|
||||
Vpin = 2200 * Rth / (Rs + Rth) (2200 is the ADC max limit of 2200 mV)
|
||||
|
||||
The equation for the thermistor is as follows (google it if you want to know
|
||||
more about it):
|
||||
|
||||
Rth = Ro * exp(B * (1 / T - 1 / To)) (To is 298.15K (25C) and Ro is the
|
||||
nominal resistance at 25C)
|
||||
|
||||
Mingling the above two equations and assuming Rs = Ro and B = 3435 yields the
|
||||
following formula for sensors.conf:
|
||||
|
||||
compute tempx 1 / (1 / 298.15 - (` (2200 / @ - 1)) / 3435) - 273.15,
|
||||
2200 / (1 + (^ (3435 / 298.15 - 3435 / (273.15 + @))))
|
||||
|
||||
|
||||
Fan Speed Control
|
||||
-----------------
|
||||
|
||||
The VT1211 provides 2 programmable PWM outputs to control the speeds of 2
|
||||
fans. Writing a 2 to any of the two pwm[1-2]_enable sysfs nodes will put the
|
||||
PWM controller in automatic mode. There is only a single controller that
|
||||
controls both PWM outputs but each PWM output can be individually enabled and
|
||||
disabled.
|
||||
|
||||
Each PWM has 4 associated distinct output duty-cycles: full, high, low and
|
||||
off. Full and off are internally hard-wired to 255 (100%) and 0 (0%),
|
||||
respectively. High and low can be programmed via
|
||||
pwm[1-2]_auto_point[2-3]_pwm. Each PWM output can be associated with a
|
||||
different thermal input but - and here's the weird part - only one set of
|
||||
thermal thresholds exist that controls both PWMs output duty-cycles. The
|
||||
thermal thresholds are accessible via pwm[1-2]_auto_point[1-4]_temp. Note
|
||||
that even though there are 2 sets of 4 auto points each, they map to the same
|
||||
registers in the VT1211 and programming one set is sufficient (actually only
|
||||
the first set pwm1_auto_point[1-4]_temp is writable, the second set is
|
||||
read-only).
|
||||
|
||||
PWM Auto Point PWM Output Duty-Cycle
|
||||
------------------------------------------------
|
||||
pwm[1-2]_auto_point4_pwm full speed duty-cycle (hard-wired to 255)
|
||||
pwm[1-2]_auto_point3_pwm high speed duty-cycle
|
||||
pwm[1-2]_auto_point2_pwm low speed duty-cycle
|
||||
pwm[1-2]_auto_point1_pwm off duty-cycle (hard-wired to 0)
|
||||
|
||||
Temp Auto Point Thermal Threshold
|
||||
---------------------------------------------
|
||||
pwm[1-2]_auto_point4_temp full speed temp
|
||||
pwm[1-2]_auto_point3_temp high speed temp
|
||||
pwm[1-2]_auto_point2_temp low speed temp
|
||||
pwm[1-2]_auto_point1_temp off temp
|
||||
|
||||
Long story short, the controller implements the following algorithm to set the
|
||||
PWM output duty-cycle based on the input temperature:
|
||||
|
||||
Thermal Threshold Output Duty-Cycle
|
||||
(Rising Temp) (Falling Temp)
|
||||
----------------------------------------------------------
|
||||
full speed duty-cycle full speed duty-cycle
|
||||
full speed temp
|
||||
high speed duty-cycle full speed duty-cycle
|
||||
high speed temp
|
||||
low speed duty-cycle high speed duty-cycle
|
||||
low speed temp
|
||||
off duty-cycle low speed duty-cycle
|
||||
off temp
|
85
Documentation/hwmon/w83627ehf
Normal file
85
Documentation/hwmon/w83627ehf
Normal file
@ -0,0 +1,85 @@
|
||||
Kernel driver w83627ehf
|
||||
=======================
|
||||
|
||||
Supported chips:
|
||||
* Winbond W83627EHF/EHG (ISA access ONLY)
|
||||
Prefix: 'w83627ehf'
|
||||
Addresses scanned: ISA address retrieved from Super I/O registers
|
||||
Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf
|
||||
|
||||
Authors:
|
||||
Jean Delvare <khali@linux-fr.org>
|
||||
Yuan Mu (Winbond)
|
||||
Rudolf Marek <r.marek@sh.cvut.cz>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the Winbond W83627EHF and W83627EHG
|
||||
super I/O chips. We will refer to them collectively as Winbond chips.
|
||||
|
||||
The chips implement three temperature sensors, five fan rotation
|
||||
speed sensors, ten analog voltage sensors, alarms with beep warnings (control
|
||||
unimplemented), and some automatic fan regulation strategies (plus manual
|
||||
fan control mode).
|
||||
|
||||
Temperatures are measured in degrees Celsius and measurement resolution is 1
|
||||
degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
|
||||
the temperature gets higher than high limit; it stays on until the temperature
|
||||
falls below the Hysteresis value.
|
||||
|
||||
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||
triggered if the rotation speed has dropped below a programmable limit. Fan
|
||||
readings can be divided by a programmable divider (1, 2, 4, 8, 16, 32, 64 or
|
||||
128) to give the readings more range or accuracy. The driver sets the most
|
||||
suitable fan divisor itself. Some fans might not be present because they
|
||||
share pins with other functions.
|
||||
|
||||
Voltage sensors (also known as IN sensors) report their values in millivolts.
|
||||
An alarm is triggered if the voltage has crossed a programmable minimum
|
||||
or maximum limit.
|
||||
|
||||
The driver supports automatic fan control mode known as Thermal Cruise.
|
||||
In this mode, the chip attempts to keep the measured temperature in a
|
||||
predefined temperature range. If the temperature goes out of range, fan
|
||||
is driven slower/faster to reach the predefined range again.
|
||||
|
||||
The mode works for fan1-fan4. Mapping of temperatures to pwm outputs is as
|
||||
follows:
|
||||
|
||||
temp1 -> pwm1
|
||||
temp2 -> pwm2
|
||||
temp3 -> pwm3
|
||||
prog -> pwm4 (the programmable setting is not supported by the driver)
|
||||
|
||||
/sys files
|
||||
----------
|
||||
|
||||
pwm[1-4] - this file stores PWM duty cycle or DC value (fan speed) in range:
|
||||
0 (stop) to 255 (full)
|
||||
|
||||
pwm[1-4]_enable - this file controls mode of fan/temperature control:
|
||||
* 1 Manual Mode, write to pwm file any value 0-255 (full speed)
|
||||
* 2 Thermal Cruise
|
||||
|
||||
Thermal Cruise mode
|
||||
-------------------
|
||||
|
||||
If the temperature is in the range defined by:
|
||||
|
||||
pwm[1-4]_target - set target temperature, unit millidegree Celcius
|
||||
(range 0 - 127000)
|
||||
pwm[1-4]_tolerance - tolerance, unit millidegree Celcius (range 0 - 15000)
|
||||
|
||||
there are no changes to fan speed. Once the temperature leaves the interval,
|
||||
fan speed increases (temp is higher) or decreases if lower than desired.
|
||||
There are defined steps and times, but not exported by the driver yet.
|
||||
|
||||
pwm[1-4]_min_output - minimum fan speed (range 1 - 255), when the temperature
|
||||
is below defined range.
|
||||
pwm[1-4]_stop_time - how many milliseconds [ms] must elapse to switch
|
||||
corresponding fan off. (when the temperature was below
|
||||
defined range).
|
||||
|
||||
Note: last two functions are influenced by other control bits, not yet exported
|
||||
by the driver, so a change might not have any effect.
|
@ -5,7 +5,7 @@ Supported chips:
|
||||
* Winbond W83791D
|
||||
Prefix: 'w83791d'
|
||||
Addresses scanned: I2C 0x2c - 0x2f
|
||||
Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83791Da.pdf
|
||||
Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83791D_W83791Gb.pdf
|
||||
|
||||
Author: Charles Spirakis <bezaur@gmail.com>
|
||||
|
||||
@ -20,6 +20,9 @@ Credits:
|
||||
Chunhao Huang <DZShen@Winbond.com.tw>,
|
||||
Rudolf Marek <r.marek@sh.cvut.cz>
|
||||
|
||||
Additional contributors:
|
||||
Sven Anders <anders@anduras.de>
|
||||
|
||||
Module Parameters
|
||||
-----------------
|
||||
|
||||
@ -46,7 +49,8 @@ Module Parameters
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the Winbond W83791D chip.
|
||||
This driver implements support for the Winbond W83791D chip. The W83791G
|
||||
chip appears to be the same as the W83791D but is lead free.
|
||||
|
||||
Detection of the chip can sometimes be foiled because it can be in an
|
||||
internal state that allows no clean access (Bank with ID register is not
|
||||
@ -71,34 +75,36 @@ Voltage sensors (also known as IN sensors) report their values in millivolts.
|
||||
An alarm is triggered if the voltage has crossed a programmable minimum
|
||||
or maximum limit.
|
||||
|
||||
Alarms are provided as output from a "realtime status register". The
|
||||
following bits are defined:
|
||||
The bit ordering for the alarm "realtime status register" and the
|
||||
"beep enable registers" are different.
|
||||
|
||||
bit - alarm on:
|
||||
0 - Vcore
|
||||
1 - VINR0
|
||||
2 - +3.3VIN
|
||||
3 - 5VDD
|
||||
4 - temp1
|
||||
5 - temp2
|
||||
6 - fan1
|
||||
7 - fan2
|
||||
8 - +12VIN
|
||||
9 - -12VIN
|
||||
10 - -5VIN
|
||||
11 - fan3
|
||||
12 - chassis
|
||||
13 - temp3
|
||||
14 - VINR1
|
||||
15 - reserved
|
||||
16 - tart1
|
||||
17 - tart2
|
||||
18 - tart3
|
||||
19 - VSB
|
||||
20 - VBAT
|
||||
21 - fan4
|
||||
22 - fan5
|
||||
23 - reserved
|
||||
in0 (VCORE) : alarms: 0x000001 beep_enable: 0x000001
|
||||
in1 (VINR0) : alarms: 0x000002 beep_enable: 0x002000 <== mismatch
|
||||
in2 (+3.3VIN): alarms: 0x000004 beep_enable: 0x000004
|
||||
in3 (5VDD) : alarms: 0x000008 beep_enable: 0x000008
|
||||
in4 (+12VIN) : alarms: 0x000100 beep_enable: 0x000100
|
||||
in5 (-12VIN) : alarms: 0x000200 beep_enable: 0x000200
|
||||
in6 (-5VIN) : alarms: 0x000400 beep_enable: 0x000400
|
||||
in7 (VSB) : alarms: 0x080000 beep_enable: 0x010000 <== mismatch
|
||||
in8 (VBAT) : alarms: 0x100000 beep_enable: 0x020000 <== mismatch
|
||||
in9 (VINR1) : alarms: 0x004000 beep_enable: 0x004000
|
||||
temp1 : alarms: 0x000010 beep_enable: 0x000010
|
||||
temp2 : alarms: 0x000020 beep_enable: 0x000020
|
||||
temp3 : alarms: 0x002000 beep_enable: 0x000002 <== mismatch
|
||||
fan1 : alarms: 0x000040 beep_enable: 0x000040
|
||||
fan2 : alarms: 0x000080 beep_enable: 0x000080
|
||||
fan3 : alarms: 0x000800 beep_enable: 0x000800
|
||||
fan4 : alarms: 0x200000 beep_enable: 0x200000
|
||||
fan5 : alarms: 0x400000 beep_enable: 0x400000
|
||||
tart1 : alarms: 0x010000 beep_enable: 0x040000 <== mismatch
|
||||
tart2 : alarms: 0x020000 beep_enable: 0x080000 <== mismatch
|
||||
tart3 : alarms: 0x040000 beep_enable: 0x100000 <== mismatch
|
||||
case_open : alarms: 0x001000 beep_enable: 0x001000
|
||||
user_enable : alarms: -------- beep_enable: 0x800000
|
||||
|
||||
*** NOTE: It is the responsibility of user-space code to handle the fact
|
||||
that the beep enable and alarm bits are in different positions when using that
|
||||
feature of the chip.
|
||||
|
||||
When an alarm goes off, you can be warned by a beeping signal through your
|
||||
computer speaker. It is possible to enable all beeping globally, or only
|
||||
@ -109,5 +115,6 @@ often will do no harm, but will return 'old' values.
|
||||
|
||||
W83791D TODO:
|
||||
---------------
|
||||
Provide a patch for per-file alarms as discussed on the mailing list
|
||||
Provide a patch for per-file alarms and beep enables as defined in the hwmon
|
||||
documentation (Documentation/hwmon/sysfs-interface)
|
||||
Provide a patch for smart-fan control (still need appropriate motherboard/fans)
|
||||
|
@ -3309,6 +3309,12 @@ W: http://linuxtv.org
|
||||
T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git
|
||||
S: Maintained
|
||||
|
||||
VT1211 HARDWARE MONITOR DRIVER
|
||||
P: Juerg Haefliger
|
||||
M: juergh@gmail.com
|
||||
L: lm-sensors@lm-sensors.org
|
||||
S: Maintained
|
||||
|
||||
VT8231 HARDWARE MONITOR DRIVER
|
||||
P: Roger Lucas
|
||||
M: roger@planbit.co.uk
|
||||
|
@ -53,7 +53,7 @@ config SENSORS_ADM1021
|
||||
|
||||
config SENSORS_ADM1025
|
||||
tristate "Analog Devices ADM1025 and compatibles"
|
||||
depends on HWMON && I2C && EXPERIMENTAL
|
||||
depends on HWMON && I2C
|
||||
select HWMON_VID
|
||||
help
|
||||
If you say yes here you get support for Analog Devices ADM1025
|
||||
@ -94,6 +94,16 @@ config SENSORS_ADM9240
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adm9240.
|
||||
|
||||
config SENSORS_K8TEMP
|
||||
tristate "AMD K8 processor sensor"
|
||||
depends on HWMON && X86 && PCI && EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for the temperature
|
||||
sensor(s) inside your AMD K8 CPU.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called k8temp.
|
||||
|
||||
config SENSORS_ASB100
|
||||
tristate "Asus ASB100 Bach"
|
||||
depends on HWMON && I2C && EXPERIMENTAL
|
||||
@ -121,7 +131,7 @@ config SENSORS_ATXP1
|
||||
|
||||
config SENSORS_DS1621
|
||||
tristate "Dallas Semiconductor DS1621 and DS1625"
|
||||
depends on HWMON && I2C && EXPERIMENTAL
|
||||
depends on HWMON && I2C
|
||||
help
|
||||
If you say yes here you get support for Dallas Semiconductor
|
||||
DS1621 and DS1625 sensor chips.
|
||||
@ -141,7 +151,7 @@ config SENSORS_F71805F
|
||||
|
||||
config SENSORS_FSCHER
|
||||
tristate "FSC Hermes"
|
||||
depends on HWMON && I2C && EXPERIMENTAL
|
||||
depends on HWMON && I2C
|
||||
help
|
||||
If you say yes here you get support for Fujitsu Siemens
|
||||
Computers Hermes sensor chips.
|
||||
@ -151,7 +161,7 @@ config SENSORS_FSCHER
|
||||
|
||||
config SENSORS_FSCPOS
|
||||
tristate "FSC Poseidon"
|
||||
depends on HWMON && I2C && EXPERIMENTAL
|
||||
depends on HWMON && I2C
|
||||
help
|
||||
If you say yes here you get support for Fujitsu Siemens
|
||||
Computers Poseidon sensor chips.
|
||||
@ -171,7 +181,7 @@ config SENSORS_GL518SM
|
||||
|
||||
config SENSORS_GL520SM
|
||||
tristate "Genesys Logic GL520SM"
|
||||
depends on HWMON && I2C && EXPERIMENTAL
|
||||
depends on HWMON && I2C
|
||||
select HWMON_VID
|
||||
help
|
||||
If you say yes here you get support for Genesys Logic GL520SM
|
||||
@ -186,15 +196,15 @@ config SENSORS_IT87
|
||||
select I2C_ISA
|
||||
select HWMON_VID
|
||||
help
|
||||
If you say yes here you get support for ITE IT87xx sensor chips
|
||||
and clones: SiS960.
|
||||
If you say yes here you get support for ITE IT8705F, IT8712F,
|
||||
IT8716F and IT8718F sensor chips, and the SiS960 clone.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called it87.
|
||||
|
||||
config SENSORS_LM63
|
||||
tristate "National Semiconductor LM63"
|
||||
depends on HWMON && I2C && EXPERIMENTAL
|
||||
depends on HWMON && I2C
|
||||
help
|
||||
If you say yes here you get support for the National Semiconductor
|
||||
LM63 remote diode digital temperature sensor with integrated fan
|
||||
@ -231,7 +241,7 @@ config SENSORS_LM75
|
||||
|
||||
config SENSORS_LM77
|
||||
tristate "National Semiconductor LM77"
|
||||
depends on HWMON && I2C && EXPERIMENTAL
|
||||
depends on HWMON && I2C
|
||||
help
|
||||
If you say yes here you get support for National Semiconductor LM77
|
||||
sensor chips.
|
||||
@ -241,7 +251,7 @@ config SENSORS_LM77
|
||||
|
||||
config SENSORS_LM78
|
||||
tristate "National Semiconductor LM78 and compatibles"
|
||||
depends on HWMON && I2C && EXPERIMENTAL
|
||||
depends on HWMON && I2C
|
||||
select I2C_ISA
|
||||
select HWMON_VID
|
||||
help
|
||||
@ -284,7 +294,7 @@ config SENSORS_LM85
|
||||
|
||||
config SENSORS_LM87
|
||||
tristate "National Semiconductor LM87"
|
||||
depends on HWMON && I2C && EXPERIMENTAL
|
||||
depends on HWMON && I2C
|
||||
select HWMON_VID
|
||||
help
|
||||
If you say yes here you get support for National Semiconductor LM87
|
||||
@ -309,7 +319,7 @@ config SENSORS_LM90
|
||||
|
||||
config SENSORS_LM92
|
||||
tristate "National Semiconductor LM92 and compatibles"
|
||||
depends on HWMON && I2C && EXPERIMENTAL
|
||||
depends on HWMON && I2C
|
||||
help
|
||||
If you say yes here you get support for National Semiconductor LM92
|
||||
and Maxim MAX6635 sensor chips.
|
||||
@ -319,7 +329,7 @@ config SENSORS_LM92
|
||||
|
||||
config SENSORS_MAX1619
|
||||
tristate "Maxim MAX1619 sensor chip"
|
||||
depends on HWMON && I2C && EXPERIMENTAL
|
||||
depends on HWMON && I2C
|
||||
help
|
||||
If you say yes here you get support for MAX1619 sensor chip.
|
||||
|
||||
@ -354,7 +364,7 @@ config SENSORS_SIS5595
|
||||
|
||||
config SENSORS_SMSC47M1
|
||||
tristate "SMSC LPC47M10x and compatibles"
|
||||
depends on HWMON && I2C && EXPERIMENTAL
|
||||
depends on HWMON && I2C
|
||||
select I2C_ISA
|
||||
help
|
||||
If you say yes here you get support for the integrated fan
|
||||
@ -407,8 +417,19 @@ config SENSORS_VIA686A
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called via686a.
|
||||
|
||||
config SENSORS_VT1211
|
||||
tristate "VIA VT1211"
|
||||
depends on HWMON && EXPERIMENTAL
|
||||
select HWMON_VID
|
||||
help
|
||||
If you say yes here then you get support for hardware monitoring
|
||||
features of the VIA VT1211 Super-I/O chip.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called vt1211.
|
||||
|
||||
config SENSORS_VT8231
|
||||
tristate "VT8231"
|
||||
tristate "VIA VT8231"
|
||||
depends on HWMON && I2C && PCI && EXPERIMENTAL
|
||||
select HWMON_VID
|
||||
select I2C_ISA
|
||||
|
@ -27,6 +27,7 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
|
||||
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
|
||||
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
|
||||
obj-$(CONFIG_SENSORS_IT87) += it87.o
|
||||
obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
|
||||
obj-$(CONFIG_SENSORS_LM63) += lm63.o
|
||||
obj-$(CONFIG_SENSORS_LM70) += lm70.o
|
||||
obj-$(CONFIG_SENSORS_LM75) += lm75.o
|
||||
@ -45,6 +46,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
|
||||
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
|
||||
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
|
||||
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
|
||||
obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
|
||||
obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
|
||||
obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
|
||||
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
|
||||
|
@ -1354,13 +1354,39 @@ LEAVE_UPDATE:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int abituguru_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct abituguru_data *data = platform_get_drvdata(pdev);
|
||||
/* make sure all communications with the uguru are done and no new
|
||||
ones are started */
|
||||
mutex_lock(&data->update_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int abituguru_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct abituguru_data *data = platform_get_drvdata(pdev);
|
||||
/* See if the uGuru is still ready */
|
||||
if (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT)
|
||||
data->uguru_ready = 0;
|
||||
mutex_unlock(&data->update_lock);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define abituguru_suspend NULL
|
||||
#define abituguru_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct platform_driver abituguru_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = ABIT_UGURU_NAME,
|
||||
},
|
||||
.probe = abituguru_probe,
|
||||
.remove = __devexit_p(abituguru_remove),
|
||||
.probe = abituguru_probe,
|
||||
.remove = __devexit_p(abituguru_remove),
|
||||
.suspend = abituguru_suspend,
|
||||
.resume = abituguru_resume,
|
||||
};
|
||||
|
||||
static int __init abituguru_detect(void)
|
||||
|
@ -190,6 +190,21 @@ static int adm1021_attach_adapter(struct i2c_adapter *adapter)
|
||||
return i2c_probe(adapter, &addr_data, adm1021_detect);
|
||||
}
|
||||
|
||||
static struct attribute *adm1021_attributes[] = {
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_min.attr,
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp2_max.attr,
|
||||
&dev_attr_temp2_min.attr,
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adm1021_group = {
|
||||
.attrs = adm1021_attributes,
|
||||
};
|
||||
|
||||
static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
int i;
|
||||
@ -287,22 +302,19 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
adm1021_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1021_group)))
|
||||
goto error2;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto error2;
|
||||
goto error3;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
|
||||
return 0;
|
||||
|
||||
error3:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &adm1021_group);
|
||||
error2:
|
||||
i2c_detach_client(new_client);
|
||||
error1:
|
||||
@ -326,6 +338,7 @@ static int adm1021_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1021_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -315,6 +315,49 @@ static int adm1025_attach_adapter(struct i2c_adapter *adapter)
|
||||
return i2c_probe(adapter, &addr_data, adm1025_detect);
|
||||
}
|
||||
|
||||
static struct attribute *adm1025_attributes[] = {
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
&dev_attr_in3_input.attr,
|
||||
&dev_attr_in5_input.attr,
|
||||
&dev_attr_in0_min.attr,
|
||||
&dev_attr_in1_min.attr,
|
||||
&dev_attr_in2_min.attr,
|
||||
&dev_attr_in3_min.attr,
|
||||
&dev_attr_in5_min.attr,
|
||||
&dev_attr_in0_max.attr,
|
||||
&dev_attr_in1_max.attr,
|
||||
&dev_attr_in2_max.attr,
|
||||
&dev_attr_in3_max.attr,
|
||||
&dev_attr_in5_max.attr,
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_temp1_min.attr,
|
||||
&dev_attr_temp2_min.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp2_max.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
&dev_attr_vrm.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adm1025_group = {
|
||||
.attrs = adm1025_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *adm1025_attributes_opt[] = {
|
||||
&dev_attr_in4_input.attr,
|
||||
&dev_attr_in4_min.attr,
|
||||
&dev_attr_in4_max.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adm1025_group_opt = {
|
||||
.attrs = adm1025_attributes_opt,
|
||||
};
|
||||
|
||||
/*
|
||||
* The following function does more than just detection. If detection
|
||||
* succeeds, it also registers the new chip.
|
||||
@ -415,46 +458,31 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
adm1025_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1025_group)))
|
||||
goto exit_detach;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
device_create_file(&new_client->dev, &dev_attr_vrm);
|
||||
|
||||
/* Pin 11 is either in4 (+12V) or VID4 */
|
||||
if (!(config & 0x20)) {
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_max);
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in4_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in4_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in4_max)))
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &adm1025_group);
|
||||
sysfs_remove_group(&new_client->dev.kobj, &adm1025_group_opt);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -511,6 +539,8 @@ static int adm1025_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1025_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -323,15 +323,6 @@ static int adm1026_attach_adapter(struct i2c_adapter *adapter)
|
||||
return i2c_probe(adapter, &addr_data, adm1026_detect);
|
||||
}
|
||||
|
||||
static int adm1026_detach_client(struct i2c_client *client)
|
||||
{
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
i2c_detach_client(client);
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adm1026_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
int res;
|
||||
@ -1450,6 +1441,135 @@ static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
|
||||
static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
|
||||
static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
|
||||
|
||||
static struct attribute *adm1026_attributes[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in9_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in9_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in9_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in10_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in10_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in10_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in11_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in11_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in11_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in12_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in12_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in12_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in13_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in13_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in13_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in14_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in14_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in14_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in15_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in15_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in15_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in16_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in16_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in16_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan4_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan4_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan5_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan5_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan6_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan6_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan7_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan7_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan7_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan8_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan8_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan8_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_offset.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_offset.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_offset.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit.dev_attr.attr,
|
||||
&dev_attr_temp1_crit_enable.attr,
|
||||
&dev_attr_temp2_crit_enable.attr,
|
||||
&dev_attr_temp3_crit_enable.attr,
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
&dev_attr_vrm.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_alarm_mask.attr,
|
||||
&dev_attr_gpio.attr,
|
||||
&dev_attr_gpio_mask.attr,
|
||||
&dev_attr_pwm1.attr,
|
||||
&dev_attr_pwm2.attr,
|
||||
&dev_attr_pwm3.attr,
|
||||
&dev_attr_pwm1_enable.attr,
|
||||
&dev_attr_pwm2_enable.attr,
|
||||
&dev_attr_pwm3_enable.attr,
|
||||
&dev_attr_temp1_auto_point1_pwm.attr,
|
||||
&dev_attr_temp2_auto_point1_pwm.attr,
|
||||
&dev_attr_temp3_auto_point1_pwm.attr,
|
||||
&dev_attr_temp1_auto_point2_pwm.attr,
|
||||
&dev_attr_temp2_auto_point2_pwm.attr,
|
||||
&dev_attr_temp3_auto_point2_pwm.attr,
|
||||
&dev_attr_analog_out.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adm1026_group = {
|
||||
.attrs = adm1026_attributes,
|
||||
};
|
||||
|
||||
static int adm1026_detect(struct i2c_adapter *adapter, int address,
|
||||
int kind)
|
||||
{
|
||||
@ -1554,145 +1674,20 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
|
||||
adm1026_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1026_group)))
|
||||
goto exitdetach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exitdetach;
|
||||
goto exitremove;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in11_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in11_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in11_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in12_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in12_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in12_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in13_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in13_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in13_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in14_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in14_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in14_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in15_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in15_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in15_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in16_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in16_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in16_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan4_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan4_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan4_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan5_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan5_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan5_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan6_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan6_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan6_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan7_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan7_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan7_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan8_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan8_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan8_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_offset.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_offset.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_offset.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_auto_point1_temp.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_auto_point1_temp.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp3_auto_point1_temp.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_auto_point2_temp.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_auto_point2_temp.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp3_auto_point2_temp.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
device_create_file(&new_client->dev, &dev_attr_vrm);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarm_mask);
|
||||
device_create_file(&new_client->dev, &dev_attr_gpio);
|
||||
device_create_file(&new_client->dev, &dev_attr_gpio_mask);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm3);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm3_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_auto_point1_pwm);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_auto_point1_pwm);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_auto_point1_pwm);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_auto_point2_pwm);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_auto_point2_pwm);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_auto_point2_pwm);
|
||||
device_create_file(&new_client->dev, &dev_attr_analog_out);
|
||||
return 0;
|
||||
|
||||
/* Error out and cleanup code */
|
||||
exitremove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &adm1026_group);
|
||||
exitdetach:
|
||||
i2c_detach_client(new_client);
|
||||
exitfree:
|
||||
@ -1700,6 +1695,17 @@ exitfree:
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adm1026_detach_client(struct i2c_client *client)
|
||||
{
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1026_group);
|
||||
i2c_detach_client(client);
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init sm_adm1026_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adm1026_driver);
|
||||
|
@ -730,6 +730,61 @@ static int adm1031_attach_adapter(struct i2c_adapter *adapter)
|
||||
return i2c_probe(adapter, &addr_data, adm1031_detect);
|
||||
}
|
||||
|
||||
static struct attribute *adm1031_attributes[] = {
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan1_div.attr,
|
||||
&dev_attr_fan1_min.attr,
|
||||
&dev_attr_pwm1.attr,
|
||||
&dev_attr_auto_fan1_channel.attr,
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_min.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_crit.attr,
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_temp2_min.attr,
|
||||
&dev_attr_temp2_max.attr,
|
||||
&dev_attr_temp2_crit.attr,
|
||||
|
||||
&dev_attr_auto_temp1_off.attr,
|
||||
&dev_attr_auto_temp1_min.attr,
|
||||
&dev_attr_auto_temp1_max.attr,
|
||||
|
||||
&dev_attr_auto_temp2_off.attr,
|
||||
&dev_attr_auto_temp2_min.attr,
|
||||
&dev_attr_auto_temp2_max.attr,
|
||||
|
||||
&dev_attr_auto_fan1_min_pwm.attr,
|
||||
|
||||
&dev_attr_alarms.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adm1031_group = {
|
||||
.attrs = adm1031_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *adm1031_attributes_opt[] = {
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan2_div.attr,
|
||||
&dev_attr_fan2_min.attr,
|
||||
&dev_attr_pwm2.attr,
|
||||
&dev_attr_auto_fan2_channel.attr,
|
||||
&dev_attr_temp3_input.attr,
|
||||
&dev_attr_temp3_min.attr,
|
||||
&dev_attr_temp3_max.attr,
|
||||
&dev_attr_temp3_crit.attr,
|
||||
&dev_attr_auto_temp3_off.attr,
|
||||
&dev_attr_auto_temp3_min.attr,
|
||||
&dev_attr_auto_temp3_max.attr,
|
||||
&dev_attr_auto_fan2_min_pwm.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adm1031_group_opt = {
|
||||
.attrs = adm1031_attributes_opt,
|
||||
};
|
||||
|
||||
/* This function is called by i2c_probe */
|
||||
static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
@ -789,57 +844,26 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
adm1031_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1031_group)))
|
||||
goto exit_detach;
|
||||
|
||||
if (kind == adm1031) {
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj,
|
||||
&adm1031_group_opt)))
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1);
|
||||
device_create_file(&new_client->dev, &dev_attr_auto_fan1_channel);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit);
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_auto_temp1_off);
|
||||
device_create_file(&new_client->dev, &dev_attr_auto_temp1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_auto_temp1_max);
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_auto_temp2_off);
|
||||
device_create_file(&new_client->dev, &dev_attr_auto_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_auto_temp2_max);
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_auto_fan1_min_pwm);
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
|
||||
if (kind == adm1031) {
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2);
|
||||
device_create_file(&new_client->dev,
|
||||
&dev_attr_auto_fan2_channel);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_auto_temp3_off);
|
||||
device_create_file(&new_client->dev, &dev_attr_auto_temp3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_auto_temp3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_auto_fan2_min_pwm);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &adm1031_group);
|
||||
sysfs_remove_group(&new_client->dev.kobj, &adm1031_group_opt);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -854,6 +878,8 @@ static int adm1031_detach_client(struct i2c_client *client)
|
||||
int ret;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1031_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
|
||||
if ((ret = i2c_detach_client(client)) != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -465,6 +465,45 @@ static ssize_t chassis_clear(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear);
|
||||
|
||||
static struct attribute *adm9240_attributes[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_max.dev_attr.attr,
|
||||
&dev_attr_temp1_input.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_min.dev_attr.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_aout_output.attr,
|
||||
&dev_attr_chassis_clear.attr,
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adm9240_group = {
|
||||
.attrs = adm9240_attributes,
|
||||
};
|
||||
|
||||
|
||||
/*** sensor chip detect and driver install ***/
|
||||
|
||||
@ -548,72 +587,19 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
adm9240_init_client(new_client);
|
||||
|
||||
/* populate sysfs filesystem */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in0_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in0_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in0_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in1_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in1_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in1_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in2_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in2_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in2_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in3_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in3_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in3_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in4_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in4_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in4_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in5_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in5_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in5_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_max_hyst.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_div.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan2_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan2_div.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan2_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
device_create_file(&new_client->dev, &dev_attr_aout_output);
|
||||
device_create_file(&new_client->dev, &dev_attr_chassis_clear);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &adm9240_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -635,6 +621,7 @@ static int adm9240_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm9240_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -298,12 +298,6 @@ sysfs_in(4);
|
||||
sysfs_in(5);
|
||||
sysfs_in(6);
|
||||
|
||||
#define device_create_file_in(client, offset) do { \
|
||||
device_create_file(&client->dev, &dev_attr_in##offset##_input); \
|
||||
device_create_file(&client->dev, &dev_attr_in##offset##_min); \
|
||||
device_create_file(&client->dev, &dev_attr_in##offset##_max); \
|
||||
} while (0)
|
||||
|
||||
/* 3 Fans */
|
||||
static ssize_t show_fan(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
@ -421,12 +415,6 @@ sysfs_fan(1);
|
||||
sysfs_fan(2);
|
||||
sysfs_fan(3);
|
||||
|
||||
#define device_create_file_fan(client, offset) do { \
|
||||
device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
|
||||
device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
|
||||
device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
|
||||
} while (0)
|
||||
|
||||
/* 4 Temp. Sensors */
|
||||
static int sprintf_temp_from_reg(u16 reg, char *buf, int nr)
|
||||
{
|
||||
@ -515,12 +503,6 @@ sysfs_temp(3);
|
||||
sysfs_temp(4);
|
||||
|
||||
/* VID */
|
||||
#define device_create_file_temp(client, num) do { \
|
||||
device_create_file(&client->dev, &dev_attr_temp##num##_input); \
|
||||
device_create_file(&client->dev, &dev_attr_temp##num##_max); \
|
||||
device_create_file(&client->dev, &dev_attr_temp##num##_max_hyst); \
|
||||
} while (0)
|
||||
|
||||
static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct asb100_data *data = asb100_update_device(dev);
|
||||
@ -528,8 +510,6 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
|
||||
#define device_create_file_vid(client) \
|
||||
device_create_file(&client->dev, &dev_attr_cpu0_vid)
|
||||
|
||||
/* VRM */
|
||||
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
@ -549,8 +529,6 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const
|
||||
|
||||
/* Alarms */
|
||||
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
|
||||
#define device_create_file_vrm(client) \
|
||||
device_create_file(&client->dev, &dev_attr_vrm);
|
||||
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -559,8 +537,6 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
#define device_create_file_alarms(client) \
|
||||
device_create_file(&client->dev, &dev_attr_alarms)
|
||||
|
||||
/* 1 PWM */
|
||||
static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
@ -607,10 +583,65 @@ static ssize_t set_pwm_enable1(struct device *dev, struct device_attribute *attr
|
||||
static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1);
|
||||
static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
|
||||
show_pwm_enable1, set_pwm_enable1);
|
||||
#define device_create_file_pwm1(client) do { \
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1); \
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1_enable); \
|
||||
} while (0)
|
||||
|
||||
static struct attribute *asb100_attributes[] = {
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in0_min.attr,
|
||||
&dev_attr_in0_max.attr,
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in1_min.attr,
|
||||
&dev_attr_in1_max.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
&dev_attr_in2_min.attr,
|
||||
&dev_attr_in2_max.attr,
|
||||
&dev_attr_in3_input.attr,
|
||||
&dev_attr_in3_min.attr,
|
||||
&dev_attr_in3_max.attr,
|
||||
&dev_attr_in4_input.attr,
|
||||
&dev_attr_in4_min.attr,
|
||||
&dev_attr_in4_max.attr,
|
||||
&dev_attr_in5_input.attr,
|
||||
&dev_attr_in5_min.attr,
|
||||
&dev_attr_in5_max.attr,
|
||||
&dev_attr_in6_input.attr,
|
||||
&dev_attr_in6_min.attr,
|
||||
&dev_attr_in6_max.attr,
|
||||
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan1_min.attr,
|
||||
&dev_attr_fan1_div.attr,
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan2_min.attr,
|
||||
&dev_attr_fan2_div.attr,
|
||||
&dev_attr_fan3_input.attr,
|
||||
&dev_attr_fan3_min.attr,
|
||||
&dev_attr_fan3_div.attr,
|
||||
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_max_hyst.attr,
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_temp2_max.attr,
|
||||
&dev_attr_temp2_max_hyst.attr,
|
||||
&dev_attr_temp3_input.attr,
|
||||
&dev_attr_temp3_max.attr,
|
||||
&dev_attr_temp3_max_hyst.attr,
|
||||
&dev_attr_temp4_input.attr,
|
||||
&dev_attr_temp4_max.attr,
|
||||
&dev_attr_temp4_max_hyst.attr,
|
||||
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
&dev_attr_vrm.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_pwm1.attr,
|
||||
&dev_attr_pwm1_enable.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group asb100_group = {
|
||||
.attrs = asb100_attributes,
|
||||
};
|
||||
|
||||
/* This function is called when:
|
||||
asb100_driver is inserted (when this module is loaded), for each
|
||||
@ -810,38 +841,19 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2));
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &asb100_group)))
|
||||
goto ERROR3;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto ERROR3;
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
device_create_file_in(new_client, 0);
|
||||
device_create_file_in(new_client, 1);
|
||||
device_create_file_in(new_client, 2);
|
||||
device_create_file_in(new_client, 3);
|
||||
device_create_file_in(new_client, 4);
|
||||
device_create_file_in(new_client, 5);
|
||||
device_create_file_in(new_client, 6);
|
||||
|
||||
device_create_file_fan(new_client, 1);
|
||||
device_create_file_fan(new_client, 2);
|
||||
device_create_file_fan(new_client, 3);
|
||||
|
||||
device_create_file_temp(new_client, 1);
|
||||
device_create_file_temp(new_client, 2);
|
||||
device_create_file_temp(new_client, 3);
|
||||
device_create_file_temp(new_client, 4);
|
||||
|
||||
device_create_file_vid(new_client);
|
||||
device_create_file_vrm(new_client);
|
||||
|
||||
device_create_file_alarms(new_client);
|
||||
|
||||
device_create_file_pwm1(new_client);
|
||||
|
||||
return 0;
|
||||
|
||||
ERROR4:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &asb100_group);
|
||||
ERROR3:
|
||||
i2c_detach_client(data->lm75[1]);
|
||||
i2c_detach_client(data->lm75[0]);
|
||||
@ -861,8 +873,10 @@ static int asb100_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
/* main client */
|
||||
if (data)
|
||||
if (data) {
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &asb100_group);
|
||||
}
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/hwmon-vid.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
|
||||
@ -116,8 +117,7 @@ static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *att
|
||||
{
|
||||
struct atxp1_data *data;
|
||||
struct i2c_client *client;
|
||||
char vid;
|
||||
char cvid;
|
||||
int vid, cvid;
|
||||
unsigned int vcore;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
@ -251,6 +251,17 @@ static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *att
|
||||
*/
|
||||
static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
|
||||
|
||||
static struct attribute *atxp1_attributes[] = {
|
||||
&dev_attr_gpio1.attr,
|
||||
&dev_attr_gpio2.attr,
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group atxp1_group = {
|
||||
.attrs = atxp1_attributes,
|
||||
};
|
||||
|
||||
|
||||
static int atxp1_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
@ -320,21 +331,23 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_gpio1);
|
||||
device_create_file(&new_client->dev, &dev_attr_gpio2);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
|
||||
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);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -349,6 +362,7 @@ static int atxp1_detach_client(struct i2c_client * client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &atxp1_group);
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include "lm75.h"
|
||||
|
||||
/* Addresses to scan */
|
||||
@ -178,6 +179,18 @@ static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL);
|
||||
static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min);
|
||||
static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
|
||||
|
||||
static struct attribute *ds1621_attributes[] = {
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_min.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group ds1621_group = {
|
||||
.attrs = ds1621_attributes,
|
||||
};
|
||||
|
||||
|
||||
static int ds1621_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
@ -253,21 +266,19 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
|
||||
ds1621_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &ds1621_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
|
||||
return 0;
|
||||
|
||||
/* OK, this is not exactly good programming practice, usually. But it is
|
||||
very code-efficient in this case. */
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &ds1621_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -282,6 +293,7 @@ static int ds1621_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &ds1621_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* f71805f.c - driver for the Fintek F71805F/FG Super-I/O chip integrated
|
||||
* hardware monitoring features
|
||||
* Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
|
||||
* Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.org>
|
||||
*
|
||||
* The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates
|
||||
* complete hardware monitoring features: voltage, fan and temperature
|
||||
@ -31,6 +31,7 @@
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static struct platform_device *pdev;
|
||||
@ -147,7 +148,7 @@ struct f71805f_data {
|
||||
u8 temp_high[3];
|
||||
u8 temp_hyst[3];
|
||||
u8 temp_mode;
|
||||
u8 alarms[3];
|
||||
unsigned long alarms;
|
||||
};
|
||||
|
||||
static inline long in_from_reg(u8 reg)
|
||||
@ -311,10 +312,9 @@ static struct f71805f_data *f71805f_update_device(struct device *dev)
|
||||
data->temp[nr] = f71805f_read8(data,
|
||||
F71805F_REG_TEMP(nr));
|
||||
}
|
||||
for (nr = 0; nr < 3; nr++) {
|
||||
data->alarms[nr] = f71805f_read8(data,
|
||||
F71805F_REG_STATUS(nr));
|
||||
}
|
||||
data->alarms = f71805f_read8(data, F71805F_REG_STATUS(0))
|
||||
+ (f71805f_read8(data, F71805F_REG_STATUS(1)) << 8)
|
||||
+ (f71805f_read8(data, F71805F_REG_STATUS(2)) << 16);
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
@ -557,8 +557,7 @@ static ssize_t show_alarms_in(struct device *dev, struct device_attribute
|
||||
{
|
||||
struct f71805f_data *data = f71805f_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", data->alarms[0] |
|
||||
((data->alarms[1] & 0x01) << 8));
|
||||
return sprintf(buf, "%lu\n", data->alarms & 0x1ff);
|
||||
}
|
||||
|
||||
static ssize_t show_alarms_fan(struct device *dev, struct device_attribute
|
||||
@ -566,7 +565,7 @@ static ssize_t show_alarms_fan(struct device *dev, struct device_attribute
|
||||
{
|
||||
struct f71805f_data *data = f71805f_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", data->alarms[2] & 0x07);
|
||||
return sprintf(buf, "%lu\n", (data->alarms >> 16) & 0x07);
|
||||
}
|
||||
|
||||
static ssize_t show_alarms_temp(struct device *dev, struct device_attribute
|
||||
@ -574,7 +573,17 @@ static ssize_t show_alarms_temp(struct device *dev, struct device_attribute
|
||||
{
|
||||
struct f71805f_data *data = f71805f_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", (data->alarms[1] >> 3) & 0x07);
|
||||
return sprintf(buf, "%lu\n", (data->alarms >> 11) & 0x07);
|
||||
}
|
||||
|
||||
static ssize_t show_alarm(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71805f_data *data = f71805f_update_device(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
int bitnr = attr->index;
|
||||
|
||||
return sprintf(buf, "%lu\n", (data->alarms >> bitnr) & 1);
|
||||
}
|
||||
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute
|
||||
@ -585,88 +594,189 @@ static ssize_t show_name(struct device *dev, struct device_attribute
|
||||
return sprintf(buf, "%s\n", data->name);
|
||||
}
|
||||
|
||||
static struct device_attribute f71805f_dev_attr[] = {
|
||||
__ATTR(in0_input, S_IRUGO, show_in0, NULL),
|
||||
__ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max),
|
||||
__ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min),
|
||||
__ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL),
|
||||
__ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL),
|
||||
__ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL),
|
||||
__ATTR(name, S_IRUGO, show_name, NULL),
|
||||
static DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL);
|
||||
static DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max);
|
||||
static DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min);
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 1);
|
||||
static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 1);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 2);
|
||||
static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 2);
|
||||
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 3);
|
||||
static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 3);
|
||||
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 4);
|
||||
static SENSOR_DEVICE_ATTR(in4_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 4);
|
||||
static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(in5_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 5);
|
||||
static SENSOR_DEVICE_ATTR(in5_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 5);
|
||||
static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(in6_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 6);
|
||||
static SENSOR_DEVICE_ATTR(in6_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 6);
|
||||
static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 7);
|
||||
static SENSOR_DEVICE_ATTR(in7_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 7);
|
||||
static SENSOR_DEVICE_ATTR(in7_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 7);
|
||||
static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 8);
|
||||
static SENSOR_DEVICE_ATTR(in8_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 8);
|
||||
static SENSOR_DEVICE_ATTR(in8_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 8);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
|
||||
show_fan_min, set_fan_min, 0);
|
||||
static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
|
||||
show_fan_min, set_fan_min, 1);
|
||||
static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
|
||||
show_fan_min, set_fan_min, 2);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
|
||||
show_temp_max, set_temp_max, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
|
||||
show_temp_hyst, set_temp_hyst, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR,
|
||||
show_temp_max, set_temp_max, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR,
|
||||
show_temp_hyst, set_temp_hyst, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR,
|
||||
show_temp_max, set_temp_max, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR,
|
||||
show_temp_hyst, set_temp_hyst, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
|
||||
static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8);
|
||||
static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11);
|
||||
static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12);
|
||||
static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
|
||||
static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 16);
|
||||
static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 17);
|
||||
static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 18);
|
||||
static DEVICE_ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL);
|
||||
static DEVICE_ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL);
|
||||
static DEVICE_ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL);
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
static struct attribute *f71805f_attributes[] = {
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in0_max.attr,
|
||||
&dev_attr_in0_min.attr,
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_min.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_type.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_in0_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_alarm.dev_attr.attr,
|
||||
&dev_attr_alarms_in.attr,
|
||||
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
|
||||
&dev_attr_alarms_temp.attr,
|
||||
&dev_attr_alarms_fan.attr,
|
||||
|
||||
&dev_attr_name.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute f71805f_sensor_attr[] = {
|
||||
SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
|
||||
SENSOR_ATTR(in1_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 1),
|
||||
SENSOR_ATTR(in1_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 1),
|
||||
SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
|
||||
SENSOR_ATTR(in2_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 2),
|
||||
SENSOR_ATTR(in2_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 2),
|
||||
SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
|
||||
SENSOR_ATTR(in3_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 3),
|
||||
SENSOR_ATTR(in3_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 3),
|
||||
SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
|
||||
SENSOR_ATTR(in4_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 4),
|
||||
SENSOR_ATTR(in4_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 4),
|
||||
SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
|
||||
SENSOR_ATTR(in5_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 5),
|
||||
SENSOR_ATTR(in5_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 5),
|
||||
SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
|
||||
SENSOR_ATTR(in6_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 6),
|
||||
SENSOR_ATTR(in6_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 6),
|
||||
SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
|
||||
SENSOR_ATTR(in7_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 7),
|
||||
SENSOR_ATTR(in7_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 7),
|
||||
SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
|
||||
SENSOR_ATTR(in8_max, S_IRUGO | S_IWUSR,
|
||||
show_in_max, set_in_max, 8),
|
||||
SENSOR_ATTR(in8_min, S_IRUGO | S_IWUSR,
|
||||
show_in_min, set_in_min, 8),
|
||||
|
||||
SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
|
||||
SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR,
|
||||
show_temp_max, set_temp_max, 0),
|
||||
SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
|
||||
show_temp_hyst, set_temp_hyst, 0),
|
||||
SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
|
||||
SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
|
||||
SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR,
|
||||
show_temp_max, set_temp_max, 1),
|
||||
SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR,
|
||||
show_temp_hyst, set_temp_hyst, 1),
|
||||
SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
|
||||
SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
|
||||
SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR,
|
||||
show_temp_max, set_temp_max, 2),
|
||||
SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR,
|
||||
show_temp_hyst, set_temp_hyst, 2),
|
||||
SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
|
||||
static const struct attribute_group f71805f_group = {
|
||||
.attrs = f71805f_attributes,
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute f71805f_fan_attr[] = {
|
||||
SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
|
||||
SENSOR_ATTR(fan1_min, S_IRUGO | S_IWUSR,
|
||||
show_fan_min, set_fan_min, 0),
|
||||
SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
|
||||
SENSOR_ATTR(fan2_min, S_IRUGO | S_IWUSR,
|
||||
show_fan_min, set_fan_min, 1),
|
||||
SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
|
||||
SENSOR_ATTR(fan3_min, S_IRUGO | S_IWUSR,
|
||||
show_fan_min, set_fan_min, 2),
|
||||
static struct attribute *f71805f_attributes_fan[3][4] = {
|
||||
{
|
||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_alarm.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_fan2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_alarm.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_fan3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_alarm.dev_attr.attr,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static const struct attribute_group f71805f_group_fan[3] = {
|
||||
{ .attrs = f71805f_attributes_fan[0] },
|
||||
{ .attrs = f71805f_attributes_fan[1] },
|
||||
{ .attrs = f71805f_attributes_fan[2] },
|
||||
};
|
||||
|
||||
/*
|
||||
@ -714,43 +824,35 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
/* Initialize the F71805F chip */
|
||||
f71805f_init_device(data);
|
||||
|
||||
/* Register sysfs interface files */
|
||||
for (i = 0; i < ARRAY_SIZE(f71805f_dev_attr); i++) {
|
||||
err = device_create_file(&pdev->dev, &f71805f_dev_attr[i]);
|
||||
if (err)
|
||||
goto exit_class;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(f71805f_sensor_attr); i++) {
|
||||
err = device_create_file(&pdev->dev,
|
||||
&f71805f_sensor_attr[i].dev_attr);
|
||||
if (err)
|
||||
goto exit_class;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(f71805f_fan_attr); i++) {
|
||||
if (!(data->fan_enabled & (1 << (i / 2))))
|
||||
if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group)))
|
||||
goto exit_free;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (!(data->fan_enabled & (1 << i)))
|
||||
continue;
|
||||
err = device_create_file(&pdev->dev,
|
||||
&f71805f_fan_attr[i].dev_attr);
|
||||
if (err)
|
||||
goto exit_class;
|
||||
if ((err = sysfs_create_group(&pdev->dev.kobj,
|
||||
&f71805f_group_fan[i])))
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_class:
|
||||
dev_err(&pdev->dev, "Sysfs interface creation failed\n");
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
|
||||
for (i = 0; i < 3; i++)
|
||||
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]);
|
||||
exit_free:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(data);
|
||||
exit:
|
||||
return err;
|
||||
@ -759,9 +861,13 @@ exit:
|
||||
static int __devexit f71805f_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct f71805f_data *data = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
|
||||
for (i = 0; i < 3; i++)
|
||||
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]);
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/*
|
||||
* Addresses to scan
|
||||
@ -240,47 +241,45 @@ sysfs_alarms(FSCHER_REG_EVENTS)
|
||||
sysfs_control(FSCHER_REG_CONTROL)
|
||||
sysfs_watchdog(FSCHER_REG_WDOG_CONTROL, FSCHER_REG_WDOG_STATE, FSCHER_REG_WDOG_PRESET)
|
||||
|
||||
#define device_create_file_fan(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_fan##offset##_status); \
|
||||
device_create_file(&client->dev, &dev_attr_pwm##offset); \
|
||||
device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
|
||||
device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
|
||||
} while (0)
|
||||
static struct attribute *fscher_attributes[] = {
|
||||
&dev_attr_revision.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_control.attr,
|
||||
|
||||
#define device_create_file_temp(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_temp##offset##_status); \
|
||||
device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
|
||||
} while (0)
|
||||
&dev_attr_watchdog_status.attr,
|
||||
&dev_attr_watchdog_control.attr,
|
||||
&dev_attr_watchdog_preset.attr,
|
||||
|
||||
#define device_create_file_in(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_in##offset##_input); \
|
||||
} while (0)
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
|
||||
#define device_create_file_revision(client) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_revision); \
|
||||
} while (0)
|
||||
&dev_attr_fan1_status.attr,
|
||||
&dev_attr_fan1_div.attr,
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_pwm1.attr,
|
||||
&dev_attr_fan2_status.attr,
|
||||
&dev_attr_fan2_div.attr,
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_pwm2.attr,
|
||||
&dev_attr_fan3_status.attr,
|
||||
&dev_attr_fan3_div.attr,
|
||||
&dev_attr_fan3_input.attr,
|
||||
&dev_attr_pwm3.attr,
|
||||
|
||||
#define device_create_file_alarms(client) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_alarms); \
|
||||
} while (0)
|
||||
&dev_attr_temp1_status.attr,
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp2_status.attr,
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_temp3_status.attr,
|
||||
&dev_attr_temp3_input.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define device_create_file_control(client) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_control); \
|
||||
} while (0)
|
||||
static const struct attribute_group fscher_group = {
|
||||
.attrs = fscher_attributes,
|
||||
};
|
||||
|
||||
#define device_create_file_watchdog(client) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_watchdog_status); \
|
||||
device_create_file(&client->dev, &dev_attr_watchdog_control); \
|
||||
device_create_file(&client->dev, &dev_attr_watchdog_preset); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Real code
|
||||
*/
|
||||
@ -342,31 +341,19 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
fscher_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &fscher_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
device_create_file_revision(new_client);
|
||||
device_create_file_alarms(new_client);
|
||||
device_create_file_control(new_client);
|
||||
device_create_file_watchdog(new_client);
|
||||
|
||||
device_create_file_in(new_client, 0);
|
||||
device_create_file_in(new_client, 1);
|
||||
device_create_file_in(new_client, 2);
|
||||
|
||||
device_create_file_fan(new_client, 1);
|
||||
device_create_file_fan(new_client, 2);
|
||||
device_create_file_fan(new_client, 3);
|
||||
|
||||
device_create_file_temp(new_client, 1);
|
||||
device_create_file_temp(new_client, 2);
|
||||
device_create_file_temp(new_client, 3);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &fscher_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -381,6 +368,7 @@ static int fscher_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &fscher_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/*
|
||||
* Addresses to scan
|
||||
@ -432,6 +433,44 @@ static DEVICE_ATTR(in0_input, S_IRUGO, show_volt_12, NULL);
|
||||
static DEVICE_ATTR(in1_input, S_IRUGO, show_volt_5, NULL);
|
||||
static DEVICE_ATTR(in2_input, S_IRUGO, show_volt_batt, NULL);
|
||||
|
||||
static struct attribute *fscpos_attributes[] = {
|
||||
&dev_attr_event.attr,
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
|
||||
&dev_attr_wdog_control.attr,
|
||||
&dev_attr_wdog_preset.attr,
|
||||
&dev_attr_wdog_state.attr,
|
||||
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_status.attr,
|
||||
&dev_attr_temp1_reset.attr,
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_temp2_status.attr,
|
||||
&dev_attr_temp2_reset.attr,
|
||||
&dev_attr_temp3_input.attr,
|
||||
&dev_attr_temp3_status.attr,
|
||||
&dev_attr_temp3_reset.attr,
|
||||
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan1_status.attr,
|
||||
&dev_attr_fan1_ripple.attr,
|
||||
&dev_attr_pwm1.attr,
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan2_status.attr,
|
||||
&dev_attr_fan2_ripple.attr,
|
||||
&dev_attr_pwm2.attr,
|
||||
&dev_attr_fan3_input.attr,
|
||||
&dev_attr_fan3_status.attr,
|
||||
&dev_attr_fan3_ripple.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group fscpos_group = {
|
||||
.attrs = fscpos_attributes,
|
||||
};
|
||||
|
||||
static int fscpos_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
||||
@ -497,42 +536,19 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_event);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_wdog_control);
|
||||
device_create_file(&new_client->dev, &dev_attr_wdog_preset);
|
||||
device_create_file(&new_client->dev, &dev_attr_wdog_state);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_status);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_reset);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_status);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_reset);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_status);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_reset);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_status);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_ripple);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_status);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_ripple);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_status);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_ripple);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &fscpos_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -547,6 +563,7 @@ static int fscpos_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &fscpos_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
|
||||
@ -340,6 +341,42 @@ static DEVICE_ATTR(beep_enable, S_IWUSR|S_IRUGO,
|
||||
static DEVICE_ATTR(beep_mask, S_IWUSR|S_IRUGO,
|
||||
show_beep_mask, set_beep_mask);
|
||||
|
||||
static struct attribute *gl518_attributes[] = {
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
&dev_attr_in3_input.attr,
|
||||
&dev_attr_in0_min.attr,
|
||||
&dev_attr_in1_min.attr,
|
||||
&dev_attr_in2_min.attr,
|
||||
&dev_attr_in3_min.attr,
|
||||
&dev_attr_in0_max.attr,
|
||||
&dev_attr_in1_max.attr,
|
||||
&dev_attr_in2_max.attr,
|
||||
&dev_attr_in3_max.attr,
|
||||
|
||||
&dev_attr_fan1_auto.attr,
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan1_min.attr,
|
||||
&dev_attr_fan2_min.attr,
|
||||
&dev_attr_fan1_div.attr,
|
||||
&dev_attr_fan2_div.attr,
|
||||
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_max_hyst.attr,
|
||||
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_beep_enable.attr,
|
||||
&dev_attr_beep_mask.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group gl518_group = {
|
||||
.attrs = gl518_attributes,
|
||||
};
|
||||
|
||||
/*
|
||||
* Real code
|
||||
*/
|
||||
@ -420,43 +457,19 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
gl518_init_client((struct i2c_client *) new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &gl518_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_auto);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
device_create_file(&new_client->dev, &dev_attr_beep_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_beep_mask);
|
||||
|
||||
return 0;
|
||||
|
||||
/* OK, this is not exactly good programming practice, usually. But it is
|
||||
very code-efficient in this case. */
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &gl518_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -490,6 +503,7 @@ static int gl518_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl518_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <linux/hwmon-vid.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/* Type of the extra sensor */
|
||||
static unsigned short extra_sensor_type;
|
||||
@ -190,55 +191,29 @@ static DEVICE_ATTR(type##item, S_IRUGO, get_##type##0##item, NULL);
|
||||
#define sysfs_vid(n) \
|
||||
sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT)
|
||||
|
||||
#define device_create_file_vid(client, n) \
|
||||
device_create_file(&client->dev, &dev_attr_cpu##n##_vid)
|
||||
|
||||
#define sysfs_in(n) \
|
||||
sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \
|
||||
sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \
|
||||
sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \
|
||||
|
||||
#define device_create_file_in(client, n) \
|
||||
({device_create_file(&client->dev, &dev_attr_in##n##_input); \
|
||||
device_create_file(&client->dev, &dev_attr_in##n##_min); \
|
||||
device_create_file(&client->dev, &dev_attr_in##n##_max);})
|
||||
|
||||
#define sysfs_fan(n) \
|
||||
sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \
|
||||
sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \
|
||||
sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV)
|
||||
|
||||
#define device_create_file_fan(client, n) \
|
||||
({device_create_file(&client->dev, &dev_attr_fan##n##_input); \
|
||||
device_create_file(&client->dev, &dev_attr_fan##n##_min); \
|
||||
device_create_file(&client->dev, &dev_attr_fan##n##_div);})
|
||||
|
||||
#define sysfs_fan_off(n) \
|
||||
sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \
|
||||
|
||||
#define device_create_file_fan_off(client, n) \
|
||||
device_create_file(&client->dev, &dev_attr_fan##n##_off)
|
||||
|
||||
#define sysfs_temp(n) \
|
||||
sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \
|
||||
sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \
|
||||
sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST)
|
||||
|
||||
#define device_create_file_temp(client, n) \
|
||||
({device_create_file(&client->dev, &dev_attr_temp##n##_input); \
|
||||
device_create_file(&client->dev, &dev_attr_temp##n##_max); \
|
||||
device_create_file(&client->dev, &dev_attr_temp##n##_max_hyst);})
|
||||
|
||||
#define sysfs_alarms() \
|
||||
sysfs_ro(alarms, , GL520_REG_ALARMS) \
|
||||
sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \
|
||||
sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK)
|
||||
|
||||
#define device_create_file_alarms(client) \
|
||||
({device_create_file(&client->dev, &dev_attr_alarms); \
|
||||
device_create_file(&client->dev, &dev_attr_beep_enable); \
|
||||
device_create_file(&client->dev, &dev_attr_beep_mask);})
|
||||
|
||||
|
||||
sysfs_vid(0)
|
||||
|
||||
@ -511,6 +486,59 @@ static ssize_t set_beep_mask(struct i2c_client *client, struct gl520_data *data,
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct attribute *gl520_attributes[] = {
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in0_min.attr,
|
||||
&dev_attr_in0_max.attr,
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in1_min.attr,
|
||||
&dev_attr_in1_max.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
&dev_attr_in2_min.attr,
|
||||
&dev_attr_in2_max.attr,
|
||||
&dev_attr_in3_input.attr,
|
||||
&dev_attr_in3_min.attr,
|
||||
&dev_attr_in3_max.attr,
|
||||
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan1_min.attr,
|
||||
&dev_attr_fan1_div.attr,
|
||||
&dev_attr_fan1_off.attr,
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan2_min.attr,
|
||||
&dev_attr_fan2_div.attr,
|
||||
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_max_hyst.attr,
|
||||
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_beep_enable.attr,
|
||||
&dev_attr_beep_mask.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group gl520_group = {
|
||||
.attrs = gl520_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *gl520_attributes_opt[] = {
|
||||
&dev_attr_in4_input.attr,
|
||||
&dev_attr_in4_min.attr,
|
||||
&dev_attr_in4_max.attr,
|
||||
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_temp2_max.attr,
|
||||
&dev_attr_temp2_max_hyst.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group gl520_group_opt = {
|
||||
.attrs = gl520_attributes_opt,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Real code
|
||||
@ -572,33 +600,39 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
gl520_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &gl520_group)))
|
||||
goto exit_detach;
|
||||
|
||||
if (data->two_temps) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp2_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp2_max))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp2_max_hyst)))
|
||||
goto exit_remove_files;
|
||||
} else {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in4_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in4_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in4_max)))
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
device_create_file_vid(new_client, 0);
|
||||
|
||||
device_create_file_in(new_client, 0);
|
||||
device_create_file_in(new_client, 1);
|
||||
device_create_file_in(new_client, 2);
|
||||
device_create_file_in(new_client, 3);
|
||||
if (!data->two_temps)
|
||||
device_create_file_in(new_client, 4);
|
||||
|
||||
device_create_file_fan(new_client, 1);
|
||||
device_create_file_fan(new_client, 2);
|
||||
device_create_file_fan_off(new_client, 1);
|
||||
|
||||
device_create_file_temp(new_client, 1);
|
||||
if (data->two_temps)
|
||||
device_create_file_temp(new_client, 2);
|
||||
|
||||
device_create_file_alarms(new_client);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &gl520_group);
|
||||
sysfs_remove_group(&new_client->dev.kobj, &gl520_group_opt);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -652,6 +686,8 @@ static int gl520_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -587,7 +587,9 @@ static int __init hdaps_init(void)
|
||||
input_set_abs_params(hdaps_idev, ABS_Y,
|
||||
-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
|
||||
|
||||
input_register_device(hdaps_idev);
|
||||
ret = input_register_device(hdaps_idev);
|
||||
if (ret)
|
||||
goto out_idev;
|
||||
|
||||
/* start up our timer for the input device */
|
||||
init_timer(&hdaps_timer);
|
||||
@ -598,6 +600,8 @@ static int __init hdaps_init(void)
|
||||
printk(KERN_INFO "hdaps: driver successfully loaded.\n");
|
||||
return 0;
|
||||
|
||||
out_idev:
|
||||
input_free_device(hdaps_idev);
|
||||
out_group:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
|
||||
out_device:
|
||||
|
@ -4,10 +4,12 @@
|
||||
|
||||
Supports: IT8705F Super I/O chip w/LPC interface
|
||||
IT8712F Super I/O chip w/LPC interface & SMBus
|
||||
IT8716F Super I/O chip w/LPC interface
|
||||
IT8718F Super I/O chip w/LPC interface
|
||||
Sis950 A clone of the IT8705F
|
||||
|
||||
Copyright (C) 2001 Chris Gauthron <chrisg@0-in.com>
|
||||
Largely inspired by lm78.c of the same package
|
||||
Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
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
|
||||
@ -24,13 +26,6 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
djg@pdp8.net David Gesswein 7/18/01
|
||||
Modified to fix bug with not all alarms enabled.
|
||||
Added ability to read battery voltage and select temperature sensor
|
||||
type at module load time.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
@ -42,6 +37,7 @@
|
||||
#include <linux/hwmon-vid.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
@ -50,12 +46,13 @@ static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
|
||||
static unsigned short isa_address;
|
||||
|
||||
/* Insmod parameters */
|
||||
I2C_CLIENT_INSMOD_2(it87, it8712);
|
||||
I2C_CLIENT_INSMOD_4(it87, it8712, it8716, it8718);
|
||||
|
||||
#define REG 0x2e /* The register to read/write */
|
||||
#define DEV 0x07 /* Register: Logical device select */
|
||||
#define VAL 0x2f /* The value to read/write */
|
||||
#define PME 0x04 /* The device with the fan registers in it */
|
||||
#define GPIO 0x07 /* The device with the IT8718F VID value in it */
|
||||
#define DEVID 0x20 /* Register: Device ID */
|
||||
#define DEVREV 0x22 /* Register: Device Revision */
|
||||
|
||||
@ -77,10 +74,10 @@ static int superio_inw(int reg)
|
||||
}
|
||||
|
||||
static inline void
|
||||
superio_select(void)
|
||||
superio_select(int ldn)
|
||||
{
|
||||
outb(DEV, REG);
|
||||
outb(PME, VAL);
|
||||
outb(ldn, VAL);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -99,20 +96,27 @@ superio_exit(void)
|
||||
outb(0x02, VAL);
|
||||
}
|
||||
|
||||
/* Logical device 4 registers */
|
||||
#define IT8712F_DEVID 0x8712
|
||||
#define IT8705F_DEVID 0x8705
|
||||
#define IT8716F_DEVID 0x8716
|
||||
#define IT8718F_DEVID 0x8718
|
||||
#define IT87_ACT_REG 0x30
|
||||
#define IT87_BASE_REG 0x60
|
||||
|
||||
/* Logical device 7 registers (IT8712F and later) */
|
||||
#define IT87_SIO_PINX2_REG 0x2c /* Pin selection */
|
||||
#define IT87_SIO_VID_REG 0xfc /* VID value */
|
||||
|
||||
/* Update battery voltage after every reading if true */
|
||||
static int update_vbat;
|
||||
|
||||
/* Not all BIOSes properly configure the PWM registers */
|
||||
static int fix_pwm_polarity;
|
||||
|
||||
/* Chip Type */
|
||||
|
||||
/* Values read from Super-I/O config space */
|
||||
static u16 chip_type;
|
||||
static u8 vid_value;
|
||||
|
||||
/* Many IT87 constants specified below */
|
||||
|
||||
@ -131,13 +135,21 @@ static u16 chip_type;
|
||||
#define IT87_REG_ALARM2 0x02
|
||||
#define IT87_REG_ALARM3 0x03
|
||||
|
||||
/* The IT8718F has the VID value in a different register, in Super-I/O
|
||||
configuration space. */
|
||||
#define IT87_REG_VID 0x0a
|
||||
/* Warning: register 0x0b is used for something completely different in
|
||||
new chips/revisions. I suspect only 16-bit tachometer mode will work
|
||||
for these. */
|
||||
#define IT87_REG_FAN_DIV 0x0b
|
||||
#define IT87_REG_FAN_16BIT 0x0c
|
||||
|
||||
/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */
|
||||
|
||||
#define IT87_REG_FAN(nr) (0x0d + (nr))
|
||||
#define IT87_REG_FAN_MIN(nr) (0x10 + (nr))
|
||||
#define IT87_REG_FANX(nr) (0x18 + (nr))
|
||||
#define IT87_REG_FANX_MIN(nr) (0x1b + (nr))
|
||||
#define IT87_REG_FAN_MAIN_CTRL 0x13
|
||||
#define IT87_REG_FAN_CTL 0x14
|
||||
#define IT87_REG_PWM(nr) (0x15 + (nr))
|
||||
@ -169,7 +181,16 @@ static inline u8 FAN_TO_REG(long rpm, int div)
|
||||
254);
|
||||
}
|
||||
|
||||
static inline u16 FAN16_TO_REG(long rpm)
|
||||
{
|
||||
if (rpm == 0)
|
||||
return 0xffff;
|
||||
return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
|
||||
}
|
||||
|
||||
#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
|
||||
/* The divider is fixed to 2 in 16-bit mode */
|
||||
#define FAN16_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:1350000/((val)*2))
|
||||
|
||||
#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\
|
||||
((val)+500)/1000),-128,127))
|
||||
@ -181,7 +202,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
|
||||
static int DIV_TO_REG(int val)
|
||||
{
|
||||
int answer = 0;
|
||||
while ((val >>= 1) != 0)
|
||||
while (answer < 7 && (val >>= 1))
|
||||
answer++;
|
||||
return answer;
|
||||
}
|
||||
@ -203,10 +224,11 @@ struct it87_data {
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
||||
u8 in[9]; /* Register value */
|
||||
u8 in_max[9]; /* Register value */
|
||||
u8 in_min[9]; /* Register value */
|
||||
u8 fan[3]; /* Register value */
|
||||
u8 fan_min[3]; /* Register value */
|
||||
u8 in_max[8]; /* Register value */
|
||||
u8 in_min[8]; /* Register value */
|
||||
u8 has_fan; /* Bitfield, fans enabled */
|
||||
u16 fan[3]; /* Register values, possibly combined */
|
||||
u16 fan_min[3]; /* Register values, possibly combined */
|
||||
u8 temp[3]; /* Register value */
|
||||
u8 temp_high[3]; /* Register value */
|
||||
u8 temp_low[3]; /* Register value */
|
||||
@ -545,15 +567,15 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
int i, min[3];
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
int min;
|
||||
u8 old;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
old = it87_read_value(client, IT87_REG_FAN_DIV);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
min[i] = FAN_FROM_REG(data->fan_min[i], DIV_FROM_REG(data->fan_div[i]));
|
||||
/* Save fan min limit */
|
||||
min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
|
||||
|
||||
switch (nr) {
|
||||
case 0:
|
||||
@ -573,10 +595,10 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
val |= 0x1 << 6;
|
||||
it87_write_value(client, IT87_REG_FAN_DIV, val);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i]));
|
||||
it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]);
|
||||
}
|
||||
/* Restore fan min limit */
|
||||
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
|
||||
it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
@ -657,6 +679,59 @@ show_pwm_offset(1);
|
||||
show_pwm_offset(2);
|
||||
show_pwm_offset(3);
|
||||
|
||||
/* A different set of callbacks for 16-bit fans */
|
||||
static ssize_t show_fan16(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_fan16_min(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan_min[nr]));
|
||||
}
|
||||
|
||||
static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
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 it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->fan_min[nr] = FAN16_TO_REG(val);
|
||||
it87_write_value(client, IT87_REG_FAN_MIN(nr),
|
||||
data->fan_min[nr] & 0xff);
|
||||
it87_write_value(client, IT87_REG_FANX_MIN(nr),
|
||||
data->fan_min[nr] >> 8);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
/* We want to use the same sysfs file names as 8-bit fans, but we need
|
||||
different variable names, so we have to use SENSOR_ATTR instead of
|
||||
SENSOR_DEVICE_ATTR. */
|
||||
#define show_fan16_offset(offset) \
|
||||
static struct sensor_device_attribute sensor_dev_attr_fan##offset##_input16 \
|
||||
= SENSOR_ATTR(fan##offset##_input, S_IRUGO, \
|
||||
show_fan16, NULL, offset - 1); \
|
||||
static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \
|
||||
= SENSOR_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_fan16_min, set_fan16_min, offset - 1)
|
||||
|
||||
show_fan16_offset(1);
|
||||
show_fan16_offset(2);
|
||||
show_fan16_offset(3);
|
||||
|
||||
/* Alarms */
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -684,8 +759,6 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
|
||||
#define device_create_file_vrm(client) \
|
||||
device_create_file(&client->dev, &dev_attr_vrm)
|
||||
|
||||
static ssize_t
|
||||
show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
@ -694,8 +767,88 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
|
||||
}
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
|
||||
#define device_create_file_vid(client) \
|
||||
device_create_file(&client->dev, &dev_attr_cpu0_vid)
|
||||
|
||||
static struct attribute *it87_attributes[] = {
|
||||
&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_in0_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_max.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_type.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_type.dev_attr.attr,
|
||||
|
||||
&dev_attr_alarms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group it87_group = {
|
||||
.attrs = it87_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *it87_attributes_opt[] = {
|
||||
&sensor_dev_attr_fan1_input16.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_min16.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_input16.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_min16.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_input16.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_min16.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_div.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm1.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm2.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm3.dev_attr.attr,
|
||||
|
||||
&dev_attr_vrm.attr,
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group it87_group_opt = {
|
||||
.attrs = it87_attributes_opt,
|
||||
};
|
||||
|
||||
/* This function is called when:
|
||||
* it87_driver is inserted (when this module is loaded), for each
|
||||
@ -721,10 +874,12 @@ static int __init it87_find(unsigned short *address)
|
||||
superio_enter();
|
||||
chip_type = superio_inw(DEVID);
|
||||
if (chip_type != IT8712F_DEVID
|
||||
&& chip_type != IT8716F_DEVID
|
||||
&& chip_type != IT8718F_DEVID
|
||||
&& chip_type != IT8705F_DEVID)
|
||||
goto exit;
|
||||
|
||||
superio_select();
|
||||
superio_select(PME);
|
||||
if (!(superio_inb(IT87_ACT_REG) & 0x01)) {
|
||||
pr_info("it87: Device not activated, skipping\n");
|
||||
goto exit;
|
||||
@ -740,6 +895,21 @@ static int __init it87_find(unsigned short *address)
|
||||
pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n",
|
||||
chip_type, *address, superio_inb(DEVREV) & 0x0f);
|
||||
|
||||
/* Read GPIO config and VID value from LDN 7 (GPIO) */
|
||||
if (chip_type != IT8705F_DEVID) {
|
||||
int reg;
|
||||
|
||||
superio_select(GPIO);
|
||||
if (chip_type == it8718)
|
||||
vid_value = superio_inb(IT87_SIO_VID_REG);
|
||||
|
||||
reg = superio_inb(IT87_SIO_PINX2_REG);
|
||||
if (reg & (1 << 0))
|
||||
pr_info("it87: in3 is VCC (+5V)\n");
|
||||
if (reg & (1 << 1))
|
||||
pr_info("it87: in7 is VCCH (+5V Stand-By)\n");
|
||||
}
|
||||
|
||||
exit:
|
||||
superio_exit();
|
||||
return err;
|
||||
@ -800,8 +970,19 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
i = it87_read_value(new_client, IT87_REG_CHIPID);
|
||||
if (i == 0x90) {
|
||||
kind = it87;
|
||||
if ((is_isa) && (chip_type == IT8712F_DEVID))
|
||||
kind = it8712;
|
||||
if (is_isa) {
|
||||
switch (chip_type) {
|
||||
case IT8712F_DEVID:
|
||||
kind = it8712;
|
||||
break;
|
||||
case IT8716F_DEVID:
|
||||
kind = it8716;
|
||||
break;
|
||||
case IT8718F_DEVID:
|
||||
kind = it8718;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (kind == 0)
|
||||
@ -818,6 +999,10 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
name = "it87";
|
||||
} else if (kind == it8712) {
|
||||
name = "it8712";
|
||||
} else if (kind == it8716) {
|
||||
name = "it8716";
|
||||
} else if (kind == it8718) {
|
||||
name = "it8718";
|
||||
}
|
||||
|
||||
/* Fill in the remaining client fields and put it into the global list */
|
||||
@ -842,76 +1027,103 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
it87_init_client(new_client, data);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &it87_group)))
|
||||
goto ERROR3;
|
||||
|
||||
/* Do not create fan files for disabled fans */
|
||||
if (data->type == it8716 || data->type == it8718) {
|
||||
/* 16-bit tachometers */
|
||||
if (data->has_fan & (1 << 0)) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_input16.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_min16.dev_attr)))
|
||||
goto ERROR4;
|
||||
}
|
||||
if (data->has_fan & (1 << 1)) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan2_input16.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan2_min16.dev_attr)))
|
||||
goto ERROR4;
|
||||
}
|
||||
if (data->has_fan & (1 << 2)) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan3_input16.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan3_min16.dev_attr)))
|
||||
goto ERROR4;
|
||||
}
|
||||
} else {
|
||||
/* 8-bit tachometers with clock divider */
|
||||
if (data->has_fan & (1 << 0)) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_input.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_min.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_div.dev_attr)))
|
||||
goto ERROR4;
|
||||
}
|
||||
if (data->has_fan & (1 << 1)) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan2_input.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan2_min.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan2_div.dev_attr)))
|
||||
goto ERROR4;
|
||||
}
|
||||
if (data->has_fan & (1 << 2)) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan3_input.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan3_min.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan3_div.dev_attr)))
|
||||
goto ERROR4;
|
||||
}
|
||||
}
|
||||
|
||||
if (enable_pwm_interface) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_pwm1_enable.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_pwm2_enable.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_pwm3_enable.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_pwm1.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_pwm2.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_pwm3.dev_attr)))
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
if (data->type == it8712 || data->type == it8716
|
||||
|| data->type == it8718) {
|
||||
data->vrm = vid_which_vrm();
|
||||
/* VID reading from Super-I/O config space if available */
|
||||
data->vid = vid_value;
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_vrm))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_cpu0_vid)))
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto ERROR3;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
if (enable_pwm_interface) {
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr);
|
||||
}
|
||||
|
||||
if (data->type == it8712) {
|
||||
data->vrm = vid_which_vrm();
|
||||
device_create_file_vrm(new_client);
|
||||
device_create_file_vid(new_client);
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
ERROR4:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &it87_group);
|
||||
sysfs_remove_group(&new_client->dev.kobj, &it87_group_opt);
|
||||
ERROR3:
|
||||
i2c_detach_client(new_client);
|
||||
ERROR2:
|
||||
@ -929,6 +1141,8 @@ static int it87_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &it87_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &it87_group_opt);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
@ -1045,6 +1259,22 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
|
||||
data->manual_pwm_ctl[i] = 0xff;
|
||||
}
|
||||
|
||||
/* Some chips seem to have default value 0xff for all limit
|
||||
* registers. For low voltage limits it makes no sense and triggers
|
||||
* alarms, so change to 0 instead. For high temperature limits, it
|
||||
* means -1 degree C, which surprisingly doesn't trigger an alarm,
|
||||
* but is still confusing, so change to 127 degrees C. */
|
||||
for (i = 0; i < 8; i++) {
|
||||
tmp = it87_read_value(client, IT87_REG_VIN_MIN(i));
|
||||
if (tmp == 0xff)
|
||||
it87_write_value(client, IT87_REG_VIN_MIN(i), 0);
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
tmp = it87_read_value(client, IT87_REG_TEMP_HIGH(i));
|
||||
if (tmp == 0xff)
|
||||
it87_write_value(client, IT87_REG_TEMP_HIGH(i), 127);
|
||||
}
|
||||
|
||||
/* Check if temperature channnels are reset manually or by some reason */
|
||||
tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE);
|
||||
if ((tmp & 0x3f) == 0) {
|
||||
@ -1068,6 +1298,18 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
|
||||
data->fan_main_ctrl |= 0x70;
|
||||
it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
|
||||
}
|
||||
data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
|
||||
|
||||
/* Set tachometers to 16-bit mode if needed */
|
||||
if (data->type == it8716 || data->type == it8718) {
|
||||
tmp = it87_read_value(client, IT87_REG_FAN_16BIT);
|
||||
if (~tmp & 0x07 & data->has_fan) {
|
||||
dev_dbg(&client->dev,
|
||||
"Setting fan1-3 to 16-bit mode\n");
|
||||
it87_write_value(client, IT87_REG_FAN_16BIT,
|
||||
tmp | 0x07);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set current fan mode registers and the default settings for the
|
||||
* other mode registers */
|
||||
@ -1118,18 +1360,26 @@ static struct it87_data *it87_update_device(struct device *dev)
|
||||
data->in_max[i] =
|
||||
it87_read_value(client, IT87_REG_VIN_MAX(i));
|
||||
}
|
||||
/* in8 (battery) has no limit registers */
|
||||
data->in[8] =
|
||||
it87_read_value(client, IT87_REG_VIN(8));
|
||||
/* Temperature sensor doesn't have limit registers, set
|
||||
to min and max value */
|
||||
data->in_min[8] = 0;
|
||||
data->in_max[8] = 255;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
data->fan[i] =
|
||||
it87_read_value(client, IT87_REG_FAN(i));
|
||||
/* Skip disabled fans */
|
||||
if (!(data->has_fan & (1 << i)))
|
||||
continue;
|
||||
|
||||
data->fan_min[i] =
|
||||
it87_read_value(client, IT87_REG_FAN_MIN(i));
|
||||
data->fan[i] = it87_read_value(client,
|
||||
IT87_REG_FAN(i));
|
||||
/* Add high byte if in 16-bit mode */
|
||||
if (data->type == it8716 || data->type == it8718) {
|
||||
data->fan[i] |= it87_read_value(client,
|
||||
IT87_REG_FANX(i)) << 8;
|
||||
data->fan_min[i] |= it87_read_value(client,
|
||||
IT87_REG_FANX_MIN(i)) << 8;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
data->temp[i] =
|
||||
@ -1140,10 +1390,14 @@ static struct it87_data *it87_update_device(struct device *dev)
|
||||
it87_read_value(client, IT87_REG_TEMP_LOW(i));
|
||||
}
|
||||
|
||||
i = it87_read_value(client, IT87_REG_FAN_DIV);
|
||||
data->fan_div[0] = i & 0x07;
|
||||
data->fan_div[1] = (i >> 3) & 0x07;
|
||||
data->fan_div[2] = (i & 0x40) ? 3 : 1;
|
||||
/* Newer chips don't have clock dividers */
|
||||
if ((data->has_fan & 0x07) && data->type != it8716
|
||||
&& data->type != it8718) {
|
||||
i = it87_read_value(client, IT87_REG_FAN_DIV);
|
||||
data->fan_div[0] = i & 0x07;
|
||||
data->fan_div[1] = (i >> 3) & 0x07;
|
||||
data->fan_div[2] = (i & 0x40) ? 3 : 1;
|
||||
}
|
||||
|
||||
data->alarms =
|
||||
it87_read_value(client, IT87_REG_ALARM1) |
|
||||
@ -1153,9 +1407,11 @@ static struct it87_data *it87_update_device(struct device *dev)
|
||||
|
||||
data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE);
|
||||
/* The 8705 does not have VID capability */
|
||||
if (data->type == it8712) {
|
||||
if (data->type == it8712 || data->type == it8716) {
|
||||
data->vid = it87_read_value(client, IT87_REG_VID);
|
||||
data->vid &= 0x1f;
|
||||
/* The older IT8712F revisions had only 5 VID pins,
|
||||
but we assume it is always safe to read 6 bits. */
|
||||
data->vid &= 0x3f;
|
||||
}
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
@ -1193,8 +1449,9 @@ static void __exit sm_it87_exit(void)
|
||||
}
|
||||
|
||||
|
||||
MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>");
|
||||
MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver");
|
||||
MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>, "
|
||||
"Jean Delvare <khali@linux-fr.org>");
|
||||
MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F, SiS950 driver");
|
||||
module_param(update_vbat, bool, 0);
|
||||
MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
|
||||
module_param(fix_pwm_polarity, bool, 0);
|
||||
|
294
drivers/hwmon/k8temp.c
Normal file
294
drivers/hwmon/k8temp.c
Normal file
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* k8temp.c - Linux kernel module for hardware monitoring
|
||||
*
|
||||
* Copyright (C) 2006 Rudolf Marek <r.marek@sh.cvut.cz>
|
||||
*
|
||||
* Inspired from the w83785 and amd756 drivers.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define TEMP_FROM_REG(val) (((((val) >> 16) & 0xff) - 49) * 1000)
|
||||
#define REG_TEMP 0xe4
|
||||
#define SEL_PLACE 0x40
|
||||
#define SEL_CORE 0x04
|
||||
|
||||
struct k8temp_data {
|
||||
struct class_device *class_dev;
|
||||
struct mutex update_lock;
|
||||
const char *name;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
|
||||
/* registers values */
|
||||
u8 sensorsp; /* sensor presence bits - SEL_CORE & SEL_PLACE */
|
||||
u32 temp[2][2]; /* core, place */
|
||||
};
|
||||
|
||||
static struct k8temp_data *k8temp_update_device(struct device *dev)
|
||||
{
|
||||
struct k8temp_data *data = dev_get_drvdata(dev);
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
u8 tmp;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (!data->valid
|
||||
|| time_after(jiffies, data->last_updated + HZ)) {
|
||||
pci_read_config_byte(pdev, REG_TEMP, &tmp);
|
||||
tmp &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */
|
||||
pci_write_config_byte(pdev, REG_TEMP, tmp);
|
||||
pci_read_config_dword(pdev, REG_TEMP, &data->temp[0][0]);
|
||||
|
||||
if (data->sensorsp & SEL_PLACE) {
|
||||
tmp |= SEL_PLACE; /* Select sensor 1, core0 */
|
||||
pci_write_config_byte(pdev, REG_TEMP, tmp);
|
||||
pci_read_config_dword(pdev, REG_TEMP,
|
||||
&data->temp[0][1]);
|
||||
}
|
||||
|
||||
if (data->sensorsp & SEL_CORE) {
|
||||
tmp &= ~SEL_PLACE; /* Select sensor 0, core1 */
|
||||
tmp |= SEL_CORE;
|
||||
pci_write_config_byte(pdev, REG_TEMP, tmp);
|
||||
pci_read_config_dword(pdev, REG_TEMP,
|
||||
&data->temp[1][0]);
|
||||
|
||||
if (data->sensorsp & SEL_PLACE) {
|
||||
tmp |= SEL_PLACE; /* Select sensor 1, core1 */
|
||||
pci_write_config_byte(pdev, REG_TEMP, tmp);
|
||||
pci_read_config_dword(pdev, REG_TEMP,
|
||||
&data->temp[1][1]);
|
||||
}
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sysfs stuff
|
||||
*/
|
||||
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct k8temp_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", data->name);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t show_temp(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr =
|
||||
to_sensor_dev_attr_2(devattr);
|
||||
int core = attr->nr;
|
||||
int place = attr->index;
|
||||
struct k8temp_data *data = k8temp_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
TEMP_FROM_REG(data->temp[core][place]));
|
||||
}
|
||||
|
||||
/* core, place */
|
||||
|
||||
static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 1, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 1, 1);
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
|
||||
static struct pci_device_id k8temp_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, k8temp_ids);
|
||||
|
||||
static int __devinit k8temp_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
int err;
|
||||
u8 scfg;
|
||||
u32 temp;
|
||||
struct k8temp_data *data;
|
||||
u32 cpuid = cpuid_eax(1);
|
||||
|
||||
/* this feature should be available since SH-C0 core */
|
||||
if ((cpuid == 0xf40) || (cpuid == 0xf50) || (cpuid == 0xf51)) {
|
||||
err = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL))) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
pci_read_config_byte(pdev, REG_TEMP, &scfg);
|
||||
scfg &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */
|
||||
pci_write_config_byte(pdev, REG_TEMP, scfg);
|
||||
pci_read_config_byte(pdev, REG_TEMP, &scfg);
|
||||
|
||||
if (scfg & (SEL_PLACE | SEL_CORE)) {
|
||||
dev_err(&pdev->dev, "Configuration bit(s) stuck at 1!\n");
|
||||
err = -ENODEV;
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
scfg |= (SEL_PLACE | SEL_CORE);
|
||||
pci_write_config_byte(pdev, REG_TEMP, scfg);
|
||||
|
||||
/* now we know if we can change core and/or sensor */
|
||||
pci_read_config_byte(pdev, REG_TEMP, &data->sensorsp);
|
||||
|
||||
if (data->sensorsp & SEL_PLACE) {
|
||||
scfg &= ~SEL_CORE; /* Select sensor 1, core0 */
|
||||
pci_write_config_byte(pdev, REG_TEMP, scfg);
|
||||
pci_read_config_dword(pdev, REG_TEMP, &temp);
|
||||
scfg |= SEL_CORE; /* prepare for next selection */
|
||||
if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */
|
||||
data->sensorsp &= ~SEL_PLACE;
|
||||
}
|
||||
|
||||
if (data->sensorsp & SEL_CORE) {
|
||||
scfg &= ~SEL_PLACE; /* Select sensor 0, core1 */
|
||||
pci_write_config_byte(pdev, REG_TEMP, scfg);
|
||||
pci_read_config_dword(pdev, REG_TEMP, &temp);
|
||||
if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */
|
||||
data->sensorsp &= ~SEL_CORE;
|
||||
}
|
||||
|
||||
data->name = "k8temp";
|
||||
mutex_init(&data->update_lock);
|
||||
dev_set_drvdata(&pdev->dev, data);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = device_create_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
|
||||
/* sensor can be changed and reports something */
|
||||
if (data->sensorsp & SEL_PLACE) {
|
||||
err = device_create_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
/* core can be changed and reports something */
|
||||
if (data->sensorsp & SEL_CORE) {
|
||||
err = device_create_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp3_input.dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
if (data->sensorsp & SEL_PLACE)
|
||||
err = device_create_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp4_input.
|
||||
dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
err = device_create_file(&pdev->dev, &dev_attr_name);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp3_input.dev_attr);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp4_input.dev_attr);
|
||||
device_remove_file(&pdev->dev, &dev_attr_name);
|
||||
exit_free:
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
kfree(data);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __devexit k8temp_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct k8temp_data *data = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp3_input.dev_attr);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp4_input.dev_attr);
|
||||
device_remove_file(&pdev->dev, &dev_attr_name);
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static struct pci_driver k8temp_driver = {
|
||||
.name = "k8temp",
|
||||
.id_table = k8temp_ids,
|
||||
.probe = k8temp_probe,
|
||||
.remove = __devexit_p(k8temp_remove),
|
||||
};
|
||||
|
||||
static int __init k8temp_init(void)
|
||||
{
|
||||
return pci_register_driver(&k8temp_driver);
|
||||
}
|
||||
|
||||
static void __exit k8temp_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&k8temp_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Rudolf Marek <r.marek@sh.cvut.cz>");
|
||||
MODULE_DESCRIPTION("AMD K8 core temperature monitor");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(k8temp_init)
|
||||
module_exit(k8temp_exit)
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* lm63.c - driver for the National Semiconductor LM63 temperature sensor
|
||||
* with integrated fan control
|
||||
* Copyright (C) 2004-2005 Jean Delvare <khali@linux-fr.org>
|
||||
* Copyright (C) 2004-2006 Jean Delvare <khali@linux-fr.org>
|
||||
* Based on the lm90 driver.
|
||||
*
|
||||
* The LM63 is a sensor chip made by National Semiconductor. It measures
|
||||
@ -46,6 +46,7 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/*
|
||||
* Addresses to scan
|
||||
@ -330,6 +331,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
|
||||
static ssize_t show_alarm(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
int bitnr = attr->index;
|
||||
|
||||
return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
|
||||
set_fan, 1);
|
||||
@ -350,8 +361,52 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2);
|
||||
static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
|
||||
set_temp2_crit_hyst);
|
||||
|
||||
/* Individual alarm files */
|
||||
static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
|
||||
/* Raw alarm file for compatibility */
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
static struct attribute *lm63_attributes[] = {
|
||||
&dev_attr_pwm1.attr,
|
||||
&dev_attr_pwm1_enable.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr.attr,
|
||||
&dev_attr_temp2_crit_hyst.attr,
|
||||
|
||||
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm63_group = {
|
||||
.attrs = lm63_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *lm63_attributes_fan1[] = {
|
||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_min.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm63_group_fan1 = {
|
||||
.attrs = lm63_attributes_fan1,
|
||||
};
|
||||
|
||||
/*
|
||||
* Real code
|
||||
*/
|
||||
@ -438,37 +493,26 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
lm63_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj,
|
||||
&lm63_group)))
|
||||
goto exit_detach;
|
||||
if (data->config & 0x04) { /* tachometer enabled */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj,
|
||||
&lm63_group_fan1)))
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
if (data->config & 0x04) { /* tachometer enabled */
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_min.dev_attr);
|
||||
}
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -518,6 +562,8 @@ static int lm63_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm63_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -112,6 +112,18 @@ static int lm75_attach_adapter(struct i2c_adapter *adapter)
|
||||
return i2c_probe(adapter, &addr_data, lm75_detect);
|
||||
}
|
||||
|
||||
static struct attribute *lm75_attributes[] = {
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_max_hyst.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm75_group = {
|
||||
.attrs = lm75_attributes,
|
||||
};
|
||||
|
||||
/* This function is called by i2c_probe */
|
||||
static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
@ -199,18 +211,19 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
lm75_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm75_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -223,6 +236,7 @@ static int lm75_detach_client(struct i2c_client *client)
|
||||
{
|
||||
struct lm75_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm75_group);
|
||||
i2c_detach_client(client);
|
||||
kfree(data);
|
||||
return 0;
|
||||
|
@ -212,6 +212,23 @@ static int lm77_attach_adapter(struct i2c_adapter *adapter)
|
||||
return i2c_probe(adapter, &addr_data, lm77_detect);
|
||||
}
|
||||
|
||||
static struct attribute *lm77_attributes[] = {
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_crit.attr,
|
||||
&dev_attr_temp1_min.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_crit_hyst.attr,
|
||||
&dev_attr_temp1_min_hyst.attr,
|
||||
&dev_attr_temp1_max_hyst.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm77_group = {
|
||||
.attrs = lm77_attributes,
|
||||
};
|
||||
|
||||
/* This function is called by i2c_probe */
|
||||
static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
@ -317,22 +334,19 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
lm77_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm77_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -345,6 +359,7 @@ static int lm77_detach_client(struct i2c_client *client)
|
||||
{
|
||||
struct lm77_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm77_group);
|
||||
i2c_detach_client(client);
|
||||
kfree(data);
|
||||
return 0;
|
||||
|
@ -482,6 +482,50 @@ static int lm78_isa_attach_adapter(struct i2c_adapter *adapter)
|
||||
return lm78_detect(adapter, isa_address, -1);
|
||||
}
|
||||
|
||||
static struct attribute *lm78_attributes[] = {
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in0_min.attr,
|
||||
&dev_attr_in0_max.attr,
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in1_min.attr,
|
||||
&dev_attr_in1_max.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
&dev_attr_in2_min.attr,
|
||||
&dev_attr_in2_max.attr,
|
||||
&dev_attr_in3_input.attr,
|
||||
&dev_attr_in3_min.attr,
|
||||
&dev_attr_in3_max.attr,
|
||||
&dev_attr_in4_input.attr,
|
||||
&dev_attr_in4_min.attr,
|
||||
&dev_attr_in4_max.attr,
|
||||
&dev_attr_in5_input.attr,
|
||||
&dev_attr_in5_min.attr,
|
||||
&dev_attr_in5_max.attr,
|
||||
&dev_attr_in6_input.attr,
|
||||
&dev_attr_in6_min.attr,
|
||||
&dev_attr_in6_max.attr,
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_max_hyst.attr,
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan1_min.attr,
|
||||
&dev_attr_fan1_div.attr,
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan2_min.attr,
|
||||
&dev_attr_fan2_div.attr,
|
||||
&dev_attr_fan3_input.attr,
|
||||
&dev_attr_fan3_min.attr,
|
||||
&dev_attr_fan3_div.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm78_group = {
|
||||
.attrs = lm78_attributes,
|
||||
};
|
||||
|
||||
/* This function is called by i2c_probe */
|
||||
static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
@ -616,50 +660,19 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
}
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group)))
|
||||
goto ERROR3;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto ERROR3;
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
|
||||
return 0;
|
||||
|
||||
ERROR4:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm78_group);
|
||||
ERROR3:
|
||||
i2c_detach_client(new_client);
|
||||
ERROR2:
|
||||
@ -677,6 +690,7 @@ static int lm78_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm78_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -394,6 +394,48 @@ static int lm80_attach_adapter(struct i2c_adapter *adapter)
|
||||
return i2c_probe(adapter, &addr_data, lm80_detect);
|
||||
}
|
||||
|
||||
static struct attribute *lm80_attributes[] = {
|
||||
&dev_attr_in0_min.attr,
|
||||
&dev_attr_in1_min.attr,
|
||||
&dev_attr_in2_min.attr,
|
||||
&dev_attr_in3_min.attr,
|
||||
&dev_attr_in4_min.attr,
|
||||
&dev_attr_in5_min.attr,
|
||||
&dev_attr_in6_min.attr,
|
||||
&dev_attr_in0_max.attr,
|
||||
&dev_attr_in1_max.attr,
|
||||
&dev_attr_in2_max.attr,
|
||||
&dev_attr_in3_max.attr,
|
||||
&dev_attr_in4_max.attr,
|
||||
&dev_attr_in5_max.attr,
|
||||
&dev_attr_in6_max.attr,
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
&dev_attr_in3_input.attr,
|
||||
&dev_attr_in4_input.attr,
|
||||
&dev_attr_in5_input.attr,
|
||||
&dev_attr_in6_input.attr,
|
||||
&dev_attr_fan1_min.attr,
|
||||
&dev_attr_fan2_min.attr,
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan1_div.attr,
|
||||
&dev_attr_fan2_div.attr,
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_max_hyst.attr,
|
||||
&dev_attr_temp1_crit.attr,
|
||||
&dev_attr_temp1_crit_hyst.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm80_group = {
|
||||
.attrs = lm80_attributes,
|
||||
};
|
||||
|
||||
static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
int i, cur;
|
||||
@ -452,48 +494,19 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2));
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm80_group)))
|
||||
goto error_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto error_detach;
|
||||
goto error_remove;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
|
||||
return 0;
|
||||
|
||||
error_remove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm80_group);
|
||||
error_detach:
|
||||
i2c_detach_client(new_client);
|
||||
error_free:
|
||||
@ -508,7 +521,7 @@ static int lm80_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &lm80_group);
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* lm83.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org>
|
||||
* Copyright (C) 2003-2006 Jean Delvare <khali@linux-fr.org>
|
||||
*
|
||||
* Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
|
||||
* a sensor chip made by National Semiconductor. It reports up to four
|
||||
@ -40,6 +40,7 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/*
|
||||
* Addresses to scan
|
||||
@ -191,6 +192,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
|
||||
return sprintf(buf, "%d\n", data->alarms);
|
||||
}
|
||||
|
||||
static ssize_t show_alarm(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm83_data *data = lm83_update_device(dev);
|
||||
int bitnr = attr->index;
|
||||
|
||||
return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
|
||||
@ -208,8 +219,64 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8);
|
||||
static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp,
|
||||
set_temp, 8);
|
||||
static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8);
|
||||
|
||||
/* Individual alarm files */
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
|
||||
static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
|
||||
static SENSOR_DEVICE_ATTR(temp4_input_fault, S_IRUGO, show_alarm, NULL, 10);
|
||||
static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 12);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 13);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15);
|
||||
/* Raw alarm file for compatibility */
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
static struct attribute *lm83_attributes[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_input_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm83_group = {
|
||||
.attrs = lm83_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *lm83_attributes_opt[] = {
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_crit.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_input_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm83_group_opt = {
|
||||
.attrs = lm83_attributes_opt,
|
||||
};
|
||||
|
||||
/*
|
||||
* Real code
|
||||
*/
|
||||
@ -318,59 +385,32 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
goto exit_free;
|
||||
|
||||
/*
|
||||
* Initialize the LM83 chip
|
||||
* (Nothing to do for this one.)
|
||||
*/
|
||||
|
||||
/* Register sysfs hooks */
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register sysfs hooks
|
||||
* The LM82 can only monitor one external diode which is
|
||||
* at the same register as the LM83 temp3 entry - so we
|
||||
* declare 1 and 3 common, and then 2 and 4 only for the LM83.
|
||||
*/
|
||||
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp3_input.dev_attr);
|
||||
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp3_max.dev_attr);
|
||||
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp3_crit.dev_attr);
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm83_group)))
|
||||
goto exit_detach;
|
||||
|
||||
if (kind == lm83) {
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp4_input.dev_attr);
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj,
|
||||
&lm83_group_opt)))
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp4_max.dev_attr);
|
||||
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp4_crit.dev_attr);
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm83_group);
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm83_group_opt);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -385,6 +425,8 @@ static int lm83_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm83_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -1025,6 +1025,89 @@ static int lm85_attach_adapter(struct i2c_adapter *adapter)
|
||||
return i2c_probe(adapter, &addr_data, lm85_detect);
|
||||
}
|
||||
|
||||
static struct attribute *lm85_attributes[] = {
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan3_input.attr,
|
||||
&dev_attr_fan4_input.attr,
|
||||
&dev_attr_fan1_min.attr,
|
||||
&dev_attr_fan2_min.attr,
|
||||
&dev_attr_fan3_min.attr,
|
||||
&dev_attr_fan4_min.attr,
|
||||
&dev_attr_pwm1.attr,
|
||||
&dev_attr_pwm2.attr,
|
||||
&dev_attr_pwm3.attr,
|
||||
&dev_attr_pwm1_enable.attr,
|
||||
&dev_attr_pwm2_enable.attr,
|
||||
&dev_attr_pwm3_enable.attr,
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
&dev_attr_in3_input.attr,
|
||||
&dev_attr_in0_min.attr,
|
||||
&dev_attr_in1_min.attr,
|
||||
&dev_attr_in2_min.attr,
|
||||
&dev_attr_in3_min.attr,
|
||||
&dev_attr_in0_max.attr,
|
||||
&dev_attr_in1_max.attr,
|
||||
&dev_attr_in2_max.attr,
|
||||
&dev_attr_in3_max.attr,
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_temp3_input.attr,
|
||||
&dev_attr_temp1_min.attr,
|
||||
&dev_attr_temp2_min.attr,
|
||||
&dev_attr_temp3_min.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp2_max.attr,
|
||||
&dev_attr_temp3_max.attr,
|
||||
&dev_attr_vrm.attr,
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_pwm1_auto_channels.attr,
|
||||
&dev_attr_pwm2_auto_channels.attr,
|
||||
&dev_attr_pwm3_auto_channels.attr,
|
||||
&dev_attr_pwm1_auto_pwm_min.attr,
|
||||
&dev_attr_pwm2_auto_pwm_min.attr,
|
||||
&dev_attr_pwm3_auto_pwm_min.attr,
|
||||
&dev_attr_pwm1_auto_pwm_minctl.attr,
|
||||
&dev_attr_pwm2_auto_pwm_minctl.attr,
|
||||
&dev_attr_pwm3_auto_pwm_minctl.attr,
|
||||
&dev_attr_pwm1_auto_pwm_freq.attr,
|
||||
&dev_attr_pwm2_auto_pwm_freq.attr,
|
||||
&dev_attr_pwm3_auto_pwm_freq.attr,
|
||||
&dev_attr_temp1_auto_temp_off.attr,
|
||||
&dev_attr_temp2_auto_temp_off.attr,
|
||||
&dev_attr_temp3_auto_temp_off.attr,
|
||||
&dev_attr_temp1_auto_temp_min.attr,
|
||||
&dev_attr_temp2_auto_temp_min.attr,
|
||||
&dev_attr_temp3_auto_temp_min.attr,
|
||||
&dev_attr_temp1_auto_temp_max.attr,
|
||||
&dev_attr_temp2_auto_temp_max.attr,
|
||||
&dev_attr_temp3_auto_temp_max.attr,
|
||||
&dev_attr_temp1_auto_temp_crit.attr,
|
||||
&dev_attr_temp2_auto_temp_crit.attr,
|
||||
&dev_attr_temp3_auto_temp_crit.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm85_group = {
|
||||
.attrs = lm85_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *lm85_attributes_opt[] = {
|
||||
&dev_attr_in4_input.attr,
|
||||
&dev_attr_in4_min.attr,
|
||||
&dev_attr_in4_max.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm85_group_opt = {
|
||||
.attrs = lm85_attributes_opt,
|
||||
};
|
||||
|
||||
static int lm85_detect(struct i2c_adapter *adapter, int address,
|
||||
int kind)
|
||||
{
|
||||
@ -1163,87 +1246,33 @@ static int lm85_detect(struct i2c_adapter *adapter, int address,
|
||||
lm85_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm85_group)))
|
||||
goto ERROR2;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan4_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan4_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm3);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm3_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_vrm);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1_auto_channels);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2_auto_channels);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm3_auto_channels);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_minctl);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_minctl);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_minctl);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_freq);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_freq);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_freq);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_off);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_off);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_off);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_crit);
|
||||
|
||||
/* The ADT7463 has an optional VRM 10 mode where pin 21 is used
|
||||
as a sixth digital VID input rather than an analog input. */
|
||||
data->vid = lm85_read_value(new_client, LM85_REG_VID);
|
||||
if (!(kind == adt7463 && (data->vid & 0x80))) {
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_max);
|
||||
if (!(kind == adt7463 && (data->vid & 0x80)))
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in4_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in4_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in4_max)))
|
||||
goto ERROR3;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto ERROR3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
/* Error out and cleanup code */
|
||||
ERROR3:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm85_group);
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm85_group_opt);
|
||||
ERROR2:
|
||||
i2c_detach_client(new_client);
|
||||
ERROR1:
|
||||
@ -1256,6 +1285,8 @@ static int lm85_detach_client(struct i2c_client *client)
|
||||
{
|
||||
struct lm85_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm85_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm85_group_opt);
|
||||
i2c_detach_client(client);
|
||||
kfree(data);
|
||||
return 0;
|
||||
|
@ -542,6 +542,78 @@ static int lm87_attach_adapter(struct i2c_adapter *adapter)
|
||||
return i2c_probe(adapter, &addr_data, lm87_detect);
|
||||
}
|
||||
|
||||
static struct attribute *lm87_attributes[] = {
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in1_min.attr,
|
||||
&dev_attr_in1_max.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
&dev_attr_in2_min.attr,
|
||||
&dev_attr_in2_max.attr,
|
||||
&dev_attr_in3_input.attr,
|
||||
&dev_attr_in3_min.attr,
|
||||
&dev_attr_in3_max.attr,
|
||||
&dev_attr_in4_input.attr,
|
||||
&dev_attr_in4_min.attr,
|
||||
&dev_attr_in4_max.attr,
|
||||
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_min.attr,
|
||||
&dev_attr_temp1_crit.attr,
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_temp2_max.attr,
|
||||
&dev_attr_temp2_min.attr,
|
||||
&dev_attr_temp2_crit.attr,
|
||||
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_aout_output.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm87_group = {
|
||||
.attrs = lm87_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *lm87_attributes_opt[] = {
|
||||
&dev_attr_in6_input.attr,
|
||||
&dev_attr_in6_min.attr,
|
||||
&dev_attr_in6_max.attr,
|
||||
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan1_min.attr,
|
||||
&dev_attr_fan1_div.attr,
|
||||
|
||||
&dev_attr_in7_input.attr,
|
||||
&dev_attr_in7_min.attr,
|
||||
&dev_attr_in7_max.attr,
|
||||
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan2_min.attr,
|
||||
&dev_attr_fan2_div.attr,
|
||||
|
||||
&dev_attr_temp3_input.attr,
|
||||
&dev_attr_temp3_max.attr,
|
||||
&dev_attr_temp3_min.attr,
|
||||
&dev_attr_temp3_crit.attr,
|
||||
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in0_min.attr,
|
||||
&dev_attr_in0_max.attr,
|
||||
&dev_attr_in5_input.attr,
|
||||
&dev_attr_in5_min.attr,
|
||||
&dev_attr_in5_max.attr,
|
||||
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
&dev_attr_vrm.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm87_group_opt = {
|
||||
.attrs = lm87_attributes_opt,
|
||||
};
|
||||
|
||||
/*
|
||||
* The following function does more than just detection. If detection
|
||||
* succeeds, it also registers the new chip.
|
||||
@ -609,77 +681,90 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
data->in_scale[7] = 1875;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm87_group)))
|
||||
goto exit_detach;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_max);
|
||||
|
||||
if (data->channel & CHAN_NO_FAN(0)) {
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_max);
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in6_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in6_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in6_max)))
|
||||
goto exit_remove;
|
||||
} else {
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_div);
|
||||
}
|
||||
if (data->channel & CHAN_NO_FAN(1)) {
|
||||
device_create_file(&new_client->dev, &dev_attr_in7_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in7_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in7_max);
|
||||
} else {
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_div);
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan1_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan1_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan1_div)))
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit);
|
||||
if (data->channel & CHAN_NO_FAN(1)) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in7_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in7_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in7_max)))
|
||||
goto exit_remove;
|
||||
} else {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan2_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan2_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan2_div)))
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
if (data->channel & CHAN_TEMP3) {
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_crit);
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp3_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp3_max))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp3_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp3_crit)))
|
||||
goto exit_remove;
|
||||
} else {
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_max);
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in0_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in0_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in0_max))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in5_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in5_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in5_max)))
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
if (!(data->channel & CHAN_NO_VID)) {
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
device_create_file(&new_client->dev, &dev_attr_vrm);
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_cpu0_vid))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_vrm)))
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
device_create_file(&new_client->dev, &dev_attr_aout_output);
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm87_group);
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm87_group_opt);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -732,6 +817,8 @@ static int lm87_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm87_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm87_group_opt);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* lm90.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org>
|
||||
* Copyright (C) 2003-2006 Jean Delvare <khali@linux-fr.org>
|
||||
*
|
||||
* Based on the lm83 driver. The LM90 is a sensor chip made by National
|
||||
* Semiconductor. It reports up to two temperatures (its own plus up to
|
||||
@ -79,6 +79,7 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/*
|
||||
* Addresses to scan
|
||||
@ -327,6 +328,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
|
||||
return sprintf(buf, "%d\n", data->alarms);
|
||||
}
|
||||
|
||||
static ssize_t show_alarm(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm90_data *data = lm90_update_device(dev);
|
||||
int bitnr = attr->index;
|
||||
|
||||
return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
|
||||
@ -344,8 +355,45 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8,
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
|
||||
set_temphyst, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4);
|
||||
|
||||
/* Individual alarm files */
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
|
||||
/* Raw alarm file for compatibility */
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
static struct attribute *lm90_attributes[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm90_group = {
|
||||
.attrs = lm90_attributes,
|
||||
};
|
||||
|
||||
/* pec used for ADM1032 only */
|
||||
static ssize_t show_pec(struct device *dev, struct device_attribute *dummy,
|
||||
char *buf)
|
||||
@ -569,39 +617,25 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
lm90_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm90_group)))
|
||||
goto exit_detach;
|
||||
if (new_client->flags & I2C_CLIENT_PEC) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_pec)))
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_crit_hyst.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_crit_hyst.dev_attr);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
|
||||
if (new_client->flags & I2C_CLIENT_PEC)
|
||||
device_create_file(&new_client->dev, &dev_attr_pec);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm90_group);
|
||||
device_remove_file(&new_client->dev, &dev_attr_pec);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -634,6 +668,8 @@ static int lm90_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm90_group);
|
||||
device_remove_file(&client->dev, &dev_attr_pec);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -288,6 +288,23 @@ static int max6635_check(struct i2c_client *client)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct attribute *lm92_attributes[] = {
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_crit.attr,
|
||||
&dev_attr_temp1_crit_hyst.attr,
|
||||
&dev_attr_temp1_min.attr,
|
||||
&dev_attr_temp1_min_hyst.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_max_hyst.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group lm92_group = {
|
||||
.attrs = lm92_attributes,
|
||||
};
|
||||
|
||||
/* The following function does more than just detection. If detection
|
||||
succeeds, it also registers the new chip. */
|
||||
static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
@ -359,23 +376,19 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
lm92_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &lm92_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -397,6 +410,7 @@ static int lm92_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm92_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
|
||||
0x29, 0x2a, 0x2b,
|
||||
@ -172,6 +173,22 @@ static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2,
|
||||
set_temp_hyst2);
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
static struct attribute *max1619_attributes[] = {
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_temp2_min.attr,
|
||||
&dev_attr_temp2_max.attr,
|
||||
&dev_attr_temp2_crit.attr,
|
||||
&dev_attr_temp2_crit_hyst.attr,
|
||||
|
||||
&dev_attr_alarms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group max1619_group = {
|
||||
.attrs = max1619_attributes,
|
||||
};
|
||||
|
||||
/*
|
||||
* Real code
|
||||
*/
|
||||
@ -273,22 +290,19 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
max1619_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &max1619_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -318,6 +332,7 @@ static int max1619_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &max1619_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -328,6 +328,12 @@ static struct sensor_device_attribute fan_min[] = {
|
||||
SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2),
|
||||
};
|
||||
|
||||
#define FAN_UNIT_ATTRS(X) \
|
||||
&fan_input[X].dev_attr.attr, \
|
||||
&fan_status[X].dev_attr.attr, \
|
||||
&fan_div[X].dev_attr.attr, \
|
||||
&fan_min[X].dev_attr.attr
|
||||
|
||||
static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
@ -360,6 +366,19 @@ static struct sensor_device_attribute pwm[] = {
|
||||
SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2),
|
||||
};
|
||||
|
||||
static struct attribute * pc8736x_fan_attr_array[] = {
|
||||
FAN_UNIT_ATTRS(0),
|
||||
FAN_UNIT_ATTRS(1),
|
||||
FAN_UNIT_ATTRS(2),
|
||||
&pwm[0].dev_attr.attr,
|
||||
&pwm[1].dev_attr.attr,
|
||||
&pwm[2].dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
static const struct attribute_group pc8736x_fan_group = {
|
||||
.attrs = pc8736x_fan_attr_array,
|
||||
};
|
||||
|
||||
static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
@ -472,6 +491,61 @@ static struct sensor_device_attribute in_max[] = {
|
||||
SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10),
|
||||
};
|
||||
|
||||
#define VIN_UNIT_ATTRS(X) \
|
||||
&in_input[X].dev_attr.attr, \
|
||||
&in_status[X].dev_attr.attr, \
|
||||
&in_min[X].dev_attr.attr, \
|
||||
&in_max[X].dev_attr.attr
|
||||
|
||||
static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
|
||||
}
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
|
||||
|
||||
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->vrm);
|
||||
}
|
||||
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pc87360_data *data = i2c_get_clientdata(client);
|
||||
data->vrm = simple_strtoul(buf, NULL, 10);
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
|
||||
|
||||
static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->in_alarms);
|
||||
}
|
||||
static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
|
||||
|
||||
static struct attribute *pc8736x_vin_attr_array[] = {
|
||||
VIN_UNIT_ATTRS(0),
|
||||
VIN_UNIT_ATTRS(1),
|
||||
VIN_UNIT_ATTRS(2),
|
||||
VIN_UNIT_ATTRS(3),
|
||||
VIN_UNIT_ATTRS(4),
|
||||
VIN_UNIT_ATTRS(5),
|
||||
VIN_UNIT_ATTRS(6),
|
||||
VIN_UNIT_ATTRS(7),
|
||||
VIN_UNIT_ATTRS(8),
|
||||
VIN_UNIT_ATTRS(9),
|
||||
VIN_UNIT_ATTRS(10),
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
&dev_attr_vrm.attr,
|
||||
&dev_attr_alarms_in.attr,
|
||||
NULL
|
||||
};
|
||||
static const struct attribute_group pc8736x_vin_group = {
|
||||
.attrs = pc8736x_vin_attr_array,
|
||||
};
|
||||
|
||||
static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
@ -590,33 +664,22 @@ static struct sensor_device_attribute therm_crit[] = {
|
||||
show_therm_crit, set_therm_crit, 2+11),
|
||||
};
|
||||
|
||||
static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
|
||||
}
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
|
||||
#define THERM_UNIT_ATTRS(X) \
|
||||
&therm_input[X].dev_attr.attr, \
|
||||
&therm_status[X].dev_attr.attr, \
|
||||
&therm_min[X].dev_attr.attr, \
|
||||
&therm_max[X].dev_attr.attr, \
|
||||
&therm_crit[X].dev_attr.attr
|
||||
|
||||
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->vrm);
|
||||
}
|
||||
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pc87360_data *data = i2c_get_clientdata(client);
|
||||
data->vrm = simple_strtoul(buf, NULL, 10);
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
|
||||
|
||||
static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pc87360_data *data = pc87360_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->in_alarms);
|
||||
}
|
||||
static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
|
||||
static struct attribute * pc8736x_therm_attr_array[] = {
|
||||
THERM_UNIT_ATTRS(0),
|
||||
THERM_UNIT_ATTRS(1),
|
||||
THERM_UNIT_ATTRS(2),
|
||||
NULL
|
||||
};
|
||||
static const struct attribute_group pc8736x_therm_group = {
|
||||
.attrs = pc8736x_therm_attr_array,
|
||||
};
|
||||
|
||||
static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
@ -736,6 +799,25 @@ static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *att
|
||||
}
|
||||
static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL);
|
||||
|
||||
#define TEMP_UNIT_ATTRS(X) \
|
||||
&temp_input[X].dev_attr.attr, \
|
||||
&temp_status[X].dev_attr.attr, \
|
||||
&temp_min[X].dev_attr.attr, \
|
||||
&temp_max[X].dev_attr.attr, \
|
||||
&temp_crit[X].dev_attr.attr
|
||||
|
||||
static struct attribute * pc8736x_temp_attr_array[] = {
|
||||
TEMP_UNIT_ATTRS(0),
|
||||
TEMP_UNIT_ATTRS(1),
|
||||
TEMP_UNIT_ATTRS(2),
|
||||
/* include the few miscellaneous atts here */
|
||||
&dev_attr_alarms_temp.attr,
|
||||
NULL
|
||||
};
|
||||
static const struct attribute_group pc8736x_temp_group = {
|
||||
.attrs = pc8736x_temp_attr_array,
|
||||
};
|
||||
|
||||
/*
|
||||
* Device detection, registration and update
|
||||
*/
|
||||
@ -936,60 +1018,69 @@ static int pc87360_detect(struct i2c_adapter *adapter)
|
||||
pc87360_init_client(client, use_thermistors);
|
||||
}
|
||||
|
||||
/* Register sysfs hooks */
|
||||
/* Register all-or-nothing sysfs groups */
|
||||
|
||||
if (data->innr &&
|
||||
(err = sysfs_create_group(&client->dev.kobj,
|
||||
&pc8736x_vin_group)))
|
||||
goto ERROR3;
|
||||
|
||||
if (data->innr == 14 &&
|
||||
(err = sysfs_create_group(&client->dev.kobj,
|
||||
&pc8736x_therm_group)))
|
||||
goto ERROR3;
|
||||
|
||||
/* create device attr-files for varying sysfs groups */
|
||||
|
||||
if (data->tempnr) {
|
||||
for (i = 0; i < data->tempnr; i++) {
|
||||
if ((err = device_create_file(dev,
|
||||
&temp_input[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&temp_min[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&temp_max[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&temp_crit[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&temp_status[i].dev_attr)))
|
||||
goto ERROR3;
|
||||
}
|
||||
if ((err = device_create_file(dev, &dev_attr_alarms_temp)))
|
||||
goto ERROR3;
|
||||
}
|
||||
|
||||
for (i = 0; i < data->fannr; i++) {
|
||||
if (FAN_CONFIG_MONITOR(data->fan_conf, i)
|
||||
&& ((err = device_create_file(dev,
|
||||
&fan_input[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&fan_min[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&fan_div[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&fan_status[i].dev_attr))))
|
||||
goto ERROR3;
|
||||
|
||||
if (FAN_CONFIG_CONTROL(data->fan_conf, i)
|
||||
&& (err = device_create_file(dev, &pwm[i].dev_attr)))
|
||||
goto ERROR3;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto ERROR3;
|
||||
}
|
||||
|
||||
if (data->innr) {
|
||||
for (i = 0; i < 11; i++) {
|
||||
device_create_file(dev, &in_input[i].dev_attr);
|
||||
device_create_file(dev, &in_min[i].dev_attr);
|
||||
device_create_file(dev, &in_max[i].dev_attr);
|
||||
device_create_file(dev, &in_status[i].dev_attr);
|
||||
}
|
||||
device_create_file(dev, &dev_attr_cpu0_vid);
|
||||
device_create_file(dev, &dev_attr_vrm);
|
||||
device_create_file(dev, &dev_attr_alarms_in);
|
||||
}
|
||||
|
||||
if (data->tempnr) {
|
||||
for (i = 0; i < data->tempnr; i++) {
|
||||
device_create_file(dev, &temp_input[i].dev_attr);
|
||||
device_create_file(dev, &temp_min[i].dev_attr);
|
||||
device_create_file(dev, &temp_max[i].dev_attr);
|
||||
device_create_file(dev, &temp_crit[i].dev_attr);
|
||||
device_create_file(dev, &temp_status[i].dev_attr);
|
||||
}
|
||||
device_create_file(dev, &dev_attr_alarms_temp);
|
||||
}
|
||||
|
||||
if (data->innr == 14) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
device_create_file(dev, &therm_input[i].dev_attr);
|
||||
device_create_file(dev, &therm_min[i].dev_attr);
|
||||
device_create_file(dev, &therm_max[i].dev_attr);
|
||||
device_create_file(dev, &therm_crit[i].dev_attr);
|
||||
device_create_file(dev, &therm_status[i].dev_attr);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < data->fannr; i++) {
|
||||
if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
|
||||
device_create_file(dev, &fan_input[i].dev_attr);
|
||||
device_create_file(dev, &fan_min[i].dev_attr);
|
||||
device_create_file(dev, &fan_div[i].dev_attr);
|
||||
device_create_file(dev, &fan_status[i].dev_attr);
|
||||
}
|
||||
if (FAN_CONFIG_CONTROL(data->fan_conf, i))
|
||||
device_create_file(dev, &pwm[i].dev_attr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
ERROR3:
|
||||
/* can still remove groups whose members were added individually */
|
||||
sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
|
||||
|
||||
i2c_detach_client(client);
|
||||
ERROR2:
|
||||
for (i = 0; i < 3; i++) {
|
||||
@ -1009,6 +1100,11 @@ static int pc87360_detach_client(struct i2c_client *client)
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
|
||||
|
||||
if ((i = i2c_detach_client(client)))
|
||||
return i;
|
||||
|
||||
|
@ -61,6 +61,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
@ -473,6 +474,50 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
|
||||
return sprintf(buf, "%d\n", data->alarms);
|
||||
}
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
static struct attribute *sis5595_attributes[] = {
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in0_min.attr,
|
||||
&dev_attr_in0_max.attr,
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in1_min.attr,
|
||||
&dev_attr_in1_max.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
&dev_attr_in2_min.attr,
|
||||
&dev_attr_in2_max.attr,
|
||||
&dev_attr_in3_input.attr,
|
||||
&dev_attr_in3_min.attr,
|
||||
&dev_attr_in3_max.attr,
|
||||
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan1_min.attr,
|
||||
&dev_attr_fan1_div.attr,
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan2_min.attr,
|
||||
&dev_attr_fan2_div.attr,
|
||||
|
||||
&dev_attr_alarms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group sis5595_group = {
|
||||
.attrs = sis5595_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *sis5595_attributes_opt[] = {
|
||||
&dev_attr_in4_input.attr,
|
||||
&dev_attr_in4_min.attr,
|
||||
&dev_attr_in4_max.attr,
|
||||
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_max_hyst.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group sis5595_group_opt = {
|
||||
.attrs = sis5595_attributes_opt,
|
||||
};
|
||||
|
||||
/* This is called when the module is loaded */
|
||||
static int sis5595_detect(struct i2c_adapter *adapter)
|
||||
@ -566,43 +611,37 @@ static int sis5595_detect(struct i2c_adapter *adapter)
|
||||
}
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &sis5595_group)))
|
||||
goto exit_detach;
|
||||
if (data->maxins == 4) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in4_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in4_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in4_max)))
|
||||
goto exit_remove_files;
|
||||
} else {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp1_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp1_max))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp1_max_hyst)))
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_max);
|
||||
if (data->maxins == 4) {
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_max);
|
||||
}
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
if (data->maxins == 3) {
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
|
||||
}
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &sis5595_group);
|
||||
sysfs_remove_group(&new_client->dev.kobj, &sis5595_group_opt);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -619,6 +658,8 @@ static int sis5595_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &sis5595_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &sis5595_group_opt);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -176,9 +176,6 @@ sysfs_temp(2);
|
||||
sysfs_temp(3);
|
||||
sysfs_temp(4);
|
||||
|
||||
#define device_create_file_temp(client, num) \
|
||||
device_create_file(&client->dev, &dev_attr_temp##num##_input)
|
||||
|
||||
/* FAN: 1 RPM/bit
|
||||
REG: count of 90kHz pulses / revolution */
|
||||
static int fan_from_reg(u16 reg)
|
||||
@ -205,8 +202,22 @@ sysfs_fan(2);
|
||||
sysfs_fan(3);
|
||||
sysfs_fan(4);
|
||||
|
||||
#define device_create_file_fan(client, num) \
|
||||
device_create_file(&client->dev, &dev_attr_fan##num##_input)
|
||||
static struct attribute *smsc47b397_attributes[] = {
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_temp3_input.attr,
|
||||
&dev_attr_temp4_input.attr,
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan3_input.attr,
|
||||
&dev_attr_fan4_input.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group smsc47b397_group = {
|
||||
.attrs = smsc47b397_attributes,
|
||||
};
|
||||
|
||||
static int smsc47b397_detach_client(struct i2c_client *client)
|
||||
{
|
||||
@ -214,6 +225,7 @@ static int smsc47b397_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &smsc47b397_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
@ -268,24 +280,19 @@ static int smsc47b397_detect(struct i2c_adapter *adapter)
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
goto error_free;
|
||||
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &smsc47b397_group)))
|
||||
goto error_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto error_detach;
|
||||
goto error_remove;
|
||||
}
|
||||
|
||||
device_create_file_temp(new_client, 1);
|
||||
device_create_file_temp(new_client, 2);
|
||||
device_create_file_temp(new_client, 3);
|
||||
device_create_file_temp(new_client, 4);
|
||||
|
||||
device_create_file_fan(new_client, 1);
|
||||
device_create_file_fan(new_client, 2);
|
||||
device_create_file_fan(new_client, 3);
|
||||
device_create_file_fan(new_client, 4);
|
||||
|
||||
return 0;
|
||||
|
||||
error_remove:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &smsc47b397_group);
|
||||
error_detach:
|
||||
i2c_detach_client(new_client);
|
||||
error_free:
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* Address is autodetected, there is no default value */
|
||||
@ -347,6 +348,30 @@ fan_present(2);
|
||||
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
|
||||
|
||||
/* Almost all sysfs files may or may not be created depending on the chip
|
||||
setup so we create them individually. It is still convenient to define a
|
||||
group to remove them all at once. */
|
||||
static struct attribute *smsc47m1_attributes[] = {
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan1_min.attr,
|
||||
&dev_attr_fan1_div.attr,
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan2_min.attr,
|
||||
&dev_attr_fan2_div.attr,
|
||||
|
||||
&dev_attr_pwm1.attr,
|
||||
&dev_attr_pwm1_enable.attr,
|
||||
&dev_attr_pwm2.attr,
|
||||
&dev_attr_pwm2_enable.attr,
|
||||
|
||||
&dev_attr_alarms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group smsc47m1_group = {
|
||||
.attrs = smsc47m1_attributes,
|
||||
};
|
||||
|
||||
static int __init smsc47m1_find(unsigned short *addr)
|
||||
{
|
||||
u8 val;
|
||||
@ -429,7 +454,8 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
|
||||
pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)
|
||||
== 0x04;
|
||||
if (!(fan1 || fan2 || pwm1 || pwm2)) {
|
||||
dev_warn(&new_client->dev, "Device is not configured, will not use\n");
|
||||
dev_warn(&adapter->dev, "Device at 0x%x is not configured, "
|
||||
"will not use\n", new_client->addr);
|
||||
err = -ENODEV;
|
||||
goto error_free;
|
||||
}
|
||||
@ -446,46 +472,62 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
|
||||
smsc47m1_update_device(&new_client->dev, 1);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto error_detach;
|
||||
}
|
||||
|
||||
if (fan1) {
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_div);
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan1_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan1_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan1_div)))
|
||||
goto error_remove_files;
|
||||
} else
|
||||
dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, "
|
||||
"skipping\n");
|
||||
|
||||
if (fan2) {
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_div);
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan2_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan2_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan2_div)))
|
||||
goto error_remove_files;
|
||||
} else
|
||||
dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, "
|
||||
"skipping\n");
|
||||
|
||||
if (pwm1) {
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_pwm1))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_pwm1_enable)))
|
||||
goto error_remove_files;
|
||||
} else
|
||||
dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, "
|
||||
"skipping\n");
|
||||
if (pwm2) {
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_pwm2))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_pwm2_enable)))
|
||||
goto error_remove_files;
|
||||
} else
|
||||
dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "
|
||||
"skipping\n");
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
if ((err = device_create_file(&new_client->dev, &dev_attr_alarms)))
|
||||
goto error_remove_files;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto error_remove_files;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_detach:
|
||||
error_remove_files:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &smsc47m1_group);
|
||||
i2c_detach_client(new_client);
|
||||
error_free:
|
||||
kfree(data);
|
||||
@ -500,6 +542,7 @@ static int smsc47m1_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &smsc47m1_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/hwmon-vid.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
|
||||
@ -370,6 +371,75 @@ static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 0x0200);
|
||||
static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 0x0400);
|
||||
static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 0x0800);
|
||||
|
||||
static struct attribute *smsc47m192_attributes[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_alarm.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_offset.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_offset.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_offset.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_input_fault.dev_attr.attr,
|
||||
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
&dev_attr_vrm.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group smsc47m192_group = {
|
||||
.attrs = smsc47m192_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *smsc47m192_attributes_in4[] = {
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_alarm.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group smsc47m192_group_in4 = {
|
||||
.attrs = smsc47m192_attributes_in4,
|
||||
};
|
||||
|
||||
/* This function is called when:
|
||||
* smsc47m192_driver is inserted (when this module is loaded), for each
|
||||
available adapter
|
||||
@ -471,80 +541,28 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
|
||||
smsc47m192_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
data->class_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &smsc47m192_group)))
|
||||
goto exit_detach;
|
||||
}
|
||||
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in0_input.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in0_min.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in0_max.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in0_alarm.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in1_input.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in1_min.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in1_max.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in1_alarm.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in2_input.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in2_min.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in2_max.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in2_alarm.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in3_input.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in3_min.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in3_max.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in3_alarm.dev_attr);
|
||||
|
||||
/* Pin 110 is either in4 (+12V) or VID4 */
|
||||
config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
|
||||
if (!(config & 0x20)) {
|
||||
device_create_file(&client->dev,
|
||||
&sensor_dev_attr_in4_input.dev_attr);
|
||||
device_create_file(&client->dev,
|
||||
&sensor_dev_attr_in4_min.dev_attr);
|
||||
device_create_file(&client->dev,
|
||||
&sensor_dev_attr_in4_max.dev_attr);
|
||||
device_create_file(&client->dev,
|
||||
&sensor_dev_attr_in4_alarm.dev_attr);
|
||||
if ((err = sysfs_create_group(&client->dev.kobj,
|
||||
&smsc47m192_group_in4)))
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in5_input.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in5_min.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in5_max.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in5_alarm.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in6_input.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in6_min.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in6_max.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in6_alarm.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in7_input.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in7_min.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in7_max.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_in7_alarm.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_temp1_min.dev_attr);
|
||||
device_create_file(&client->dev,
|
||||
&sensor_dev_attr_temp1_offset.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_temp1_alarm.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_temp2_max.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_temp2_min.dev_attr);
|
||||
device_create_file(&client->dev,
|
||||
&sensor_dev_attr_temp2_offset.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_temp2_alarm.dev_attr);
|
||||
device_create_file(&client->dev,
|
||||
&sensor_dev_attr_temp2_input_fault.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_temp3_input.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_temp3_max.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_temp3_min.dev_attr);
|
||||
device_create_file(&client->dev,
|
||||
&sensor_dev_attr_temp3_offset.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_temp3_alarm.dev_attr);
|
||||
device_create_file(&client->dev,
|
||||
&sensor_dev_attr_temp3_input_fault.dev_attr);
|
||||
device_create_file(&client->dev, &dev_attr_cpu0_vid);
|
||||
device_create_file(&client->dev, &dev_attr_vrm);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
|
||||
exit_detach:
|
||||
i2c_detach_client(client);
|
||||
exit_free:
|
||||
@ -559,6 +577,8 @@ static int smsc47m192_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
@ -570,6 +571,48 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
|
||||
}
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
static struct attribute *via686a_attributes[] = {
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
&dev_attr_in3_input.attr,
|
||||
&dev_attr_in4_input.attr,
|
||||
&dev_attr_in0_min.attr,
|
||||
&dev_attr_in1_min.attr,
|
||||
&dev_attr_in2_min.attr,
|
||||
&dev_attr_in3_min.attr,
|
||||
&dev_attr_in4_min.attr,
|
||||
&dev_attr_in0_max.attr,
|
||||
&dev_attr_in1_max.attr,
|
||||
&dev_attr_in2_max.attr,
|
||||
&dev_attr_in3_max.attr,
|
||||
&dev_attr_in4_max.attr,
|
||||
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_temp3_input.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp2_max.attr,
|
||||
&dev_attr_temp3_max.attr,
|
||||
&dev_attr_temp1_max_hyst.attr,
|
||||
&dev_attr_temp2_max_hyst.attr,
|
||||
&dev_attr_temp3_max_hyst.attr,
|
||||
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan1_min.attr,
|
||||
&dev_attr_fan2_min.attr,
|
||||
&dev_attr_fan1_div.attr,
|
||||
&dev_attr_fan2_div.attr,
|
||||
|
||||
&dev_attr_alarms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group via686a_group = {
|
||||
.attrs = via686a_attributes,
|
||||
};
|
||||
|
||||
/* The driver. I choose to use type i2c_driver, as at is identical to both
|
||||
smbus_driver and isa_driver, and clients could be of either kind */
|
||||
static struct i2c_driver via686a_driver = {
|
||||
@ -650,46 +693,19 @@ static int via686a_detect(struct i2c_adapter *adapter)
|
||||
via686a_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &via686a_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_max_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &via686a_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
@ -705,6 +721,7 @@ static int via686a_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &via686a_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
1355
drivers/hwmon/vt1211.c
Normal file
1355
drivers/hwmon/vt1211.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -451,37 +451,6 @@ define_temperature_sysfs(4);
|
||||
define_temperature_sysfs(5);
|
||||
define_temperature_sysfs(6);
|
||||
|
||||
#define CFG_INFO_TEMP(id) { &sensor_dev_attr_temp##id##_input.dev_attr, \
|
||||
&sensor_dev_attr_temp##id##_max_hyst.dev_attr, \
|
||||
&sensor_dev_attr_temp##id##_max.dev_attr }
|
||||
#define CFG_INFO_VOLT(id) { &sensor_dev_attr_in##id##_input.dev_attr, \
|
||||
&sensor_dev_attr_in##id##_min.dev_attr, \
|
||||
&sensor_dev_attr_in##id##_max.dev_attr }
|
||||
|
||||
struct str_device_attr_table {
|
||||
struct device_attribute *input;
|
||||
struct device_attribute *min;
|
||||
struct device_attribute *max;
|
||||
};
|
||||
|
||||
static struct str_device_attr_table cfg_info_temp[] = {
|
||||
{ &dev_attr_temp1_input, &dev_attr_temp1_max_hyst, &dev_attr_temp1_max },
|
||||
CFG_INFO_TEMP(2),
|
||||
CFG_INFO_TEMP(3),
|
||||
CFG_INFO_TEMP(4),
|
||||
CFG_INFO_TEMP(5),
|
||||
CFG_INFO_TEMP(6)
|
||||
};
|
||||
|
||||
static struct str_device_attr_table cfg_info_volt[] = {
|
||||
CFG_INFO_VOLT(0),
|
||||
CFG_INFO_VOLT(1),
|
||||
CFG_INFO_VOLT(2),
|
||||
CFG_INFO_VOLT(3),
|
||||
CFG_INFO_VOLT(4),
|
||||
{ &dev_attr_in5_input, &dev_attr_in5_min, &dev_attr_in5_max }
|
||||
};
|
||||
|
||||
/* Fans */
|
||||
static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -585,6 +554,107 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
static struct attribute *vt8231_attributes_temps[6][4] = {
|
||||
{
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_max_hyst.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_max.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_max.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_temp6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_max.dev_attr.attr,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static const struct attribute_group vt8231_group_temps[6] = {
|
||||
{ .attrs = vt8231_attributes_temps[0] },
|
||||
{ .attrs = vt8231_attributes_temps[1] },
|
||||
{ .attrs = vt8231_attributes_temps[2] },
|
||||
{ .attrs = vt8231_attributes_temps[3] },
|
||||
{ .attrs = vt8231_attributes_temps[4] },
|
||||
{ .attrs = vt8231_attributes_temps[5] },
|
||||
};
|
||||
|
||||
static struct attribute *vt8231_attributes_volts[6][4] = {
|
||||
{
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_max.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_max.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_max.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_max.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_max.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&dev_attr_in5_input.attr,
|
||||
&dev_attr_in5_min.attr,
|
||||
&dev_attr_in5_max.attr,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static const struct attribute_group vt8231_group_volts[6] = {
|
||||
{ .attrs = vt8231_attributes_volts[0] },
|
||||
{ .attrs = vt8231_attributes_volts[1] },
|
||||
{ .attrs = vt8231_attributes_volts[2] },
|
||||
{ .attrs = vt8231_attributes_volts[3] },
|
||||
{ .attrs = vt8231_attributes_volts[4] },
|
||||
{ .attrs = vt8231_attributes_volts[5] },
|
||||
};
|
||||
|
||||
static struct attribute *vt8231_attributes[] = {
|
||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_div.dev_attr.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group vt8231_group = {
|
||||
.attrs = vt8231_attributes,
|
||||
};
|
||||
|
||||
static struct i2c_driver vt8231_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
@ -671,43 +741,43 @@ int vt8231_detect(struct i2c_adapter *adapter)
|
||||
vt8231_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
data->class_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &vt8231_group)))
|
||||
goto exit_detach;
|
||||
}
|
||||
|
||||
/* Must update device information to find out the config field */
|
||||
data->uch_config = vt8231_read_value(client, VT8231_REG_UCH_CONFIG);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cfg_info_temp); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) {
|
||||
if (ISTEMP(i, data->uch_config)) {
|
||||
device_create_file(&client->dev,
|
||||
cfg_info_temp[i].input);
|
||||
device_create_file(&client->dev, cfg_info_temp[i].max);
|
||||
device_create_file(&client->dev, cfg_info_temp[i].min);
|
||||
if ((err = sysfs_create_group(&client->dev.kobj,
|
||||
&vt8231_group_temps[i])))
|
||||
goto exit_remove_files;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cfg_info_volt); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) {
|
||||
if (ISVOLT(i, data->uch_config)) {
|
||||
device_create_file(&client->dev,
|
||||
cfg_info_volt[i].input);
|
||||
device_create_file(&client->dev, cfg_info_volt[i].max);
|
||||
device_create_file(&client->dev, cfg_info_volt[i].min);
|
||||
if ((err = sysfs_create_group(&client->dev.kobj,
|
||||
&vt8231_group_volts[i])))
|
||||
goto exit_remove_files;
|
||||
}
|
||||
}
|
||||
|
||||
device_create_file(&client->dev, &sensor_dev_attr_fan1_input.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_fan2_input.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_fan1_min.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_fan2_min.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_fan1_div.dev_attr);
|
||||
device_create_file(&client->dev, &sensor_dev_attr_fan2_div.dev_attr);
|
||||
|
||||
device_create_file(&client->dev, &dev_attr_alarms);
|
||||
data->class_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
|
||||
sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
|
||||
sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &vt8231_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(client);
|
||||
exit_free:
|
||||
@ -720,10 +790,18 @@ exit_release:
|
||||
static int vt8231_detach_client(struct i2c_client *client)
|
||||
{
|
||||
struct vt8231_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
int err, i;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
|
||||
sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
|
||||
sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &vt8231_group);
|
||||
|
||||
if ((err = i2c_detach_client(client))) {
|
||||
return err;
|
||||
}
|
||||
|
@ -2,6 +2,9 @@
|
||||
w83627ehf - Driver for the hardware monitoring functionality of
|
||||
the Winbond W83627EHF Super-I/O chip
|
||||
Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
|
||||
Copyright (C) 2006 Yuan Mu (Winbond),
|
||||
Rudolf Marek <r.marek@sh.cvut.cz>
|
||||
David Hubbard <david.c.hubbard@gmail.com>
|
||||
|
||||
Shamelessly ripped from the w83627hf driver
|
||||
Copyright (C) 2003 Mark Studebaker
|
||||
@ -29,8 +32,8 @@
|
||||
|
||||
Supports the following chips:
|
||||
|
||||
Chip #vin #fan #pwm #temp chip_id man_id
|
||||
w83627ehf 10 5 - 3 0x88 0x5ca3
|
||||
Chip #vin #fan #pwm #temp chip_id man_id
|
||||
w83627ehf 10 5 4 3 0x88,0xa1 0x5ca3
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -145,10 +148,44 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
|
||||
#define W83627EHF_REG_ALARM2 0x45A
|
||||
#define W83627EHF_REG_ALARM3 0x45B
|
||||
|
||||
/* SmartFan registers */
|
||||
/* DC or PWM output fan configuration */
|
||||
static const u8 W83627EHF_REG_PWM_ENABLE[] = {
|
||||
0x04, /* SYS FAN0 output mode and PWM mode */
|
||||
0x04, /* CPU FAN0 output mode and PWM mode */
|
||||
0x12, /* AUX FAN mode */
|
||||
0x62, /* CPU fan1 mode */
|
||||
};
|
||||
|
||||
static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
|
||||
static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
|
||||
|
||||
/* FAN Duty Cycle, be used to control */
|
||||
static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
|
||||
static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
|
||||
static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
|
||||
|
||||
|
||||
/* Advanced Fan control, some values are common for all fans */
|
||||
static const u8 W83627EHF_REG_FAN_MIN_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
|
||||
static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0C, 0x0D, 0x17, 0x66 };
|
||||
|
||||
/*
|
||||
* Conversions
|
||||
*/
|
||||
|
||||
/* 1 is PWM mode, output in ms */
|
||||
static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
|
||||
{
|
||||
return mode ? 100 * reg : 400 * reg;
|
||||
}
|
||||
|
||||
static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
|
||||
{
|
||||
return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
|
||||
(msec + 200) / 400), 1, 255);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
fan_from_reg(u8 reg, unsigned int div)
|
||||
{
|
||||
@ -170,12 +207,12 @@ temp1_from_reg(s8 reg)
|
||||
}
|
||||
|
||||
static inline s8
|
||||
temp1_to_reg(int temp)
|
||||
temp1_to_reg(int temp, int min, int max)
|
||||
{
|
||||
if (temp <= -128000)
|
||||
return -128;
|
||||
if (temp >= 127000)
|
||||
return 127;
|
||||
if (temp <= min)
|
||||
return min / 1000;
|
||||
if (temp >= max)
|
||||
return max / 1000;
|
||||
if (temp < 0)
|
||||
return (temp - 500) / 1000;
|
||||
return (temp + 500) / 1000;
|
||||
@ -223,6 +260,16 @@ struct w83627ehf_data {
|
||||
s16 temp_max[2];
|
||||
s16 temp_max_hyst[2];
|
||||
u32 alarms;
|
||||
|
||||
u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
|
||||
u8 pwm_enable[4]; /* 1->manual
|
||||
2->thermal cruise (also called SmartFan I) */
|
||||
u8 pwm[4];
|
||||
u8 target_temp[4];
|
||||
u8 tolerance[4];
|
||||
|
||||
u8 fan_min_output[4]; /* minimum fan speed */
|
||||
u8 fan_stop_time[4];
|
||||
};
|
||||
|
||||
static inline int is_word_sized(u16 reg)
|
||||
@ -349,6 +396,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client);
|
||||
int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
|
||||
int i;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
@ -416,6 +464,34 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
/* pwmcfg, tolarance mapped for i=0, i=1 to same reg */
|
||||
if (i != 1) {
|
||||
pwmcfg = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_PWM_ENABLE[i]);
|
||||
tolerance = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_TOLERANCE[i]);
|
||||
}
|
||||
data->pwm_mode[i] =
|
||||
((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
|
||||
? 0 : 1;
|
||||
data->pwm_enable[i] =
|
||||
((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
|
||||
& 3) + 1;
|
||||
data->pwm[i] = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_PWM[i]);
|
||||
data->fan_min_output[i] = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_FAN_MIN_OUTPUT[i]);
|
||||
data->fan_stop_time[i] = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_FAN_STOP_TIME[i]);
|
||||
data->target_temp[i] =
|
||||
w83627ehf_read_value(client,
|
||||
W83627EHF_REG_TARGET[i]) &
|
||||
(data->pwm_mode[i] == 1 ? 0x7f : 0xff);
|
||||
data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
|
||||
& 0x0f;
|
||||
}
|
||||
|
||||
/* Measured temperatures and limits */
|
||||
data->temp1 = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_TEMP1);
|
||||
@ -546,14 +622,6 @@ static struct sensor_device_attribute sda_in_max[] = {
|
||||
SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
|
||||
};
|
||||
|
||||
static void device_create_file_in(struct device *dev, int i)
|
||||
{
|
||||
device_create_file(dev, &sda_in_input[i].dev_attr);
|
||||
device_create_file(dev, &sda_in_alarm[i].dev_attr);
|
||||
device_create_file(dev, &sda_in_min[i].dev_attr);
|
||||
device_create_file(dev, &sda_in_max[i].dev_attr);
|
||||
}
|
||||
|
||||
#define show_fan_reg(reg) \
|
||||
static ssize_t \
|
||||
show_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
@ -681,14 +749,6 @@ static struct sensor_device_attribute sda_fan_div[] = {
|
||||
SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
|
||||
};
|
||||
|
||||
static void device_create_file_fan(struct device *dev, int i)
|
||||
{
|
||||
device_create_file(dev, &sda_fan_input[i].dev_attr);
|
||||
device_create_file(dev, &sda_fan_alarm[i].dev_attr);
|
||||
device_create_file(dev, &sda_fan_div[i].dev_attr);
|
||||
device_create_file(dev, &sda_fan_min[i].dev_attr);
|
||||
}
|
||||
|
||||
#define show_temp1_reg(reg) \
|
||||
static ssize_t \
|
||||
show_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
@ -711,7 +771,7 @@ store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
u32 val = simple_strtoul(buf, NULL, 10); \
|
||||
\
|
||||
mutex_lock(&data->update_lock); \
|
||||
data->temp1_##reg = temp1_to_reg(val); \
|
||||
data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
|
||||
w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
|
||||
data->temp1_##reg); \
|
||||
mutex_unlock(&data->update_lock); \
|
||||
@ -777,10 +837,309 @@ static struct sensor_device_attribute sda_temp[] = {
|
||||
SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
|
||||
};
|
||||
|
||||
#define show_pwm_reg(reg) \
|
||||
static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct w83627ehf_data *data = w83627ehf_update_device(dev); \
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
|
||||
int nr = sensor_attr->index; \
|
||||
return sprintf(buf, "%d\n", data->reg[nr]); \
|
||||
}
|
||||
|
||||
show_pwm_reg(pwm_mode)
|
||||
show_pwm_reg(pwm_enable)
|
||||
show_pwm_reg(pwm)
|
||||
|
||||
static ssize_t
|
||||
store_pwm_mode(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
u16 reg;
|
||||
|
||||
if (val > 1)
|
||||
return -EINVAL;
|
||||
mutex_lock(&data->update_lock);
|
||||
reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
|
||||
data->pwm_mode[nr] = val;
|
||||
reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
|
||||
if (!val)
|
||||
reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
|
||||
w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
store_pwm(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->pwm[nr] = val;
|
||||
w83627ehf_write_value(client, W83627EHF_REG_PWM[nr], val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
store_pwm_enable(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
u16 reg;
|
||||
|
||||
if (!val || (val > 2)) /* only modes 1 and 2 are supported */
|
||||
return -EINVAL;
|
||||
mutex_lock(&data->update_lock);
|
||||
reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
|
||||
data->pwm_enable[nr] = val;
|
||||
reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
|
||||
reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
|
||||
w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
#define show_tol_temp(reg) \
|
||||
static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct w83627ehf_data *data = w83627ehf_update_device(dev); \
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
|
||||
int nr = sensor_attr->index; \
|
||||
return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
|
||||
}
|
||||
|
||||
show_tol_temp(tolerance)
|
||||
show_tol_temp(target_temp)
|
||||
|
||||
static ssize_t
|
||||
store_target_temp(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->target_temp[nr] = val;
|
||||
w83627ehf_write_value(client, W83627EHF_REG_TARGET[nr], val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
store_tolerance(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client);
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
u16 reg;
|
||||
/* Limit the temp to 0C - 15C */
|
||||
u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
reg = w83627ehf_read_value(client, W83627EHF_REG_TOLERANCE[nr]);
|
||||
data->tolerance[nr] = val;
|
||||
if (nr == 1)
|
||||
reg = (reg & 0x0f) | (val << 4);
|
||||
else
|
||||
reg = (reg & 0xf0) | val;
|
||||
w83627ehf_write_value(client, W83627EHF_REG_TOLERANCE[nr], reg);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct sensor_device_attribute sda_pwm[] = {
|
||||
SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
|
||||
SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
|
||||
SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
|
||||
SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute sda_pwm_mode[] = {
|
||||
SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
|
||||
store_pwm_mode, 0),
|
||||
SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
|
||||
store_pwm_mode, 1),
|
||||
SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
|
||||
store_pwm_mode, 2),
|
||||
SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
|
||||
store_pwm_mode, 3),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute sda_pwm_enable[] = {
|
||||
SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
|
||||
store_pwm_enable, 0),
|
||||
SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
|
||||
store_pwm_enable, 1),
|
||||
SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
|
||||
store_pwm_enable, 2),
|
||||
SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
|
||||
store_pwm_enable, 3),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute sda_target_temp[] = {
|
||||
SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
|
||||
store_target_temp, 0),
|
||||
SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
|
||||
store_target_temp, 1),
|
||||
SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
|
||||
store_target_temp, 2),
|
||||
SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
|
||||
store_target_temp, 3),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute sda_tolerance[] = {
|
||||
SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
|
||||
store_tolerance, 0),
|
||||
SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
|
||||
store_tolerance, 1),
|
||||
SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
|
||||
store_tolerance, 2),
|
||||
SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
|
||||
store_tolerance, 3),
|
||||
};
|
||||
|
||||
/* Smart Fan registers */
|
||||
|
||||
#define fan_functions(reg, REG) \
|
||||
static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct w83627ehf_data *data = w83627ehf_update_device(dev); \
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
|
||||
int nr = sensor_attr->index; \
|
||||
return sprintf(buf, "%d\n", data->reg[nr]); \
|
||||
}\
|
||||
static ssize_t \
|
||||
store_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{\
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client); \
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
|
||||
int nr = sensor_attr->index; \
|
||||
u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
|
||||
mutex_lock(&data->update_lock); \
|
||||
data->reg[nr] = val; \
|
||||
w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
|
||||
mutex_unlock(&data->update_lock); \
|
||||
return count; \
|
||||
}
|
||||
|
||||
fan_functions(fan_min_output, FAN_MIN_OUTPUT)
|
||||
|
||||
#define fan_time_functions(reg, REG) \
|
||||
static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct w83627ehf_data *data = w83627ehf_update_device(dev); \
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
|
||||
int nr = sensor_attr->index; \
|
||||
return sprintf(buf, "%d\n", \
|
||||
step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
|
||||
} \
|
||||
\
|
||||
static ssize_t \
|
||||
store_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client); \
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
|
||||
int nr = sensor_attr->index; \
|
||||
u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
|
||||
data->pwm_mode[nr]); \
|
||||
mutex_lock(&data->update_lock); \
|
||||
data->reg[nr] = val; \
|
||||
w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
|
||||
mutex_unlock(&data->update_lock); \
|
||||
return count; \
|
||||
} \
|
||||
|
||||
fan_time_functions(fan_stop_time, FAN_STOP_TIME)
|
||||
|
||||
|
||||
static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
|
||||
SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
|
||||
store_fan_stop_time, 3),
|
||||
SENSOR_ATTR(pwm4_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
|
||||
store_fan_min_output, 3),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute sda_sf3_arrays[] = {
|
||||
SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
|
||||
store_fan_stop_time, 0),
|
||||
SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
|
||||
store_fan_stop_time, 1),
|
||||
SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
|
||||
store_fan_stop_time, 2),
|
||||
SENSOR_ATTR(pwm1_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
|
||||
store_fan_min_output, 0),
|
||||
SENSOR_ATTR(pwm2_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
|
||||
store_fan_min_output, 1),
|
||||
SENSOR_ATTR(pwm3_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
|
||||
store_fan_min_output, 2),
|
||||
};
|
||||
|
||||
/*
|
||||
* Driver and client management
|
||||
*/
|
||||
|
||||
static void w83627ehf_device_remove_files(struct device *dev)
|
||||
{
|
||||
/* some entries in the following arrays may not have been used in
|
||||
* device_create_file(), but device_remove_file() will ignore them */
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
|
||||
device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
|
||||
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
|
||||
device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
|
||||
for (i = 0; i < 10; i++) {
|
||||
device_remove_file(dev, &sda_in_input[i].dev_attr);
|
||||
device_remove_file(dev, &sda_in_alarm[i].dev_attr);
|
||||
device_remove_file(dev, &sda_in_min[i].dev_attr);
|
||||
device_remove_file(dev, &sda_in_max[i].dev_attr);
|
||||
}
|
||||
for (i = 0; i < 5; i++) {
|
||||
device_remove_file(dev, &sda_fan_input[i].dev_attr);
|
||||
device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
|
||||
device_remove_file(dev, &sda_fan_div[i].dev_attr);
|
||||
device_remove_file(dev, &sda_fan_min[i].dev_attr);
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
device_remove_file(dev, &sda_pwm[i].dev_attr);
|
||||
device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
|
||||
device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
|
||||
device_remove_file(dev, &sda_target_temp[i].dev_attr);
|
||||
device_remove_file(dev, &sda_tolerance[i].dev_attr);
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
|
||||
device_remove_file(dev, &sda_temp[i].dev_attr);
|
||||
}
|
||||
|
||||
static struct i2c_driver w83627ehf_driver;
|
||||
|
||||
static void w83627ehf_init_client(struct i2c_client *client)
|
||||
@ -810,6 +1169,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
|
||||
struct i2c_client *client;
|
||||
struct w83627ehf_data *data;
|
||||
struct device *dev;
|
||||
u8 fan4pin, fan5pin;
|
||||
int i, err = 0;
|
||||
|
||||
if (!request_region(address + REGION_OFFSET, REGION_LENGTH,
|
||||
@ -848,35 +1208,87 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
|
||||
data->fan_min[i] = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_FAN_MIN[i]);
|
||||
|
||||
/* fan4 and fan5 share some pins with the GPIO and serial flash */
|
||||
|
||||
superio_enter();
|
||||
fan5pin = superio_inb(0x24) & 0x2;
|
||||
fan4pin = superio_inb(0x29) & 0x6;
|
||||
superio_exit();
|
||||
|
||||
/* It looks like fan4 and fan5 pins can be alternatively used
|
||||
as fan on/off switches */
|
||||
|
||||
data->has_fan = 0x07; /* fan1, fan2 and fan3 */
|
||||
i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
|
||||
if (i & (1 << 2))
|
||||
if ((i & (1 << 2)) && (!fan4pin))
|
||||
data->has_fan |= (1 << 3);
|
||||
if (i & (1 << 0))
|
||||
if ((i & (1 << 0)) && (!fan5pin))
|
||||
data->has_fan |= (1 << 4);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
|
||||
if ((err = device_create_file(dev,
|
||||
&sda_sf3_arrays[i].dev_attr)))
|
||||
goto exit_remove;
|
||||
|
||||
/* if fan4 is enabled create the sf3 files for it */
|
||||
if (data->has_fan & (1 << 3))
|
||||
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
|
||||
if ((err = device_create_file(dev,
|
||||
&sda_sf3_arrays_fan4[i].dev_attr)))
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sda_in_alarm[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sda_in_min[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sda_in_max[i].dev_attr)))
|
||||
goto exit_remove;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (data->has_fan & (1 << i)) {
|
||||
if ((err = device_create_file(dev,
|
||||
&sda_fan_input[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sda_fan_alarm[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sda_fan_div[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sda_fan_min[i].dev_attr)))
|
||||
goto exit_remove;
|
||||
if (i < 4 && /* w83627ehf only has 4 pwm */
|
||||
((err = device_create_file(dev,
|
||||
&sda_pwm[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sda_pwm_mode[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sda_pwm_enable[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sda_target_temp[i].dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sda_tolerance[i].dev_attr))))
|
||||
goto exit_remove;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
|
||||
if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
|
||||
goto exit_remove;
|
||||
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
device_create_file_in(dev, i);
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (data->has_fan & (1 << i))
|
||||
device_create_file_fan(dev, i);
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
|
||||
device_create_file(dev, &sda_temp[i].dev_attr);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_detach:
|
||||
exit_remove:
|
||||
w83627ehf_device_remove_files(dev);
|
||||
i2c_detach_client(client);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
@ -892,6 +1304,7 @@ static int w83627ehf_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
w83627ehf_device_remove_files(&client->dev);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -512,13 +512,6 @@ static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
|
||||
static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
|
||||
show_regs_in_max0, store_regs_in_max0);
|
||||
|
||||
#define device_create_file_in(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_in##offset##_input); \
|
||||
device_create_file(&client->dev, &dev_attr_in##offset##_min); \
|
||||
device_create_file(&client->dev, &dev_attr_in##offset##_max); \
|
||||
} while (0)
|
||||
|
||||
#define show_fan_reg(reg) \
|
||||
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
|
||||
{ \
|
||||
@ -576,12 +569,6 @@ sysfs_fan_min_offset(2);
|
||||
sysfs_fan_offset(3);
|
||||
sysfs_fan_min_offset(3);
|
||||
|
||||
#define device_create_file_fan(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
|
||||
device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
|
||||
} while (0)
|
||||
|
||||
#define show_temp_reg(reg) \
|
||||
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
|
||||
{ \
|
||||
@ -656,13 +643,6 @@ sysfs_temp_offsets(1);
|
||||
sysfs_temp_offsets(2);
|
||||
sysfs_temp_offsets(3);
|
||||
|
||||
#define device_create_file_temp(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
|
||||
device_create_file(&client->dev, &dev_attr_temp##offset##_max); \
|
||||
device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \
|
||||
} while (0)
|
||||
|
||||
static ssize_t
|
||||
show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -670,8 +650,6 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
|
||||
}
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
|
||||
#define device_create_file_vid(client) \
|
||||
device_create_file(&client->dev, &dev_attr_cpu0_vid)
|
||||
|
||||
static ssize_t
|
||||
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
@ -692,8 +670,6 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
|
||||
#define device_create_file_vrm(client) \
|
||||
device_create_file(&client->dev, &dev_attr_vrm)
|
||||
|
||||
static ssize_t
|
||||
show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
@ -702,8 +678,6 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
return sprintf(buf, "%ld\n", (long) data->alarms);
|
||||
}
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
|
||||
#define device_create_file_alarms(client) \
|
||||
device_create_file(&client->dev, &dev_attr_alarms)
|
||||
|
||||
#define show_beep_reg(REG, reg) \
|
||||
static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
@ -766,12 +740,6 @@ static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
|
||||
sysfs_beep(ENABLE, enable);
|
||||
sysfs_beep(MASK, mask);
|
||||
|
||||
#define device_create_file_beep(client) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_beep_enable); \
|
||||
device_create_file(&client->dev, &dev_attr_beep_mask); \
|
||||
} while (0)
|
||||
|
||||
static ssize_t
|
||||
show_fan_div_reg(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
@ -837,11 +805,6 @@ sysfs_fan_div(1);
|
||||
sysfs_fan_div(2);
|
||||
sysfs_fan_div(3);
|
||||
|
||||
#define device_create_file_fan_div(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
|
||||
} while (0)
|
||||
|
||||
static ssize_t
|
||||
show_pwm_reg(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
@ -896,11 +859,6 @@ sysfs_pwm(1);
|
||||
sysfs_pwm(2);
|
||||
sysfs_pwm(3);
|
||||
|
||||
#define device_create_file_pwm(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_pwm##offset); \
|
||||
} while (0)
|
||||
|
||||
static ssize_t
|
||||
show_sensor_reg(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
@ -972,12 +930,6 @@ sysfs_sensor(1);
|
||||
sysfs_sensor(2);
|
||||
sysfs_sensor(3);
|
||||
|
||||
#define device_create_file_sensor(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static int __init w83627hf_find(int sioaddr, unsigned short *addr)
|
||||
{
|
||||
u16 val;
|
||||
@ -1009,6 +961,85 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct attribute *w83627hf_attributes[] = {
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in0_min.attr,
|
||||
&dev_attr_in0_max.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
&dev_attr_in2_min.attr,
|
||||
&dev_attr_in2_max.attr,
|
||||
&dev_attr_in3_input.attr,
|
||||
&dev_attr_in3_min.attr,
|
||||
&dev_attr_in3_max.attr,
|
||||
&dev_attr_in4_input.attr,
|
||||
&dev_attr_in4_min.attr,
|
||||
&dev_attr_in4_max.attr,
|
||||
&dev_attr_in7_input.attr,
|
||||
&dev_attr_in7_min.attr,
|
||||
&dev_attr_in7_max.attr,
|
||||
&dev_attr_in8_input.attr,
|
||||
&dev_attr_in8_min.attr,
|
||||
&dev_attr_in8_max.attr,
|
||||
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan1_min.attr,
|
||||
&dev_attr_fan1_div.attr,
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan2_min.attr,
|
||||
&dev_attr_fan2_div.attr,
|
||||
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_max_hyst.attr,
|
||||
&dev_attr_temp1_type.attr,
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_temp2_max.attr,
|
||||
&dev_attr_temp2_max_hyst.attr,
|
||||
&dev_attr_temp2_type.attr,
|
||||
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_beep_enable.attr,
|
||||
&dev_attr_beep_mask.attr,
|
||||
|
||||
&dev_attr_pwm1.attr,
|
||||
&dev_attr_pwm2.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group w83627hf_group = {
|
||||
.attrs = w83627hf_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *w83627hf_attributes_opt[] = {
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in1_min.attr,
|
||||
&dev_attr_in1_max.attr,
|
||||
&dev_attr_in5_input.attr,
|
||||
&dev_attr_in5_min.attr,
|
||||
&dev_attr_in5_max.attr,
|
||||
&dev_attr_in6_input.attr,
|
||||
&dev_attr_in6_min.attr,
|
||||
&dev_attr_in6_max.attr,
|
||||
|
||||
&dev_attr_fan3_input.attr,
|
||||
&dev_attr_fan3_min.attr,
|
||||
&dev_attr_fan3_div.attr,
|
||||
|
||||
&dev_attr_temp3_input.attr,
|
||||
&dev_attr_temp3_max.attr,
|
||||
&dev_attr_temp3_max_hyst.attr,
|
||||
&dev_attr_temp3_type.attr,
|
||||
|
||||
&dev_attr_pwm3.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group w83627hf_group_opt = {
|
||||
.attrs = w83627hf_attributes_opt,
|
||||
};
|
||||
|
||||
static int w83627hf_detect(struct i2c_adapter *adapter)
|
||||
{
|
||||
int val, kind;
|
||||
@ -1108,62 +1139,72 @@ static int w83627hf_detect(struct i2c_adapter *adapter)
|
||||
data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2));
|
||||
data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3));
|
||||
|
||||
/* Register sysfs hooks */
|
||||
/* Register common device attributes */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &w83627hf_group)))
|
||||
goto ERROR3;
|
||||
|
||||
/* Register chip-specific device attributes */
|
||||
if (kind == w83627hf || kind == w83697hf)
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in5_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in5_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in5_max))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in6_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in6_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in6_max)))
|
||||
goto ERROR4;
|
||||
|
||||
if (kind != w83697hf)
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in1_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in1_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in1_max))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan3_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan3_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan3_div))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp3_input))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp3_max))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp3_max_hyst))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp3_type)))
|
||||
goto ERROR4;
|
||||
|
||||
if (kind != w83697hf && data->vid != 0xff)
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_cpu0_vid))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_vrm)))
|
||||
goto ERROR4;
|
||||
|
||||
if (kind == w83627thf || kind == w83637hf || kind == w83687thf)
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&dev_attr_pwm3)))
|
||||
goto ERROR4;
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto ERROR3;
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
device_create_file_in(new_client, 0);
|
||||
if (kind != w83697hf)
|
||||
device_create_file_in(new_client, 1);
|
||||
device_create_file_in(new_client, 2);
|
||||
device_create_file_in(new_client, 3);
|
||||
device_create_file_in(new_client, 4);
|
||||
if (kind == w83627hf || kind == w83697hf) {
|
||||
device_create_file_in(new_client, 5);
|
||||
device_create_file_in(new_client, 6);
|
||||
}
|
||||
device_create_file_in(new_client, 7);
|
||||
device_create_file_in(new_client, 8);
|
||||
|
||||
device_create_file_fan(new_client, 1);
|
||||
device_create_file_fan(new_client, 2);
|
||||
if (kind != w83697hf)
|
||||
device_create_file_fan(new_client, 3);
|
||||
|
||||
device_create_file_temp(new_client, 1);
|
||||
device_create_file_temp(new_client, 2);
|
||||
if (kind != w83697hf)
|
||||
device_create_file_temp(new_client, 3);
|
||||
|
||||
if (kind != w83697hf && data->vid != 0xff) {
|
||||
device_create_file_vid(new_client);
|
||||
device_create_file_vrm(new_client);
|
||||
}
|
||||
|
||||
device_create_file_fan_div(new_client, 1);
|
||||
device_create_file_fan_div(new_client, 2);
|
||||
if (kind != w83697hf)
|
||||
device_create_file_fan_div(new_client, 3);
|
||||
|
||||
device_create_file_alarms(new_client);
|
||||
|
||||
device_create_file_beep(new_client);
|
||||
|
||||
device_create_file_pwm(new_client, 1);
|
||||
device_create_file_pwm(new_client, 2);
|
||||
if (kind == w83627thf || kind == w83637hf || kind == w83687thf)
|
||||
device_create_file_pwm(new_client, 3);
|
||||
|
||||
device_create_file_sensor(new_client, 1);
|
||||
device_create_file_sensor(new_client, 2);
|
||||
if (kind != w83697hf)
|
||||
device_create_file_sensor(new_client, 3);
|
||||
|
||||
return 0;
|
||||
|
||||
ERROR4:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group);
|
||||
sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group_opt);
|
||||
ERROR3:
|
||||
i2c_detach_client(new_client);
|
||||
ERROR2:
|
||||
@ -1181,6 +1222,9 @@ static int w83627hf_detach_client(struct i2c_client *client)
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &w83627hf_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &w83627hf_group_opt);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <linux/i2c-isa.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-vid.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/io.h>
|
||||
@ -360,13 +361,6 @@ sysfs_in_offsets(6);
|
||||
sysfs_in_offsets(7);
|
||||
sysfs_in_offsets(8);
|
||||
|
||||
#define device_create_file_in(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_in##offset##_input); \
|
||||
device_create_file(&client->dev, &dev_attr_in##offset##_min); \
|
||||
device_create_file(&client->dev, &dev_attr_in##offset##_max); \
|
||||
} while (0)
|
||||
|
||||
#define show_fan_reg(reg) \
|
||||
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
|
||||
{ \
|
||||
@ -421,12 +415,6 @@ sysfs_fan_min_offset(2);
|
||||
sysfs_fan_offset(3);
|
||||
sysfs_fan_min_offset(3);
|
||||
|
||||
#define device_create_file_fan(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
|
||||
device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
|
||||
} while (0)
|
||||
|
||||
#define show_temp_reg(reg) \
|
||||
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
|
||||
{ \
|
||||
@ -497,13 +485,6 @@ sysfs_temp_offsets(1);
|
||||
sysfs_temp_offsets(2);
|
||||
sysfs_temp_offsets(3);
|
||||
|
||||
#define device_create_file_temp(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
|
||||
device_create_file(&client->dev, &dev_attr_temp##offset##_max); \
|
||||
device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \
|
||||
} while (0)
|
||||
|
||||
static ssize_t
|
||||
show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -511,10 +492,8 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
|
||||
}
|
||||
|
||||
static
|
||||
DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
|
||||
#define device_create_file_vid(client) \
|
||||
device_create_file(&client->dev, &dev_attr_cpu0_vid);
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
|
||||
|
||||
static ssize_t
|
||||
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -535,10 +514,8 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf
|
||||
return count;
|
||||
}
|
||||
|
||||
static
|
||||
DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
|
||||
#define device_create_file_vrm(client) \
|
||||
device_create_file(&client->dev, &dev_attr_vrm);
|
||||
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
|
||||
|
||||
static ssize_t
|
||||
show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -546,10 +523,8 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
|
||||
static
|
||||
DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
|
||||
#define device_create_file_alarms(client) \
|
||||
device_create_file(&client->dev, &dev_attr_alarms);
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
|
||||
|
||||
static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct w83781d_data *data = w83781d_update_device(dev);
|
||||
@ -615,12 +590,6 @@ static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_re
|
||||
sysfs_beep(ENABLE, enable);
|
||||
sysfs_beep(MASK, mask);
|
||||
|
||||
#define device_create_file_beep(client) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_beep_enable); \
|
||||
device_create_file(&client->dev, &dev_attr_beep_mask); \
|
||||
} while (0)
|
||||
|
||||
static ssize_t
|
||||
show_fan_div_reg(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
@ -686,11 +655,6 @@ sysfs_fan_div(1);
|
||||
sysfs_fan_div(2);
|
||||
sysfs_fan_div(3);
|
||||
|
||||
#define device_create_file_fan_div(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
|
||||
} while (0)
|
||||
|
||||
static ssize_t
|
||||
show_pwm_reg(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
@ -787,16 +751,6 @@ sysfs_pwmenable(2); /* only PWM2 can be enabled/disabled */
|
||||
sysfs_pwm(3);
|
||||
sysfs_pwm(4);
|
||||
|
||||
#define device_create_file_pwm(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_pwm##offset); \
|
||||
} while (0)
|
||||
|
||||
#define device_create_file_pwmenable(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_pwm##offset##_enable); \
|
||||
} while (0)
|
||||
|
||||
static ssize_t
|
||||
show_sensor_reg(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
@ -865,11 +819,6 @@ sysfs_sensor(1);
|
||||
sysfs_sensor(2);
|
||||
sysfs_sensor(3);
|
||||
|
||||
#define device_create_file_sensor(client, offset) \
|
||||
do { \
|
||||
device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
|
||||
} while (0)
|
||||
|
||||
/* This function is called when:
|
||||
* w83781d_driver is inserted (when this module is loaded), for each
|
||||
available adapter
|
||||
@ -994,11 +943,69 @@ ERROR_SC_0:
|
||||
return err;
|
||||
}
|
||||
|
||||
#define IN_UNIT_ATTRS(X) \
|
||||
&dev_attr_in##X##_input.attr, \
|
||||
&dev_attr_in##X##_min.attr, \
|
||||
&dev_attr_in##X##_max.attr
|
||||
|
||||
#define FAN_UNIT_ATTRS(X) \
|
||||
&dev_attr_fan##X##_input.attr, \
|
||||
&dev_attr_fan##X##_min.attr, \
|
||||
&dev_attr_fan##X##_div.attr
|
||||
|
||||
#define TEMP_UNIT_ATTRS(X) \
|
||||
&dev_attr_temp##X##_input.attr, \
|
||||
&dev_attr_temp##X##_max.attr, \
|
||||
&dev_attr_temp##X##_max_hyst.attr
|
||||
|
||||
static struct attribute* w83781d_attributes[] = {
|
||||
IN_UNIT_ATTRS(0),
|
||||
IN_UNIT_ATTRS(2),
|
||||
IN_UNIT_ATTRS(3),
|
||||
IN_UNIT_ATTRS(4),
|
||||
IN_UNIT_ATTRS(5),
|
||||
IN_UNIT_ATTRS(6),
|
||||
FAN_UNIT_ATTRS(1),
|
||||
FAN_UNIT_ATTRS(2),
|
||||
FAN_UNIT_ATTRS(3),
|
||||
TEMP_UNIT_ATTRS(1),
|
||||
TEMP_UNIT_ATTRS(2),
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
&dev_attr_vrm.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_beep_mask.attr,
|
||||
&dev_attr_beep_enable.attr,
|
||||
NULL
|
||||
};
|
||||
static const struct attribute_group w83781d_group = {
|
||||
.attrs = w83781d_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *w83781d_attributes_opt[] = {
|
||||
IN_UNIT_ATTRS(1),
|
||||
IN_UNIT_ATTRS(7),
|
||||
IN_UNIT_ATTRS(8),
|
||||
TEMP_UNIT_ATTRS(3),
|
||||
&dev_attr_pwm1.attr,
|
||||
&dev_attr_pwm2.attr,
|
||||
&dev_attr_pwm2_enable.attr,
|
||||
&dev_attr_pwm3.attr,
|
||||
&dev_attr_pwm4.attr,
|
||||
&dev_attr_temp1_type.attr,
|
||||
&dev_attr_temp2_type.attr,
|
||||
&dev_attr_temp3_type.attr,
|
||||
NULL
|
||||
};
|
||||
static const struct attribute_group w83781d_group_opt = {
|
||||
.attrs = w83781d_attributes_opt,
|
||||
};
|
||||
|
||||
static int
|
||||
w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
int i = 0, val1 = 0, val2;
|
||||
struct i2c_client *new_client;
|
||||
struct i2c_client *client;
|
||||
struct device *dev;
|
||||
struct w83781d_data *data;
|
||||
int err;
|
||||
const char *client_name = "";
|
||||
@ -1075,13 +1082,14 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
goto ERROR1;
|
||||
}
|
||||
|
||||
new_client = &data->client;
|
||||
i2c_set_clientdata(new_client, data);
|
||||
new_client->addr = address;
|
||||
client = &data->client;
|
||||
i2c_set_clientdata(client, data);
|
||||
client->addr = address;
|
||||
mutex_init(&data->lock);
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
|
||||
new_client->flags = 0;
|
||||
client->adapter = adapter;
|
||||
client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
|
||||
client->flags = 0;
|
||||
dev = &client->dev;
|
||||
|
||||
/* Now, we do the remaining detection. */
|
||||
|
||||
@ -1090,20 +1098,18 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
force_*=... parameter, and the Winbond will be reset to the right
|
||||
bank. */
|
||||
if (kind < 0) {
|
||||
if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) {
|
||||
dev_dbg(&new_client->dev, "Detection failed at step "
|
||||
"3\n");
|
||||
if (w83781d_read_value(client, W83781D_REG_CONFIG) & 0x80) {
|
||||
dev_dbg(dev, "Detection failed at step 3\n");
|
||||
err = -ENODEV;
|
||||
goto ERROR2;
|
||||
}
|
||||
val1 = w83781d_read_value(new_client, W83781D_REG_BANK);
|
||||
val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);
|
||||
val1 = w83781d_read_value(client, W83781D_REG_BANK);
|
||||
val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
|
||||
/* Check for Winbond or Asus ID if in bank 0 */
|
||||
if ((!(val1 & 0x07)) &&
|
||||
(((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
|
||||
|| ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
|
||||
dev_dbg(&new_client->dev, "Detection failed at step "
|
||||
"4\n");
|
||||
dev_dbg(dev, "Detection failed at step 4\n");
|
||||
err = -ENODEV;
|
||||
goto ERROR2;
|
||||
}
|
||||
@ -1112,9 +1118,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) ||
|
||||
((val1 & 0x80) && (val2 == 0x5c)))) {
|
||||
if (w83781d_read_value
|
||||
(new_client, W83781D_REG_I2C_ADDR) != address) {
|
||||
dev_dbg(&new_client->dev, "Detection failed "
|
||||
"at step 5\n");
|
||||
(client, W83781D_REG_I2C_ADDR) != address) {
|
||||
dev_dbg(dev, "Detection failed at step 5\n");
|
||||
err = -ENODEV;
|
||||
goto ERROR2;
|
||||
}
|
||||
@ -1123,27 +1128,26 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
|
||||
/* We have either had a force parameter, or we have already detected the
|
||||
Winbond. Put it now into bank 0 and Vendor ID High Byte */
|
||||
w83781d_write_value(new_client, W83781D_REG_BANK,
|
||||
(w83781d_read_value(new_client,
|
||||
W83781D_REG_BANK) & 0x78) |
|
||||
0x80);
|
||||
w83781d_write_value(client, W83781D_REG_BANK,
|
||||
(w83781d_read_value(client, W83781D_REG_BANK)
|
||||
& 0x78) | 0x80);
|
||||
|
||||
/* Determine the chip type. */
|
||||
if (kind <= 0) {
|
||||
/* get vendor ID */
|
||||
val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);
|
||||
val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
|
||||
if (val2 == 0x5c)
|
||||
vendid = winbond;
|
||||
else if (val2 == 0x12)
|
||||
vendid = asus;
|
||||
else {
|
||||
dev_dbg(&new_client->dev, "Chip was made by neither "
|
||||
dev_dbg(dev, "Chip was made by neither "
|
||||
"Winbond nor Asus?\n");
|
||||
err = -ENODEV;
|
||||
goto ERROR2;
|
||||
}
|
||||
|
||||
val1 = w83781d_read_value(new_client, W83781D_REG_WCHIPID);
|
||||
val1 = w83781d_read_value(client, W83781D_REG_WCHIPID);
|
||||
if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
|
||||
kind = w83781d;
|
||||
else if (val1 == 0x30 && vendid == winbond)
|
||||
@ -1157,7 +1161,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
kind = as99127f;
|
||||
else {
|
||||
if (kind == 0)
|
||||
dev_warn(&new_client->dev, "Ignoring 'force' "
|
||||
dev_warn(dev, "Ignoring 'force' "
|
||||
"parameter for unknown chip at "
|
||||
"adapter %d, address 0x%02x\n",
|
||||
i2c_adapter_id(adapter), address);
|
||||
@ -1179,20 +1183,20 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
}
|
||||
|
||||
/* Fill in the remaining client fields and put into the global list */
|
||||
strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
|
||||
strlcpy(client->name, client_name, I2C_NAME_SIZE);
|
||||
data->type = kind;
|
||||
|
||||
data->valid = 0;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Tell the I2C layer a new client has arrived */
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
if ((err = i2c_attach_client(client)))
|
||||
goto ERROR2;
|
||||
|
||||
/* attach secondary i2c lm75-like clients */
|
||||
if (!is_isa) {
|
||||
if ((err = w83781d_detect_subclients(adapter, address,
|
||||
kind, new_client)))
|
||||
kind, client)))
|
||||
goto ERROR3;
|
||||
} else {
|
||||
data->lm75[0] = NULL;
|
||||
@ -1200,11 +1204,11 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
}
|
||||
|
||||
/* Initialize the chip */
|
||||
w83781d_init_client(new_client);
|
||||
w83781d_init_client(client);
|
||||
|
||||
/* A few vars need to be filled upon startup */
|
||||
for (i = 1; i <= 3; i++) {
|
||||
data->fan_min[i - 1] = w83781d_read_value(new_client,
|
||||
data->fan_min[i - 1] = w83781d_read_value(client,
|
||||
W83781D_REG_FAN_MIN(i));
|
||||
}
|
||||
if (kind != w83781d && kind != as99127f)
|
||||
@ -1212,65 +1216,68 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
data->pwmenable[i] = 1;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
|
||||
goto ERROR4;
|
||||
|
||||
if (kind != w83783s) {
|
||||
if ((err = device_create_file(dev, &dev_attr_in1_input))
|
||||
|| (err = device_create_file(dev, &dev_attr_in1_min))
|
||||
|| (err = device_create_file(dev, &dev_attr_in1_max)))
|
||||
goto ERROR4;
|
||||
}
|
||||
if (kind != as99127f && kind != w83781d && kind != w83783s) {
|
||||
if ((err = device_create_file(dev, &dev_attr_in7_input))
|
||||
|| (err = device_create_file(dev, &dev_attr_in7_min))
|
||||
|| (err = device_create_file(dev, &dev_attr_in7_max))
|
||||
|| (err = device_create_file(dev, &dev_attr_in8_input))
|
||||
|| (err = device_create_file(dev, &dev_attr_in8_min))
|
||||
|| (err = device_create_file(dev, &dev_attr_in8_max)))
|
||||
goto ERROR4;
|
||||
}
|
||||
if (kind != w83783s) {
|
||||
if ((err = device_create_file(dev, &dev_attr_temp3_input))
|
||||
|| (err = device_create_file(dev, &dev_attr_temp3_max))
|
||||
|| (err = device_create_file(dev,
|
||||
&dev_attr_temp3_max_hyst)))
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
if (kind != w83781d && kind != as99127f) {
|
||||
if ((err = device_create_file(dev, &dev_attr_pwm1))
|
||||
|| (err = device_create_file(dev, &dev_attr_pwm2))
|
||||
|| (err = device_create_file(dev, &dev_attr_pwm2_enable)))
|
||||
goto ERROR4;
|
||||
}
|
||||
if (kind == w83782d && !is_isa) {
|
||||
if ((err = device_create_file(dev, &dev_attr_pwm3))
|
||||
|| (err = device_create_file(dev, &dev_attr_pwm4)))
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
if (kind != as99127f && kind != w83781d) {
|
||||
if ((err = device_create_file(dev, &dev_attr_temp1_type))
|
||||
|| (err = device_create_file(dev,
|
||||
&dev_attr_temp2_type)))
|
||||
goto ERROR4;
|
||||
if (kind != w83783s) {
|
||||
if ((err = device_create_file(dev,
|
||||
&dev_attr_temp3_type)))
|
||||
goto ERROR4;
|
||||
}
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
device_create_file_in(new_client, 0);
|
||||
if (kind != w83783s)
|
||||
device_create_file_in(new_client, 1);
|
||||
device_create_file_in(new_client, 2);
|
||||
device_create_file_in(new_client, 3);
|
||||
device_create_file_in(new_client, 4);
|
||||
device_create_file_in(new_client, 5);
|
||||
device_create_file_in(new_client, 6);
|
||||
if (kind != as99127f && kind != w83781d && kind != w83783s) {
|
||||
device_create_file_in(new_client, 7);
|
||||
device_create_file_in(new_client, 8);
|
||||
}
|
||||
|
||||
device_create_file_fan(new_client, 1);
|
||||
device_create_file_fan(new_client, 2);
|
||||
device_create_file_fan(new_client, 3);
|
||||
|
||||
device_create_file_temp(new_client, 1);
|
||||
device_create_file_temp(new_client, 2);
|
||||
if (kind != w83783s)
|
||||
device_create_file_temp(new_client, 3);
|
||||
|
||||
device_create_file_vid(new_client);
|
||||
device_create_file_vrm(new_client);
|
||||
|
||||
device_create_file_fan_div(new_client, 1);
|
||||
device_create_file_fan_div(new_client, 2);
|
||||
device_create_file_fan_div(new_client, 3);
|
||||
|
||||
device_create_file_alarms(new_client);
|
||||
|
||||
device_create_file_beep(new_client);
|
||||
|
||||
if (kind != w83781d && kind != as99127f) {
|
||||
device_create_file_pwm(new_client, 1);
|
||||
device_create_file_pwm(new_client, 2);
|
||||
device_create_file_pwmenable(new_client, 2);
|
||||
}
|
||||
if (kind == w83782d && !is_isa) {
|
||||
device_create_file_pwm(new_client, 3);
|
||||
device_create_file_pwm(new_client, 4);
|
||||
}
|
||||
|
||||
if (kind != as99127f && kind != w83781d) {
|
||||
device_create_file_sensor(new_client, 1);
|
||||
device_create_file_sensor(new_client, 2);
|
||||
if (kind != w83783s)
|
||||
device_create_file_sensor(new_client, 3);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
ERROR4:
|
||||
sysfs_remove_group(&dev->kobj, &w83781d_group);
|
||||
sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
|
||||
|
||||
if (data->lm75[1]) {
|
||||
i2c_detach_client(data->lm75[1]);
|
||||
kfree(data->lm75[1]);
|
||||
@ -1280,7 +1287,7 @@ ERROR4:
|
||||
kfree(data->lm75[0]);
|
||||
}
|
||||
ERROR3:
|
||||
i2c_detach_client(new_client);
|
||||
i2c_detach_client(client);
|
||||
ERROR2:
|
||||
kfree(data);
|
||||
ERROR1:
|
||||
@ -1297,9 +1304,11 @@ w83781d_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
/* main client */
|
||||
if (data)
|
||||
if (data) {
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &w83781d_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt);
|
||||
}
|
||||
if (i2c_is_isa_client(client))
|
||||
release_region(client->addr, W83781D_EXTENT);
|
||||
|
||||
|
@ -27,9 +27,9 @@
|
||||
|
||||
The w83791d chip appears to be part way between the 83781d and the
|
||||
83792d. Thus, this file is derived from both the w83792d.c and
|
||||
w83781d.c files, but its output is more along the lines of the
|
||||
83781d (which means there are no changes to the user-mode sensors
|
||||
program which treats the 83791d as an 83781d).
|
||||
w83781d.c files.
|
||||
|
||||
The w83791g chip is the same as the w83791d but lead-free.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
@ -1172,6 +1172,7 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
|
||||
(w83791d_read(client, W83791D_REG_BEEP_CTRL[1]) << 8) +
|
||||
(w83791d_read(client, W83791D_REG_BEEP_CTRL[2]) << 16);
|
||||
|
||||
/* Extract global beep enable flag */
|
||||
data->beep_enable =
|
||||
(data->beep_mask >> GLOBAL_BEEP_ENABLE_SHIFT) & 0x01;
|
||||
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
|
||||
@ -381,41 +382,6 @@ static ssize_t store_in_##reg (struct device *dev, \
|
||||
store_in_reg(MIN, min);
|
||||
store_in_reg(MAX, max);
|
||||
|
||||
static struct sensor_device_attribute sda_in_input[] = {
|
||||
SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
|
||||
SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
|
||||
SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
|
||||
SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
|
||||
SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
|
||||
SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
|
||||
SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
|
||||
SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
|
||||
SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
|
||||
};
|
||||
static struct sensor_device_attribute sda_in_min[] = {
|
||||
SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
|
||||
SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
|
||||
SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
|
||||
SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
|
||||
SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
|
||||
SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
|
||||
SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
|
||||
SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
|
||||
SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
|
||||
};
|
||||
static struct sensor_device_attribute sda_in_max[] = {
|
||||
SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
|
||||
SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
|
||||
SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
|
||||
SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
|
||||
SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
|
||||
SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
|
||||
SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
|
||||
SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
|
||||
SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
|
||||
};
|
||||
|
||||
|
||||
#define show_fan_reg(reg) \
|
||||
static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
@ -499,35 +465,6 @@ store_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct sensor_device_attribute sda_fan_input[] = {
|
||||
SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 1),
|
||||
SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 2),
|
||||
SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 3),
|
||||
SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 4),
|
||||
SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 5),
|
||||
SENSOR_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 6),
|
||||
SENSOR_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 7),
|
||||
};
|
||||
static struct sensor_device_attribute sda_fan_min[] = {
|
||||
SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 1),
|
||||
SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 2),
|
||||
SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 3),
|
||||
SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 4),
|
||||
SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 5),
|
||||
SENSOR_ATTR(fan6_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 6),
|
||||
SENSOR_ATTR(fan7_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 7),
|
||||
};
|
||||
static struct sensor_device_attribute sda_fan_div[] = {
|
||||
SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 1),
|
||||
SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 2),
|
||||
SENSOR_ATTR(fan3_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 3),
|
||||
SENSOR_ATTR(fan4_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 4),
|
||||
SENSOR_ATTR(fan5_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 5),
|
||||
SENSOR_ATTR(fan6_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 6),
|
||||
SENSOR_ATTR(fan7_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 7),
|
||||
};
|
||||
|
||||
|
||||
/* read/write the temperature1, includes measured value and limits */
|
||||
|
||||
static ssize_t show_temp1(struct device *dev, struct device_attribute *attr,
|
||||
@ -595,24 +532,6 @@ static ssize_t store_temp23(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct sensor_device_attribute_2 sda_temp_input[] = {
|
||||
SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0),
|
||||
SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0),
|
||||
SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute_2 sda_temp_max[] = {
|
||||
SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 1),
|
||||
SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 2),
|
||||
SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 2),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
|
||||
SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 2),
|
||||
SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 4),
|
||||
SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 4),
|
||||
};
|
||||
|
||||
/* get reatime status of all sensors items: voltage, temp, fan */
|
||||
static ssize_t
|
||||
show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
@ -621,9 +540,6 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
return sprintf(buf, "%d\n", data->alarms);
|
||||
}
|
||||
|
||||
static
|
||||
DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
|
||||
|
||||
static ssize_t
|
||||
show_pwm(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -715,21 +631,6 @@ store_pwmenable(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct sensor_device_attribute sda_pwm[] = {
|
||||
SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
|
||||
SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
|
||||
SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
|
||||
};
|
||||
static struct sensor_device_attribute sda_pwm_enable[] = {
|
||||
SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
|
||||
show_pwmenable, store_pwmenable, 1),
|
||||
SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
|
||||
show_pwmenable, store_pwmenable, 2),
|
||||
SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
|
||||
show_pwmenable, store_pwmenable, 3),
|
||||
};
|
||||
|
||||
|
||||
static ssize_t
|
||||
show_pwm_mode(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -767,16 +668,6 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct sensor_device_attribute sda_pwm_mode[] = {
|
||||
SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO,
|
||||
show_pwm_mode, store_pwm_mode, 0),
|
||||
SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO,
|
||||
show_pwm_mode, store_pwm_mode, 1),
|
||||
SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO,
|
||||
show_pwm_mode, store_pwm_mode, 2),
|
||||
};
|
||||
|
||||
|
||||
static ssize_t
|
||||
show_regs_chassis(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -785,8 +676,6 @@ show_regs_chassis(struct device *dev, struct device_attribute *attr,
|
||||
return sprintf(buf, "%d\n", data->chassis);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
|
||||
|
||||
static ssize_t
|
||||
show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -815,9 +704,6 @@ store_chassis_clear(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
|
||||
show_chassis_clear, store_chassis_clear);
|
||||
|
||||
/* For Smart Fan I / Thermal Cruise */
|
||||
static ssize_t
|
||||
show_thermal_cruise(struct device *dev, struct device_attribute *attr,
|
||||
@ -853,15 +739,6 @@ store_thermal_cruise(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct sensor_device_attribute sda_thermal_cruise[] = {
|
||||
SENSOR_ATTR(thermal_cruise1, S_IWUSR | S_IRUGO,
|
||||
show_thermal_cruise, store_thermal_cruise, 1),
|
||||
SENSOR_ATTR(thermal_cruise2, S_IWUSR | S_IRUGO,
|
||||
show_thermal_cruise, store_thermal_cruise, 2),
|
||||
SENSOR_ATTR(thermal_cruise3, S_IWUSR | S_IRUGO,
|
||||
show_thermal_cruise, store_thermal_cruise, 3),
|
||||
};
|
||||
|
||||
/* For Smart Fan I/Thermal Cruise and Smart Fan II */
|
||||
static ssize_t
|
||||
show_tolerance(struct device *dev, struct device_attribute *attr,
|
||||
@ -901,15 +778,6 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct sensor_device_attribute sda_tolerance[] = {
|
||||
SENSOR_ATTR(tolerance1, S_IWUSR | S_IRUGO,
|
||||
show_tolerance, store_tolerance, 1),
|
||||
SENSOR_ATTR(tolerance2, S_IWUSR | S_IRUGO,
|
||||
show_tolerance, store_tolerance, 2),
|
||||
SENSOR_ATTR(tolerance3, S_IWUSR | S_IRUGO,
|
||||
show_tolerance, store_tolerance, 3),
|
||||
};
|
||||
|
||||
/* For Smart Fan II */
|
||||
static ssize_t
|
||||
show_sf2_point(struct device *dev, struct device_attribute *attr,
|
||||
@ -946,36 +814,6 @@ store_sf2_point(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct sensor_device_attribute_2 sda_sf2_point[] = {
|
||||
SENSOR_ATTR_2(sf2_point1_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 1, 1),
|
||||
SENSOR_ATTR_2(sf2_point2_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 2, 1),
|
||||
SENSOR_ATTR_2(sf2_point3_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 3, 1),
|
||||
SENSOR_ATTR_2(sf2_point4_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 4, 1),
|
||||
|
||||
SENSOR_ATTR_2(sf2_point1_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 1, 2),
|
||||
SENSOR_ATTR_2(sf2_point2_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 2, 2),
|
||||
SENSOR_ATTR_2(sf2_point3_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 3, 2),
|
||||
SENSOR_ATTR_2(sf2_point4_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 4, 2),
|
||||
|
||||
SENSOR_ATTR_2(sf2_point1_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 1, 3),
|
||||
SENSOR_ATTR_2(sf2_point2_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 2, 3),
|
||||
SENSOR_ATTR_2(sf2_point3_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 3, 3),
|
||||
SENSOR_ATTR_2(sf2_point4_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 4, 3),
|
||||
};
|
||||
|
||||
|
||||
static ssize_t
|
||||
show_sf2_level(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -1016,29 +854,6 @@ store_sf2_level(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct sensor_device_attribute_2 sda_sf2_level[] = {
|
||||
SENSOR_ATTR_2(sf2_level1_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 1, 1),
|
||||
SENSOR_ATTR_2(sf2_level2_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 2, 1),
|
||||
SENSOR_ATTR_2(sf2_level3_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 3, 1),
|
||||
|
||||
SENSOR_ATTR_2(sf2_level1_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 1, 2),
|
||||
SENSOR_ATTR_2(sf2_level2_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 2, 2),
|
||||
SENSOR_ATTR_2(sf2_level3_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 3, 2),
|
||||
|
||||
SENSOR_ATTR_2(sf2_level1_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 1, 3),
|
||||
SENSOR_ATTR_2(sf2_level2_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 2, 3),
|
||||
SENSOR_ATTR_2(sf2_level3_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 3, 3),
|
||||
};
|
||||
|
||||
/* This function is called when:
|
||||
* w83792d_driver is inserted (when this module is loaded), for each
|
||||
available adapter
|
||||
@ -1139,12 +954,297 @@ ERROR_SC_0:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void device_create_file_fan(struct device *dev, int i)
|
||||
{
|
||||
device_create_file(dev, &sda_fan_input[i].dev_attr);
|
||||
device_create_file(dev, &sda_fan_div[i].dev_attr);
|
||||
device_create_file(dev, &sda_fan_min[i].dev_attr);
|
||||
}
|
||||
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 7);
|
||||
static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 8);
|
||||
static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO,
|
||||
show_in_min, store_in_min, 0);
|
||||
static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO,
|
||||
show_in_min, store_in_min, 1);
|
||||
static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO,
|
||||
show_in_min, store_in_min, 2);
|
||||
static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO,
|
||||
show_in_min, store_in_min, 3);
|
||||
static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO,
|
||||
show_in_min, store_in_min, 4);
|
||||
static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO,
|
||||
show_in_min, store_in_min, 5);
|
||||
static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO,
|
||||
show_in_min, store_in_min, 6);
|
||||
static SENSOR_DEVICE_ATTR(in7_min, S_IWUSR | S_IRUGO,
|
||||
show_in_min, store_in_min, 7);
|
||||
static SENSOR_DEVICE_ATTR(in8_min, S_IWUSR | S_IRUGO,
|
||||
show_in_min, store_in_min, 8);
|
||||
static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO,
|
||||
show_in_max, store_in_max, 0);
|
||||
static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO,
|
||||
show_in_max, store_in_max, 1);
|
||||
static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO,
|
||||
show_in_max, store_in_max, 2);
|
||||
static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO,
|
||||
show_in_max, store_in_max, 3);
|
||||
static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO,
|
||||
show_in_max, store_in_max, 4);
|
||||
static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO,
|
||||
show_in_max, store_in_max, 5);
|
||||
static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO,
|
||||
show_in_max, store_in_max, 6);
|
||||
static SENSOR_DEVICE_ATTR(in7_max, S_IWUSR | S_IRUGO,
|
||||
show_in_max, store_in_max, 7);
|
||||
static SENSOR_DEVICE_ATTR(in8_max, S_IWUSR | S_IRUGO,
|
||||
show_in_max, store_in_max, 8);
|
||||
static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0);
|
||||
static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR,
|
||||
show_temp1, store_temp1, 0, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp23,
|
||||
store_temp23, 0, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp23,
|
||||
store_temp23, 1, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR,
|
||||
show_temp1, store_temp1, 0, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR,
|
||||
show_temp23, store_temp23, 0, 4);
|
||||
static SENSOR_DEVICE_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR,
|
||||
show_temp23, store_temp23, 1, 4);
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
|
||||
static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
|
||||
static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
|
||||
show_chassis_clear, store_chassis_clear);
|
||||
static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0);
|
||||
static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1);
|
||||
static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2);
|
||||
static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
|
||||
show_pwmenable, store_pwmenable, 1);
|
||||
static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
|
||||
show_pwmenable, store_pwmenable, 2);
|
||||
static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
|
||||
show_pwmenable, store_pwmenable, 3);
|
||||
static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO,
|
||||
show_pwm_mode, store_pwm_mode, 0);
|
||||
static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO,
|
||||
show_pwm_mode, store_pwm_mode, 1);
|
||||
static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO,
|
||||
show_pwm_mode, store_pwm_mode, 2);
|
||||
static SENSOR_DEVICE_ATTR(tolerance1, S_IWUSR | S_IRUGO,
|
||||
show_tolerance, store_tolerance, 1);
|
||||
static SENSOR_DEVICE_ATTR(tolerance2, S_IWUSR | S_IRUGO,
|
||||
show_tolerance, store_tolerance, 2);
|
||||
static SENSOR_DEVICE_ATTR(tolerance3, S_IWUSR | S_IRUGO,
|
||||
show_tolerance, store_tolerance, 3);
|
||||
static SENSOR_DEVICE_ATTR(thermal_cruise1, S_IWUSR | S_IRUGO,
|
||||
show_thermal_cruise, store_thermal_cruise, 1);
|
||||
static SENSOR_DEVICE_ATTR(thermal_cruise2, S_IWUSR | S_IRUGO,
|
||||
show_thermal_cruise, store_thermal_cruise, 2);
|
||||
static SENSOR_DEVICE_ATTR(thermal_cruise3, S_IWUSR | S_IRUGO,
|
||||
show_thermal_cruise, store_thermal_cruise, 3);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_point1_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 1, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_point2_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 2, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_point3_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 3, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_point4_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 4, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_point1_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 1, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_point2_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 2, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_point3_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 3, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_point4_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 4, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_point1_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 1, 3);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_point2_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 2, 3);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_point3_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 3, 3);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_point4_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_point, store_sf2_point, 4, 3);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_level1_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 1, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_level2_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 2, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_level3_fan1, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 3, 1);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_level1_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 1, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_level2_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 2, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_level3_fan2, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 3, 2);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_level1_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 1, 3);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_level2_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 2, 3);
|
||||
static SENSOR_DEVICE_ATTR_2(sf2_level3_fan3, S_IRUGO | S_IWUSR,
|
||||
show_sf2_level, store_sf2_level, 3, 3);
|
||||
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 7);
|
||||
static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
|
||||
show_fan_min, store_fan_min, 1);
|
||||
static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
|
||||
show_fan_min, store_fan_min, 2);
|
||||
static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
|
||||
show_fan_min, store_fan_min, 3);
|
||||
static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
|
||||
show_fan_min, store_fan_min, 4);
|
||||
static SENSOR_DEVICE_ATTR(fan5_min, S_IWUSR | S_IRUGO,
|
||||
show_fan_min, store_fan_min, 5);
|
||||
static SENSOR_DEVICE_ATTR(fan6_min, S_IWUSR | S_IRUGO,
|
||||
show_fan_min, store_fan_min, 6);
|
||||
static SENSOR_DEVICE_ATTR(fan7_min, S_IWUSR | S_IRUGO,
|
||||
show_fan_min, store_fan_min, 7);
|
||||
static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO,
|
||||
show_fan_div, store_fan_div, 1);
|
||||
static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO,
|
||||
show_fan_div, store_fan_div, 2);
|
||||
static SENSOR_DEVICE_ATTR(fan3_div, S_IWUSR | S_IRUGO,
|
||||
show_fan_div, store_fan_div, 3);
|
||||
static SENSOR_DEVICE_ATTR(fan4_div, S_IWUSR | S_IRUGO,
|
||||
show_fan_div, store_fan_div, 4);
|
||||
static SENSOR_DEVICE_ATTR(fan5_div, S_IWUSR | S_IRUGO,
|
||||
show_fan_div, store_fan_div, 5);
|
||||
static SENSOR_DEVICE_ATTR(fan6_div, S_IWUSR | S_IRUGO,
|
||||
show_fan_div, store_fan_div, 6);
|
||||
static SENSOR_DEVICE_ATTR(fan7_div, S_IWUSR | S_IRUGO,
|
||||
show_fan_div, store_fan_div, 7);
|
||||
|
||||
static struct attribute *w83792d_attributes_fan[4][4] = {
|
||||
{
|
||||
&sensor_dev_attr_fan4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan4_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan4_div.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_fan5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan5_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan5_div.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_fan6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan6_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan6_div.dev_attr.attr,
|
||||
NULL
|
||||
}, {
|
||||
&sensor_dev_attr_fan7_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan7_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan7_div.dev_attr.attr,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static const struct attribute_group w83792d_group_fan[4] = {
|
||||
{ .attrs = w83792d_attributes_fan[0] },
|
||||
{ .attrs = w83792d_attributes_fan[1] },
|
||||
{ .attrs = w83792d_attributes_fan[2] },
|
||||
{ .attrs = w83792d_attributes_fan[3] },
|
||||
};
|
||||
|
||||
static struct attribute *w83792d_attributes[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in5_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_min.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_max.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm1.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm1_mode.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm2.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm2_mode.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm3.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm3_mode.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_chassis.attr,
|
||||
&dev_attr_chassis_clear.attr,
|
||||
&sensor_dev_attr_tolerance1.dev_attr.attr,
|
||||
&sensor_dev_attr_thermal_cruise1.dev_attr.attr,
|
||||
&sensor_dev_attr_tolerance2.dev_attr.attr,
|
||||
&sensor_dev_attr_thermal_cruise2.dev_attr.attr,
|
||||
&sensor_dev_attr_tolerance3.dev_attr.attr,
|
||||
&sensor_dev_attr_thermal_cruise3.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_point1_fan1.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_point2_fan1.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_point3_fan1.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_point4_fan1.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_point1_fan2.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_point2_fan2.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_point3_fan2.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_point4_fan2.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_point1_fan3.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_point2_fan3.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_point3_fan3.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_point4_fan3.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_level1_fan1.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_level2_fan1.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_level3_fan1.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_level1_fan2.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_level2_fan2.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_level3_fan2.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_level1_fan3.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_level2_fan3.dev_attr.attr,
|
||||
&sensor_dev_attr_sf2_level3_fan3.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_div.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group w83792d_group = {
|
||||
.attrs = w83792d_attributes,
|
||||
};
|
||||
|
||||
static int
|
||||
w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
@ -1268,59 +1368,46 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
}
|
||||
|
||||
/* Register sysfs hooks */
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
if ((err = sysfs_create_group(&dev->kobj, &w83792d_group)))
|
||||
goto ERROR3;
|
||||
}
|
||||
for (i = 0; i < 9; i++) {
|
||||
device_create_file(dev, &sda_in_input[i].dev_attr);
|
||||
device_create_file(dev, &sda_in_max[i].dev_attr);
|
||||
device_create_file(dev, &sda_in_min[i].dev_attr);
|
||||
}
|
||||
for (i = 0; i < 3; i++)
|
||||
device_create_file_fan(dev, i);
|
||||
|
||||
/* Read GPIO enable register to check if pins for fan 4,5 are used as
|
||||
GPIO */
|
||||
val1 = w83792d_read_value(client, W83792D_REG_GPIO_EN);
|
||||
|
||||
if (!(val1 & 0x40))
|
||||
device_create_file_fan(dev, 3);
|
||||
if ((err = sysfs_create_group(&dev->kobj,
|
||||
&w83792d_group_fan[0])))
|
||||
goto exit_remove_files;
|
||||
|
||||
if (!(val1 & 0x20))
|
||||
device_create_file_fan(dev, 4);
|
||||
if ((err = sysfs_create_group(&dev->kobj,
|
||||
&w83792d_group_fan[1])))
|
||||
goto exit_remove_files;
|
||||
|
||||
val1 = w83792d_read_value(client, W83792D_REG_PIN);
|
||||
if (val1 & 0x40)
|
||||
device_create_file_fan(dev, 5);
|
||||
if ((err = sysfs_create_group(&dev->kobj,
|
||||
&w83792d_group_fan[2])))
|
||||
goto exit_remove_files;
|
||||
|
||||
if (val1 & 0x04)
|
||||
device_create_file_fan(dev, 6);
|
||||
if ((err = sysfs_create_group(&dev->kobj,
|
||||
&w83792d_group_fan[3])))
|
||||
goto exit_remove_files;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
device_create_file(dev, &sda_temp_input[i].dev_attr);
|
||||
device_create_file(dev, &sda_temp_max[i].dev_attr);
|
||||
device_create_file(dev, &sda_temp_max_hyst[i].dev_attr);
|
||||
device_create_file(dev, &sda_thermal_cruise[i].dev_attr);
|
||||
device_create_file(dev, &sda_tolerance[i].dev_attr);
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sda_pwm); i++) {
|
||||
device_create_file(dev, &sda_pwm[i].dev_attr);
|
||||
device_create_file(dev, &sda_pwm_enable[i].dev_attr);
|
||||
device_create_file(dev, &sda_pwm_mode[i].dev_attr);
|
||||
}
|
||||
|
||||
device_create_file(dev, &dev_attr_alarms);
|
||||
device_create_file(dev, &dev_attr_chassis);
|
||||
device_create_file(dev, &dev_attr_chassis_clear);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sda_sf2_point); i++)
|
||||
device_create_file(dev, &sda_sf2_point[i].dev_attr);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sda_sf2_level); i++)
|
||||
device_create_file(dev, &sda_sf2_level[i].dev_attr);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_files:
|
||||
sysfs_remove_group(&dev->kobj, &w83792d_group);
|
||||
for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
|
||||
sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]);
|
||||
ERROR3:
|
||||
if (data->lm75[0] != NULL) {
|
||||
i2c_detach_client(data->lm75[0]);
|
||||
@ -1342,11 +1429,16 @@ static int
|
||||
w83792d_detach_client(struct i2c_client *client)
|
||||
{
|
||||
struct w83792d_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
int err, i;
|
||||
|
||||
/* main client */
|
||||
if (data)
|
||||
if (data) {
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &w83792d_group);
|
||||
for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
|
||||
sysfs_remove_group(&client->dev.kobj,
|
||||
&w83792d_group_fan[i]);
|
||||
}
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -236,21 +236,30 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
* Nothing yet, assume it is already started.
|
||||
*/
|
||||
|
||||
err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
|
||||
err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_max.dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
goto exit_detach;
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_max.dev_attr);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_detach:
|
||||
exit_remove:
|
||||
device_remove_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_remove_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_max.dev_attr);
|
||||
i2c_detach_client(new_client);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
@ -264,7 +273,10 @@ static int w83l785ts_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
|
||||
device_remove_file(&client->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_remove_file(&client->dev,
|
||||
&sensor_dev_attr_temp1_max.dev_attr);
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
||||
|
@ -479,6 +479,7 @@
|
||||
|
||||
#define PCI_VENDOR_ID_AMD 0x1022
|
||||
#define PCI_DEVICE_ID_AMD_K8_NB 0x1100
|
||||
#define PCI_DEVICE_ID_AMD_K8_NB_MISC 0x1103
|
||||
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
|
||||
#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
|
||||
#define PCI_DEVICE_ID_AMD_SCSI 0x2020
|
||||
|
Loading…
Reference in New Issue
Block a user