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:
Linus Torvalds 2006-09-28 16:23:27 -07:00
commit 2ff712585a
51 changed files with 5743 additions and 1931 deletions

View File

@ -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

View 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
View 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

View 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.

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1354,13 +1354,39 @@ static struct abituguru_data *abituguru_update_device(struct device *dev)
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)

View File

@ -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;

View File

@ -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;

View File

@ -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 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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
View 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)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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;

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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 @@ int vt8231_detect(struct i2c_adapter *adapter)
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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
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 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
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);

View File

@ -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;

View File

@ -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 @@ w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
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;

View File

@ -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;

View File

@ -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