Merge branch 'release' of git://lm-sensors.org/kernel/mhoffman/hwmon-2.6
* 'release' of git://lm-sensors.org/kernel/mhoffman/hwmon-2.6: (53 commits) hwmon: (vt8231) fix sparse warning hwmon: (sis5595) fix sparse warning hwmon: (w83627hf) don't assume bank 0 hwmon: (w83627hf) Fix setting fan min right after driver load hwmon: (w83627hf) De-macro sysfs callback functions hwmon: Add new combined driver for FSC chips hwmon: (ibmpex) Release IPMI user if hwmon registration fails hwmon: (dme1737) Add sch311x support hwmon: (dme1737) group functions logically hwmon: (dme1737) cleanups hwmon: IBM power meter driver hwmon: (coretemp) Add support for Celeron 4xx hwmon: (lm87) Disable VID when it should be hwmon: (w83781d) Add individual alarm and beep files hwmon: VRM is not read from registers MAINTAINERS: update hwmon subsystem git trees hwmon: Fix the code examples in documentation hwmon: update sysfs interface document - error handling hwmon: (thmc50) Fix a debug message hwmon: (thmc50) Don't create temp3 if not enabled ...
This commit is contained in:
commit
4fa435018d
@ -4,7 +4,7 @@ Kernel driver coretemp
|
||||
Supported chips:
|
||||
* All Intel Core family
|
||||
Prefix: 'coretemp'
|
||||
CPUID: family 0x6, models 0xe, 0xf
|
||||
CPUID: family 0x6, models 0xe, 0xf, 0x16
|
||||
Datasheet: Intel 64 and IA-32 Architectures Software Developer's Manual
|
||||
Volume 3A: System Programming Guide
|
||||
|
||||
|
@ -6,6 +6,10 @@ Supported chips:
|
||||
Prefix: 'dme1737'
|
||||
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
|
||||
Datasheet: Provided by SMSC upon request and under NDA
|
||||
* SMSC SCH3112, SCH3114, SCH3116
|
||||
Prefix: 'sch311x'
|
||||
Addresses scanned: none, address read from Super-I/O config space
|
||||
Datasheet: http://www.nuhorizons.com/FeaturedProducts/Volume1/SMSC/311x.pdf
|
||||
|
||||
Authors:
|
||||
Juerg Haefliger <juergh@gmail.com>
|
||||
@ -27,16 +31,25 @@ Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the hardware monitoring capabilities of the
|
||||
SMSC DME1737 and Asus A8000 (which are the same) Super-I/O chips. This chip
|
||||
features monitoring of 3 temp sensors temp[1-3] (2 remote diodes and 1
|
||||
internal), 7 voltages in[0-6] (6 external and 1 internal) and 6 fan speeds
|
||||
fan[1-6]. Additionally, the chip implements 5 PWM outputs pwm[1-3,5-6] for
|
||||
controlling fan speeds both manually and automatically.
|
||||
SMSC DME1737 and Asus A8000 (which are the same) and SMSC SCH311x Super-I/O
|
||||
chips. These chips feature monitoring of 3 temp sensors temp[1-3] (2 remote
|
||||
diodes and 1 internal), 7 voltages in[0-6] (6 external and 1 internal) and up
|
||||
to 6 fan speeds fan[1-6]. Additionally, the chips implement up to 5 PWM
|
||||
outputs pwm[1-3,5-6] for controlling fan speeds both manually and
|
||||
automatically.
|
||||
|
||||
Fan[3-6] and pwm[3,5-6] are optional features and their availability is
|
||||
dependent on the configuration of the chip. The driver will detect which
|
||||
features are present during initialization and create the sysfs attributes
|
||||
accordingly.
|
||||
For the DME1737 and A8000, fan[1-2] and pwm[1-2] are always present. Fan[3-6]
|
||||
and pwm[3,5-6] are optional features and their availability depends on the
|
||||
configuration of the chip. The driver will detect which features are present
|
||||
during initialization and create the sysfs attributes accordingly.
|
||||
|
||||
For the SCH311x, fan[1-3] and pwm[1-3] are always present and fan[4-6] and
|
||||
pwm[5-6] don't exist.
|
||||
|
||||
The hardware monitoring features of the DME1737 and A8000 are only accessible
|
||||
via SMBus, while the SCH311x only provides access via the ISA bus. The driver
|
||||
will therefore register itself as an I2C client driver if it detects a DME1737
|
||||
or A8000 and as a platform driver if it detects a SCH311x chip.
|
||||
|
||||
|
||||
Voltage Monitoring
|
||||
|
@ -6,6 +6,10 @@ Supported chips:
|
||||
Prefix: 'f71805f'
|
||||
Addresses scanned: none, address read from Super I/O config space
|
||||
Datasheet: Available from the Fintek website
|
||||
* Fintek F71806F/FG
|
||||
Prefix: 'f71872f'
|
||||
Addresses scanned: none, address read from Super I/O config space
|
||||
Datasheet: Available from the Fintek website
|
||||
* Fintek F71872F/FG
|
||||
Prefix: 'f71872f'
|
||||
Addresses scanned: none, address read from Super I/O config space
|
||||
@ -38,6 +42,9 @@ The Fintek F71872F/FG Super I/O chip is almost the same, with two
|
||||
additional internal voltages monitored (VSB and battery). It also features
|
||||
6 VID inputs. The VID inputs are not yet supported by this driver.
|
||||
|
||||
The Fintek F71806F/FG Super-I/O chip is essentially the same as the
|
||||
F71872F/FG, and is undistinguishable therefrom.
|
||||
|
||||
The driver assumes that no more than one chip is present, which seems
|
||||
reasonable.
|
||||
|
||||
|
@ -90,7 +90,8 @@ 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.
|
||||
2 additional fans. They are supported by the driver for the IT8716F and
|
||||
IT8718F but not for the IT8712F
|
||||
|
||||
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
|
||||
|
@ -56,16 +56,6 @@ should work with. This is hardcoded by the mainboard and/or processor itself.
|
||||
It is a value in volts. When it is unconnected, you will often find the
|
||||
value 3.50 V here.
|
||||
|
||||
In addition to the alarms described above, there are a couple of additional
|
||||
ones. There is a BTI alarm, which gets triggered when an external chip has
|
||||
crossed its limits. Usually, this is connected to all LM75 chips; if at
|
||||
least one crosses its limits, this bit gets set. The CHAS alarm triggers
|
||||
if your computer case is open. The FIFO alarms should never trigger; it
|
||||
indicates an internal error. The SMI_IN alarm indicates some other chip
|
||||
has triggered an SMI interrupt. As we do not use SMI interrupts at all,
|
||||
this condition usually indicates there is a problem with some other
|
||||
device.
|
||||
|
||||
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 have disappeared! Note that in the current implementation, all
|
||||
|
@ -7,7 +7,7 @@ Supported chips:
|
||||
Addresses scanned: I2C 0x2c-0x2e
|
||||
Datasheet: http://www.national.com/ds.cgi/LM/LM93.pdf
|
||||
|
||||
Author:
|
||||
Authors:
|
||||
Mark M. Hoffman <mhoffman@lightlink.com>
|
||||
Ported to 2.6 by Eric J. Bowersox <ericb@aspsys.com>
|
||||
Adapted to 2.6.20 by Carsten Emde <ce@osadl.org>
|
||||
@ -16,7 +16,6 @@ Author:
|
||||
Module Parameters
|
||||
-----------------
|
||||
|
||||
(specific to LM93)
|
||||
* init: integer
|
||||
Set to non-zero to force some initializations (default is 0).
|
||||
* disable_block: integer
|
||||
@ -37,30 +36,13 @@ Module Parameters
|
||||
I.e. this parameter controls the VID pin input thresholds; if your VID
|
||||
inputs are not working, try changing this. The default value is "0".
|
||||
|
||||
(common among sensor drivers)
|
||||
* force: short array (min = 1, max = 48)
|
||||
List of adapter,address pairs to assume to be present. Autodetection
|
||||
of the target device will still be attempted. Use one of the more
|
||||
specific force directives below if this doesn't detect the device.
|
||||
* force_lm93: short array (min = 1, max = 48)
|
||||
List of adapter,address pairs which are unquestionably assumed to contain
|
||||
a 'lm93' chip
|
||||
* ignore: short array (min = 1, max = 48)
|
||||
List of adapter,address pairs not to scan
|
||||
* ignore_range: short array (min = 1, max = 48)
|
||||
List of adapter,start-addr,end-addr triples not to scan
|
||||
* probe: short array (min = 1, max = 48)
|
||||
List of adapter,address pairs to scan additionally
|
||||
* probe_range: short array (min = 1, max = 48)
|
||||
List of adapter,start-addr,end-addr triples to scan additionally
|
||||
|
||||
|
||||
Hardware Description
|
||||
--------------------
|
||||
|
||||
(from the datasheet)
|
||||
|
||||
The LM93, hardware monitor, has a two wire digital interface compatible with
|
||||
The LM93 hardware monitor has a two wire digital interface compatible with
|
||||
SMBus 2.0. Using an 8-bit ADC, the LM93 measures the temperature of two remote
|
||||
diode connected transistors as well as its own die and 16 power supply
|
||||
voltages. To set fan speed, the LM93 has two PWM outputs that are each
|
||||
@ -69,18 +51,12 @@ table based. The LM93 includes a digital filter that can be invoked to smooth
|
||||
temperature readings for better control of fan speed. The LM93 has four
|
||||
tachometer inputs to measure fan speed. Limit and status registers for all
|
||||
measured values are included. The LM93 builds upon the functionality of
|
||||
previous motherboard management ASICs and uses some of the LM85 s features
|
||||
previous motherboard management ASICs and uses some of the LM85's features
|
||||
(i.e. smart tachometer mode). It also adds measurement and control support
|
||||
for dynamic Vccp monitoring and PROCHOT. It is designed to monitor a dual
|
||||
processor Xeon class motherboard with a minimum of external components.
|
||||
|
||||
|
||||
Driver Description
|
||||
------------------
|
||||
|
||||
This driver implements support for the National Semiconductor LM93.
|
||||
|
||||
|
||||
User Interface
|
||||
--------------
|
||||
|
||||
@ -101,7 +77,7 @@ These intervals can be found in the sysfs files prochot1_interval and
|
||||
prochot2_interval. The values in these files specify the intervals for
|
||||
#P1_PROCHOT and #P2_PROCHOT, respectively. Selecting a value not in this
|
||||
list will cause the driver to use the next largest interval. The available
|
||||
intervals are:
|
||||
intervals are (in seconds):
|
||||
|
||||
#PROCHOT intervals: 0.73, 1.46, 2.9, 5.8, 11.7, 23.3, 46.6, 93.2, 186, 372
|
||||
|
||||
@ -111,12 +87,12 @@ assert #P2_PROCHOT, and vice-versa. This mode is enabled by writing a
|
||||
non-zero integer to the sysfs file prochot_short.
|
||||
|
||||
The LM93 can also override the #PROCHOT pins by driving a PWM signal onto
|
||||
one or both of them. When overridden, the signal has a period of 3.56 mS,
|
||||
one or both of them. When overridden, the signal has a period of 3.56 ms,
|
||||
a minimum pulse width of 5 clocks (at 22.5kHz => 6.25% duty cycle), and
|
||||
a maximum pulse width of 80 clocks (at 22.5kHz => 99.88% duty cycle).
|
||||
|
||||
The sysfs files prochot1_override and prochot2_override contain boolean
|
||||
intgers which enable or disable the override function for #P1_PROCHOT and
|
||||
integers which enable or disable the override function for #P1_PROCHOT and
|
||||
#P2_PROCHOT, respectively. The sysfs file prochot_override_duty_cycle
|
||||
contains a value controlling the duty cycle for the PWM signal used when
|
||||
the override function is enabled. This value ranges from 0 to 15, with 0
|
||||
@ -166,7 +142,7 @@ frequency values are constrained by the hardware. Selecting a value which is
|
||||
not available will cause the driver to use the next largest value. Also note
|
||||
that this parameter has implications for the Smart Tach Mode (see above).
|
||||
|
||||
PWM Output Frequencies: 12, 36, 48, 60, 72, 84, 96, 22500 (h/w default)
|
||||
PWM Output Frequencies (in Hz): 12, 36, 48, 60, 72, 84, 96, 22500 (default)
|
||||
|
||||
Automatic PWM:
|
||||
|
||||
@ -178,7 +154,7 @@ individual control sources to which the PWM output is bound.
|
||||
The eight control sources are: temp1-temp4 (aka "zones" in the datasheet),
|
||||
#PROCHOT 1 & 2, and #VRDHOT 1 & 2. The bindings are expressed as a bitmask
|
||||
in the sysfs files pwm<n>_auto_channels, where a "1" enables the binding, and
|
||||
a "0" disables it. The h/w default is 0x0f (all temperatures bound).
|
||||
a "0" disables it. The h/w default is 0x0f (all temperatures bound).
|
||||
|
||||
0x01 - Temp 1
|
||||
0x02 - Temp 2
|
||||
@ -324,89 +300,3 @@ LM93 Unique sysfs Files
|
||||
|
||||
gpio input state of 8 GPIO pins; read-only
|
||||
|
||||
|
||||
Sample Configuration File
|
||||
-------------------------
|
||||
|
||||
Here is a sample LM93 chip config for sensors.conf:
|
||||
|
||||
---------- cut here ----------
|
||||
chip "lm93-*"
|
||||
|
||||
# VOLTAGE INPUTS
|
||||
|
||||
# labels and scaling based on datasheet recommendations
|
||||
label in1 "+12V1"
|
||||
compute in1 @ * 12.945, @ / 12.945
|
||||
set in1_min 12 * 0.90
|
||||
set in1_max 12 * 1.10
|
||||
|
||||
label in2 "+12V2"
|
||||
compute in2 @ * 12.945, @ / 12.945
|
||||
set in2_min 12 * 0.90
|
||||
set in2_max 12 * 1.10
|
||||
|
||||
label in3 "+12V3"
|
||||
compute in3 @ * 12.945, @ / 12.945
|
||||
set in3_min 12 * 0.90
|
||||
set in3_max 12 * 1.10
|
||||
|
||||
label in4 "FSB_Vtt"
|
||||
|
||||
label in5 "3GIO"
|
||||
|
||||
label in6 "ICH_Core"
|
||||
|
||||
label in7 "Vccp1"
|
||||
|
||||
label in8 "Vccp2"
|
||||
|
||||
label in9 "+3.3V"
|
||||
set in9_min 3.3 * 0.90
|
||||
set in9_max 3.3 * 1.10
|
||||
|
||||
label in10 "+5V"
|
||||
set in10_min 5.0 * 0.90
|
||||
set in10_max 5.0 * 1.10
|
||||
|
||||
label in11 "SCSI_Core"
|
||||
|
||||
label in12 "Mem_Core"
|
||||
|
||||
label in13 "Mem_Vtt"
|
||||
|
||||
label in14 "Gbit_Core"
|
||||
|
||||
# Assuming R1/R2 = 4.1143, and 3.3V reference
|
||||
# -12V = (4.1143 + 1) * (@ - 3.3) + 3.3
|
||||
label in15 "-12V"
|
||||
compute in15 @ * 5.1143 - 13.57719, (@ + 13.57719) / 5.1143
|
||||
set in15_min -12 * 0.90
|
||||
set in15_max -12 * 1.10
|
||||
|
||||
label in16 "+3.3VSB"
|
||||
set in16_min 3.3 * 0.90
|
||||
set in16_max 3.3 * 1.10
|
||||
|
||||
# TEMPERATURE INPUTS
|
||||
|
||||
label temp1 "CPU1"
|
||||
label temp2 "CPU2"
|
||||
label temp3 "LM93"
|
||||
|
||||
# TACHOMETER INPUTS
|
||||
|
||||
label fan1 "Fan1"
|
||||
set fan1_min 3000
|
||||
label fan2 "Fan2"
|
||||
set fan2_min 3000
|
||||
label fan3 "Fan3"
|
||||
set fan3_min 3000
|
||||
label fan4 "Fan4"
|
||||
set fan4_min 3000
|
||||
|
||||
# PWM OUTPUTS
|
||||
|
||||
label pwm1 "CPU1"
|
||||
label pwm2 "CPU2"
|
||||
|
||||
|
@ -67,6 +67,10 @@ between readings to be caught and alarmed. The exact definition of an
|
||||
alarm (for example, whether a threshold must be met or must be exceeded
|
||||
to cause an alarm) is chip-dependent.
|
||||
|
||||
When setting values of hwmon sysfs attributes, the string representation of
|
||||
the desired value must be written, note that strings which are not a number
|
||||
are interpreted as 0! For more on how written strings are interpreted see the
|
||||
"sysfs attribute writes interpretation" section at the end of this file.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
@ -78,8 +82,21 @@ RW read/write value
|
||||
Read/write values may be read-only for some chips, depending on the
|
||||
hardware implementation.
|
||||
|
||||
All entries are optional, and should only be created in a given driver
|
||||
if the chip has the feature.
|
||||
All entries (except name) are optional, and should only be created in a
|
||||
given driver if the chip has the feature.
|
||||
|
||||
|
||||
********
|
||||
* Name *
|
||||
********
|
||||
|
||||
name The chip name.
|
||||
This should be a short, lowercase string, not containing
|
||||
spaces nor dashes, representing the chip name. This is
|
||||
the only mandatory attribute.
|
||||
I2C devices get this attribute created automatically.
|
||||
RO
|
||||
|
||||
|
||||
************
|
||||
* Voltages *
|
||||
@ -104,18 +121,17 @@ in[0-*]_input Voltage input value.
|
||||
by the chip driver, and must be done by the application.
|
||||
However, some drivers (notably lm87 and via686a)
|
||||
do scale, because of internal resistors built into a chip.
|
||||
These drivers will output the actual voltage.
|
||||
These drivers will output the actual voltage. Rule of
|
||||
thumb: drivers should report the voltage values at the
|
||||
"pins" of the chip.
|
||||
|
||||
Typical usage:
|
||||
in0_* CPU #1 voltage (not scaled)
|
||||
in1_* CPU #2 voltage (not scaled)
|
||||
in2_* 3.3V nominal (not scaled)
|
||||
in3_* 5.0V nominal (scaled)
|
||||
in4_* 12.0V nominal (scaled)
|
||||
in5_* -12.0V nominal (scaled)
|
||||
in6_* -5.0V nominal (scaled)
|
||||
in7_* varies
|
||||
in8_* varies
|
||||
in[0-*]_label Suggested voltage channel label.
|
||||
Text string
|
||||
Should only be created if the driver has hints about what
|
||||
this voltage channel is being used for, and user-space
|
||||
doesn't. In all other cases, the label is provided by
|
||||
user-space.
|
||||
RO
|
||||
|
||||
cpu[0-*]_vid CPU core reference voltage.
|
||||
Unit: millivolt
|
||||
@ -159,6 +175,13 @@ fan[1-*]_target
|
||||
Only makes sense if the chip supports closed-loop fan speed
|
||||
control based on the measured fan speed.
|
||||
|
||||
fan[1-*]_label Suggested fan channel label.
|
||||
Text string
|
||||
Should only be created if the driver has hints about what
|
||||
this fan channel is being used for, and user-space doesn't.
|
||||
In all other cases, the label is provided by user-space.
|
||||
RO
|
||||
|
||||
Also see the Alarms section for status flags associated with fans.
|
||||
|
||||
|
||||
@ -219,12 +242,12 @@ temp[1-*]_auto_point[1-*]_temp_hyst
|
||||
****************
|
||||
|
||||
temp[1-*]_type Sensor type selection.
|
||||
Integers 1 to 6 or thermistor Beta value (typically 3435)
|
||||
Integers 1 to 6
|
||||
RW
|
||||
1: PII/Celeron Diode
|
||||
2: 3904 transistor
|
||||
3: thermal diode
|
||||
4: thermistor (default/unknown Beta)
|
||||
4: thermistor
|
||||
5: AMD AMDSI
|
||||
6: Intel PECI
|
||||
Not all types are supported by all chips
|
||||
@ -260,18 +283,19 @@ temp[1-*]_crit_hyst
|
||||
from the critical value.
|
||||
RW
|
||||
|
||||
temp[1-4]_offset
|
||||
temp[1-*]_offset
|
||||
Temperature offset which is added to the temperature reading
|
||||
by the chip.
|
||||
Unit: millidegree Celsius
|
||||
Read/Write value.
|
||||
|
||||
If there are multiple temperature sensors, temp1_* is
|
||||
generally the sensor inside the chip itself,
|
||||
reported as "motherboard temperature". temp2_* to
|
||||
temp4_* are generally sensors external to the chip
|
||||
itself, for example the thermal diode inside the CPU or
|
||||
a thermistor nearby.
|
||||
temp[1-*]_label Suggested temperature channel label.
|
||||
Text string
|
||||
Should only be created if the driver has hints about what
|
||||
this temperature channel is being used for, and user-space
|
||||
doesn't. In all other cases, the label is provided by
|
||||
user-space.
|
||||
RO
|
||||
|
||||
Some chips measure temperature using external thermistors and an ADC, and
|
||||
report the temperature measurement as a voltage. Converting this voltage
|
||||
@ -393,14 +417,53 @@ beep_mask Bitmask for beep.
|
||||
RW
|
||||
|
||||
|
||||
*********
|
||||
* Other *
|
||||
*********
|
||||
sysfs attribute writes interpretation
|
||||
-------------------------------------
|
||||
|
||||
eeprom Raw EEPROM data in binary form.
|
||||
RO
|
||||
hwmon sysfs attributes always contain numbers, so the first thing to do is to
|
||||
convert the input to a number, there are 2 ways todo this depending whether
|
||||
the number can be negative or not:
|
||||
unsigned long u = simple_strtoul(buf, NULL, 10);
|
||||
long s = simple_strtol(buf, NULL, 10);
|
||||
|
||||
pec Enable or disable PEC (SMBus only)
|
||||
0: disable
|
||||
1: enable
|
||||
RW
|
||||
With buf being the buffer with the user input being passed by the kernel.
|
||||
Notice that we do not use the second argument of strto[u]l, and thus cannot
|
||||
tell when 0 is returned, if this was really 0 or is caused by invalid input.
|
||||
This is done deliberately as checking this everywhere would add a lot of
|
||||
code to the kernel.
|
||||
|
||||
Notice that it is important to always store the converted value in an
|
||||
unsigned long or long, so that no wrap around can happen before any further
|
||||
checking.
|
||||
|
||||
After the input string is converted to an (unsigned) long, the value should be
|
||||
checked if its acceptable. Be careful with further conversions on the value
|
||||
before checking it for validity, as these conversions could still cause a wrap
|
||||
around before the check. For example do not multiply the result, and only
|
||||
add/subtract if it has been divided before the add/subtract.
|
||||
|
||||
What to do if a value is found to be invalid, depends on the type of the
|
||||
sysfs attribute that is being set. If it is a continuous setting like a
|
||||
tempX_max or inX_max attribute, then the value should be clamped to its
|
||||
limits using SENSORS_LIMIT(value, min_limit, max_limit). If it is not
|
||||
continuous like for example a tempX_type, then when an invalid value is
|
||||
written, -EINVAL should be returned.
|
||||
|
||||
Example1, temp1_max, register is a signed 8 bit value (-128 - 127 degrees):
|
||||
|
||||
long v = simple_strtol(buf, NULL, 10) / 1000;
|
||||
v = SENSORS_LIMIT(v, -128, 127);
|
||||
/* write v to register */
|
||||
|
||||
Example2, fan divider setting, valid values 2, 4 and 8:
|
||||
|
||||
unsigned long v = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
switch (v) {
|
||||
case 2: v = 1; break;
|
||||
case 4: v = 2; break;
|
||||
case 8: v = 3; break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
/* write v to register */
|
||||
|
@ -75,46 +75,64 @@ 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 bit ordering for the alarm "realtime status register" and the
|
||||
"beep enable registers" are different.
|
||||
The w83791d has a global bit used to enable beeping from the speaker when an
|
||||
alarm is triggered as well as a bitmask to enable or disable the beep for
|
||||
specific alarms. You need both the global beep enable bit and the
|
||||
corresponding beep bit to be on for a triggered alarm to sound a beep.
|
||||
|
||||
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
|
||||
The sysfs interface to the gloabal enable is via the sysfs beep_enable file.
|
||||
This file is used for both legacy and new code.
|
||||
|
||||
*** 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.
|
||||
The sysfs interface to the beep bitmask has migrated from the original legacy
|
||||
method of a single sysfs beep_mask file to a newer method using multiple
|
||||
*_beep files as described in .../Documentation/hwmon/sysfs-interface.
|
||||
|
||||
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
|
||||
the beeping for some alarms.
|
||||
A similar change has occured for the bitmap corresponding to the alarms. The
|
||||
original legacy method used a single sysfs alarms file containing a bitmap
|
||||
of triggered alarms. The newer method uses multiple sysfs *_alarm files
|
||||
(again following the pattern described in sysfs-interface).
|
||||
|
||||
The driver only reads the chip values each 3 seconds; reading them more
|
||||
often will do no harm, but will return 'old' values.
|
||||
Since both methods read and write the underlying hardware, they can be used
|
||||
interchangeably and changes in one will automatically be reflected by
|
||||
the other. If you use the legacy bitmask method, your user-space code is
|
||||
responsible for handling the fact that the alarms and beep_mask bitmaps
|
||||
are not the same (see the table below).
|
||||
|
||||
NOTE: All new code should be written to use the newer sysfs-interface
|
||||
specification as that avoids bitmap problems and is the preferred interface
|
||||
going forward.
|
||||
|
||||
The driver reads the hardware chip values at most once every three seconds.
|
||||
User mode code requesting values more often will receive cached values.
|
||||
|
||||
Alarms bitmap vs. beep_mask bitmask
|
||||
------------------------------------
|
||||
For legacy code using the alarms and beep_mask files:
|
||||
|
||||
in0 (VCORE) : alarms: 0x000001 beep_mask: 0x000001
|
||||
in1 (VINR0) : alarms: 0x000002 beep_mask: 0x002000 <== mismatch
|
||||
in2 (+3.3VIN): alarms: 0x000004 beep_mask: 0x000004
|
||||
in3 (5VDD) : alarms: 0x000008 beep_mask: 0x000008
|
||||
in4 (+12VIN) : alarms: 0x000100 beep_mask: 0x000100
|
||||
in5 (-12VIN) : alarms: 0x000200 beep_mask: 0x000200
|
||||
in6 (-5VIN) : alarms: 0x000400 beep_mask: 0x000400
|
||||
in7 (VSB) : alarms: 0x080000 beep_mask: 0x010000 <== mismatch
|
||||
in8 (VBAT) : alarms: 0x100000 beep_mask: 0x020000 <== mismatch
|
||||
in9 (VINR1) : alarms: 0x004000 beep_mask: 0x004000
|
||||
temp1 : alarms: 0x000010 beep_mask: 0x000010
|
||||
temp2 : alarms: 0x000020 beep_mask: 0x000020
|
||||
temp3 : alarms: 0x002000 beep_mask: 0x000002 <== mismatch
|
||||
fan1 : alarms: 0x000040 beep_mask: 0x000040
|
||||
fan2 : alarms: 0x000080 beep_mask: 0x000080
|
||||
fan3 : alarms: 0x000800 beep_mask: 0x000800
|
||||
fan4 : alarms: 0x200000 beep_mask: 0x200000
|
||||
fan5 : alarms: 0x400000 beep_mask: 0x400000
|
||||
tart1 : alarms: 0x010000 beep_mask: 0x040000 <== mismatch
|
||||
tart2 : alarms: 0x020000 beep_mask: 0x080000 <== mismatch
|
||||
tart3 : alarms: 0x040000 beep_mask: 0x100000 <== mismatch
|
||||
case_open : alarms: 0x001000 beep_mask: 0x001000
|
||||
global_enable: alarms: -------- beep_mask: 0x800000 (modified via beep_enable)
|
||||
|
||||
W83791D TODO:
|
||||
---------------
|
||||
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)
|
||||
|
@ -1660,7 +1660,8 @@ P: Mark M. Hoffman
|
||||
M: mhoffman@lightlink.com
|
||||
L: lm-sensors@lm-sensors.org
|
||||
W: http://www.lm-sensors.org/
|
||||
T: git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git
|
||||
T: git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git testing
|
||||
T: git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git release
|
||||
S: Maintained
|
||||
|
||||
HARDWARE RANDOM NUMBER GENERATOR CORE
|
||||
@ -4177,7 +4178,7 @@ W83791D HARDWARE MONITORING DRIVER
|
||||
P: Charles Spirakis
|
||||
M: bezaur@gmail.com
|
||||
L: lm-sensors@lm-sensors.org
|
||||
S: Maintained
|
||||
S: Odd Fixes
|
||||
|
||||
W83793 HARDWARE MONITORING DRIVER
|
||||
P: Rudolf Marek
|
||||
|
@ -30,7 +30,7 @@ config HWMON_VID
|
||||
|
||||
config SENSORS_ABITUGURU
|
||||
tristate "Abit uGuru (rev 1 & 2)"
|
||||
depends on EXPERIMENTAL
|
||||
depends on X86 && EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for the sensor part of the first
|
||||
and second revision of the Abit uGuru chip. The voltage and frequency
|
||||
@ -45,7 +45,7 @@ config SENSORS_ABITUGURU
|
||||
|
||||
config SENSORS_ABITUGURU3
|
||||
tristate "Abit uGuru (rev 3)"
|
||||
depends on HWMON && EXPERIMENTAL
|
||||
depends on X86 && EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for the sensor part of the
|
||||
third revision of the Abit uGuru chip. Only reading the sensors
|
||||
@ -133,6 +133,16 @@ config SENSORS_ADM9240
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adm9240.
|
||||
|
||||
config SENSORS_ADT7470
|
||||
tristate "Analog Devices ADT7470"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for the Analog Devices
|
||||
ADT7470 temperature monitoring chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adt7470.
|
||||
|
||||
config SENSORS_K8TEMP
|
||||
tristate "AMD Athlon64/FX or Opteron temperature sensor"
|
||||
depends on X86 && PCI && EXPERIMENTAL
|
||||
@ -172,7 +182,7 @@ config SENSORS_AMS_I2C
|
||||
|
||||
config SENSORS_ASB100
|
||||
tristate "Asus ASB100 Bach"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
depends on X86 && I2C && EXPERIMENTAL
|
||||
select HWMON_VID
|
||||
help
|
||||
If you say yes here you get support for the ASB100 Bach sensor
|
||||
@ -206,19 +216,39 @@ config SENSORS_DS1621
|
||||
will be called ds1621.
|
||||
|
||||
config SENSORS_F71805F
|
||||
tristate "Fintek F71805F/FG and F71872F/FG"
|
||||
tristate "Fintek F71805F/FG, F71806F/FG and F71872F/FG"
|
||||
depends on EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for hardware monitoring
|
||||
features of the Fintek F71805F/FG and F71872F/FG Super-I/O
|
||||
chips.
|
||||
features of the Fintek F71805F/FG, F71806F/FG and F71872F/FG
|
||||
Super-I/O chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called f71805f.
|
||||
|
||||
config SENSORS_F71882FG
|
||||
tristate "Fintek F71882FG and F71883FG"
|
||||
depends on EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for hardware monitoring
|
||||
features of the Fintek F71882FG and F71883FG Super-I/O chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called f71882fg.
|
||||
|
||||
config SENSORS_F75375S
|
||||
tristate "Fintek F75375S/SP and F75373";
|
||||
depends on I2C && EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for hardware monitoring
|
||||
features of the Fintek F75375S/SP and F75373
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called f75375s.
|
||||
|
||||
config SENSORS_FSCHER
|
||||
tristate "FSC Hermes"
|
||||
depends on I2C
|
||||
depends on X86 && I2C
|
||||
help
|
||||
If you say yes here you get support for Fujitsu Siemens
|
||||
Computers Hermes sensor chips.
|
||||
@ -228,7 +258,7 @@ config SENSORS_FSCHER
|
||||
|
||||
config SENSORS_FSCPOS
|
||||
tristate "FSC Poseidon"
|
||||
depends on I2C
|
||||
depends on X86 && I2C
|
||||
help
|
||||
If you say yes here you get support for Fujitsu Siemens
|
||||
Computers Poseidon sensor chips.
|
||||
@ -236,6 +266,20 @@ config SENSORS_FSCPOS
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called fscpos.
|
||||
|
||||
config SENSORS_FSCHMD
|
||||
tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles"
|
||||
depends on X86 && I2C && EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for various Fujitsu Siemens
|
||||
Computers sensor chips.
|
||||
|
||||
This is a new merged driver for FSC sensor chips which is intended
|
||||
as a replacment for the fscpos, fscscy and fscher drivers and adds
|
||||
support for several other FCS sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called fschmd.
|
||||
|
||||
config SENSORS_GL518SM
|
||||
tristate "Genesys Logic GL518SM"
|
||||
depends on I2C
|
||||
@ -265,6 +309,19 @@ config SENSORS_CORETEMP
|
||||
sensor inside your CPU. Supported all are all known variants
|
||||
of Intel Core family.
|
||||
|
||||
config SENSORS_IBMPEX
|
||||
tristate "IBM PowerExecutive temperature/power sensors"
|
||||
select IPMI_SI
|
||||
depends on IPMI_HANDLER
|
||||
help
|
||||
If you say yes here you get support for the temperature and
|
||||
power sensors in various IBM System X servers that support
|
||||
PowerExecutive. So far this includes the x3550, x3650, x3655,
|
||||
x3755, and certain HS20 blades.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ibmpex.
|
||||
|
||||
config SENSORS_IT87
|
||||
tristate "ITE IT87xx and compatibles"
|
||||
select HWMON_VID
|
||||
@ -401,7 +458,7 @@ config SENSORS_LM92
|
||||
|
||||
config SENSORS_LM93
|
||||
tristate "National Semiconductor LM93 and compatibles"
|
||||
depends on HWMON && I2C
|
||||
depends on I2C
|
||||
select HWMON_VID
|
||||
help
|
||||
If you say yes here you get support for National Semiconductor LM93
|
||||
@ -466,13 +523,13 @@ config SENSORS_SIS5595
|
||||
will be called sis5595.
|
||||
|
||||
config SENSORS_DME1737
|
||||
tristate "SMSC DME1737 and compatibles"
|
||||
tristate "SMSC DME1737, SCH311x and compatibles"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
select HWMON_VID
|
||||
help
|
||||
If you say yes here you get support for the hardware monitoring
|
||||
and fan control features of the SMSC DME1737 (and compatibles
|
||||
like the Asus A8000) Super-I/O chip.
|
||||
like the Asus A8000) and SCH311x Super-I/O chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called dme1737.
|
||||
|
@ -22,6 +22,7 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
|
||||
obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
|
||||
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
|
||||
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
|
||||
obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
|
||||
obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
|
||||
obj-$(CONFIG_SENSORS_AMS) += ams/
|
||||
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
|
||||
@ -29,11 +30,15 @@ obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
|
||||
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
|
||||
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
|
||||
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
|
||||
obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
|
||||
obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
|
||||
obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
|
||||
obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o
|
||||
obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o
|
||||
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
|
||||
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
|
||||
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
|
||||
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
|
||||
obj-$(CONFIG_SENSORS_IT87) += it87.o
|
||||
obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
|
||||
obj-$(CONFIG_SENSORS_LM63) += lm63.o
|
||||
|
@ -176,7 +176,7 @@ MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n"
|
||||
The structure is dynamically allocated, at the same time when a new
|
||||
abituguru device is allocated. */
|
||||
struct abituguru_data {
|
||||
struct class_device *class_dev; /* hwmon registered device */
|
||||
struct device *hwmon_dev; /* hwmon registered device */
|
||||
struct mutex update_lock; /* protect access to data and uGuru */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
unsigned short addr; /* uguru base address */
|
||||
@ -1287,11 +1287,11 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
|
||||
&abituguru_sysfs_attr[i].dev_attr))
|
||||
goto abituguru_probe_error;
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
if (!IS_ERR(data->class_dev))
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (!IS_ERR(data->hwmon_dev))
|
||||
return 0; /* success */
|
||||
|
||||
res = PTR_ERR(data->class_dev);
|
||||
res = PTR_ERR(data->hwmon_dev);
|
||||
abituguru_probe_error:
|
||||
for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
|
||||
device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
|
||||
@ -1308,7 +1308,7 @@ static int __devexit abituguru_remove(struct platform_device *pdev)
|
||||
int i;
|
||||
struct abituguru_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
|
||||
device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
|
||||
for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
|
||||
|
@ -124,7 +124,7 @@ struct abituguru3_motherboard_info {
|
||||
The structure is dynamically allocated, at the same time when a new
|
||||
abituguru3 device is allocated. */
|
||||
struct abituguru3_data {
|
||||
struct class_device *class_dev; /* hwmon registered device */
|
||||
struct device *hwmon_dev; /* hwmon registered device */
|
||||
struct mutex update_lock; /* protect access to data and uGuru */
|
||||
unsigned short addr; /* uguru base address */
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
@ -933,9 +933,9 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
|
||||
&abituguru3_sysfs_attr[i].dev_attr))
|
||||
goto abituguru3_probe_error;
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
res = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
res = PTR_ERR(data->hwmon_dev);
|
||||
goto abituguru3_probe_error;
|
||||
}
|
||||
|
||||
@ -957,7 +957,7 @@ static int __devexit abituguru3_remove(struct platform_device *pdev)
|
||||
struct abituguru3_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
|
||||
device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
|
||||
for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
|
||||
|
@ -47,7 +47,7 @@ static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN,
|
||||
|
||||
struct ad7418_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct attribute_group attrs;
|
||||
enum chips type;
|
||||
struct mutex lock;
|
||||
@ -172,7 +172,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ad7418_data *data = i2c_get_clientdata(client);
|
||||
int temp = simple_strtol(buf, NULL, 10);
|
||||
long temp = simple_strtol(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
data->temp[attr->index] = LM75_TEMP_TO_REG(temp);
|
||||
@ -326,9 +326,9 @@ static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -347,7 +347,7 @@ exit:
|
||||
static int ad7418_detach_client(struct i2c_client *client)
|
||||
{
|
||||
struct ad7418_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||
i2c_detach_client(client);
|
||||
kfree(data);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
adm1021.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
monitoring
|
||||
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
|
||||
Philip Edelbrock <phil@netroedge.com>
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
@ -32,93 +33,77 @@
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
|
||||
0x29, 0x2a, 0x2b,
|
||||
0x4c, 0x4d, 0x4e,
|
||||
0x4c, 0x4d, 0x4e,
|
||||
I2C_CLIENT_END };
|
||||
|
||||
/* Insmod parameters */
|
||||
I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066);
|
||||
I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm,
|
||||
mc1066);
|
||||
|
||||
/* adm1021 constants specified below */
|
||||
|
||||
/* The adm1021 registers */
|
||||
/* Read-only */
|
||||
#define ADM1021_REG_TEMP 0x00
|
||||
#define ADM1021_REG_REMOTE_TEMP 0x01
|
||||
/* For nr in 0-1 */
|
||||
#define ADM1021_REG_TEMP(nr) (nr)
|
||||
#define ADM1021_REG_STATUS 0x02
|
||||
#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/
|
||||
#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */
|
||||
#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */
|
||||
/* 0x41 = AD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi */
|
||||
#define ADM1021_REG_MAN_ID 0xFE
|
||||
/* ADM1021 = 0x0X, ADM1023 = 0x3X */
|
||||
#define ADM1021_REG_DEV_ID 0xFF
|
||||
/* These use different addresses for reading/writing */
|
||||
#define ADM1021_REG_CONFIG_R 0x03
|
||||
#define ADM1021_REG_CONFIG_W 0x09
|
||||
#define ADM1021_REG_CONV_RATE_R 0x04
|
||||
#define ADM1021_REG_CONV_RATE_W 0x0A
|
||||
/* These are for the ADM1023's additional precision on the remote temp sensor */
|
||||
#define ADM1021_REG_REM_TEMP_PREC 0x010
|
||||
#define ADM1021_REG_REM_OFFSET 0x011
|
||||
#define ADM1021_REG_REM_OFFSET_PREC 0x012
|
||||
#define ADM1021_REG_REM_TOS_PREC 0x013
|
||||
#define ADM1021_REG_REM_THYST_PREC 0x014
|
||||
#define ADM1023_REG_REM_TEMP_PREC 0x10
|
||||
#define ADM1023_REG_REM_OFFSET 0x11
|
||||
#define ADM1023_REG_REM_OFFSET_PREC 0x12
|
||||
#define ADM1023_REG_REM_TOS_PREC 0x13
|
||||
#define ADM1023_REG_REM_THYST_PREC 0x14
|
||||
/* limits */
|
||||
#define ADM1021_REG_TOS_R 0x05
|
||||
#define ADM1021_REG_TOS_W 0x0B
|
||||
#define ADM1021_REG_REMOTE_TOS_R 0x07
|
||||
#define ADM1021_REG_REMOTE_TOS_W 0x0D
|
||||
#define ADM1021_REG_THYST_R 0x06
|
||||
#define ADM1021_REG_THYST_W 0x0C
|
||||
#define ADM1021_REG_REMOTE_THYST_R 0x08
|
||||
#define ADM1021_REG_REMOTE_THYST_W 0x0E
|
||||
/* For nr in 0-1 */
|
||||
#define ADM1021_REG_TOS_R(nr) (0x05 + 2 * (nr))
|
||||
#define ADM1021_REG_TOS_W(nr) (0x0B + 2 * (nr))
|
||||
#define ADM1021_REG_THYST_R(nr) (0x06 + 2 * (nr))
|
||||
#define ADM1021_REG_THYST_W(nr) (0x0C + 2 * (nr))
|
||||
/* write-only */
|
||||
#define ADM1021_REG_ONESHOT 0x0F
|
||||
|
||||
|
||||
/* Conversions. Rounding and limit checking is only done on the TO_REG
|
||||
variants. Note that you should be a bit careful with which arguments
|
||||
these macros are called: arguments may be evaluated more than once.
|
||||
Fixing this is just not worth it. */
|
||||
/* Conversions note: 1021 uses normal integer signed-byte format*/
|
||||
#define TEMP_FROM_REG(val) (val > 127 ? (val-256)*1000 : val*1000)
|
||||
#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? (val/1000)+256 : val/1000),0,255))
|
||||
|
||||
/* Initial values */
|
||||
|
||||
/* Note: Even though I left the low and high limits named os and hyst,
|
||||
they don't quite work like a thermostat the way the LM75 does. I.e.,
|
||||
a lower temp than THYST actually triggers an alarm instead of
|
||||
/* Note: Even though I left the low and high limits named os and hyst,
|
||||
they don't quite work like a thermostat the way the LM75 does. I.e.,
|
||||
a lower temp than THYST actually triggers an alarm instead of
|
||||
clearing it. Weird, ey? --Phil */
|
||||
|
||||
/* Each client has this additional data */
|
||||
struct adm1021_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
enum chips type;
|
||||
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
||||
u8 temp_max; /* Register values */
|
||||
u8 temp_hyst;
|
||||
u8 temp_input;
|
||||
u8 remote_temp_max;
|
||||
u8 remote_temp_hyst;
|
||||
u8 remote_temp_input;
|
||||
u8 alarms;
|
||||
/* Special values for ADM1023 only */
|
||||
u8 remote_temp_prec;
|
||||
u8 remote_temp_os_prec;
|
||||
u8 remote_temp_hyst_prec;
|
||||
u8 remote_temp_offset;
|
||||
u8 remote_temp_offset_prec;
|
||||
s8 temp_max[2]; /* Register values */
|
||||
s8 temp_min[2];
|
||||
s8 temp[2];
|
||||
u8 alarms;
|
||||
/* Special values for ADM1023 only */
|
||||
u8 remote_temp_prec;
|
||||
u8 remote_temp_os_prec;
|
||||
u8 remote_temp_hyst_prec;
|
||||
u8 remote_temp_offset;
|
||||
u8 remote_temp_offset_prec;
|
||||
};
|
||||
|
||||
static int adm1021_attach_adapter(struct i2c_adapter *adapter);
|
||||
static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind);
|
||||
static void adm1021_init_client(struct i2c_client *client);
|
||||
static int adm1021_detach_client(struct i2c_client *client);
|
||||
static int adm1021_read_value(struct i2c_client *client, u8 reg);
|
||||
static int adm1021_write_value(struct i2c_client *client, u8 reg,
|
||||
u16 value);
|
||||
static struct adm1021_data *adm1021_update_device(struct device *dev);
|
||||
|
||||
/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
|
||||
@ -135,54 +120,105 @@ static struct i2c_driver adm1021_driver = {
|
||||
.detach_client = adm1021_detach_client,
|
||||
};
|
||||
|
||||
#define show(value) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct adm1021_data *data = adm1021_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
|
||||
}
|
||||
show(temp_max);
|
||||
show(temp_hyst);
|
||||
show(temp_input);
|
||||
show(remote_temp_max);
|
||||
show(remote_temp_hyst);
|
||||
show(remote_temp_input);
|
||||
static ssize_t show_temp(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct adm1021_data *data = adm1021_update_device(dev);
|
||||
|
||||
#define show2(value) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct adm1021_data *data = adm1021_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", data->value); \
|
||||
return sprintf(buf, "%d\n", 1000 * data->temp[index]);
|
||||
}
|
||||
show2(alarms);
|
||||
|
||||
#define set(value, reg) \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct adm1021_data *data = i2c_get_clientdata(client); \
|
||||
int temp = simple_strtoul(buf, NULL, 10); \
|
||||
\
|
||||
mutex_lock(&data->update_lock); \
|
||||
data->value = TEMP_TO_REG(temp); \
|
||||
adm1021_write_value(client, reg, data->value); \
|
||||
mutex_unlock(&data->update_lock); \
|
||||
return count; \
|
||||
static ssize_t show_temp_max(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct adm1021_data *data = adm1021_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", 1000 * data->temp_max[index]);
|
||||
}
|
||||
set(temp_max, ADM1021_REG_TOS_W);
|
||||
set(temp_hyst, ADM1021_REG_THYST_W);
|
||||
set(remote_temp_max, ADM1021_REG_REMOTE_TOS_W);
|
||||
set(remote_temp_hyst, ADM1021_REG_REMOTE_THYST_W);
|
||||
|
||||
static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
|
||||
static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst);
|
||||
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL);
|
||||
static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remote_temp_max);
|
||||
static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst);
|
||||
static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL);
|
||||
static ssize_t show_temp_min(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct adm1021_data *data = adm1021_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", 1000 * data->temp_min[index]);
|
||||
}
|
||||
|
||||
static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
struct adm1021_data *data = adm1021_update_device(dev);
|
||||
return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
|
||||
}
|
||||
|
||||
static ssize_t show_alarms(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct adm1021_data *data = adm1021_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
|
||||
static ssize_t set_temp_max(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1021_data *data = i2c_get_clientdata(client);
|
||||
long temp = simple_strtol(buf, NULL, 10) / 1000;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_max[index] = SENSORS_LIMIT(temp, -128, 127);
|
||||
if (!read_only)
|
||||
i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index),
|
||||
data->temp_max[index]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t set_temp_min(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm1021_data *data = i2c_get_clientdata(client);
|
||||
long temp = simple_strtol(buf, NULL, 10) / 1000;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_min[index] = SENSORS_LIMIT(temp, -128, 127);
|
||||
if (!read_only)
|
||||
i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index),
|
||||
data->temp_min[index]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
|
||||
set_temp_max, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
|
||||
set_temp_min, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
|
||||
set_temp_max, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
|
||||
set_temp_min, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
|
||||
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
|
||||
static int adm1021_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
||||
@ -191,12 +227,17 @@ static int adm1021_attach_adapter(struct i2c_adapter *adapter)
|
||||
}
|
||||
|
||||
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,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
NULL
|
||||
};
|
||||
@ -208,35 +249,44 @@ static const struct attribute_group adm1021_group = {
|
||||
static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
int i;
|
||||
struct i2c_client *new_client;
|
||||
struct i2c_client *client;
|
||||
struct adm1021_data *data;
|
||||
int err = 0;
|
||||
const char *type_name = "";
|
||||
int conv_rate, status, config;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
pr_debug("adm1021: detect failed, "
|
||||
"smbus byte data not supported!\n");
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/* OK. For now, we presume we have a valid client. We now create the
|
||||
client structure, even though we cannot fill it completely yet.
|
||||
But it allows us to access adm1021_{read,write}_value. */
|
||||
But it allows us to access adm1021 register values. */
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL))) {
|
||||
pr_debug("adm1021: detect failed, kzalloc failed!\n");
|
||||
err = -ENOMEM;
|
||||
goto error0;
|
||||
}
|
||||
|
||||
new_client = &data->client;
|
||||
i2c_set_clientdata(new_client, data);
|
||||
new_client->addr = address;
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = &adm1021_driver;
|
||||
new_client->flags = 0;
|
||||
client = &data->client;
|
||||
i2c_set_clientdata(client, data);
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &adm1021_driver;
|
||||
status = i2c_smbus_read_byte_data(client, ADM1021_REG_STATUS);
|
||||
conv_rate = i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_CONV_RATE_R);
|
||||
config = i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R);
|
||||
|
||||
/* Now, we do the remaining detection. */
|
||||
if (kind < 0) {
|
||||
if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00
|
||||
|| (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00
|
||||
|| (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) {
|
||||
if ((status & 0x03) != 0x00 || (config & 0x3F) != 0x00
|
||||
|| (conv_rate & 0xF8) != 0x00) {
|
||||
pr_debug("adm1021: detect failed, "
|
||||
"chip not detected!\n");
|
||||
err = -ENODEV;
|
||||
goto error1;
|
||||
}
|
||||
@ -244,9 +294,10 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
|
||||
/* Determine the chip type. */
|
||||
if (kind <= 0) {
|
||||
i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID);
|
||||
i = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID);
|
||||
if (i == 0x41)
|
||||
if ((adm1021_read_value(new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030)
|
||||
if ((i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_DEV_ID) & 0xF0) == 0x30)
|
||||
kind = adm1023;
|
||||
else
|
||||
kind = adm1021;
|
||||
@ -255,15 +306,16 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
else if (i == 0x23)
|
||||
kind = gl523sm;
|
||||
else if ((i == 0x4d) &&
|
||||
(adm1021_read_value(new_client, ADM1021_REG_DEV_ID) == 0x01))
|
||||
(i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_DEV_ID) == 0x01))
|
||||
kind = max1617a;
|
||||
else if (i == 0x54)
|
||||
kind = mc1066;
|
||||
/* LM84 Mfr ID in a different place, and it has more unused bits */
|
||||
else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00
|
||||
&& (kind == 0 /* skip extra detection */
|
||||
|| ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00
|
||||
&& (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00)))
|
||||
else if (conv_rate == 0x00
|
||||
&& (kind == 0 /* skip extra detection */
|
||||
|| ((config & 0x7F) == 0x00
|
||||
&& (status & 0xAB) == 0x00)))
|
||||
kind = lm84;
|
||||
else
|
||||
kind = max1617;
|
||||
@ -286,37 +338,38 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
} else if (kind == mc1066) {
|
||||
type_name = "mc1066";
|
||||
}
|
||||
pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n",
|
||||
type_name, i2c_adapter_id(adapter), address);
|
||||
|
||||
/* Fill in the remaining client fields and put it into the global list */
|
||||
strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
|
||||
/* Fill in the remaining client fields */
|
||||
strlcpy(client->name, type_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 error1;
|
||||
|
||||
/* Initialize the ADM1021 chip */
|
||||
if (kind != lm84)
|
||||
adm1021_init_client(new_client);
|
||||
if (kind != lm84 && !read_only)
|
||||
adm1021_init_client(client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1021_group)))
|
||||
if ((err = sysfs_create_group(&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);
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto error3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error3:
|
||||
sysfs_remove_group(&new_client->dev.kobj, &adm1021_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1021_group);
|
||||
error2:
|
||||
i2c_detach_client(new_client);
|
||||
i2c_detach_client(client);
|
||||
error1:
|
||||
kfree(data);
|
||||
error0:
|
||||
@ -326,10 +379,10 @@ error0:
|
||||
static void adm1021_init_client(struct i2c_client *client)
|
||||
{
|
||||
/* Enable ADC and disable suspend mode */
|
||||
adm1021_write_value(client, ADM1021_REG_CONFIG_W,
|
||||
adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF);
|
||||
i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W,
|
||||
i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R) & 0xBF);
|
||||
/* Set Conversion rate to 1/sec (this can be tinkered with) */
|
||||
adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04);
|
||||
i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04);
|
||||
}
|
||||
|
||||
static int adm1021_detach_client(struct i2c_client *client)
|
||||
@ -337,7 +390,7 @@ static int adm1021_detach_client(struct i2c_client *client)
|
||||
struct adm1021_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1021_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
@ -347,19 +400,6 @@ static int adm1021_detach_client(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* All registers are byte-sized */
|
||||
static int adm1021_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value)
|
||||
{
|
||||
if (!read_only)
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct adm1021_data *adm1021_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
@ -369,21 +409,36 @@ static struct adm1021_data *adm1021_update_device(struct device *dev)
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
int i;
|
||||
|
||||
dev_dbg(&client->dev, "Starting adm1021 update\n");
|
||||
|
||||
data->temp_input = adm1021_read_value(client, ADM1021_REG_TEMP);
|
||||
data->temp_max = adm1021_read_value(client, ADM1021_REG_TOS_R);
|
||||
data->temp_hyst = adm1021_read_value(client, ADM1021_REG_THYST_R);
|
||||
data->remote_temp_input = adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP);
|
||||
data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R);
|
||||
data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R);
|
||||
data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c;
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->temp[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_TEMP(i));
|
||||
data->temp_max[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_TOS_R(i));
|
||||
data->temp_min[i] = i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_THYST_R(i));
|
||||
}
|
||||
data->alarms = i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_STATUS) & 0x7c;
|
||||
if (data->type == adm1023) {
|
||||
data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC);
|
||||
data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC);
|
||||
data->remote_temp_hyst_prec = adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC);
|
||||
data->remote_temp_offset = adm1021_read_value(client, ADM1021_REG_REM_OFFSET);
|
||||
data->remote_temp_offset_prec = adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC);
|
||||
data->remote_temp_prec =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1023_REG_REM_TEMP_PREC);
|
||||
data->remote_temp_os_prec =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1023_REG_REM_TOS_PREC);
|
||||
data->remote_temp_hyst_prec =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1023_REG_REM_THYST_PREC);
|
||||
data->remote_temp_offset =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1023_REG_REM_OFFSET);
|
||||
data->remote_temp_offset_prec =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1023_REG_REM_OFFSET_PREC);
|
||||
}
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
|
@ -133,7 +133,7 @@ static struct i2c_driver adm1025_driver = {
|
||||
|
||||
struct adm1025_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
@ -292,7 +292,7 @@ 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 adm1025_data *data = adm1025_update_device(dev);
|
||||
struct adm1025_data *data = dev_get_drvdata(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)
|
||||
@ -472,9 +472,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -538,7 +538,7 @@ static int adm1025_detach_client(struct i2c_client *client)
|
||||
struct adm1025_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1025_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt);
|
||||
|
||||
|
@ -260,7 +260,7 @@ struct pwm_data {
|
||||
|
||||
struct adm1026_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
enum chips type;
|
||||
|
||||
struct mutex update_lock;
|
||||
@ -1221,7 +1221,7 @@ 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)
|
||||
{
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
struct adm1026_data *data = dev_get_drvdata(dev);
|
||||
return sprintf(buf,"%d\n", data->vrm);
|
||||
}
|
||||
static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
@ -1676,9 +1676,9 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exitremove;
|
||||
}
|
||||
|
||||
@ -1698,7 +1698,7 @@ exit:
|
||||
static int adm1026_detach_client(struct i2c_client *client)
|
||||
{
|
||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1026_group);
|
||||
i2c_detach_client(client);
|
||||
kfree(data);
|
||||
|
@ -141,7 +141,7 @@ static struct i2c_driver adm1029_driver = {
|
||||
|
||||
struct adm1029_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
@ -391,9 +391,9 @@ static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -431,7 +431,7 @@ static int adm1029_detach_client(struct i2c_client *client)
|
||||
struct adm1029_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1029_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
|
@ -70,7 +70,7 @@ typedef u8 auto_chan_table_t[8][2];
|
||||
/* Each client has this additional data */
|
||||
struct adm1031_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
int chip_type;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
@ -853,9 +853,9 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -877,7 +877,7 @@ static int adm1031_detach_client(struct i2c_client *client)
|
||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||
int ret;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_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) {
|
||||
|
@ -150,7 +150,7 @@ static struct i2c_driver adm9240_driver = {
|
||||
struct adm9240_data {
|
||||
enum chips type;
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid;
|
||||
unsigned long last_updated_measure;
|
||||
@ -590,9 +590,9 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -620,7 +620,7 @@ static int adm9240_detach_client(struct i2c_client *client)
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &adm9240_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
|
1050
drivers/hwmon/adt7470.c
Normal file
1050
drivers/hwmon/adt7470.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -127,7 +127,7 @@ static s16 rest_x;
|
||||
static s16 rest_y;
|
||||
static struct timer_list applesmc_timer;
|
||||
static struct input_dev *applesmc_idev;
|
||||
static struct class_device *hwmon_class_dev;
|
||||
static struct device *hwmon_dev;
|
||||
|
||||
/* Indicates whether this computer has an accelerometer. */
|
||||
static unsigned int applesmc_accelerometer;
|
||||
@ -1287,9 +1287,9 @@ static int __init applesmc_init(void)
|
||||
goto out_light_wq;
|
||||
}
|
||||
|
||||
hwmon_class_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(hwmon_class_dev)) {
|
||||
ret = PTR_ERR(hwmon_class_dev);
|
||||
hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(hwmon_dev)) {
|
||||
ret = PTR_ERR(hwmon_dev);
|
||||
goto out_light_ledclass;
|
||||
}
|
||||
|
||||
@ -1331,7 +1331,7 @@ out:
|
||||
|
||||
static void __exit applesmc_exit(void)
|
||||
{
|
||||
hwmon_device_unregister(hwmon_class_dev);
|
||||
hwmon_device_unregister(hwmon_dev);
|
||||
if (applesmc_light) {
|
||||
led_classdev_unregister(&applesmc_backlight);
|
||||
destroy_workqueue(applesmc_led_wq);
|
||||
|
@ -143,7 +143,7 @@ static int FAN_FROM_REG(u8 val, int div)
|
||||
|
||||
/* TEMP: 0.001C/bit (-128C to +127C)
|
||||
REG: 1C/bit, two's complement */
|
||||
static u8 TEMP_TO_REG(int temp)
|
||||
static u8 TEMP_TO_REG(long temp)
|
||||
{
|
||||
int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
|
||||
ntemp += (ntemp<0 ? -500 : 500);
|
||||
@ -182,7 +182,7 @@ static u8 DIV_TO_REG(long val)
|
||||
dynamically allocated, at the same time the client itself is allocated. */
|
||||
struct asb100_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex lock;
|
||||
enum chips type;
|
||||
|
||||
@ -448,7 +448,7 @@ static ssize_t set_##reg(struct device *dev, const char *buf, \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct asb100_data *data = i2c_get_clientdata(client); \
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
\
|
||||
mutex_lock(&data->update_lock); \
|
||||
switch (nr) { \
|
||||
@ -514,7 +514,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
|
||||
/* VRM */
|
||||
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct asb100_data *data = asb100_update_device(dev);
|
||||
struct asb100_data *data = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%d\n", data->vrm);
|
||||
}
|
||||
|
||||
@ -844,9 +844,9 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
@ -874,7 +874,7 @@ static int asb100_detach_client(struct i2c_client *client)
|
||||
|
||||
/* main client */
|
||||
if (data) {
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &asb100_group);
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ static struct i2c_driver atxp1_driver = {
|
||||
|
||||
struct atxp1_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
unsigned long last_updated;
|
||||
u8 valid;
|
||||
@ -335,9 +335,9 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -361,7 +361,7 @@ static int atxp1_detach_client(struct i2c_client * client)
|
||||
struct atxp1_data * data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &atxp1_group);
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
|
@ -47,7 +47,7 @@ typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW;
|
||||
static struct coretemp_data *coretemp_update_device(struct device *dev);
|
||||
|
||||
struct coretemp_data {
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
const char *name;
|
||||
u32 id;
|
||||
@ -58,8 +58,6 @@ struct coretemp_data {
|
||||
u8 alarm;
|
||||
};
|
||||
|
||||
static struct coretemp_data *coretemp_update_device(struct device *dev);
|
||||
|
||||
/*
|
||||
* Sysfs stuff
|
||||
*/
|
||||
@ -228,9 +226,9 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
|
||||
if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
|
||||
goto exit_free;
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
dev_err(&pdev->dev, "Class registration failed (%d)\n",
|
||||
err);
|
||||
goto exit_class;
|
||||
@ -250,7 +248,7 @@ static int __devexit coretemp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct coretemp_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(data);
|
||||
@ -350,7 +348,7 @@ static int coretemp_cpu_callback(struct notifier_block *nfb,
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block __cpuinitdata coretemp_cpu_notifier = {
|
||||
static struct notifier_block coretemp_cpu_notifier = {
|
||||
.notifier_call = coretemp_cpu_callback,
|
||||
};
|
||||
#endif /* !CONFIG_HOTPLUG_CPU */
|
||||
@ -371,9 +369,10 @@ static int __init coretemp_init(void)
|
||||
for_each_online_cpu(i) {
|
||||
struct cpuinfo_x86 *c = &(cpu_data)[i];
|
||||
|
||||
/* check if family 6, models e, f */
|
||||
/* check if family 6, models e, f, 16 */
|
||||
if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
|
||||
!((c->x86_model == 0xe) || (c->x86_model == 0xf))) {
|
||||
!((c->x86_model == 0xe) || (c->x86_model == 0xf) ||
|
||||
(c->x86_model == 0x16))) {
|
||||
|
||||
/* supported CPU not found, but report the unknown
|
||||
family 6 CPU */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -73,7 +73,7 @@ static const u8 DS1621_REG_TEMP[3] = {
|
||||
/* Each client has this additional data */
|
||||
struct ds1621_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
@ -151,7 +151,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ds1621_data *data = ds1621_update_client(dev);
|
||||
u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));
|
||||
u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10));
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp[attr->index] = val;
|
||||
@ -266,9 +266,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -289,7 +289,7 @@ static int ds1621_detach_client(struct i2c_client *client)
|
||||
struct ds1621_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &ds1621_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
|
@ -10,6 +10,9 @@
|
||||
* The F71872F/FG is almost the same, with two more voltages monitored,
|
||||
* and 6 VID inputs.
|
||||
*
|
||||
* The F71806F/FG is essentially the same as the F71872F/FG. It even has
|
||||
* the same chip ID, so the driver can't differentiate between.
|
||||
*
|
||||
* 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
|
||||
@ -159,7 +162,7 @@ struct f71805f_auto_point {
|
||||
struct f71805f_data {
|
||||
unsigned short addr;
|
||||
const char *name;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
@ -1378,9 +1381,9 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
@ -1407,7 +1410,7 @@ static int __devexit f71805f_remove(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int i;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
|
||||
for (i = 0; i < 4; i++)
|
||||
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
|
||||
@ -1485,7 +1488,7 @@ static int __init f71805f_find(int sioaddr, unsigned short *address,
|
||||
|
||||
static const char *names[] = {
|
||||
"F71805F/FG",
|
||||
"F71872F/FG",
|
||||
"F71872F/FG or F71806F/FG",
|
||||
};
|
||||
|
||||
superio_enter(sioaddr);
|
||||
|
950
drivers/hwmon/f71882fg.c
Normal file
950
drivers/hwmon/f71882fg.c
Normal file
@ -0,0 +1,950 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
|
||||
* Copyright (C) 2007 by Hans de Goede <j.w.r.degoede@hhs.nl> *
|
||||
* *
|
||||
* 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., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define DRVNAME "f71882fg"
|
||||
|
||||
#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device*/
|
||||
#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
|
||||
#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */
|
||||
|
||||
#define SIO_REG_LDSEL 0x07 /* Logical device select */
|
||||
#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
|
||||
#define SIO_REG_DEVREV 0x22 /* Device revision */
|
||||
#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
|
||||
#define SIO_REG_ENABLE 0x30 /* Logical device enable */
|
||||
#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
|
||||
|
||||
#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
|
||||
#define SIO_F71882_ID 0x0541 /* Chipset ID */
|
||||
|
||||
#define REGION_LENGTH 8
|
||||
#define ADDR_REG_OFFSET 5
|
||||
#define DATA_REG_OFFSET 6
|
||||
|
||||
#define F71882FG_REG_PECI 0x0A
|
||||
|
||||
#define F71882FG_REG_IN_STATUS 0x12
|
||||
#define F71882FG_REG_IN_BEEP 0x13
|
||||
#define F71882FG_REG_IN(nr) (0x20 + (nr))
|
||||
#define F71882FG_REG_IN1_HIGH 0x32
|
||||
|
||||
#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
|
||||
#define F71882FG_REG_FAN_STATUS 0x92
|
||||
#define F71882FG_REG_FAN_BEEP 0x93
|
||||
|
||||
#define F71882FG_REG_TEMP(nr) (0x72 + 2 * (nr))
|
||||
#define F71882FG_REG_TEMP_OVT(nr) (0x82 + 2 * (nr))
|
||||
#define F71882FG_REG_TEMP_HIGH(nr) (0x83 + 2 * (nr))
|
||||
#define F71882FG_REG_TEMP_STATUS 0x62
|
||||
#define F71882FG_REG_TEMP_BEEP 0x63
|
||||
#define F71882FG_REG_TEMP_HYST1 0x6C
|
||||
#define F71882FG_REG_TEMP_HYST23 0x6D
|
||||
#define F71882FG_REG_TEMP_TYPE 0x6B
|
||||
#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
|
||||
|
||||
#define F71882FG_REG_START 0x01
|
||||
|
||||
#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
|
||||
|
||||
static struct platform_device *f71882fg_pdev = NULL;
|
||||
|
||||
/* Super-I/O Function prototypes */
|
||||
static inline int superio_inb(int base, int reg);
|
||||
static inline int superio_inw(int base, int reg);
|
||||
static inline void superio_enter(int base);
|
||||
static inline void superio_select(int base, int ld);
|
||||
static inline void superio_exit(int base);
|
||||
|
||||
static inline u16 fan_from_reg ( u16 reg );
|
||||
|
||||
struct f71882fg_data {
|
||||
unsigned short addr;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
unsigned long last_limits; /* In jiffies */
|
||||
|
||||
/* Register Values */
|
||||
u8 in[9];
|
||||
u8 in1_max;
|
||||
u8 in_status;
|
||||
u8 in_beep;
|
||||
u16 fan[4];
|
||||
u8 fan_status;
|
||||
u8 fan_beep;
|
||||
u8 temp[3];
|
||||
u8 temp_ovt[3];
|
||||
u8 temp_high[3];
|
||||
u8 temp_hyst[3];
|
||||
u8 temp_type[3];
|
||||
u8 temp_status;
|
||||
u8 temp_beep;
|
||||
u8 temp_diode_open;
|
||||
};
|
||||
|
||||
static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg);
|
||||
static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg);
|
||||
static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val);
|
||||
|
||||
/* Sysfs in*/
|
||||
static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf);
|
||||
static ssize_t show_in_max(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
static ssize_t store_in_max(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count);
|
||||
static ssize_t show_in_beep(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
static ssize_t store_in_beep(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count);
|
||||
static ssize_t show_in_alarm(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
/* Sysfs Fan */
|
||||
static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf);
|
||||
static ssize_t show_fan_beep(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
static ssize_t store_fan_beep(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count);
|
||||
static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
/* Sysfs Temp */
|
||||
static ssize_t show_temp(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
static ssize_t show_temp_max(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
static ssize_t store_temp_max(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count);
|
||||
static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count);
|
||||
static ssize_t show_temp_crit(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
static ssize_t store_temp_crit(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count);
|
||||
static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
static ssize_t show_temp_type(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
static ssize_t show_temp_beep(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
static ssize_t store_temp_beep(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count);
|
||||
static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
static ssize_t show_temp_fault(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf);
|
||||
/* Sysfs misc */
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf);
|
||||
|
||||
static int __devinit f71882fg_probe(struct platform_device * pdev);
|
||||
static int __devexit f71882fg_remove(struct platform_device *pdev);
|
||||
static int __init f71882fg_init(void);
|
||||
static int __init f71882fg_find(int sioaddr, unsigned short *address);
|
||||
static int __init f71882fg_device_add(unsigned short address);
|
||||
static void __exit f71882fg_exit(void);
|
||||
|
||||
static struct platform_driver f71882fg_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRVNAME,
|
||||
},
|
||||
.probe = f71882fg_probe,
|
||||
.remove = __devexit_p(f71882fg_remove),
|
||||
};
|
||||
|
||||
static struct device_attribute f71882fg_dev_attr[] =
|
||||
{
|
||||
__ATTR( name, S_IRUGO, show_name, NULL ),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute f71882fg_in_temp_attr[] =
|
||||
{
|
||||
SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
|
||||
SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
|
||||
SENSOR_ATTR(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max, 1),
|
||||
SENSOR_ATTR(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep, 1),
|
||||
SENSOR_ATTR(in1_alarm, S_IRUGO, show_in_alarm, 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),
|
||||
SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
|
||||
SENSOR_ATTR(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
|
||||
store_temp_max, 0),
|
||||
SENSOR_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
|
||||
store_temp_max_hyst, 0),
|
||||
SENSOR_ATTR(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
|
||||
store_temp_crit, 0),
|
||||
SENSOR_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 0),
|
||||
SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
|
||||
SENSOR_ATTR(temp1_beep, S_IRUGO|S_IWUSR, show_temp_beep,
|
||||
store_temp_beep, 0),
|
||||
SENSOR_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0),
|
||||
SENSOR_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0),
|
||||
SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
|
||||
SENSOR_ATTR(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
|
||||
store_temp_max, 1),
|
||||
SENSOR_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
|
||||
store_temp_max_hyst, 1),
|
||||
SENSOR_ATTR(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
|
||||
store_temp_crit, 1),
|
||||
SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1),
|
||||
SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
|
||||
SENSOR_ATTR(temp2_beep, S_IRUGO|S_IWUSR, show_temp_beep,
|
||||
store_temp_beep, 1),
|
||||
SENSOR_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 1),
|
||||
SENSOR_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1),
|
||||
SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
|
||||
SENSOR_ATTR(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
|
||||
store_temp_max, 2),
|
||||
SENSOR_ATTR(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
|
||||
store_temp_max_hyst, 2),
|
||||
SENSOR_ATTR(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
|
||||
store_temp_crit, 2),
|
||||
SENSOR_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 2),
|
||||
SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
|
||||
SENSOR_ATTR(temp3_beep, S_IRUGO|S_IWUSR, show_temp_beep,
|
||||
store_temp_beep, 2),
|
||||
SENSOR_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 2),
|
||||
SENSOR_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2)
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute f71882fg_fan_attr[] =
|
||||
{
|
||||
SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
|
||||
SENSOR_ATTR(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
|
||||
store_fan_beep, 0),
|
||||
SENSOR_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0),
|
||||
SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
|
||||
SENSOR_ATTR(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
|
||||
store_fan_beep, 1),
|
||||
SENSOR_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 1),
|
||||
SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
|
||||
SENSOR_ATTR(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
|
||||
store_fan_beep, 2),
|
||||
SENSOR_ATTR(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 2),
|
||||
SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
|
||||
SENSOR_ATTR(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
|
||||
store_fan_beep, 3),
|
||||
SENSOR_ATTR(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 3)
|
||||
};
|
||||
|
||||
|
||||
/* Super I/O functions */
|
||||
static inline int superio_inb(int base, int reg)
|
||||
{
|
||||
outb(reg, base);
|
||||
return inb(base + 1);
|
||||
}
|
||||
|
||||
static int superio_inw(int base, int reg)
|
||||
{
|
||||
int val;
|
||||
outb(reg++, base);
|
||||
val = inb(base + 1) << 8;
|
||||
outb(reg, base);
|
||||
val |= inb(base + 1);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void superio_enter(int base)
|
||||
{
|
||||
/* according to the datasheet the key must be send twice! */
|
||||
outb( SIO_UNLOCK_KEY, base);
|
||||
outb( SIO_UNLOCK_KEY, base);
|
||||
}
|
||||
|
||||
static inline void superio_select( int base, int ld)
|
||||
{
|
||||
outb(SIO_REG_LDSEL, base);
|
||||
outb(ld, base + 1);
|
||||
}
|
||||
|
||||
static inline void superio_exit(int base)
|
||||
{
|
||||
outb(SIO_LOCK_KEY, base);
|
||||
}
|
||||
|
||||
static inline u16 fan_from_reg(u16 reg)
|
||||
{
|
||||
return reg ? (1500000 / reg) : 0;
|
||||
}
|
||||
|
||||
static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
outb(reg, data->addr + ADDR_REG_OFFSET);
|
||||
val = inb(data->addr + DATA_REG_OFFSET);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
outb(reg++, data->addr + ADDR_REG_OFFSET);
|
||||
val = inb(data->addr + DATA_REG_OFFSET) << 8;
|
||||
outb(reg, data->addr + ADDR_REG_OFFSET);
|
||||
val |= inb(data->addr + DATA_REG_OFFSET);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
|
||||
{
|
||||
outb(reg, data->addr + ADDR_REG_OFFSET);
|
||||
outb(val, data->addr + DATA_REG_OFFSET);
|
||||
}
|
||||
|
||||
static struct f71882fg_data *f71882fg_update_device(struct device * dev)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr, reg, reg2;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
/* Update once every 60 seconds */
|
||||
if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
|
||||
!data->valid) {
|
||||
data->in1_max = f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
|
||||
data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
|
||||
|
||||
/* Get High & boundary temps*/
|
||||
for (nr = 0; nr < 3; nr++) {
|
||||
data->temp_ovt[nr] = f71882fg_read8(data,
|
||||
F71882FG_REG_TEMP_OVT(nr));
|
||||
data->temp_high[nr] = f71882fg_read8(data,
|
||||
F71882FG_REG_TEMP_HIGH(nr));
|
||||
}
|
||||
|
||||
/* Have to hardcode hyst*/
|
||||
data->temp_hyst[0] = f71882fg_read8(data,
|
||||
F71882FG_REG_TEMP_HYST1) >> 4;
|
||||
/* Hyst temps 2 & 3 stored in same register */
|
||||
reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST23);
|
||||
data->temp_hyst[1] = reg & 0x0F;
|
||||
data->temp_hyst[2] = reg >> 4;
|
||||
|
||||
/* Have to hardcode type, because temp1 is special */
|
||||
reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
|
||||
reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
|
||||
if ((reg2 & 0x03) == 0x01)
|
||||
data->temp_type[0] = 6 /* PECI */;
|
||||
else if ((reg2 & 0x03) == 0x02)
|
||||
data->temp_type[0] = 5 /* AMDSI */;
|
||||
else
|
||||
data->temp_type[0] = (reg & 0x02) ? 2 : 4;
|
||||
|
||||
data->temp_type[1] = (reg & 0x04) ? 2 : 4;
|
||||
data->temp_type[2] = (reg & 0x08) ? 2 : 4;
|
||||
|
||||
data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
|
||||
|
||||
data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
|
||||
|
||||
data->last_limits = jiffies;
|
||||
}
|
||||
|
||||
/* Update every second */
|
||||
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
|
||||
data->temp_status = f71882fg_read8(data,
|
||||
F71882FG_REG_TEMP_STATUS);
|
||||
data->temp_diode_open = f71882fg_read8(data,
|
||||
F71882FG_REG_TEMP_DIODE_OPEN);
|
||||
for (nr = 0; nr < 3; nr++)
|
||||
data->temp[nr] = f71882fg_read8(data,
|
||||
F71882FG_REG_TEMP(nr));
|
||||
|
||||
data->fan_status = f71882fg_read8(data,
|
||||
F71882FG_REG_FAN_STATUS);
|
||||
for (nr = 0; nr < 4; nr++)
|
||||
data->fan[nr] = f71882fg_read16(data,
|
||||
F71882FG_REG_FAN(nr));
|
||||
|
||||
data->in_status = f71882fg_read8(data,
|
||||
F71882FG_REG_IN_STATUS);
|
||||
for (nr = 0; nr < 9; nr++)
|
||||
data->in[nr] = f71882fg_read8(data,
|
||||
F71882FG_REG_IN(nr));
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Sysfs Interface */
|
||||
static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
int speed = fan_from_reg(data->fan[nr]);
|
||||
|
||||
if (speed == FAN_MIN_DETECT)
|
||||
speed = 0;
|
||||
|
||||
return sprintf(buf, "%d\n", speed);
|
||||
}
|
||||
|
||||
static ssize_t show_fan_beep(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
if (data->fan_beep & (1 << nr))
|
||||
return sprintf(buf, "1\n");
|
||||
else
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
static ssize_t store_fan_beep(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
int val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (val)
|
||||
data->fan_beep |= 1 << nr;
|
||||
else
|
||||
data->fan_beep &= ~(1 << nr);
|
||||
|
||||
f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
if (data->fan_status & (1 << nr))
|
||||
return sprintf(buf, "1\n");
|
||||
else
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%d\n", data->in[nr] * 8);
|
||||
}
|
||||
|
||||
static ssize_t show_in_max(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", data->in1_max * 8);
|
||||
}
|
||||
|
||||
static ssize_t store_in_max(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int val = simple_strtoul(buf, NULL, 10) / 8;
|
||||
|
||||
if (val > 255)
|
||||
val = 255;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
|
||||
data->in1_max = val;
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_in_beep(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
if (data->in_beep & (1 << nr))
|
||||
return sprintf(buf, "1\n");
|
||||
else
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
static ssize_t store_in_beep(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
int val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (val)
|
||||
data->in_beep |= 1 << nr;
|
||||
else
|
||||
data->in_beep &= ~(1 << nr);
|
||||
|
||||
f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_in_alarm(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
if (data->in_status & (1 << nr))
|
||||
return sprintf(buf, "1\n");
|
||||
else
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%d\n", data->temp[nr] * 1000);
|
||||
}
|
||||
|
||||
static ssize_t show_temp_max(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
|
||||
}
|
||||
|
||||
static ssize_t store_temp_max(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
int val = simple_strtoul(buf, NULL, 10) / 1000;
|
||||
|
||||
if (val > 255)
|
||||
val = 255;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
|
||||
data->temp_high[nr] = val;
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
(data->temp_high[nr] - data->temp_hyst[nr]) * 1000);
|
||||
}
|
||||
|
||||
static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
int val = simple_strtoul(buf, NULL, 10) / 1000;
|
||||
ssize_t ret = count;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
/* convert abs to relative and check */
|
||||
val = data->temp_high[nr] - val;
|
||||
if (val < 0 || val > 15) {
|
||||
ret = -EINVAL;
|
||||
goto store_temp_max_hyst_exit;
|
||||
}
|
||||
|
||||
data->temp_hyst[nr] = val;
|
||||
|
||||
/* convert value to register contents */
|
||||
switch (nr) {
|
||||
case 0:
|
||||
val = val << 4;
|
||||
break;
|
||||
case 1:
|
||||
val = val | (data->temp_hyst[2] << 4);
|
||||
break;
|
||||
case 2:
|
||||
val = data->temp_hyst[1] | (val << 4);
|
||||
break;
|
||||
}
|
||||
|
||||
f71882fg_write8(data, nr ? F71882FG_REG_TEMP_HYST23 :
|
||||
F71882FG_REG_TEMP_HYST1, val);
|
||||
|
||||
store_temp_max_hyst_exit:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t show_temp_crit(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
|
||||
}
|
||||
|
||||
static ssize_t store_temp_crit(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
int val = simple_strtoul(buf, NULL, 10) / 1000;
|
||||
|
||||
if (val > 255)
|
||||
val = 255;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
|
||||
data->temp_ovt[nr] = val;
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
(data->temp_ovt[nr] - data->temp_hyst[nr]) * 1000);
|
||||
}
|
||||
|
||||
static ssize_t show_temp_type(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
return sprintf(buf, "%d\n", data->temp_type[nr]);
|
||||
}
|
||||
|
||||
static ssize_t show_temp_beep(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
if (data->temp_beep & (1 << (nr + 1)))
|
||||
return sprintf(buf, "1\n");
|
||||
else
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
static ssize_t store_temp_beep(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
struct f71882fg_data *data = dev_get_drvdata(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
int val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (val)
|
||||
data->temp_beep |= 1 << (nr + 1);
|
||||
else
|
||||
data->temp_beep &= ~(1 << (nr + 1));
|
||||
|
||||
f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
if (data->temp_status & (1 << (nr + 1)))
|
||||
return sprintf(buf, "1\n");
|
||||
else
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
static ssize_t show_temp_fault(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct f71882fg_data *data = f71882fg_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
if (data->temp_diode_open & (1 << (nr + 1)))
|
||||
return sprintf(buf, "1\n");
|
||||
else
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, DRVNAME "\n");
|
||||
}
|
||||
|
||||
|
||||
static int __devinit f71882fg_probe(struct platform_device * pdev)
|
||||
{
|
||||
struct f71882fg_data *data;
|
||||
int err, i;
|
||||
u8 start_reg;
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
|
||||
data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
|
||||
mutex_init(&data->update_lock);
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
/* Register sysfs interface files */
|
||||
for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++) {
|
||||
err = device_create_file(&pdev->dev, &f71882fg_dev_attr[i]);
|
||||
if (err)
|
||||
goto exit_unregister_sysfs;
|
||||
}
|
||||
|
||||
start_reg = f71882fg_read8(data, F71882FG_REG_START);
|
||||
if (start_reg & 0x01) {
|
||||
for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++) {
|
||||
err = device_create_file(&pdev->dev,
|
||||
&f71882fg_in_temp_attr[i].dev_attr);
|
||||
if (err)
|
||||
goto exit_unregister_sysfs;
|
||||
}
|
||||
}
|
||||
|
||||
if (start_reg & 0x02) {
|
||||
for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++) {
|
||||
err = device_create_file(&pdev->dev,
|
||||
&f71882fg_fan_attr[i].dev_attr);
|
||||
if (err)
|
||||
goto exit_unregister_sysfs;
|
||||
}
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_unregister_sysfs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_unregister_sysfs:
|
||||
for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++)
|
||||
device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
|
||||
device_remove_file(&pdev->dev,
|
||||
&f71882fg_in_temp_attr[i].dev_attr);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
|
||||
device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
|
||||
|
||||
kfree(data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit f71882fg_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
struct f71882fg_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++)
|
||||
device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
|
||||
device_remove_file(&pdev->dev,
|
||||
&f71882fg_in_temp_attr[i].dev_attr);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
|
||||
device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
|
||||
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init f71882fg_find(int sioaddr, unsigned short *address)
|
||||
{
|
||||
int err = -ENODEV;
|
||||
u16 devid;
|
||||
u8 start_reg;
|
||||
struct f71882fg_data data;
|
||||
|
||||
superio_enter(sioaddr);
|
||||
|
||||
devid = superio_inw(sioaddr, SIO_REG_MANID);
|
||||
if (devid != SIO_FINTEK_ID) {
|
||||
printk(KERN_INFO DRVNAME ": Not a Fintek device\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
devid = superio_inw(sioaddr, SIO_REG_DEVID);
|
||||
if (devid != SIO_F71882_ID) {
|
||||
printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
superio_select(sioaddr, SIO_F71882FG_LD_HWM);
|
||||
if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
|
||||
printk(KERN_WARNING DRVNAME ": Device not activated\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*address = superio_inw(sioaddr, SIO_REG_ADDR);
|
||||
if (*address == 0)
|
||||
{
|
||||
printk(KERN_WARNING DRVNAME ": Base address not set\n");
|
||||
goto exit;
|
||||
}
|
||||
*address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
|
||||
|
||||
data.addr = *address;
|
||||
start_reg = f71882fg_read8(&data, F71882FG_REG_START);
|
||||
if (!(start_reg & 0x03)) {
|
||||
printk(KERN_WARNING DRVNAME
|
||||
": Hardware monitoring not activated\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
printk(KERN_INFO DRVNAME ": Found F71882FG chip at %#x, revision %d\n",
|
||||
(unsigned int)*address,
|
||||
(int)superio_inb(sioaddr, SIO_REG_DEVREV));
|
||||
exit:
|
||||
superio_exit(sioaddr);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init f71882fg_device_add(unsigned short address)
|
||||
{
|
||||
struct resource res = {
|
||||
.start = address,
|
||||
.end = address + REGION_LENGTH - 1,
|
||||
.flags = IORESOURCE_IO,
|
||||
};
|
||||
int err;
|
||||
|
||||
f71882fg_pdev = platform_device_alloc(DRVNAME, address);
|
||||
if (!f71882fg_pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
res.name = f71882fg_pdev->name;
|
||||
err = platform_device_add_resources(f71882fg_pdev, &res, 1);
|
||||
if (err) {
|
||||
printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
|
||||
goto exit_device_put;
|
||||
}
|
||||
|
||||
err = platform_device_add(f71882fg_pdev);
|
||||
if (err) {
|
||||
printk(KERN_ERR DRVNAME ": Device addition failed\n");
|
||||
goto exit_device_put;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_device_put:
|
||||
platform_device_put(f71882fg_pdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init f71882fg_init(void)
|
||||
{
|
||||
int err = -ENODEV;
|
||||
unsigned short address;
|
||||
|
||||
if (f71882fg_find(0x2e, &address) && f71882fg_find(0x4e, &address))
|
||||
goto exit;
|
||||
|
||||
if ((err = platform_driver_register(&f71882fg_driver)))
|
||||
goto exit;
|
||||
|
||||
if ((err = f71882fg_device_add(address)))
|
||||
goto exit_driver;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_driver:
|
||||
platform_driver_unregister(&f71882fg_driver);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit f71882fg_exit(void)
|
||||
{
|
||||
platform_device_unregister(f71882fg_pdev);
|
||||
platform_driver_unregister(&f71882fg_driver);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
|
||||
MODULE_AUTHOR("Hans Edgington (hans@edgington.nl)");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(f71882fg_init);
|
||||
module_exit(f71882fg_exit);
|
691
drivers/hwmon/f75375s.c
Normal file
691
drivers/hwmon/f75375s.c
Normal file
@ -0,0 +1,691 @@
|
||||
/*
|
||||
* f75375s.c - driver for the Fintek F75375/SP and F75373
|
||||
* hardware monitoring features
|
||||
* Copyright (C) 2006-2007 Riku Voipio <riku.voipio@movial.fi>
|
||||
*
|
||||
* Datasheets available at:
|
||||
*
|
||||
* f75375:
|
||||
* http://www.fintek.com.tw/files/productfiles/2005111152950.pdf
|
||||
*
|
||||
* f75373:
|
||||
* http://www.fintek.com.tw/files/productfiles/2005111153128.pdf
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END };
|
||||
|
||||
/* Insmod parameters */
|
||||
I2C_CLIENT_INSMOD_2(f75373, f75375);
|
||||
|
||||
/* Fintek F75375 registers */
|
||||
#define F75375_REG_CONFIG0 0x0
|
||||
#define F75375_REG_CONFIG1 0x1
|
||||
#define F75375_REG_CONFIG2 0x2
|
||||
#define F75375_REG_CONFIG3 0x3
|
||||
#define F75375_REG_ADDR 0x4
|
||||
#define F75375_REG_INTR 0x31
|
||||
#define F75375_CHIP_ID 0x5A
|
||||
#define F75375_REG_VERSION 0x5C
|
||||
#define F75375_REG_VENDOR 0x5D
|
||||
#define F75375_REG_FAN_TIMER 0x60
|
||||
|
||||
#define F75375_REG_VOLT(nr) (0x10 + (nr))
|
||||
#define F75375_REG_VOLT_HIGH(nr) (0x20 + (nr) * 2)
|
||||
#define F75375_REG_VOLT_LOW(nr) (0x21 + (nr) * 2)
|
||||
|
||||
#define F75375_REG_TEMP(nr) (0x14 + (nr))
|
||||
#define F75375_REG_TEMP_HIGH(nr) (0x28 + (nr) * 2)
|
||||
#define F75375_REG_TEMP_HYST(nr) (0x29 + (nr) * 2)
|
||||
|
||||
#define F75375_REG_FAN(nr) (0x16 + (nr) * 2)
|
||||
#define F75375_REG_FAN_MIN(nr) (0x2C + (nr) * 2)
|
||||
#define F75375_REG_FAN_FULL(nr) (0x70 + (nr) * 0x10)
|
||||
#define F75375_REG_FAN_PWM_DUTY(nr) (0x76 + (nr) * 0x10)
|
||||
#define F75375_REG_FAN_PWM_CLOCK(nr) (0x7D + (nr) * 0x10)
|
||||
|
||||
#define F75375_REG_FAN_EXP(nr) (0x74 + (nr) * 0x10)
|
||||
#define F75375_REG_FAN_B_TEMP(nr, step) ((0xA0 + (nr) * 0x10) + (step))
|
||||
#define F75375_REG_FAN_B_SPEED(nr, step) \
|
||||
((0xA5 + (nr) * 0x10) + (step) * 2)
|
||||
|
||||
#define F75375_REG_PWM1_RAISE_DUTY 0x69
|
||||
#define F75375_REG_PWM2_RAISE_DUTY 0x6A
|
||||
#define F75375_REG_PWM1_DROP_DUTY 0x6B
|
||||
#define F75375_REG_PWM2_DROP_DUTY 0x6C
|
||||
|
||||
#define FAN_CTRL_LINEAR(nr) (4 + nr)
|
||||
#define FAN_CTRL_MODE(nr) (5 + ((nr) * 2))
|
||||
|
||||
/*
|
||||
* Data structures and manipulation thereof
|
||||
*/
|
||||
|
||||
struct f75375_data {
|
||||
unsigned short addr;
|
||||
struct i2c_client client;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
const char *name;
|
||||
int kind;
|
||||
struct mutex update_lock; /* protect register access */
|
||||
char valid;
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
unsigned long last_limits; /* In jiffies */
|
||||
|
||||
/* Register values */
|
||||
u8 in[4];
|
||||
u8 in_max[4];
|
||||
u8 in_min[4];
|
||||
u16 fan[2];
|
||||
u16 fan_min[2];
|
||||
u16 fan_full[2];
|
||||
u16 fan_exp[2];
|
||||
u8 fan_timer;
|
||||
u8 pwm[2];
|
||||
u8 pwm_mode[2];
|
||||
u8 pwm_enable[2];
|
||||
s8 temp[2];
|
||||
s8 temp_high[2];
|
||||
s8 temp_max_hyst[2];
|
||||
};
|
||||
|
||||
static int f75375_attach_adapter(struct i2c_adapter *adapter);
|
||||
static int f75375_detect(struct i2c_adapter *adapter, int address, int kind);
|
||||
static int f75375_detach_client(struct i2c_client *client);
|
||||
|
||||
static struct i2c_driver f75375_driver = {
|
||||
.driver = {
|
||||
.name = "f75375",
|
||||
},
|
||||
.attach_adapter = f75375_attach_adapter,
|
||||
.detach_client = f75375_detach_client,
|
||||
};
|
||||
|
||||
static inline int f75375_read8(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
/* in most cases, should be called while holding update_lock */
|
||||
static inline u16 f75375_read16(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return ((i2c_smbus_read_byte_data(client, reg) << 8)
|
||||
| i2c_smbus_read_byte_data(client, reg + 1));
|
||||
}
|
||||
|
||||
static inline void f75375_write8(struct i2c_client *client, u8 reg,
|
||||
u8 value)
|
||||
{
|
||||
i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static inline void f75375_write16(struct i2c_client *client, u8 reg,
|
||||
u16 value)
|
||||
{
|
||||
int err = i2c_smbus_write_byte_data(client, reg, (value << 8));
|
||||
if (err)
|
||||
return;
|
||||
i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF));
|
||||
}
|
||||
|
||||
static struct f75375_data *f75375_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct f75375_data *data = i2c_get_clientdata(client);
|
||||
int nr;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
/* Limit registers cache is refreshed after 60 seconds */
|
||||
if (time_after(jiffies, data->last_limits + 60 * HZ)
|
||||
|| !data->valid) {
|
||||
for (nr = 0; nr < 2; nr++) {
|
||||
data->temp_high[nr] =
|
||||
f75375_read8(client, F75375_REG_TEMP_HIGH(nr));
|
||||
data->temp_max_hyst[nr] =
|
||||
f75375_read8(client, F75375_REG_TEMP_HYST(nr));
|
||||
data->fan_full[nr] =
|
||||
f75375_read16(client, F75375_REG_FAN_FULL(nr));
|
||||
data->fan_min[nr] =
|
||||
f75375_read16(client, F75375_REG_FAN_MIN(nr));
|
||||
data->fan_exp[nr] =
|
||||
f75375_read16(client, F75375_REG_FAN_EXP(nr));
|
||||
data->pwm[nr] = f75375_read8(client,
|
||||
F75375_REG_FAN_PWM_DUTY(nr));
|
||||
|
||||
}
|
||||
for (nr = 0; nr < 4; nr++) {
|
||||
data->in_max[nr] =
|
||||
f75375_read8(client, F75375_REG_VOLT_HIGH(nr));
|
||||
data->in_min[nr] =
|
||||
f75375_read8(client, F75375_REG_VOLT_LOW(nr));
|
||||
}
|
||||
data->fan_timer = f75375_read8(client, F75375_REG_FAN_TIMER);
|
||||
data->last_limits = jiffies;
|
||||
}
|
||||
|
||||
/* Measurement registers cache is refreshed after 2 second */
|
||||
if (time_after(jiffies, data->last_updated + 2 * HZ)
|
||||
|| !data->valid) {
|
||||
for (nr = 0; nr < 2; nr++) {
|
||||
data->temp[nr] =
|
||||
f75375_read8(client, F75375_REG_TEMP(nr));
|
||||
data->fan[nr] =
|
||||
f75375_read16(client, F75375_REG_FAN(nr));
|
||||
}
|
||||
for (nr = 0; nr < 4; nr++)
|
||||
data->in[nr] =
|
||||
f75375_read8(client, F75375_REG_VOLT(nr));
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline u16 rpm_from_reg(u16 reg)
|
||||
{
|
||||
if (reg == 0 || reg == 0xffff)
|
||||
return 0;
|
||||
return (1500000 / reg);
|
||||
}
|
||||
|
||||
static inline u16 rpm_to_reg(int rpm)
|
||||
{
|
||||
if (rpm < 367 || rpm > 0xffff)
|
||||
return 0xffff;
|
||||
return (1500000 / rpm);
|
||||
}
|
||||
|
||||
static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct f75375_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->fan_min[nr] = rpm_to_reg(val);
|
||||
f75375_write16(client, F75375_REG_FAN_MIN(nr), data->fan_min[nr]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t set_fan_exp(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct f75375_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->fan_exp[nr] = rpm_to_reg(val);
|
||||
f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_exp[nr]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct f75375_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
|
||||
f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), data->pwm[nr]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
|
||||
*attr, char *buf)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct f75375_data *data = f75375_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->pwm_enable[nr]);
|
||||
}
|
||||
|
||||
static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct f75375_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtoul(buf, NULL, 10);
|
||||
u8 fanmode;
|
||||
|
||||
if (val < 0 || val > 4)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
fanmode = f75375_read8(client, F75375_REG_FAN_TIMER);
|
||||
fanmode = ~(3 << FAN_CTRL_MODE(nr));
|
||||
|
||||
switch (val) {
|
||||
case 0: /* Full speed */
|
||||
fanmode |= (3 << FAN_CTRL_MODE(nr));
|
||||
data->pwm[nr] = 255;
|
||||
f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr),
|
||||
data->pwm[nr]);
|
||||
break;
|
||||
case 1: /* PWM */
|
||||
fanmode |= (3 << FAN_CTRL_MODE(nr));
|
||||
break;
|
||||
case 2: /* AUTOMATIC*/
|
||||
fanmode |= (2 << FAN_CTRL_MODE(nr));
|
||||
break;
|
||||
case 3: /* fan speed */
|
||||
break;
|
||||
}
|
||||
f75375_write8(client, F75375_REG_FAN_TIMER, fanmode);
|
||||
data->pwm_enable[nr] = val;
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct f75375_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtoul(buf, NULL, 10);
|
||||
u8 conf = 0;
|
||||
|
||||
if (val != 0 || val != 1 || data->kind == f75373)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
conf = f75375_read8(client, F75375_REG_CONFIG1);
|
||||
conf = ~(1 << FAN_CTRL_LINEAR(nr));
|
||||
|
||||
if (val == 0)
|
||||
conf |= (1 << FAN_CTRL_LINEAR(nr)) ;
|
||||
|
||||
f75375_write8(client, F75375_REG_CONFIG1, conf);
|
||||
data->pwm_mode[nr] = val;
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_pwm(struct device *dev, struct device_attribute
|
||||
*attr, char *buf)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct f75375_data *data = f75375_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->pwm[nr]);
|
||||
}
|
||||
|
||||
static ssize_t show_pwm_mode(struct device *dev, struct device_attribute
|
||||
*attr, char *buf)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct f75375_data *data = f75375_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->pwm_mode[nr]);
|
||||
}
|
||||
|
||||
#define VOLT_FROM_REG(val) ((val) * 8)
|
||||
#define VOLT_TO_REG(val) ((val) / 8)
|
||||
|
||||
static ssize_t show_in(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct f75375_data *data = f75375_update_device(dev);
|
||||
return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct f75375_data *data = f75375_update_device(dev);
|
||||
return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_max[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct f75375_data *data = f75375_update_device(dev);
|
||||
return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_min[nr]));
|
||||
}
|
||||
|
||||
static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct f75375_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtoul(buf, NULL, 10);
|
||||
val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_max[nr] = val;
|
||||
f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct f75375_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtoul(buf, NULL, 10);
|
||||
val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
|
||||
mutex_lock(&data->update_lock);
|
||||
data->in_min[nr] = val;
|
||||
f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
#define TEMP_FROM_REG(val) ((val) * 1000)
|
||||
#define TEMP_TO_REG(val) ((val) / 1000)
|
||||
|
||||
static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct f75375_data *data = f75375_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct f75375_data *data = f75375_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_max_hyst(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct f75375_data *data = f75375_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[nr]));
|
||||
}
|
||||
|
||||
static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct f75375_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_high[nr] = val;
|
||||
f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t set_temp_max_hyst(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct f75375_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_max_hyst[nr] = val;
|
||||
f75375_write8(client, F75375_REG_TEMP_HYST(nr),
|
||||
data->temp_max_hyst[nr]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
#define show_fan(thing) \
|
||||
static ssize_t show_##thing(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf)\
|
||||
{\
|
||||
int nr = to_sensor_dev_attr(attr)->index;\
|
||||
struct f75375_data *data = f75375_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", rpm_from_reg(data->thing[nr])); \
|
||||
}
|
||||
|
||||
show_fan(fan);
|
||||
show_fan(fan_min);
|
||||
show_fan(fan_full);
|
||||
show_fan(fan_exp);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO|S_IWUSR,
|
||||
show_in_max, set_in_max, 0);
|
||||
static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO|S_IWUSR,
|
||||
show_in_min, set_in_min, 0);
|
||||
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(temp1_input, S_IRUGO, show_temp, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR,
|
||||
show_temp_max_hyst, set_temp_max_hyst, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO|S_IWUSR,
|
||||
show_temp_max, set_temp_max, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR,
|
||||
show_temp_max_hyst, set_temp_max_hyst, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO|S_IWUSR,
|
||||
show_temp_max, set_temp_max, 1);
|
||||
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(fan1_full, S_IRUGO, show_fan_full, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO|S_IWUSR,
|
||||
show_fan_min, set_fan_min, 0);
|
||||
static SENSOR_DEVICE_ATTR(fan1_exp, S_IRUGO|S_IWUSR,
|
||||
show_fan_exp, set_fan_exp, 0);
|
||||
static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(fan2_full, S_IRUGO, show_fan_full, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO|S_IWUSR,
|
||||
show_fan_min, set_fan_min, 1);
|
||||
static SENSOR_DEVICE_ATTR(fan2_exp, S_IRUGO|S_IWUSR,
|
||||
show_fan_exp, set_fan_exp, 1);
|
||||
static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR,
|
||||
show_pwm, set_pwm, 0);
|
||||
static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR,
|
||||
show_pwm_enable, set_pwm_enable, 0);
|
||||
static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO|S_IWUSR,
|
||||
show_pwm_mode, set_pwm_mode, 0);
|
||||
static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR,
|
||||
show_pwm, set_pwm, 1);
|
||||
static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR,
|
||||
show_pwm_enable, set_pwm_enable, 1);
|
||||
static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO|S_IWUSR,
|
||||
show_pwm_mode, set_pwm_mode, 1);
|
||||
|
||||
static struct attribute *f75375_attributes[] = {
|
||||
&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_fan1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_full.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_exp.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_full.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_exp.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm1.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm1_mode.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm2.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm2_mode.dev_attr.attr,
|
||||
&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,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group f75375_group = {
|
||||
.attrs = f75375_attributes,
|
||||
};
|
||||
|
||||
static int f75375_detach_client(struct i2c_client *client)
|
||||
{
|
||||
struct f75375_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &f75375_group);
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
if (err) {
|
||||
dev_err(&client->dev,
|
||||
"Client deregistration failed, "
|
||||
"client not detached.\n");
|
||||
return err;
|
||||
}
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int f75375_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
||||
return 0;
|
||||
return i2c_probe(adapter, &addr_data, f75375_detect);
|
||||
}
|
||||
|
||||
/* This function is called by i2c_probe */
|
||||
static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct f75375_data *data;
|
||||
u8 version = 0;
|
||||
int err = 0;
|
||||
const char *name = "";
|
||||
|
||||
if (!(data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL))) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
client = &data->client;
|
||||
i2c_set_clientdata(client, data);
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &f75375_driver;
|
||||
|
||||
if (kind < 0) {
|
||||
u16 vendid = f75375_read16(client, F75375_REG_VENDOR);
|
||||
u16 chipid = f75375_read16(client, F75375_CHIP_ID);
|
||||
version = f75375_read8(client, F75375_REG_VERSION);
|
||||
if (chipid == 0x0306 && vendid == 0x1934) {
|
||||
kind = f75375;
|
||||
} else if (chipid == 0x0204 && vendid == 0x1934) {
|
||||
kind = f75373;
|
||||
} else {
|
||||
dev_err(&adapter->dev,
|
||||
"failed,%02X,%02X,%02X\n",
|
||||
chipid, version, vendid);
|
||||
goto exit_free;
|
||||
}
|
||||
}
|
||||
|
||||
if (kind == f75375) {
|
||||
name = "f75375";
|
||||
} else if (kind == f75373) {
|
||||
name = "f75373";
|
||||
}
|
||||
|
||||
dev_info(&adapter->dev, "found %s version: %02X\n", name, version);
|
||||
strlcpy(client->name, name, I2C_NAME_SIZE);
|
||||
data->kind = kind;
|
||||
mutex_init(&data->update_lock);
|
||||
if ((err = i2c_attach_client(client)))
|
||||
goto exit_free;
|
||||
|
||||
if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group)))
|
||||
goto exit_detach;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &f75375_group);
|
||||
exit_detach:
|
||||
i2c_detach_client(client);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init sensors_f75375_init(void)
|
||||
{
|
||||
return i2c_add_driver(&f75375_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_f75375_exit(void)
|
||||
{
|
||||
i2c_del_driver(&f75375_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Riku Voipio <riku.voipio@movial.fi>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("F75373/F75375 hardware monitoring driver");
|
||||
|
||||
module_init(sensors_f75375_init);
|
||||
module_exit(sensors_f75375_exit);
|
@ -134,7 +134,7 @@ static struct i2c_driver fscher_driver = {
|
||||
|
||||
struct fscher_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
@ -344,9 +344,9 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -367,7 +367,7 @@ static int fscher_detach_client(struct i2c_client *client)
|
||||
struct fscher_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &fscher_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
|
778
drivers/hwmon/fschmd.c
Normal file
778
drivers/hwmon/fschmd.c
Normal file
@ -0,0 +1,778 @@
|
||||
/* fschmd.c
|
||||
*
|
||||
* Copyright (C) 2007 Hans de Goede <j.w.r.degoede@hhs.nl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes,
|
||||
* Scylla, Heracles and Heimdall chips
|
||||
*
|
||||
* Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6
|
||||
* (candidate) fschmd drivers:
|
||||
* Copyright (C) 2006 Thilo Cestonaro
|
||||
* <thilo.cestonaro.external@fujitsu-siemens.com>
|
||||
* Copyright (C) 2004, 2005 Stefan Ott <stefan@desire.ch>
|
||||
* Copyright (C) 2003, 2004 Reinhard Nissl <rnissl@gmx.de>
|
||||
* Copyright (c) 2001 Martin Knoblauch <mkn@teraport.de, knobi@knobisoft.de>
|
||||
* Copyright (C) 2000 Hermann Jung <hej@odn.de>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
|
||||
|
||||
/* Insmod parameters */
|
||||
I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
|
||||
|
||||
/*
|
||||
* The FSCHMD registers and other defines
|
||||
*/
|
||||
|
||||
/* chip identification */
|
||||
#define FSCHMD_REG_IDENT_0 0x00
|
||||
#define FSCHMD_REG_IDENT_1 0x01
|
||||
#define FSCHMD_REG_IDENT_2 0x02
|
||||
#define FSCHMD_REG_REVISION 0x03
|
||||
|
||||
/* global control and status */
|
||||
#define FSCHMD_REG_EVENT_STATE 0x04
|
||||
#define FSCHMD_REG_CONTROL 0x05
|
||||
|
||||
#define FSCHMD_CONTROL_ALERT_LED_MASK 0x01
|
||||
|
||||
/* watchdog (support to be implemented) */
|
||||
#define FSCHMD_REG_WDOG_PRESET 0x28
|
||||
#define FSCHMD_REG_WDOG_STATE 0x23
|
||||
#define FSCHMD_REG_WDOG_CONTROL 0x21
|
||||
|
||||
/* voltages, weird order is to keep the same order as the old drivers */
|
||||
static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 };
|
||||
|
||||
/* minimum pwm at which the fan is driven (pwm can by increased depending on
|
||||
the temp. Notice that for the scy some fans share there minimum speed.
|
||||
Also notice that with the scy the sensor order is different then with the
|
||||
other chips, this order was in the 2.4 driver and kept for consistency. */
|
||||
static const u8 FSCHMD_REG_FAN_MIN[5][6] = {
|
||||
{ 0x55, 0x65 }, /* pos */
|
||||
{ 0x55, 0x65, 0xb5 }, /* her */
|
||||
{ 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */
|
||||
{ 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */
|
||||
{ 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */
|
||||
};
|
||||
|
||||
/* actual fan speed */
|
||||
static const u8 FSCHMD_REG_FAN_ACT[5][6] = {
|
||||
{ 0x0e, 0x6b, 0xab }, /* pos */
|
||||
{ 0x0e, 0x6b, 0xbb }, /* her */
|
||||
{ 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */
|
||||
{ 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */
|
||||
{ 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */
|
||||
};
|
||||
|
||||
/* fan status registers */
|
||||
static const u8 FSCHMD_REG_FAN_STATE[5][6] = {
|
||||
{ 0x0d, 0x62, 0xa2 }, /* pos */
|
||||
{ 0x0d, 0x62, 0xb2 }, /* her */
|
||||
{ 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */
|
||||
{ 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */
|
||||
{ 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */
|
||||
};
|
||||
|
||||
/* fan ripple / divider registers */
|
||||
static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = {
|
||||
{ 0x0f, 0x6f, 0xaf }, /* pos */
|
||||
{ 0x0f, 0x6f, 0xbf }, /* her */
|
||||
{ 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */
|
||||
{ 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */
|
||||
{ 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */
|
||||
};
|
||||
|
||||
static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 };
|
||||
|
||||
/* Fan status register bitmasks */
|
||||
#define FSCHMD_FAN_ALARM_MASK 0x04 /* called fault by FSC! */
|
||||
#define FSCHMD_FAN_NOT_PRESENT_MASK 0x08 /* not documented */
|
||||
|
||||
|
||||
/* actual temperature registers */
|
||||
static const u8 FSCHMD_REG_TEMP_ACT[5][5] = {
|
||||
{ 0x64, 0x32, 0x35 }, /* pos */
|
||||
{ 0x64, 0x32, 0x35 }, /* her */
|
||||
{ 0x64, 0xD0, 0x32, 0x35 }, /* scy */
|
||||
{ 0x64, 0x32, 0x35 }, /* hrc */
|
||||
{ 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */
|
||||
};
|
||||
|
||||
/* temperature state registers */
|
||||
static const u8 FSCHMD_REG_TEMP_STATE[5][5] = {
|
||||
{ 0x71, 0x81, 0x91 }, /* pos */
|
||||
{ 0x71, 0x81, 0x91 }, /* her */
|
||||
{ 0x71, 0xd1, 0x81, 0x91 }, /* scy */
|
||||
{ 0x71, 0x81, 0x91 }, /* hrc */
|
||||
{ 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */
|
||||
};
|
||||
|
||||
/* temperature high limit registers, FSC does not document these. Proven to be
|
||||
there with field testing on the fscher and fschrc, already supported / used
|
||||
in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
|
||||
at these addresses, but doesn't want to confirm they are the same as with
|
||||
the fscher?? */
|
||||
static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = {
|
||||
{ 0, 0, 0 }, /* pos */
|
||||
{ 0x76, 0x86, 0x96 }, /* her */
|
||||
{ 0x76, 0xd6, 0x86, 0x96 }, /* scy */
|
||||
{ 0x76, 0x86, 0x96 }, /* hrc */
|
||||
{ 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */
|
||||
};
|
||||
|
||||
/* These were found through experimenting with an fscher, currently they are
|
||||
not used, but we keep them around for future reference.
|
||||
static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 };
|
||||
static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */
|
||||
|
||||
static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 };
|
||||
|
||||
/* temp status register bitmasks */
|
||||
#define FSCHMD_TEMP_WORKING_MASK 0x01
|
||||
#define FSCHMD_TEMP_ALERT_MASK 0x02
|
||||
/* there only really is an alarm if the sensor is working and alert == 1 */
|
||||
#define FSCHMD_TEMP_ALARM_MASK \
|
||||
(FSCHMD_TEMP_WORKING_MASK | FSCHMD_TEMP_ALERT_MASK)
|
||||
|
||||
/* our driver name */
|
||||
#define FSCHMD_NAME "fschmd"
|
||||
|
||||
/*
|
||||
* Functions declarations
|
||||
*/
|
||||
|
||||
static int fschmd_attach_adapter(struct i2c_adapter *adapter);
|
||||
static int fschmd_detach_client(struct i2c_client *client);
|
||||
static struct fschmd_data *fschmd_update_device(struct device *dev);
|
||||
|
||||
/*
|
||||
* Driver data (common to all clients)
|
||||
*/
|
||||
|
||||
static struct i2c_driver fschmd_driver = {
|
||||
.driver = {
|
||||
.name = FSCHMD_NAME,
|
||||
},
|
||||
.attach_adapter = fschmd_attach_adapter,
|
||||
.detach_client = fschmd_detach_client,
|
||||
};
|
||||
|
||||
/*
|
||||
* Client data (each client gets its own)
|
||||
*/
|
||||
|
||||
struct fschmd_data {
|
||||
struct i2c_client client;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
int kind;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
|
||||
/* register values */
|
||||
u8 global_control; /* global control register */
|
||||
u8 volt[3]; /* 12, 5, battery voltage */
|
||||
u8 temp_act[5]; /* temperature */
|
||||
u8 temp_status[5]; /* status of sensor */
|
||||
u8 temp_max[5]; /* high temp limit, notice: undocumented! */
|
||||
u8 fan_act[6]; /* fans revolutions per second */
|
||||
u8 fan_status[6]; /* fan status */
|
||||
u8 fan_min[6]; /* fan min value for rps */
|
||||
u8 fan_ripple[6]; /* divider for rps */
|
||||
};
|
||||
|
||||
/*
|
||||
* Sysfs attr show / store functions
|
||||
*/
|
||||
|
||||
static ssize_t show_in_value(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
const int max_reading[3] = { 14200, 6600, 3300 };
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = fschmd_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", (data->volt[index] *
|
||||
max_reading[index] + 128) / 255);
|
||||
}
|
||||
|
||||
|
||||
#define TEMP_FROM_REG(val) (((val) - 128) * 1000)
|
||||
|
||||
static ssize_t show_temp_value(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = fschmd_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[index]));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_max(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = fschmd_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index]));
|
||||
}
|
||||
|
||||
static ssize_t store_temp_max(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = dev_get_drvdata(dev);
|
||||
long v = simple_strtol(buf, NULL, 10) / 1000;
|
||||
|
||||
v = SENSORS_LIMIT(v, -128, 127) + 128;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
i2c_smbus_write_byte_data(&data->client,
|
||||
FSCHMD_REG_TEMP_LIMIT[data->kind][index], v);
|
||||
data->temp_max[index] = v;
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_temp_fault(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = fschmd_update_device(dev);
|
||||
|
||||
/* bit 0 set means sensor working ok, so no fault! */
|
||||
if (data->temp_status[index] & FSCHMD_TEMP_WORKING_MASK)
|
||||
return sprintf(buf, "0\n");
|
||||
else
|
||||
return sprintf(buf, "1\n");
|
||||
}
|
||||
|
||||
static ssize_t show_temp_alarm(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = fschmd_update_device(dev);
|
||||
|
||||
if ((data->temp_status[index] & FSCHMD_TEMP_ALARM_MASK) ==
|
||||
FSCHMD_TEMP_ALARM_MASK)
|
||||
return sprintf(buf, "1\n");
|
||||
else
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
|
||||
#define RPM_FROM_REG(val) ((val) * 60)
|
||||
|
||||
static ssize_t show_fan_value(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = fschmd_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[index]));
|
||||
}
|
||||
|
||||
static ssize_t show_fan_div(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = fschmd_update_device(dev);
|
||||
|
||||
/* bits 2..7 reserved => mask with 3 */
|
||||
return sprintf(buf, "%d\n", 1 << (data->fan_ripple[index] & 3));
|
||||
}
|
||||
|
||||
static ssize_t store_fan_div(struct device *dev, struct device_attribute
|
||||
*devattr, const char *buf, size_t count)
|
||||
{
|
||||
u8 reg;
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = dev_get_drvdata(dev);
|
||||
/* supported values: 2, 4, 8 */
|
||||
unsigned long v = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
switch (v) {
|
||||
case 2: v = 1; break;
|
||||
case 4: v = 2; break;
|
||||
case 8: v = 3; break;
|
||||
default:
|
||||
dev_err(dev, "fan_div value %lu not supported. "
|
||||
"Choose one of 2, 4 or 8!\n", v);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
reg = i2c_smbus_read_byte_data(&data->client,
|
||||
FSCHMD_REG_FAN_RIPPLE[data->kind][index]);
|
||||
|
||||
/* bits 2..7 reserved => mask with 0x03 */
|
||||
reg &= ~0x03;
|
||||
reg |= v;
|
||||
|
||||
i2c_smbus_write_byte_data(&data->client,
|
||||
FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg);
|
||||
|
||||
data->fan_ripple[index] = reg;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_fan_alarm(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = fschmd_update_device(dev);
|
||||
|
||||
if (data->fan_status[index] & FSCHMD_FAN_ALARM_MASK)
|
||||
return sprintf(buf, "1\n");
|
||||
else
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
static ssize_t show_fan_fault(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = fschmd_update_device(dev);
|
||||
|
||||
if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT_MASK)
|
||||
return sprintf(buf, "1\n");
|
||||
else
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
|
||||
static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
int val = fschmd_update_device(dev)->fan_min[index];
|
||||
|
||||
/* 0 = allow turning off, 1-255 = 50-100% */
|
||||
if (val)
|
||||
val = val / 2 + 128;
|
||||
|
||||
return sprintf(buf, "%d\n", val);
|
||||
}
|
||||
|
||||
static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
|
||||
struct device_attribute *devattr, const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct fschmd_data *data = dev_get_drvdata(dev);
|
||||
unsigned long v = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
/* register: 0 = allow turning off, 1-255 = 50-100% */
|
||||
if (v) {
|
||||
v = SENSORS_LIMIT(v, 128, 255);
|
||||
v = (v - 128) * 2 + 1;
|
||||
}
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
i2c_smbus_write_byte_data(&data->client,
|
||||
FSCHMD_REG_FAN_MIN[data->kind][index], v);
|
||||
data->fan_min[index] = v;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/* The FSC hwmon family has the ability to force an attached alert led to flash
|
||||
from software, we export this as an alert_led sysfs attr */
|
||||
static ssize_t show_alert_led(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct fschmd_data *data = fschmd_update_device(dev);
|
||||
|
||||
if (data->global_control & FSCHMD_CONTROL_ALERT_LED_MASK)
|
||||
return sprintf(buf, "1\n");
|
||||
else
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
static ssize_t store_alert_led(struct device *dev,
|
||||
struct device_attribute *devattr, const char *buf, size_t count)
|
||||
{
|
||||
u8 reg;
|
||||
struct fschmd_data *data = dev_get_drvdata(dev);
|
||||
unsigned long v = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
reg = i2c_smbus_read_byte_data(&data->client, FSCHMD_REG_CONTROL);
|
||||
|
||||
if (v)
|
||||
reg |= FSCHMD_CONTROL_ALERT_LED_MASK;
|
||||
else
|
||||
reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK;
|
||||
|
||||
i2c_smbus_write_byte_data(&data->client, FSCHMD_REG_CONTROL, reg);
|
||||
|
||||
data->global_control = reg;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct sensor_device_attribute fschmd_attr[] = {
|
||||
SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
|
||||
SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
|
||||
SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
|
||||
SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute fschmd_temp_attr[] = {
|
||||
SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
|
||||
SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0),
|
||||
SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0),
|
||||
SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0),
|
||||
SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
|
||||
SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1),
|
||||
SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1),
|
||||
SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1),
|
||||
SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2),
|
||||
SENSOR_ATTR(temp3_max, 0644, show_temp_max, store_temp_max, 2),
|
||||
SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2),
|
||||
SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2),
|
||||
SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3),
|
||||
SENSOR_ATTR(temp4_max, 0644, show_temp_max, store_temp_max, 3),
|
||||
SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3),
|
||||
SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3),
|
||||
SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4),
|
||||
SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4),
|
||||
SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
|
||||
SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute fschmd_fan_attr[] = {
|
||||
SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0),
|
||||
SENSOR_ATTR(fan1_div, 0644, show_fan_div, store_fan_div, 0),
|
||||
SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0),
|
||||
SENSOR_ATTR(fan1_fault, 0444, show_fan_fault, NULL, 0),
|
||||
SENSOR_ATTR(pwm1_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
|
||||
store_pwm_auto_point1_pwm, 0),
|
||||
SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1),
|
||||
SENSOR_ATTR(fan2_div, 0644, show_fan_div, store_fan_div, 1),
|
||||
SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1),
|
||||
SENSOR_ATTR(fan2_fault, 0444, show_fan_fault, NULL, 1),
|
||||
SENSOR_ATTR(pwm2_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
|
||||
store_pwm_auto_point1_pwm, 1),
|
||||
SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2),
|
||||
SENSOR_ATTR(fan3_div, 0644, show_fan_div, store_fan_div, 2),
|
||||
SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2),
|
||||
SENSOR_ATTR(fan3_fault, 0444, show_fan_fault, NULL, 2),
|
||||
SENSOR_ATTR(pwm3_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
|
||||
store_pwm_auto_point1_pwm, 2),
|
||||
SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3),
|
||||
SENSOR_ATTR(fan4_div, 0644, show_fan_div, store_fan_div, 3),
|
||||
SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3),
|
||||
SENSOR_ATTR(fan4_fault, 0444, show_fan_fault, NULL, 3),
|
||||
SENSOR_ATTR(pwm4_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
|
||||
store_pwm_auto_point1_pwm, 3),
|
||||
SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4),
|
||||
SENSOR_ATTR(fan5_div, 0644, show_fan_div, store_fan_div, 4),
|
||||
SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4),
|
||||
SENSOR_ATTR(fan5_fault, 0444, show_fan_fault, NULL, 4),
|
||||
SENSOR_ATTR(pwm5_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
|
||||
store_pwm_auto_point1_pwm, 4),
|
||||
SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5),
|
||||
SENSOR_ATTR(fan6_div, 0644, show_fan_div, store_fan_div, 5),
|
||||
SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5),
|
||||
SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
|
||||
SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
|
||||
store_pwm_auto_point1_pwm, 5),
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Real code
|
||||
*/
|
||||
|
||||
static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct fschmd_data *data;
|
||||
u8 revision;
|
||||
const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
|
||||
"Heracles", "Heimdall" };
|
||||
const char * const client_names[5] = { "fscpos", "fscher", "fscscy",
|
||||
"fschrc", "fschmd" };
|
||||
int i, err = 0;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return 0;
|
||||
|
||||
/* OK. For now, we presume we have a valid client. We now create the
|
||||
* client structure, even though we cannot fill it completely yet.
|
||||
* But it allows us to access i2c_smbus_read_byte_data. */
|
||||
if (!(data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
|
||||
client = &data->client;
|
||||
i2c_set_clientdata(client, data);
|
||||
client->addr = address;
|
||||
client->adapter = adapter;
|
||||
client->driver = &fschmd_driver;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Detect & Identify the chip */
|
||||
if (kind <= 0) {
|
||||
char id[4];
|
||||
|
||||
id[0] = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_IDENT_0);
|
||||
id[1] = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_IDENT_1);
|
||||
id[2] = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_IDENT_2);
|
||||
id[3] = '\0';
|
||||
|
||||
if (!strcmp(id, "PEG"))
|
||||
kind = fscpos;
|
||||
else if (!strcmp(id, "HER"))
|
||||
kind = fscher;
|
||||
else if (!strcmp(id, "SCY"))
|
||||
kind = fscscy;
|
||||
else if (!strcmp(id, "HRC"))
|
||||
kind = fschrc;
|
||||
else if (!strcmp(id, "HMD"))
|
||||
kind = fschmd;
|
||||
else
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
if (kind == fscpos) {
|
||||
/* The Poseidon has hardwired temp limits, fill these
|
||||
in for the alarm resetting code */
|
||||
data->temp_max[0] = 70 + 128;
|
||||
data->temp_max[1] = 50 + 128;
|
||||
data->temp_max[2] = 50 + 128;
|
||||
}
|
||||
|
||||
/* i2c kind goes from 1-5, we want from 0-4 to address arrays */
|
||||
data->kind = kind - 1;
|
||||
strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE);
|
||||
|
||||
/* Tell the I2C layer a new client has arrived */
|
||||
if ((err = i2c_attach_client(client)))
|
||||
goto exit_free;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) {
|
||||
err = device_create_file(&client->dev,
|
||||
&fschmd_attr[i].dev_attr);
|
||||
if (err)
|
||||
goto exit_detach;
|
||||
}
|
||||
|
||||
for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) {
|
||||
/* Poseidon doesn't have TEMP_LIMIT registers */
|
||||
if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show ==
|
||||
show_temp_max)
|
||||
continue;
|
||||
|
||||
err = device_create_file(&client->dev,
|
||||
&fschmd_temp_attr[i].dev_attr);
|
||||
if (err)
|
||||
goto exit_detach;
|
||||
}
|
||||
|
||||
for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) {
|
||||
/* Poseidon doesn't have a FAN_MIN register for its 3rd fan */
|
||||
if (kind == fscpos &&
|
||||
!strcmp(fschmd_fan_attr[i].dev_attr.attr.name,
|
||||
"pwm3_auto_point1_pwm"))
|
||||
continue;
|
||||
|
||||
err = device_create_file(&client->dev,
|
||||
&fschmd_fan_attr[i].dev_attr);
|
||||
if (err)
|
||||
goto exit_detach;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
data->hwmon_dev = NULL;
|
||||
goto exit_detach;
|
||||
}
|
||||
|
||||
revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
|
||||
printk(KERN_INFO FSCHMD_NAME ": Detected FSC %s chip, revision: %d\n",
|
||||
names[data->kind], (int) revision);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_detach:
|
||||
fschmd_detach_client(client); /* will also free data for us */
|
||||
return err;
|
||||
|
||||
exit_free:
|
||||
kfree(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fschmd_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
||||
return 0;
|
||||
return i2c_probe(adapter, &addr_data, fschmd_detect);
|
||||
}
|
||||
|
||||
static int fschmd_detach_client(struct i2c_client *client)
|
||||
{
|
||||
struct fschmd_data *data = i2c_get_clientdata(client);
|
||||
int i, err;
|
||||
|
||||
/* Check if registered in case we're called from fschmd_detect
|
||||
to cleanup after an error */
|
||||
if (data->hwmon_dev)
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++)
|
||||
device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);
|
||||
for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
|
||||
device_remove_file(&client->dev,
|
||||
&fschmd_temp_attr[i].dev_attr);
|
||||
for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++)
|
||||
device_remove_file(&client->dev,
|
||||
&fschmd_fan_attr[i].dev_attr);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fschmd_data *fschmd_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct fschmd_data *data = i2c_get_clientdata(client);
|
||||
int i;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
|
||||
|
||||
for (i = 0; i < FSCHMD_NO_TEMP_SENSORS[data->kind]; i++) {
|
||||
data->temp_act[i] = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_TEMP_ACT[data->kind][i]);
|
||||
data->temp_status[i] = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_TEMP_STATE[data->kind][i]);
|
||||
|
||||
/* The fscpos doesn't have TEMP_LIMIT registers */
|
||||
if (FSCHMD_REG_TEMP_LIMIT[data->kind][i])
|
||||
data->temp_max[i] = i2c_smbus_read_byte_data(
|
||||
client,
|
||||
FSCHMD_REG_TEMP_LIMIT[data->kind][i]);
|
||||
|
||||
/* reset alarm if the alarm condition is gone,
|
||||
the chip doesn't do this itself */
|
||||
if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) ==
|
||||
FSCHMD_TEMP_ALARM_MASK &&
|
||||
data->temp_act[i] < data->temp_max[i])
|
||||
i2c_smbus_write_byte_data(client,
|
||||
FSCHMD_REG_TEMP_STATE[data->kind][i],
|
||||
FSCHMD_TEMP_ALERT_MASK);
|
||||
}
|
||||
|
||||
for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
|
||||
data->fan_act[i] = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_FAN_ACT[data->kind][i]);
|
||||
data->fan_status[i] = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_FAN_STATE[data->kind][i]);
|
||||
data->fan_ripple[i] = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_FAN_RIPPLE[data->kind][i]);
|
||||
|
||||
/* The fscpos third fan doesn't have a fan_min */
|
||||
if (FSCHMD_REG_FAN_MIN[data->kind][i])
|
||||
data->fan_min[i] = i2c_smbus_read_byte_data(
|
||||
client,
|
||||
FSCHMD_REG_FAN_MIN[data->kind][i]);
|
||||
|
||||
/* reset fan status if speed is back to > 0 */
|
||||
if ((data->fan_status[i] & FSCHMD_FAN_ALARM_MASK) &&
|
||||
data->fan_act[i])
|
||||
i2c_smbus_write_byte_data(client,
|
||||
FSCHMD_REG_FAN_STATE[data->kind][i],
|
||||
FSCHMD_FAN_ALARM_MASK);
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
data->volt[i] = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_VOLT[i]);
|
||||
|
||||
data->global_control = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_CONTROL);
|
||||
|
||||
/* To be implemented in the future
|
||||
data->watchdog[0] = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_WDOG_PRESET);
|
||||
data->watchdog[1] = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_WDOG_STATE);
|
||||
data->watchdog[2] = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_WDOG_CONTROL); */
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init fschmd_init(void)
|
||||
{
|
||||
return i2c_add_driver(&fschmd_driver);
|
||||
}
|
||||
|
||||
static void __exit fschmd_exit(void)
|
||||
{
|
||||
i2c_del_driver(&fschmd_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
|
||||
MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and "
|
||||
"Heimdall driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(fschmd_init);
|
||||
module_exit(fschmd_exit);
|
@ -115,7 +115,7 @@ static struct i2c_driver fscpos_driver = {
|
||||
*/
|
||||
struct fscpos_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* 0 until following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
@ -539,9 +539,9 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -562,7 +562,7 @@ static int fscpos_detach_client(struct i2c_client *client)
|
||||
struct fscpos_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &fscpos_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
|
@ -119,7 +119,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
|
||||
/* Each client has this additional data */
|
||||
struct gl518_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
enum chips type;
|
||||
|
||||
struct mutex update_lock;
|
||||
@ -460,9 +460,9 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -502,7 +502,7 @@ static int gl518_detach_client(struct i2c_client *client)
|
||||
struct gl518_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl518_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
|
@ -122,7 +122,7 @@ static struct i2c_driver gl520_driver = {
|
||||
/* Client data */
|
||||
struct gl520_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until the following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
@ -622,9 +622,9 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
}
|
||||
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -685,7 +685,7 @@ static int gl520_detach_client(struct i2c_client *client)
|
||||
struct gl520_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
|
||||
|
||||
|
@ -28,17 +28,17 @@ static DEFINE_IDR(hwmon_idr);
|
||||
static DEFINE_SPINLOCK(idr_lock);
|
||||
|
||||
/**
|
||||
* hwmon_device_register - register w/ hwmon sysfs class
|
||||
* hwmon_device_register - register w/ hwmon
|
||||
* @dev: the device to register
|
||||
*
|
||||
* hwmon_device_unregister() must be called when the class device is no
|
||||
* hwmon_device_unregister() must be called when the device is no
|
||||
* longer needed.
|
||||
*
|
||||
* Returns the pointer to the new struct class device.
|
||||
* Returns the pointer to the new device.
|
||||
*/
|
||||
struct class_device *hwmon_device_register(struct device *dev)
|
||||
struct device *hwmon_device_register(struct device *dev)
|
||||
{
|
||||
struct class_device *cdev;
|
||||
struct device *hwdev;
|
||||
int id, err;
|
||||
|
||||
again:
|
||||
@ -55,34 +55,33 @@ again:
|
||||
return ERR_PTR(err);
|
||||
|
||||
id = id & MAX_ID_MASK;
|
||||
cdev = class_device_create(hwmon_class, NULL, MKDEV(0,0), dev,
|
||||
HWMON_ID_FORMAT, id);
|
||||
hwdev = device_create(hwmon_class, dev, MKDEV(0,0), HWMON_ID_FORMAT, id);
|
||||
|
||||
if (IS_ERR(cdev)) {
|
||||
if (IS_ERR(hwdev)) {
|
||||
spin_lock(&idr_lock);
|
||||
idr_remove(&hwmon_idr, id);
|
||||
spin_unlock(&idr_lock);
|
||||
}
|
||||
|
||||
return cdev;
|
||||
return hwdev;
|
||||
}
|
||||
|
||||
/**
|
||||
* hwmon_device_unregister - removes the previously registered class device
|
||||
*
|
||||
* @cdev: the class device to destroy
|
||||
* @dev: the class device to destroy
|
||||
*/
|
||||
void hwmon_device_unregister(struct class_device *cdev)
|
||||
void hwmon_device_unregister(struct device *dev)
|
||||
{
|
||||
int id;
|
||||
|
||||
if (likely(sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1)) {
|
||||
class_device_unregister(cdev);
|
||||
if (likely(sscanf(dev->bus_id, HWMON_ID_FORMAT, &id) == 1)) {
|
||||
device_unregister(dev);
|
||||
spin_lock(&idr_lock);
|
||||
idr_remove(&hwmon_idr, id);
|
||||
spin_unlock(&idr_lock);
|
||||
} else
|
||||
dev_dbg(cdev->dev,
|
||||
dev_dbg(dev->parent,
|
||||
"hwmon_device_unregister() failed: bad class ID!\n");
|
||||
}
|
||||
|
||||
|
607
drivers/hwmon/ibmpex.c
Normal file
607
drivers/hwmon/ibmpex.c
Normal file
@ -0,0 +1,607 @@
|
||||
/*
|
||||
* A hwmon driver for the IBM PowerExecutive temperature/power sensors
|
||||
* Copyright (C) 2007 IBM
|
||||
*
|
||||
* Author: Darrick J. Wong <djwong@us.ibm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/ipmi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define REFRESH_INTERVAL (2 * HZ)
|
||||
#define DRVNAME "ibmpex"
|
||||
|
||||
#define PEX_GET_VERSION 1
|
||||
#define PEX_GET_SENSOR_COUNT 2
|
||||
#define PEX_GET_SENSOR_NAME 3
|
||||
#define PEX_RESET_HIGH_LOW 4
|
||||
#define PEX_GET_SENSOR_DATA 6
|
||||
|
||||
#define PEX_NET_FUNCTION 0x3A
|
||||
#define PEX_COMMAND 0x3C
|
||||
|
||||
static inline u16 extract_value(const char *data, int offset)
|
||||
{
|
||||
return be16_to_cpup((u16 *)&data[offset]);
|
||||
}
|
||||
|
||||
#define TEMP_SENSOR 1
|
||||
#define POWER_SENSOR 2
|
||||
|
||||
#define PEX_SENSOR_TYPE_LEN 3
|
||||
static u8 const power_sensor_sig[] = {0x70, 0x77, 0x72};
|
||||
static u8 const temp_sensor_sig[] = {0x74, 0x65, 0x6D};
|
||||
|
||||
#define PEX_MULT_LEN 2
|
||||
static u8 const watt_sensor_sig[] = {0x41, 0x43};
|
||||
|
||||
#define PEX_NUM_SENSOR_FUNCS 3
|
||||
static char const * const power_sensor_name_templates[] = {
|
||||
"%s%d_average",
|
||||
"%s%d_average_lowest",
|
||||
"%s%d_average_highest"
|
||||
};
|
||||
static char const * const temp_sensor_name_templates[] = {
|
||||
"%s%d_input",
|
||||
"%s%d_input_lowest",
|
||||
"%s%d_input_highest"
|
||||
};
|
||||
|
||||
static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data);
|
||||
static void ibmpex_register_bmc(int iface, struct device *dev);
|
||||
static void ibmpex_bmc_gone(int iface);
|
||||
|
||||
struct ibmpex_sensor_data {
|
||||
int in_use;
|
||||
s16 values[PEX_NUM_SENSOR_FUNCS];
|
||||
int multiplier;
|
||||
|
||||
struct sensor_device_attribute_2 attr[PEX_NUM_SENSOR_FUNCS];
|
||||
};
|
||||
|
||||
struct ibmpex_bmc_data {
|
||||
struct list_head list;
|
||||
struct device *hwmon_dev;
|
||||
struct device *bmc_device;
|
||||
struct mutex lock;
|
||||
char valid;
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
||||
struct ipmi_addr address;
|
||||
struct completion read_complete;
|
||||
ipmi_user_t user;
|
||||
int interface;
|
||||
|
||||
struct kernel_ipmi_msg tx_message;
|
||||
unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH];
|
||||
long tx_msgid;
|
||||
|
||||
unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH];
|
||||
unsigned long rx_msg_len;
|
||||
unsigned char rx_result;
|
||||
int rx_recv_type;
|
||||
|
||||
unsigned char sensor_major;
|
||||
unsigned char sensor_minor;
|
||||
|
||||
unsigned char num_sensors;
|
||||
struct ibmpex_sensor_data *sensors;
|
||||
};
|
||||
|
||||
struct ibmpex_driver_data {
|
||||
struct list_head bmc_data;
|
||||
struct ipmi_smi_watcher bmc_events;
|
||||
struct ipmi_user_hndl ipmi_hndlrs;
|
||||
};
|
||||
|
||||
static struct ibmpex_driver_data driver_data = {
|
||||
.bmc_data = LIST_HEAD_INIT(driver_data.bmc_data),
|
||||
.bmc_events = {
|
||||
.owner = THIS_MODULE,
|
||||
.new_smi = ibmpex_register_bmc,
|
||||
.smi_gone = ibmpex_bmc_gone,
|
||||
},
|
||||
.ipmi_hndlrs = {
|
||||
.ipmi_recv_hndl = ibmpex_msg_handler,
|
||||
},
|
||||
};
|
||||
|
||||
static int ibmpex_send_message(struct ibmpex_bmc_data *data)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ipmi_validate_addr(&data->address, sizeof(data->address));
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
data->tx_msgid++;
|
||||
err = ipmi_request_settime(data->user, &data->address, data->tx_msgid,
|
||||
&data->tx_message, data, 0, 0, 0);
|
||||
if (err)
|
||||
goto out1;
|
||||
|
||||
return 0;
|
||||
out1:
|
||||
printk(KERN_ERR "%s: request_settime=%x\n", __FUNCTION__, err);
|
||||
return err;
|
||||
out:
|
||||
printk(KERN_ERR "%s: validate_addr=%x\n", __FUNCTION__, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ibmpex_ver_check(struct ibmpex_bmc_data *data)
|
||||
{
|
||||
data->tx_msg_data[0] = PEX_GET_VERSION;
|
||||
data->tx_message.data_len = 1;
|
||||
ibmpex_send_message(data);
|
||||
|
||||
wait_for_completion(&data->read_complete);
|
||||
|
||||
if (data->rx_result || data->rx_msg_len != 6)
|
||||
return -ENOENT;
|
||||
|
||||
data->sensor_major = data->rx_msg_data[0];
|
||||
data->sensor_minor = data->rx_msg_data[1];
|
||||
|
||||
printk(KERN_INFO DRVNAME ": Found BMC with sensor interface "
|
||||
"v%d.%d %d-%02d-%02d on interface %d\n",
|
||||
data->sensor_major,
|
||||
data->sensor_minor,
|
||||
extract_value(data->rx_msg_data, 2),
|
||||
data->rx_msg_data[4],
|
||||
data->rx_msg_data[5],
|
||||
data->interface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ibmpex_query_sensor_count(struct ibmpex_bmc_data *data)
|
||||
{
|
||||
data->tx_msg_data[0] = PEX_GET_SENSOR_COUNT;
|
||||
data->tx_message.data_len = 1;
|
||||
ibmpex_send_message(data);
|
||||
|
||||
wait_for_completion(&data->read_complete);
|
||||
|
||||
if (data->rx_result || data->rx_msg_len != 1)
|
||||
return -ENOENT;
|
||||
|
||||
return data->rx_msg_data[0];
|
||||
}
|
||||
|
||||
static int ibmpex_query_sensor_name(struct ibmpex_bmc_data *data, int sensor)
|
||||
{
|
||||
data->tx_msg_data[0] = PEX_GET_SENSOR_NAME;
|
||||
data->tx_msg_data[1] = sensor;
|
||||
data->tx_message.data_len = 2;
|
||||
ibmpex_send_message(data);
|
||||
|
||||
wait_for_completion(&data->read_complete);
|
||||
|
||||
if (data->rx_result || data->rx_msg_len < 1)
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ibmpex_query_sensor_data(struct ibmpex_bmc_data *data, int sensor)
|
||||
{
|
||||
data->tx_msg_data[0] = PEX_GET_SENSOR_DATA;
|
||||
data->tx_msg_data[1] = sensor;
|
||||
data->tx_message.data_len = 2;
|
||||
ibmpex_send_message(data);
|
||||
|
||||
wait_for_completion(&data->read_complete);
|
||||
|
||||
if (data->rx_result || data->rx_msg_len < 26) {
|
||||
printk(KERN_ERR "Error reading sensor %d, please check.\n",
|
||||
sensor);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ibmpex_reset_high_low_data(struct ibmpex_bmc_data *data)
|
||||
{
|
||||
data->tx_msg_data[0] = PEX_RESET_HIGH_LOW;
|
||||
data->tx_message.data_len = 1;
|
||||
ibmpex_send_message(data);
|
||||
|
||||
wait_for_completion(&data->read_complete);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ibmpex_update_device(struct ibmpex_bmc_data *data)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) &&
|
||||
data->valid)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < data->num_sensors; i++) {
|
||||
if (!data->sensors[i].in_use)
|
||||
continue;
|
||||
err = ibmpex_query_sensor_data(data, i);
|
||||
if (err)
|
||||
continue;
|
||||
data->sensors[i].values[0] =
|
||||
extract_value(data->rx_msg_data, 16);
|
||||
data->sensors[i].values[1] =
|
||||
extract_value(data->rx_msg_data, 18);
|
||||
data->sensors[i].values[2] =
|
||||
extract_value(data->rx_msg_data, 20);
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
|
||||
out:
|
||||
mutex_unlock(&data->lock);
|
||||
}
|
||||
|
||||
static struct ibmpex_bmc_data *get_bmc_data(int iface)
|
||||
{
|
||||
struct ibmpex_bmc_data *p, *next;
|
||||
|
||||
list_for_each_entry_safe(p, next, &driver_data.bmc_data, list)
|
||||
if (p->interface == iface)
|
||||
return p;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", DRVNAME);
|
||||
}
|
||||
static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
|
||||
|
||||
static ssize_t ibmpex_show_sensor(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
|
||||
struct ibmpex_bmc_data *data = dev_get_drvdata(dev);
|
||||
int mult = data->sensors[attr->index].multiplier;
|
||||
ibmpex_update_device(data);
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
data->sensors[attr->index].values[attr->nr] * mult);
|
||||
}
|
||||
|
||||
static ssize_t ibmpex_reset_high_low(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct ibmpex_bmc_data *data = dev_get_drvdata(dev);
|
||||
|
||||
ibmpex_reset_high_low_data(data);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(reset_high_low, S_IWUSR, NULL,
|
||||
ibmpex_reset_high_low, 0);
|
||||
|
||||
static int is_power_sensor(const char *sensor_id, int len)
|
||||
{
|
||||
if (len < PEX_SENSOR_TYPE_LEN)
|
||||
return 0;
|
||||
|
||||
if (!memcmp(sensor_id, power_sensor_sig, PEX_SENSOR_TYPE_LEN))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_temp_sensor(const char *sensor_id, int len)
|
||||
{
|
||||
if (len < PEX_SENSOR_TYPE_LEN)
|
||||
return 0;
|
||||
|
||||
if (!memcmp(sensor_id, temp_sensor_sig, PEX_SENSOR_TYPE_LEN))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int power_sensor_multiplier(const char *sensor_id, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = PEX_SENSOR_TYPE_LEN; i < len - 1; i++)
|
||||
if (!memcmp(&sensor_id[i], watt_sensor_sig, PEX_MULT_LEN))
|
||||
return 1000000;
|
||||
|
||||
return 100000;
|
||||
}
|
||||
|
||||
static int create_sensor(struct ibmpex_bmc_data *data, int type,
|
||||
int counter, int sensor, int func)
|
||||
{
|
||||
int err;
|
||||
char *n;
|
||||
|
||||
n = kmalloc(32, GFP_KERNEL);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
if (type == TEMP_SENSOR)
|
||||
sprintf(n, temp_sensor_name_templates[func], "temp", counter);
|
||||
else if (type == POWER_SENSOR)
|
||||
sprintf(n, power_sensor_name_templates[func], "power", counter);
|
||||
|
||||
data->sensors[sensor].attr[func].dev_attr.attr.name = n;
|
||||
data->sensors[sensor].attr[func].dev_attr.attr.mode = S_IRUGO;
|
||||
data->sensors[sensor].attr[func].dev_attr.show = ibmpex_show_sensor;
|
||||
data->sensors[sensor].attr[func].index = sensor;
|
||||
data->sensors[sensor].attr[func].nr = func;
|
||||
|
||||
err = device_create_file(data->bmc_device,
|
||||
&data->sensors[sensor].attr[func].dev_attr);
|
||||
if (err) {
|
||||
data->sensors[sensor].attr[func].dev_attr.attr.name = NULL;
|
||||
kfree(n);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ibmpex_find_sensors(struct ibmpex_bmc_data *data)
|
||||
{
|
||||
int i, j, err;
|
||||
int sensor_type;
|
||||
int sensor_counter;
|
||||
int num_power = 0;
|
||||
int num_temp = 0;
|
||||
|
||||
err = ibmpex_query_sensor_count(data);
|
||||
if (err <= 0)
|
||||
return -ENOENT;
|
||||
data->num_sensors = err;
|
||||
|
||||
data->sensors = kzalloc(data->num_sensors * sizeof(*data->sensors),
|
||||
GFP_KERNEL);
|
||||
if (!data->sensors)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < data->num_sensors; i++) {
|
||||
err = ibmpex_query_sensor_name(data, i);
|
||||
if (err)
|
||||
continue;
|
||||
|
||||
if (is_power_sensor(data->rx_msg_data, data->rx_msg_len)) {
|
||||
sensor_type = POWER_SENSOR;
|
||||
num_power++;
|
||||
sensor_counter = num_power;
|
||||
data->sensors[i].multiplier =
|
||||
power_sensor_multiplier(data->rx_msg_data,
|
||||
data->rx_msg_len);
|
||||
} else if (is_temp_sensor(data->rx_msg_data,
|
||||
data->rx_msg_len)) {
|
||||
sensor_type = TEMP_SENSOR;
|
||||
num_temp++;
|
||||
sensor_counter = num_temp;
|
||||
data->sensors[i].multiplier = 1;
|
||||
} else
|
||||
continue;
|
||||
|
||||
data->sensors[i].in_use = 1;
|
||||
|
||||
/* Create attributes */
|
||||
for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
|
||||
err = create_sensor(data, sensor_type, sensor_counter,
|
||||
i, j);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
}
|
||||
}
|
||||
|
||||
err = device_create_file(data->bmc_device,
|
||||
&sensor_dev_attr_reset_high_low.dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
|
||||
err = device_create_file(data->bmc_device,
|
||||
&sensor_dev_attr_name.dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
device_remove_file(data->bmc_device,
|
||||
&sensor_dev_attr_reset_high_low.dev_attr);
|
||||
device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr);
|
||||
for (i = 0; i < data->num_sensors; i++)
|
||||
for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
|
||||
if (!data->sensors[i].attr[j].dev_attr.attr.name)
|
||||
continue;
|
||||
device_remove_file(data->bmc_device,
|
||||
&data->sensors[i].attr[j].dev_attr);
|
||||
kfree(data->sensors[i].attr[j].dev_attr.attr.name);
|
||||
}
|
||||
|
||||
kfree(data->sensors);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ibmpex_register_bmc(int iface, struct device *dev)
|
||||
{
|
||||
struct ibmpex_bmc_data *data;
|
||||
int err;
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
printk(KERN_ERR DRVNAME ": Insufficient memory for BMC "
|
||||
"interface %d.\n", data->interface);
|
||||
return;
|
||||
}
|
||||
|
||||
data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
|
||||
data->address.channel = IPMI_BMC_CHANNEL;
|
||||
data->address.data[0] = 0;
|
||||
data->interface = iface;
|
||||
data->bmc_device = dev;
|
||||
|
||||
/* Create IPMI messaging interface user */
|
||||
err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
|
||||
data, &data->user);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR DRVNAME ": Error, unable to register user with "
|
||||
"ipmi interface %d\n",
|
||||
data->interface);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_init(&data->lock);
|
||||
|
||||
/* Initialize message */
|
||||
data->tx_msgid = 0;
|
||||
init_completion(&data->read_complete);
|
||||
data->tx_message.netfn = PEX_NET_FUNCTION;
|
||||
data->tx_message.cmd = PEX_COMMAND;
|
||||
data->tx_message.data = data->tx_msg_data;
|
||||
|
||||
/* Does this BMC support PowerExecutive? */
|
||||
err = ibmpex_ver_check(data);
|
||||
if (err)
|
||||
goto out_user;
|
||||
|
||||
/* Register the BMC as a HWMON class device */
|
||||
data->hwmon_dev = hwmon_device_register(data->bmc_device);
|
||||
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
printk(KERN_ERR DRVNAME ": Error, unable to register hwmon "
|
||||
"class device for interface %d\n",
|
||||
data->interface);
|
||||
goto out_user;
|
||||
}
|
||||
|
||||
/* finally add the new bmc data to the bmc data list */
|
||||
dev_set_drvdata(dev, data);
|
||||
list_add_tail(&data->list, &driver_data.bmc_data);
|
||||
|
||||
/* Now go find all the sensors */
|
||||
err = ibmpex_find_sensors(data);
|
||||
if (err) {
|
||||
printk(KERN_ERR "Error %d allocating memory\n", err);
|
||||
goto out_register;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
out_register:
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
out_user:
|
||||
ipmi_destroy_user(data->user);
|
||||
out:
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
device_remove_file(data->bmc_device,
|
||||
&sensor_dev_attr_reset_high_low.dev_attr);
|
||||
device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr);
|
||||
for (i = 0; i < data->num_sensors; i++)
|
||||
for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
|
||||
if (!data->sensors[i].attr[j].dev_attr.attr.name)
|
||||
continue;
|
||||
device_remove_file(data->bmc_device,
|
||||
&data->sensors[i].attr[j].dev_attr);
|
||||
kfree(data->sensors[i].attr[j].dev_attr.attr.name);
|
||||
}
|
||||
|
||||
list_del(&data->list);
|
||||
dev_set_drvdata(data->bmc_device, NULL);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
ipmi_destroy_user(data->user);
|
||||
kfree(data->sensors);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static void ibmpex_bmc_gone(int iface)
|
||||
{
|
||||
struct ibmpex_bmc_data *data = get_bmc_data(iface);
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
ibmpex_bmc_delete(data);
|
||||
}
|
||||
|
||||
static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
|
||||
{
|
||||
struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
|
||||
|
||||
if (msg->msgid != data->tx_msgid) {
|
||||
printk(KERN_ERR "Received msgid (%02x) and transmitted "
|
||||
"msgid (%02x) mismatch!\n",
|
||||
(int)msg->msgid,
|
||||
(int)data->tx_msgid);
|
||||
ipmi_free_recv_msg(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
data->rx_recv_type = msg->recv_type;
|
||||
if (msg->msg.data_len > 0)
|
||||
data->rx_result = msg->msg.data[0];
|
||||
else
|
||||
data->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE;
|
||||
|
||||
if (msg->msg.data_len > 1) {
|
||||
data->rx_msg_len = msg->msg.data_len - 1;
|
||||
memcpy(data->rx_msg_data, msg->msg.data + 1, data->rx_msg_len);
|
||||
} else
|
||||
data->rx_msg_len = 0;
|
||||
|
||||
ipmi_free_recv_msg(msg);
|
||||
complete(&data->read_complete);
|
||||
}
|
||||
|
||||
static int __init ibmpex_init(void)
|
||||
{
|
||||
return ipmi_smi_watcher_register(&driver_data.bmc_events);
|
||||
}
|
||||
|
||||
static void __exit ibmpex_exit(void)
|
||||
{
|
||||
struct ibmpex_bmc_data *p, *next;
|
||||
|
||||
ipmi_smi_watcher_unregister(&driver_data.bmc_events);
|
||||
list_for_each_entry_safe(p, next, &driver_data.bmc_data, list)
|
||||
ibmpex_bmc_delete(p);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
|
||||
MODULE_DESCRIPTION("IBM PowerExecutive power/temperature sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(ibmpex_init);
|
||||
module_exit(ibmpex_exit);
|
@ -141,10 +141,10 @@ static int fix_pwm_polarity;
|
||||
|
||||
/* 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))
|
||||
static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
|
||||
static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86 };
|
||||
static const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83 };
|
||||
static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
|
||||
#define IT87_REG_FAN_MAIN_CTRL 0x13
|
||||
#define IT87_REG_FAN_CTL 0x14
|
||||
#define IT87_REG_PWM(nr) (0x15 + (nr))
|
||||
@ -222,7 +222,7 @@ struct it87_sio_data {
|
||||
/* For each registered chip, we need to keep some data in memory.
|
||||
The structure is dynamically allocated. */
|
||||
struct it87_data {
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
enum chips type;
|
||||
|
||||
unsigned short addr;
|
||||
@ -235,8 +235,8 @@ struct it87_data {
|
||||
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 */
|
||||
u16 fan[5]; /* Register values, possibly combined */
|
||||
u16 fan_min[5]; /* Register values, possibly combined */
|
||||
u8 temp[3]; /* Register value */
|
||||
u8 temp_high[3]; /* Register value */
|
||||
u8 temp_low[3]; /* Register value */
|
||||
@ -555,7 +555,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
}
|
||||
|
||||
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
|
||||
it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
|
||||
it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
@ -596,7 +596,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
/* Restore fan min limit */
|
||||
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
|
||||
it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
|
||||
it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
@ -729,9 +729,9 @@ static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->fan_min[nr] = FAN16_TO_REG(val);
|
||||
it87_write_value(data, IT87_REG_FAN_MIN(nr),
|
||||
it87_write_value(data, IT87_REG_FAN_MIN[nr],
|
||||
data->fan_min[nr] & 0xff);
|
||||
it87_write_value(data, IT87_REG_FANX_MIN(nr),
|
||||
it87_write_value(data, IT87_REG_FANX_MIN[nr],
|
||||
data->fan_min[nr] >> 8);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return count;
|
||||
@ -751,6 +751,8 @@ static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \
|
||||
show_fan16_offset(1);
|
||||
show_fan16_offset(2);
|
||||
show_fan16_offset(3);
|
||||
show_fan16_offset(4);
|
||||
show_fan16_offset(5);
|
||||
|
||||
/* Alarms */
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
@ -763,7 +765,7 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
static ssize_t
|
||||
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
struct it87_data *data = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%u\n", data->vrm);
|
||||
}
|
||||
static ssize_t
|
||||
@ -851,6 +853,10 @@ static struct attribute *it87_attributes_opt[] = {
|
||||
&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_fan4_input16.dev_attr.attr,
|
||||
&sensor_dev_attr_fan4_min16.dev_attr.attr,
|
||||
&sensor_dev_attr_fan5_input16.dev_attr.attr,
|
||||
&sensor_dev_attr_fan5_min16.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan1_min.dev_attr.attr,
|
||||
@ -1024,6 +1030,20 @@ static int __devinit it87_probe(struct platform_device *pdev)
|
||||
&sensor_dev_attr_fan3_min16.dev_attr)))
|
||||
goto ERROR4;
|
||||
}
|
||||
if (data->has_fan & (1 << 3)) {
|
||||
if ((err = device_create_file(dev,
|
||||
&sensor_dev_attr_fan4_input16.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_fan4_min16.dev_attr)))
|
||||
goto ERROR4;
|
||||
}
|
||||
if (data->has_fan & (1 << 4)) {
|
||||
if ((err = device_create_file(dev,
|
||||
&sensor_dev_attr_fan5_input16.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_fan5_min16.dev_attr)))
|
||||
goto ERROR4;
|
||||
}
|
||||
} else {
|
||||
/* 8-bit tachometers with clock divider */
|
||||
if (data->has_fan & (1 << 0)) {
|
||||
@ -1089,9 +1109,9 @@ static int __devinit it87_probe(struct platform_device *pdev)
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
@ -1113,7 +1133,7 @@ static int __devexit it87_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct it87_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &it87_group);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &it87_group_opt);
|
||||
|
||||
@ -1260,6 +1280,10 @@ static void __devinit it87_init_device(struct platform_device *pdev)
|
||||
it87_write_value(data, IT87_REG_FAN_16BIT,
|
||||
tmp | 0x07);
|
||||
}
|
||||
if (tmp & (1 << 4))
|
||||
data->has_fan |= (1 << 3); /* fan4 enabled */
|
||||
if (tmp & (1 << 5))
|
||||
data->has_fan |= (1 << 4); /* fan5 enabled */
|
||||
}
|
||||
|
||||
/* Set current fan mode registers and the default settings for the
|
||||
@ -1314,21 +1338,21 @@ static struct it87_data *it87_update_device(struct device *dev)
|
||||
data->in[8] =
|
||||
it87_read_value(data, IT87_REG_VIN(8));
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
for (i = 0; i < 5; i++) {
|
||||
/* Skip disabled fans */
|
||||
if (!(data->has_fan & (1 << i)))
|
||||
continue;
|
||||
|
||||
data->fan_min[i] =
|
||||
it87_read_value(data, IT87_REG_FAN_MIN(i));
|
||||
it87_read_value(data, IT87_REG_FAN_MIN[i]);
|
||||
data->fan[i] = it87_read_value(data,
|
||||
IT87_REG_FAN(i));
|
||||
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(data,
|
||||
IT87_REG_FANX(i)) << 8;
|
||||
IT87_REG_FANX[i]) << 8;
|
||||
data->fan_min[i] |= it87_read_value(data,
|
||||
IT87_REG_FANX_MIN(i)) << 8;
|
||||
IT87_REG_FANX_MIN[i]) << 8;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
|
@ -38,7 +38,7 @@
|
||||
#define SEL_CORE 0x04
|
||||
|
||||
struct k8temp_data {
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
const char *name;
|
||||
char valid; /* zero until following fields are valid */
|
||||
@ -225,10 +225,10 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -255,7 +255,7 @@ static void __devexit k8temp_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct k8temp_data *data = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_remove_file(&pdev->dev,
|
||||
|
@ -154,7 +154,7 @@ static struct i2c_driver lm63_driver = {
|
||||
|
||||
struct lm63_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
@ -502,9 +502,9 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -561,7 +561,7 @@ static int lm63_detach_client(struct i2c_client *client)
|
||||
struct lm63_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm63_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
#define DRVNAME "lm70"
|
||||
|
||||
struct lm70 {
|
||||
struct class_device *cdev;
|
||||
struct device *hwmon_dev;
|
||||
struct semaphore sem;
|
||||
};
|
||||
|
||||
@ -81,7 +81,7 @@ static ssize_t lm70_sense_temp(struct device *dev,
|
||||
* So it's equivalent to multiplying by 0.25 * 1000 = 250.
|
||||
*/
|
||||
val = ((int)raw/32) * 250;
|
||||
status = sprintf(buf, "%+d\n", val); /* millidegrees Celsius */
|
||||
status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */
|
||||
out:
|
||||
up(&p_lm70->sem);
|
||||
return status;
|
||||
@ -89,6 +89,14 @@ out:
|
||||
|
||||
static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL);
|
||||
|
||||
static ssize_t lm70_show_name(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "lm70\n");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL);
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
static int __devinit lm70_probe(struct spi_device *spi)
|
||||
@ -107,15 +115,16 @@ static int __devinit lm70_probe(struct spi_device *spi)
|
||||
init_MUTEX(&p_lm70->sem);
|
||||
|
||||
/* sysfs hook */
|
||||
p_lm70->cdev = hwmon_device_register(&spi->dev);
|
||||
if (IS_ERR(p_lm70->cdev)) {
|
||||
p_lm70->hwmon_dev = hwmon_device_register(&spi->dev);
|
||||
if (IS_ERR(p_lm70->hwmon_dev)) {
|
||||
dev_dbg(&spi->dev, "hwmon_device_register failed.\n");
|
||||
status = PTR_ERR(p_lm70->cdev);
|
||||
status = PTR_ERR(p_lm70->hwmon_dev);
|
||||
goto out_dev_reg_failed;
|
||||
}
|
||||
dev_set_drvdata(&spi->dev, p_lm70);
|
||||
|
||||
if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))) {
|
||||
if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))
|
||||
|| (status = device_create_file(&spi->dev, &dev_attr_name))) {
|
||||
dev_dbg(&spi->dev, "device_create_file failure.\n");
|
||||
goto out_dev_create_file_failed;
|
||||
}
|
||||
@ -123,7 +132,8 @@ static int __devinit lm70_probe(struct spi_device *spi)
|
||||
return 0;
|
||||
|
||||
out_dev_create_file_failed:
|
||||
hwmon_device_unregister(p_lm70->cdev);
|
||||
device_remove_file(&spi->dev, &dev_attr_temp1_input);
|
||||
hwmon_device_unregister(p_lm70->hwmon_dev);
|
||||
out_dev_reg_failed:
|
||||
dev_set_drvdata(&spi->dev, NULL);
|
||||
kfree(p_lm70);
|
||||
@ -135,7 +145,8 @@ static int __devexit lm70_remove(struct spi_device *spi)
|
||||
struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
|
||||
|
||||
device_remove_file(&spi->dev, &dev_attr_temp1_input);
|
||||
hwmon_device_unregister(p_lm70->cdev);
|
||||
device_remove_file(&spi->dev, &dev_attr_name);
|
||||
hwmon_device_unregister(p_lm70->hwmon_dev);
|
||||
dev_set_drvdata(&spi->dev, NULL);
|
||||
kfree(p_lm70);
|
||||
|
||||
|
@ -50,7 +50,7 @@ static const u8 LM75_REG_TEMP[3] = {
|
||||
/* Each client has this additional data */
|
||||
struct lm75_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
@ -95,7 +95,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm75_data *data = i2c_get_clientdata(client);
|
||||
int nr = attr->index;
|
||||
unsigned long temp = simple_strtoul(buf, NULL, 10);
|
||||
long temp = simple_strtol(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp[nr] = LM75_TEMP_TO_REG(temp);
|
||||
@ -219,9 +219,9 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -240,7 +240,7 @@ exit:
|
||||
static int lm75_detach_client(struct i2c_client *client)
|
||||
{
|
||||
struct lm75_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm75_group);
|
||||
i2c_detach_client(client);
|
||||
kfree(data);
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
/* TEMP: 0.001C/bit (-55C to +125C)
|
||||
REG: (0.5C/bit, two's complement) << 7 */
|
||||
static inline u16 LM75_TEMP_TO_REG(int temp)
|
||||
static inline u16 LM75_TEMP_TO_REG(long temp)
|
||||
{
|
||||
int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
|
||||
ntemp += (ntemp<0 ? -250 : 250);
|
||||
|
@ -51,7 +51,7 @@ I2C_CLIENT_INSMOD_1(lm77);
|
||||
/* Each client has this additional data */
|
||||
struct lm77_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid;
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
@ -138,7 +138,7 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct lm77_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtoul(buf, NULL, 10); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
\
|
||||
mutex_lock(&data->update_lock); \
|
||||
data->value = val; \
|
||||
@ -337,9 +337,9 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -358,7 +358,7 @@ exit:
|
||||
static int lm77_detach_client(struct i2c_client *client)
|
||||
{
|
||||
struct lm77_data *data = i2c_get_clientdata(client);
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm77_group);
|
||||
i2c_detach_client(client);
|
||||
kfree(data);
|
||||
|
@ -131,7 +131,7 @@ static inline int TEMP_FROM_REG(s8 val)
|
||||
the driver field to differentiate between I2C and ISA chips. */
|
||||
struct lm78_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex lock;
|
||||
enum chips type;
|
||||
|
||||
@ -438,6 +438,25 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
|
||||
}
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct lm78_data *data = lm78_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(da)->index;
|
||||
return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
|
||||
}
|
||||
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, 8);
|
||||
static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
|
||||
static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
|
||||
static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
|
||||
static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
|
||||
static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
|
||||
|
||||
/* This function is called when:
|
||||
* lm78_driver is inserted (when this module is loaded), for each
|
||||
available adapter
|
||||
@ -453,36 +472,47 @@ static struct attribute *lm78_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_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,
|
||||
&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,
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_max_hyst.attr,
|
||||
&sensor_dev_attr_temp1_alarm.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_fan1_alarm.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_fan2_alarm.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_fan3_alarm.dev_attr.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
|
||||
@ -585,9 +615,9 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
@ -608,7 +638,7 @@ static int lm78_detach_client(struct i2c_client *client)
|
||||
struct lm78_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm78_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
@ -659,9 +689,9 @@ static int __devinit lm78_isa_probe(struct platform_device *pdev)
|
||||
|| (err = device_create_file(&pdev->dev, &dev_attr_name)))
|
||||
goto exit_remove_files;
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -681,7 +711,7 @@ static int __devexit lm78_isa_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lm78_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &lm78_group);
|
||||
device_remove_file(&pdev->dev, &dev_attr_name);
|
||||
release_region(data->client.addr, LM78_EXTENT);
|
||||
|
@ -108,7 +108,7 @@ static inline long TEMP_FROM_REG(u16 temp)
|
||||
|
||||
struct lm80_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
@ -497,9 +497,9 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto error_remove;
|
||||
}
|
||||
|
||||
@ -520,7 +520,7 @@ static int lm80_detach_client(struct i2c_client *client)
|
||||
struct lm80_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm80_group);
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
|
@ -144,7 +144,7 @@ static struct i2c_driver lm83_driver = {
|
||||
|
||||
struct lm83_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
@ -400,9 +400,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -424,7 +424,7 @@ static int lm83_detach_client(struct i2c_client *client)
|
||||
struct lm83_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm83_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -58,6 +58,7 @@
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/hwmon-vid.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
@ -129,7 +130,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
|
||||
(((val) < 0 ? (val)-500 : (val)+500) / 1000))
|
||||
|
||||
#define FAN_FROM_REG(reg,div) ((reg) == 255 || (reg) == 0 ? 0 : \
|
||||
1350000 + (reg)*(div) / 2) / ((reg)*(div))
|
||||
(1350000 + (reg)*(div) / 2) / ((reg)*(div)))
|
||||
#define FAN_TO_REG(val,div) ((val)*(div) * 255 <= 1350000 ? 255 : \
|
||||
(1350000 + (val)*(div) / 2) / ((val)*(div)))
|
||||
|
||||
@ -145,7 +146,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
|
||||
#define CHAN_NO_FAN(nr) (1 << (nr))
|
||||
#define CHAN_TEMP3 (1 << 2)
|
||||
#define CHAN_VCC_5V (1 << 3)
|
||||
#define CHAN_NO_VID (1 << 8)
|
||||
#define CHAN_NO_VID (1 << 7)
|
||||
|
||||
/*
|
||||
* Functions declaration
|
||||
@ -176,7 +177,7 @@ static struct i2c_driver lm87_driver = {
|
||||
|
||||
struct lm87_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
@ -500,7 +501,7 @@ 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 lm87_data *data = lm87_update_device(dev);
|
||||
struct lm87_data *data = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%d\n", data->vrm);
|
||||
}
|
||||
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
@ -531,6 +532,29 @@ static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const
|
||||
}
|
||||
static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
|
||||
|
||||
static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct lm87_data *data = lm87_update_device(dev);
|
||||
int bitnr = to_sensor_dev_attr(attr)->index;
|
||||
return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
|
||||
}
|
||||
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, 8);
|
||||
static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
|
||||
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(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
|
||||
static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 14);
|
||||
static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15);
|
||||
|
||||
/*
|
||||
* Real code
|
||||
*/
|
||||
@ -546,24 +570,31 @@ static struct attribute *lm87_attributes[] = {
|
||||
&dev_attr_in1_input.attr,
|
||||
&dev_attr_in1_min.attr,
|
||||
&dev_attr_in1_max.attr,
|
||||
&sensor_dev_attr_in1_alarm.dev_attr.attr,
|
||||
&dev_attr_in2_input.attr,
|
||||
&dev_attr_in2_min.attr,
|
||||
&dev_attr_in2_max.attr,
|
||||
&sensor_dev_attr_in2_alarm.dev_attr.attr,
|
||||
&dev_attr_in3_input.attr,
|
||||
&dev_attr_in3_min.attr,
|
||||
&dev_attr_in3_max.attr,
|
||||
&sensor_dev_attr_in3_alarm.dev_attr.attr,
|
||||
&dev_attr_in4_input.attr,
|
||||
&dev_attr_in4_min.attr,
|
||||
&dev_attr_in4_max.attr,
|
||||
&sensor_dev_attr_in4_alarm.dev_attr.attr,
|
||||
|
||||
&dev_attr_temp1_input.attr,
|
||||
&dev_attr_temp1_max.attr,
|
||||
&dev_attr_temp1_min.attr,
|
||||
&dev_attr_temp1_crit.attr,
|
||||
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
|
||||
&dev_attr_temp2_input.attr,
|
||||
&dev_attr_temp2_max.attr,
|
||||
&dev_attr_temp2_min.attr,
|
||||
&dev_attr_temp2_crit.attr,
|
||||
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
||||
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_aout_output.attr,
|
||||
@ -579,30 +610,38 @@ static struct attribute *lm87_attributes_opt[] = {
|
||||
&dev_attr_in6_input.attr,
|
||||
&dev_attr_in6_min.attr,
|
||||
&dev_attr_in6_max.attr,
|
||||
&sensor_dev_attr_in6_alarm.dev_attr.attr,
|
||||
|
||||
&dev_attr_fan1_input.attr,
|
||||
&dev_attr_fan1_min.attr,
|
||||
&dev_attr_fan1_div.attr,
|
||||
&sensor_dev_attr_fan1_alarm.dev_attr.attr,
|
||||
|
||||
&dev_attr_in7_input.attr,
|
||||
&dev_attr_in7_min.attr,
|
||||
&dev_attr_in7_max.attr,
|
||||
&sensor_dev_attr_in7_alarm.dev_attr.attr,
|
||||
|
||||
&dev_attr_fan2_input.attr,
|
||||
&dev_attr_fan2_min.attr,
|
||||
&dev_attr_fan2_div.attr,
|
||||
&sensor_dev_attr_fan2_alarm.dev_attr.attr,
|
||||
|
||||
&dev_attr_temp3_input.attr,
|
||||
&dev_attr_temp3_max.attr,
|
||||
&dev_attr_temp3_min.attr,
|
||||
&dev_attr_temp3_crit.attr,
|
||||
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
||||
|
||||
&dev_attr_in0_input.attr,
|
||||
&dev_attr_in0_min.attr,
|
||||
&dev_attr_in0_max.attr,
|
||||
&sensor_dev_attr_in0_alarm.dev_attr.attr,
|
||||
&dev_attr_in5_input.attr,
|
||||
&dev_attr_in5_min.attr,
|
||||
&dev_attr_in5_max.attr,
|
||||
&sensor_dev_attr_in5_alarm.dev_attr.attr,
|
||||
|
||||
&dev_attr_cpu0_vid.attr,
|
||||
&dev_attr_vrm.attr,
|
||||
@ -690,7 +729,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in6_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in6_max)))
|
||||
&dev_attr_in6_max))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in6_alarm.dev_attr)))
|
||||
goto exit_remove;
|
||||
} else {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
@ -698,7 +739,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan1_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan1_div)))
|
||||
&dev_attr_fan1_div))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_alarm.dev_attr)))
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -708,7 +751,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in7_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in7_max)))
|
||||
&dev_attr_in7_max))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in7_alarm.dev_attr)))
|
||||
goto exit_remove;
|
||||
} else {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
@ -716,7 +761,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan2_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_fan2_div)))
|
||||
&dev_attr_fan2_div))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan2_alarm.dev_attr)))
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -728,7 +775,11 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp3_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_temp3_crit)))
|
||||
&dev_attr_temp3_crit))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp3_alarm.dev_attr))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp3_fault.dev_attr)))
|
||||
goto exit_remove;
|
||||
} else {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
@ -737,12 +788,16 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
&dev_attr_in0_min))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&dev_attr_in0_max))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in0_alarm.dev_attr))
|
||||
|| (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)))
|
||||
&dev_attr_in5_max))
|
||||
|| (err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_in5_alarm.dev_attr)))
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -755,9 +810,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -816,7 +871,7 @@ static int lm87_detach_client(struct i2c_client *client)
|
||||
struct lm87_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm87_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm87_group_opt);
|
||||
|
||||
|
@ -41,7 +41,8 @@
|
||||
* http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
|
||||
* Note that there is no easy way to differentiate between the three
|
||||
* variants. The extra address and features of the MAX6659 are not
|
||||
* supported by this driver.
|
||||
* supported by this driver. These chips lack the remote temperature
|
||||
* offset feature.
|
||||
*
|
||||
* This driver also supports the MAX6680 and MAX6681, two other sensor
|
||||
* chips made by Maxim. These are quite similar to the other Maxim
|
||||
@ -214,7 +215,7 @@ static struct i2c_driver lm90_driver = {
|
||||
|
||||
struct lm90_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
@ -226,9 +227,10 @@ struct lm90_data {
|
||||
2: local high limit
|
||||
3: local critical limit
|
||||
4: remote critical limit */
|
||||
s16 temp11[3]; /* 0: remote input
|
||||
s16 temp11[4]; /* 0: remote input
|
||||
1: remote low limit
|
||||
2: remote high limit */
|
||||
2: remote high limit
|
||||
3: remote offset (except max6657) */
|
||||
u8 temp_hyst;
|
||||
u8 alarms; /* bitvector */
|
||||
};
|
||||
@ -282,11 +284,13 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
|
||||
static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
static const u8 reg[4] = {
|
||||
static const u8 reg[6] = {
|
||||
LM90_REG_W_REMOTE_LOWH,
|
||||
LM90_REG_W_REMOTE_LOWL,
|
||||
LM90_REG_W_REMOTE_HIGHH,
|
||||
LM90_REG_W_REMOTE_HIGHL,
|
||||
LM90_REG_W_REMOTE_OFFSH,
|
||||
LM90_REG_W_REMOTE_OFFSL,
|
||||
};
|
||||
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
@ -367,6 +371,8 @@ 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);
|
||||
static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
|
||||
set_temp11, 3);
|
||||
|
||||
/* Individual alarm files */
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
|
||||
@ -652,10 +658,15 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
&dev_attr_pec)))
|
||||
goto exit_remove_files;
|
||||
}
|
||||
if (data->kind != max6657) {
|
||||
if ((err = device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_offset.dev_attr)))
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -707,9 +718,12 @@ static int lm90_detach_client(struct i2c_client *client)
|
||||
struct lm90_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm90_group);
|
||||
device_remove_file(&client->dev, &dev_attr_pec);
|
||||
if (data->kind != max6657)
|
||||
device_remove_file(&client->dev,
|
||||
&sensor_dev_attr_temp2_offset.dev_attr);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
@ -763,6 +777,13 @@ static struct lm90_data *lm90_update_device(struct device *dev)
|
||||
if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &newh) == 0
|
||||
&& lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, &l) == 0)
|
||||
data->temp11[2] = (newh << 8) | l;
|
||||
if (data->kind != max6657) {
|
||||
if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH,
|
||||
&newh) == 0
|
||||
&& lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL,
|
||||
&l) == 0)
|
||||
data->temp11[3] = (newh << 8) | l;
|
||||
}
|
||||
lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms);
|
||||
|
||||
data->last_updated = jiffies;
|
||||
|
@ -96,7 +96,7 @@ static struct i2c_driver lm92_driver;
|
||||
/* Client data (each client gets its own) */
|
||||
struct lm92_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
@ -379,9 +379,9 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -409,7 +409,7 @@ static int lm92_detach_client(struct i2c_client *client)
|
||||
struct lm92_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm92_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
|
@ -201,7 +201,7 @@ struct block1_t {
|
||||
*/
|
||||
struct lm93_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
struct mutex update_lock;
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
@ -413,7 +413,7 @@ static int LM93_TEMP_FROM_REG(u8 reg)
|
||||
|
||||
/* TEMP: 1/1000 degrees C (-128C to +127C)
|
||||
REG: 1C/bit, two's complement */
|
||||
static u8 LM93_TEMP_TO_REG(int temp)
|
||||
static u8 LM93_TEMP_TO_REG(long temp)
|
||||
{
|
||||
int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
|
||||
ntemp += (ntemp<0 ? -500 : 500);
|
||||
@ -1268,7 +1268,7 @@ static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_lim[nr].min = LM93_TEMP_TO_REG(val);
|
||||
@ -1298,7 +1298,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp_lim[nr].max = LM93_TEMP_TO_REG(val);
|
||||
@ -1329,7 +1329,7 @@ static ssize_t store_temp_auto_base(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->block10.base[nr] = LM93_TEMP_TO_REG(val);
|
||||
@ -1360,7 +1360,7 @@ static ssize_t store_temp_auto_boost(struct device *dev,
|
||||
int nr = (to_sensor_dev_attr(attr))->index;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
u32 val = simple_strtoul(buf, NULL, 10);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->boost[nr] = LM93_TEMP_TO_REG(val);
|
||||
@ -2078,8 +2078,8 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
|
||||
return sprintf(buf,"%d\n",LM93_VID_FROM_REG(data->vid[nr]));
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(vid1, S_IRUGO, show_vid, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(vid2, S_IRUGO, show_vid, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(cpu1_vid, S_IRUGO, show_vid, NULL, 1);
|
||||
|
||||
static ssize_t show_prochot(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -2431,8 +2431,8 @@ static struct attribute *lm93_attrs[] = {
|
||||
&sensor_dev_attr_pwm2_auto_spinup_time.dev_attr.attr,
|
||||
&dev_attr_pwm_auto_prochot_ramp.attr,
|
||||
&dev_attr_pwm_auto_vrdhot_ramp.attr,
|
||||
&sensor_dev_attr_vid1.dev_attr.attr,
|
||||
&sensor_dev_attr_vid2.dev_attr.attr,
|
||||
&sensor_dev_attr_cpu0_vid.dev_attr.attr,
|
||||
&sensor_dev_attr_cpu1_vid.dev_attr.attr,
|
||||
&sensor_dev_attr_prochot1.dev_attr.attr,
|
||||
&sensor_dev_attr_prochot2.dev_attr.attr,
|
||||
&sensor_dev_attr_prochot1_avg.dev_attr.attr,
|
||||
@ -2590,11 +2590,11 @@ static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
goto err_detach;
|
||||
|
||||
/* Register hwmon driver class */
|
||||
data->class_dev = hwmon_device_register(&client->dev);
|
||||
if ( !IS_ERR(data->class_dev))
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if ( !IS_ERR(data->hwmon_dev))
|
||||
return 0;
|
||||
|
||||
err = PTR_ERR(data->class_dev);
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
dev_err(&client->dev, "error registering hwmon device.\n");
|
||||
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
|
||||
err_detach:
|
||||
@ -2619,7 +2619,7 @@ static int lm93_detach_client(struct i2c_client *client)
|
||||
struct lm93_data *data = i2c_get_clientdata(client);
|
||||
int err = 0;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
|
@ -105,7 +105,7 @@ static struct i2c_driver max1619_driver = {
|
||||
|
||||
struct max1619_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
@ -293,9 +293,9 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -331,7 +331,7 @@ static int max1619_detach_client(struct i2c_client *client)
|
||||
struct max1619_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &max1619_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
|
@ -128,7 +128,7 @@ static struct i2c_driver max6650_driver = {
|
||||
struct max6650_data
|
||||
{
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
@ -523,11 +523,11 @@ static int max6650_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
if (err)
|
||||
goto err_detach;
|
||||
|
||||
data->class_dev = hwmon_device_register(&client->dev);
|
||||
if (!IS_ERR(data->class_dev))
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (!IS_ERR(data->hwmon_dev))
|
||||
return 0;
|
||||
|
||||
err = PTR_ERR(data->class_dev);
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
dev_err(&client->dev, "error registering hwmon device.\n");
|
||||
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
|
||||
err_detach:
|
||||
@ -543,7 +543,7 @@ static int max6650_detach_client(struct i2c_client *client)
|
||||
int err;
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
err = i2c_detach_client(client);
|
||||
if (!err)
|
||||
kfree(data);
|
||||
|
@ -180,7 +180,7 @@ static inline u8 PWM_TO_REG(int val, int inv)
|
||||
|
||||
struct pc87360_data {
|
||||
const char *name;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex lock;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
@ -500,7 +500,7 @@ 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);
|
||||
struct pc87360_data *data = dev_get_drvdata(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)
|
||||
@ -1054,9 +1054,9 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
|
||||
if ((err = device_create_file(dev, &dev_attr_name)))
|
||||
goto ERROR3;
|
||||
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto ERROR3;
|
||||
}
|
||||
return 0;
|
||||
@ -1083,7 +1083,7 @@ static int __devexit pc87360_remove(struct platform_device *pdev)
|
||||
struct pc87360_data *data = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
|
||||
device_remove_file(&pdev->dev, &dev_attr_name);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group);
|
||||
|
@ -42,7 +42,7 @@ static struct platform_device *pdev;
|
||||
device is using banked registers) and the register cache (needed to keep
|
||||
the data in the registers and the cache in sync at any time). */
|
||||
struct pc87427_data {
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex lock;
|
||||
int address[2];
|
||||
const char *name;
|
||||
@ -454,9 +454,9 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
@ -484,7 +484,7 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int i;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
device_remove_file(&pdev->dev, &dev_attr_name);
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (!(data->fan_enabled & (1 << i)))
|
||||
|
@ -163,7 +163,7 @@ static inline u8 DIV_TO_REG(int val)
|
||||
struct sis5595_data {
|
||||
unsigned short addr;
|
||||
const char *name;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex lock;
|
||||
|
||||
struct mutex update_lock;
|
||||
@ -517,7 +517,7 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
/* Check revision and pin registers to determine whether 4 or 5 voltages */
|
||||
pci_read_config_byte(s_bridge, PCI_REVISION_ID, &data->revision);
|
||||
data->revision = s_bridge->revision;
|
||||
/* 4 voltages, 1 temp */
|
||||
data->maxins = 3;
|
||||
if (data->revision >= REV2MIN) {
|
||||
@ -557,9 +557,9 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -580,7 +580,7 @@ static int __devexit sis5595_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sis5595_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
|
||||
|
||||
@ -739,11 +739,10 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
|
||||
int *i;
|
||||
|
||||
for (i = blacklist; *i != 0; i++) {
|
||||
struct pci_dev *dev;
|
||||
dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
|
||||
if (dev) {
|
||||
dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
|
||||
pci_dev_put(dev);
|
||||
struct pci_dev *d;
|
||||
if ((d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL))) {
|
||||
dev_err(&d->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
|
||||
pci_dev_put(d);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80};
|
||||
struct smsc47b397_data {
|
||||
unsigned short addr;
|
||||
const char *name;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex lock;
|
||||
|
||||
struct mutex update_lock;
|
||||
@ -222,7 +222,7 @@ static int __devexit smsc47b397_remove(struct platform_device *pdev)
|
||||
struct smsc47b397_data *data = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &smsc47b397_group);
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
release_region(res->start, SMSC_EXTENT);
|
||||
@ -272,9 +272,9 @@ static int __devinit smsc47b397_probe(struct platform_device *pdev)
|
||||
if ((err = sysfs_create_group(&dev->kobj, &smsc47b397_group)))
|
||||
goto error_free;
|
||||
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto error_remove;
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ struct smsc47m1_data {
|
||||
unsigned short addr;
|
||||
const char *name;
|
||||
enum chips type;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
struct mutex update_lock;
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
@ -553,7 +553,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_fan3_div.dev_attr)))
|
||||
goto error_remove_files;
|
||||
} else
|
||||
} else if (data->type == smsc47m2)
|
||||
dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
|
||||
|
||||
if (pwm1) {
|
||||
@ -580,7 +580,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_pwm3_enable.dev_attr)))
|
||||
goto error_remove_files;
|
||||
} else
|
||||
} else if (data->type == smsc47m2)
|
||||
dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n");
|
||||
|
||||
if ((err = device_create_file(dev, &dev_attr_alarms)))
|
||||
@ -588,9 +588,9 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
|
||||
if ((err = device_create_file(dev, &dev_attr_name)))
|
||||
goto error_remove_files;
|
||||
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto error_remove_files;
|
||||
}
|
||||
|
||||
@ -611,7 +611,7 @@ static int __devexit smsc47m1_remove(struct platform_device *pdev)
|
||||
struct smsc47m1_data *data = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
|
@ -97,7 +97,7 @@ static inline int TEMP_FROM_REG(s8 val)
|
||||
|
||||
struct smsc47m192_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
@ -334,7 +334,7 @@ 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 smsc47m192_data *data = smsc47m192_update_device(dev);
|
||||
struct smsc47m192_data *data = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%d\n", data->vrm);
|
||||
}
|
||||
|
||||
@ -553,9 +553,9 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -577,7 +577,7 @@ static int smsc47m192_detach_client(struct i2c_client *client)
|
||||
struct smsc47m192_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
|
||||
|
||||
|
@ -46,6 +46,11 @@ I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs "
|
||||
#define THMC50_REG_COMPANY_ID 0x3E
|
||||
#define THMC50_REG_DIE_CODE 0x3F
|
||||
#define THMC50_REG_ANALOG_OUT 0x19
|
||||
/*
|
||||
* The mirror status register cannot be used as
|
||||
* reading it does not clear alarms.
|
||||
*/
|
||||
#define THMC50_REG_INTR 0x41
|
||||
|
||||
const static u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
|
||||
const static u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
|
||||
@ -56,7 +61,7 @@ const static u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
|
||||
/* Each client has this additional data */
|
||||
struct thmc50_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
struct mutex update_lock;
|
||||
enum chips type;
|
||||
@ -69,6 +74,7 @@ struct thmc50_data {
|
||||
s8 temp_max[3];
|
||||
s8 temp_min[3];
|
||||
u8 analog_out;
|
||||
u8 alarms;
|
||||
};
|
||||
|
||||
static int thmc50_attach_adapter(struct i2c_adapter *adapter);
|
||||
@ -180,6 +186,15 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
struct thmc50_data *data = thmc50_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
|
||||
}
|
||||
|
||||
#define temp_reg(offset) \
|
||||
static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \
|
||||
NULL, offset - 1); \
|
||||
@ -192,6 +207,12 @@ temp_reg(1);
|
||||
temp_reg(2);
|
||||
temp_reg(3);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 7);
|
||||
static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_analog_out,
|
||||
set_analog_out, 0);
|
||||
static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0);
|
||||
@ -200,9 +221,12 @@ static struct attribute *thmc50_attributes[] = {
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm1.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm1_mode.dev_attr.attr,
|
||||
NULL
|
||||
@ -213,15 +237,17 @@ static const struct attribute_group thmc50_group = {
|
||||
};
|
||||
|
||||
/* for ADM1022 3rd temperature mode */
|
||||
static struct attribute *adm1022_attributes[] = {
|
||||
static struct attribute *temp3_attributes[] = {
|
||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adm1022_group = {
|
||||
.attrs = adm1022_attributes,
|
||||
static const struct attribute_group temp3_group = {
|
||||
.attrs = temp3_attributes,
|
||||
};
|
||||
|
||||
static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
@ -233,7 +259,7 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
struct thmc50_data *data;
|
||||
struct device *dev;
|
||||
int err = 0;
|
||||
const char *type_name = "";
|
||||
const char *type_name;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
pr_debug("thmc50: detect failed, "
|
||||
@ -283,13 +309,9 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
|
||||
goto exit_free;
|
||||
}
|
||||
pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
|
||||
type_name, (revision >> 4) - 0xc, revision & 0xf);
|
||||
data->type = kind;
|
||||
|
||||
if (kind == thmc50)
|
||||
type_name = "thmc50";
|
||||
else if (kind == adm1022) {
|
||||
if (kind == adm1022) {
|
||||
int id = i2c_adapter_id(client->adapter);
|
||||
int i;
|
||||
|
||||
@ -302,7 +324,11 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
data->has_temp3 = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
type_name = "thmc50";
|
||||
}
|
||||
pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
|
||||
type_name, (revision >> 4) - 0xc, revision & 0xf);
|
||||
|
||||
/* Fill in the remaining client fields & put it into the global list */
|
||||
strlcpy(client->name, type_name, I2C_NAME_SIZE);
|
||||
@ -319,23 +345,23 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
goto exit_detach;
|
||||
|
||||
/* Register ADM1022 sysfs hooks */
|
||||
if (data->type == adm1022)
|
||||
if (data->has_temp3)
|
||||
if ((err = sysfs_create_group(&client->dev.kobj,
|
||||
&adm1022_group)))
|
||||
&temp3_group)))
|
||||
goto exit_remove_sysfs_thmc50;
|
||||
|
||||
/* Register a new directory entry with module sensors */
|
||||
data->class_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_sysfs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_sysfs:
|
||||
if (data->type == adm1022)
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1022_group);
|
||||
if (data->has_temp3)
|
||||
sysfs_remove_group(&client->dev.kobj, &temp3_group);
|
||||
exit_remove_sysfs_thmc50:
|
||||
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
|
||||
exit_detach:
|
||||
@ -358,10 +384,10 @@ static int thmc50_detach_client(struct i2c_client *client)
|
||||
struct thmc50_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
|
||||
if (data->type == adm1022)
|
||||
sysfs_remove_group(&client->dev.kobj, &adm1022_group);
|
||||
if (data->has_temp3)
|
||||
sysfs_remove_group(&client->dev.kobj, &temp3_group);
|
||||
|
||||
if ((err = i2c_detach_client(client)))
|
||||
return err;
|
||||
@ -414,6 +440,8 @@ static struct thmc50_data *thmc50_update_device(struct device *dev)
|
||||
}
|
||||
data->analog_out =
|
||||
i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
|
||||
data->alarms =
|
||||
i2c_smbus_read_byte_data(client, THMC50_REG_INTR);
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
@ -294,7 +294,7 @@ static inline long TEMP_FROM_REG10(u16 val)
|
||||
struct via686a_data {
|
||||
unsigned short addr;
|
||||
const char *name;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
@ -627,9 +627,9 @@ static int __devinit via686a_probe(struct platform_device *pdev)
|
||||
if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group)))
|
||||
goto exit_free;
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -648,7 +648,7 @@ static int __devexit via686a_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct via686a_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
|
||||
|
||||
release_region(data->addr, VIA686A_EXTENT);
|
||||
|
@ -108,7 +108,7 @@ static const u8 bitalarmfan[] = {6, 7};
|
||||
struct vt1211_data {
|
||||
unsigned short addr;
|
||||
const char *name;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
@ -1191,9 +1191,9 @@ static int __devinit vt1211_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* Register device */
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
dev_err(dev, "Class registration failed (%d)\n", err);
|
||||
goto EXIT_DEV_REMOVE_SILENT;
|
||||
}
|
||||
@ -1217,7 +1217,7 @@ static int __devexit vt1211_remove(struct platform_device *pdev)
|
||||
struct vt1211_data *data = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
vt1211_remove_sysfs(pdev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(data);
|
||||
|
@ -148,7 +148,7 @@ struct vt8231_data {
|
||||
const char *name;
|
||||
|
||||
struct mutex update_lock;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
||||
@ -676,7 +676,7 @@ static struct pci_driver vt8231_pci_driver = {
|
||||
.probe = vt8231_pci_probe,
|
||||
};
|
||||
|
||||
int vt8231_probe(struct platform_device *pdev)
|
||||
static int vt8231_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct vt8231_data *data;
|
||||
@ -726,9 +726,9 @@ int vt8231_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
return 0;
|
||||
@ -756,7 +756,7 @@ static int __devexit vt8231_remove(struct platform_device *pdev)
|
||||
struct vt8231_data *data = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
|
||||
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
|
||||
|
@ -223,7 +223,7 @@ temp1_from_reg(s8 reg)
|
||||
}
|
||||
|
||||
static inline s8
|
||||
temp1_to_reg(int temp, int min, int max)
|
||||
temp1_to_reg(long temp, int min, int max)
|
||||
{
|
||||
if (temp <= min)
|
||||
return min / 1000;
|
||||
@ -256,7 +256,7 @@ struct w83627ehf_data {
|
||||
int addr; /* IO base of hw monitor block */
|
||||
const char *name;
|
||||
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex lock;
|
||||
|
||||
struct mutex update_lock;
|
||||
@ -805,7 +805,7 @@ store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct w83627ehf_data *data = dev_get_drvdata(dev); \
|
||||
u32 val = simple_strtoul(buf, NULL, 10); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
\
|
||||
mutex_lock(&data->update_lock); \
|
||||
data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
|
||||
@ -840,7 +840,7 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
struct w83627ehf_data *data = dev_get_drvdata(dev); \
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
|
||||
int nr = sensor_attr->index; \
|
||||
u32 val = simple_strtoul(buf, NULL, 10); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
\
|
||||
mutex_lock(&data->update_lock); \
|
||||
data->reg[nr] = LM75_TEMP_TO_REG(val); \
|
||||
@ -1384,9 +1384,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -1406,7 +1406,7 @@ static int __devexit w83627ehf_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct w83627ehf_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
w83627ehf_device_remove_files(&pdev->dev);
|
||||
release_region(data->addr, IOREGION_LENGTH);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -220,7 +220,7 @@ DIV_TO_REG(long val, enum chips type)
|
||||
the driver field to differentiate between I2C and ISA chips. */
|
||||
struct w83781d_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex lock;
|
||||
enum chips type;
|
||||
|
||||
@ -251,9 +251,7 @@ struct w83781d_data {
|
||||
u8 pwm2_enable; /* Boolean */
|
||||
u16 sens[3]; /* 782D/783S only.
|
||||
1 = pentium diode; 2 = 3904 diode;
|
||||
3000-5000 = thermistor beta.
|
||||
Default = 3435.
|
||||
Other Betas unimplemented */
|
||||
4 = thermistor */
|
||||
u8 vrm;
|
||||
};
|
||||
|
||||
@ -410,7 +408,7 @@ static ssize_t store_temp_##reg (struct device *dev, \
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
|
||||
struct w83781d_data *data = dev_get_drvdata(dev); \
|
||||
int nr = attr->index; \
|
||||
s32 val; \
|
||||
long val; \
|
||||
\
|
||||
val = simple_strtol(buf, NULL, 10); \
|
||||
\
|
||||
@ -456,7 +454,7 @@ 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)
|
||||
{
|
||||
struct w83781d_data *data = w83781d_update_device(dev);
|
||||
struct w83781d_data *data = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%ld\n", (long) data->vrm);
|
||||
}
|
||||
|
||||
@ -483,6 +481,39 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
|
||||
|
||||
static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct w83781d_data *data = w83781d_update_device(dev);
|
||||
int bitnr = to_sensor_dev_attr(attr)->index;
|
||||
return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
|
||||
}
|
||||
|
||||
/* The W83781D has a single alarm bit for temp2 and temp3 */
|
||||
static ssize_t show_temp3_alarm(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct w83781d_data *data = w83781d_update_device(dev);
|
||||
int bitnr = (data->type == w83781d) ? 5 : 13;
|
||||
return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
|
||||
}
|
||||
|
||||
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, 8);
|
||||
static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
|
||||
static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
|
||||
static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
|
||||
static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
|
||||
static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
|
||||
static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
|
||||
static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
|
||||
|
||||
static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct w83781d_data *data = w83781d_update_device(dev);
|
||||
@ -546,6 +577,100 @@ static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
|
||||
static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
|
||||
show_beep_enable, store_beep_enable);
|
||||
|
||||
static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct w83781d_data *data = w83781d_update_device(dev);
|
||||
int bitnr = to_sensor_dev_attr(attr)->index;
|
||||
return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
store_beep(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct w83781d_data *data = dev_get_drvdata(dev);
|
||||
int bitnr = to_sensor_dev_attr(attr)->index;
|
||||
unsigned long bit;
|
||||
u8 reg;
|
||||
|
||||
bit = simple_strtoul(buf, NULL, 10);
|
||||
if (bit & ~1)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (bit)
|
||||
data->beep_mask |= (1 << bitnr);
|
||||
else
|
||||
data->beep_mask &= ~(1 << bitnr);
|
||||
|
||||
if (bitnr < 8) {
|
||||
reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
|
||||
if (bit)
|
||||
reg |= (1 << bitnr);
|
||||
else
|
||||
reg &= ~(1 << bitnr);
|
||||
w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
|
||||
} else if (bitnr < 16) {
|
||||
reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
|
||||
if (bit)
|
||||
reg |= (1 << (bitnr - 8));
|
||||
else
|
||||
reg &= ~(1 << (bitnr - 8));
|
||||
w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
|
||||
} else {
|
||||
reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
|
||||
if (bit)
|
||||
reg |= (1 << (bitnr - 16));
|
||||
else
|
||||
reg &= ~(1 << (bitnr - 16));
|
||||
w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* The W83781D has a single beep bit for temp2 and temp3 */
|
||||
static ssize_t show_temp3_beep(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct w83781d_data *data = w83781d_update_device(dev);
|
||||
int bitnr = (data->type == w83781d) ? 5 : 13;
|
||||
return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 0);
|
||||
static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 1);
|
||||
static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 2);
|
||||
static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 3);
|
||||
static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 8);
|
||||
static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 9);
|
||||
static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 10);
|
||||
static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 16);
|
||||
static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 17);
|
||||
static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 6);
|
||||
static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 7);
|
||||
static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 11);
|
||||
static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
|
||||
show_beep, store_beep, 5);
|
||||
static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
|
||||
show_temp3_beep, store_beep, 13);
|
||||
|
||||
static ssize_t
|
||||
show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
|
||||
{
|
||||
@ -721,15 +846,19 @@ store_sensor(struct device *dev, struct device_attribute *da,
|
||||
tmp & ~BIT_SCFG2[nr]);
|
||||
data->sens[nr] = val;
|
||||
break;
|
||||
case W83781D_DEFAULT_BETA: /* thermistor */
|
||||
case W83781D_DEFAULT_BETA:
|
||||
dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
|
||||
"instead\n", W83781D_DEFAULT_BETA);
|
||||
/* fall through */
|
||||
case 4: /* thermistor */
|
||||
tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
|
||||
w83781d_write_value(data, W83781D_REG_SCFG1,
|
||||
tmp & ~BIT_SCFG1[nr]);
|
||||
data->sens[nr] = val;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n",
|
||||
(long) val, W83781D_DEFAULT_BETA);
|
||||
dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
|
||||
(long) val);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -875,17 +1004,23 @@ ERROR_SC_0:
|
||||
#define IN_UNIT_ATTRS(X) \
|
||||
&sensor_dev_attr_in##X##_input.dev_attr.attr, \
|
||||
&sensor_dev_attr_in##X##_min.dev_attr.attr, \
|
||||
&sensor_dev_attr_in##X##_max.dev_attr.attr
|
||||
&sensor_dev_attr_in##X##_max.dev_attr.attr, \
|
||||
&sensor_dev_attr_in##X##_alarm.dev_attr.attr, \
|
||||
&sensor_dev_attr_in##X##_beep.dev_attr.attr
|
||||
|
||||
#define FAN_UNIT_ATTRS(X) \
|
||||
&sensor_dev_attr_fan##X##_input.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan##X##_min.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan##X##_div.dev_attr.attr
|
||||
&sensor_dev_attr_fan##X##_div.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan##X##_alarm.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan##X##_beep.dev_attr.attr
|
||||
|
||||
#define TEMP_UNIT_ATTRS(X) \
|
||||
&sensor_dev_attr_temp##X##_input.dev_attr.attr, \
|
||||
&sensor_dev_attr_temp##X##_max.dev_attr.attr, \
|
||||
&sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr
|
||||
&sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr, \
|
||||
&sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \
|
||||
&sensor_dev_attr_temp##X##_beep.dev_attr.attr
|
||||
|
||||
static struct attribute* w83781d_attributes[] = {
|
||||
IN_UNIT_ATTRS(0),
|
||||
@ -944,7 +1079,11 @@ w83781d_create_files(struct device *dev, int kind, int is_isa)
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_in1_min.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_in1_max.dev_attr)))
|
||||
&sensor_dev_attr_in1_max.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_in1_alarm.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_in1_beep.dev_attr)))
|
||||
return err;
|
||||
}
|
||||
if (kind != as99127f && kind != w83781d && kind != w83783s) {
|
||||
@ -954,12 +1093,20 @@ w83781d_create_files(struct device *dev, int kind, int is_isa)
|
||||
&sensor_dev_attr_in7_min.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_in7_max.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_in7_alarm.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_in7_beep.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_in8_input.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_in8_min.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_in8_max.dev_attr)))
|
||||
&sensor_dev_attr_in8_max.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_in8_alarm.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_in8_beep.dev_attr)))
|
||||
return err;
|
||||
}
|
||||
if (kind != w83783s) {
|
||||
@ -968,8 +1115,19 @@ w83781d_create_files(struct device *dev, int kind, int is_isa)
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_temp3_max.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_temp3_max_hyst.dev_attr)))
|
||||
&sensor_dev_attr_temp3_max_hyst.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_temp3_alarm.dev_attr))
|
||||
|| (err = device_create_file(dev,
|
||||
&sensor_dev_attr_temp3_beep.dev_attr)))
|
||||
return err;
|
||||
|
||||
if (kind != w83781d)
|
||||
err = sysfs_chmod_file(&dev->kobj,
|
||||
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
|
||||
S_IRUGO | S_IWUSR);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (kind != w83781d && kind != as99127f) {
|
||||
@ -1156,9 +1314,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
if (err)
|
||||
goto ERROR4;
|
||||
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto ERROR4;
|
||||
}
|
||||
|
||||
@ -1192,7 +1350,7 @@ w83781d_detach_client(struct i2c_client *client)
|
||||
|
||||
/* main client */
|
||||
if (data) {
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &w83781d_group);
|
||||
sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt);
|
||||
}
|
||||
@ -1259,9 +1417,9 @@ w83781d_isa_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
goto exit_remove_files;
|
||||
|
||||
data->class_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -1283,7 +1441,7 @@ w83781d_isa_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct w83781d_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
|
||||
device_remove_file(&pdev->dev, &dev_attr_name);
|
||||
@ -1485,7 +1643,7 @@ w83781d_init_device(struct device *dev)
|
||||
tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
|
||||
for (i = 1; i <= 3; i++) {
|
||||
if (!(tmp & BIT_SCFG1[i - 1])) {
|
||||
data->sens[i - 1] = W83781D_DEFAULT_BETA;
|
||||
data->sens[i - 1] = 4;
|
||||
} else {
|
||||
if (w83781d_read_value
|
||||
(data,
|
||||
|
@ -2,7 +2,7 @@
|
||||
w83791d.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
|
||||
Copyright (C) 2006 Charles Spirakis <bezaur@gmail.com>
|
||||
Copyright (C) 2006-2007 Charles Spirakis <bezaur@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -247,7 +247,7 @@ static u8 div_to_reg(int nr, long val)
|
||||
|
||||
struct w83791d_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
@ -384,6 +384,85 @@ static struct sensor_device_attribute sda_in_max[] = {
|
||||
SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
|
||||
};
|
||||
|
||||
|
||||
static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr =
|
||||
to_sensor_dev_attr(attr);
|
||||
struct w83791d_data *data = w83791d_update_device(dev);
|
||||
int bitnr = sensor_attr->index;
|
||||
|
||||
return sprintf(buf, "%d\n", (data->beep_mask >> bitnr) & 1);
|
||||
}
|
||||
|
||||
static ssize_t store_beep(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr =
|
||||
to_sensor_dev_attr(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83791d_data *data = i2c_get_clientdata(client);
|
||||
int bitnr = sensor_attr->index;
|
||||
int bytenr = bitnr / 8;
|
||||
long val = simple_strtol(buf, NULL, 10) ? 1 : 0;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
data->beep_mask &= ~(0xff << (bytenr * 8));
|
||||
data->beep_mask |= w83791d_read(client, W83791D_REG_BEEP_CTRL[bytenr])
|
||||
<< (bytenr * 8);
|
||||
|
||||
data->beep_mask &= ~(1 << bitnr);
|
||||
data->beep_mask |= val << bitnr;
|
||||
|
||||
w83791d_write(client, W83791D_REG_BEEP_CTRL[bytenr],
|
||||
(data->beep_mask >> (bytenr * 8)) & 0xff);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr =
|
||||
to_sensor_dev_attr(attr);
|
||||
struct w83791d_data *data = w83791d_update_device(dev);
|
||||
int bitnr = sensor_attr->index;
|
||||
|
||||
return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
|
||||
}
|
||||
|
||||
/* Note: The bitmask for the beep enable/disable is different than
|
||||
the bitmask for the alarm. */
|
||||
static struct sensor_device_attribute sda_in_beep[] = {
|
||||
SENSOR_ATTR(in0_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 0),
|
||||
SENSOR_ATTR(in1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 13),
|
||||
SENSOR_ATTR(in2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 2),
|
||||
SENSOR_ATTR(in3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 3),
|
||||
SENSOR_ATTR(in4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 8),
|
||||
SENSOR_ATTR(in5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 9),
|
||||
SENSOR_ATTR(in6_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 10),
|
||||
SENSOR_ATTR(in7_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 16),
|
||||
SENSOR_ATTR(in8_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 17),
|
||||
SENSOR_ATTR(in9_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 14),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute sda_in_alarm[] = {
|
||||
SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
|
||||
SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
|
||||
SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
|
||||
SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
|
||||
SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
|
||||
SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9),
|
||||
SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10),
|
||||
SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19),
|
||||
SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20),
|
||||
SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 14),
|
||||
};
|
||||
|
||||
#define show_fan_reg(reg) \
|
||||
static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
@ -536,6 +615,22 @@ static struct sensor_device_attribute sda_fan_div[] = {
|
||||
show_fan_div, store_fan_div, 4),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute sda_fan_beep[] = {
|
||||
SENSOR_ATTR(fan1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 6),
|
||||
SENSOR_ATTR(fan2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 7),
|
||||
SENSOR_ATTR(fan3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 11),
|
||||
SENSOR_ATTR(fan4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 21),
|
||||
SENSOR_ATTR(fan5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 22),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute sda_fan_alarm[] = {
|
||||
SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
|
||||
SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
|
||||
SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
|
||||
SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21),
|
||||
SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22),
|
||||
};
|
||||
|
||||
/* read/write the temperature1, includes measured value and limits */
|
||||
static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
@ -618,6 +713,19 @@ static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
|
||||
show_temp23, store_temp23, 1, 2),
|
||||
};
|
||||
|
||||
/* Note: The bitmask for the beep enable/disable is different than
|
||||
the bitmask for the alarm. */
|
||||
static struct sensor_device_attribute sda_temp_beep[] = {
|
||||
SENSOR_ATTR(temp1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 4),
|
||||
SENSOR_ATTR(temp2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 5),
|
||||
SENSOR_ATTR(temp3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 1),
|
||||
};
|
||||
|
||||
static struct sensor_device_attribute sda_temp_alarm[] = {
|
||||
SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
|
||||
SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
|
||||
SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
|
||||
};
|
||||
|
||||
/* get reatime status of all sensors items: voltage, temp, fan */
|
||||
static ssize_t show_alarms_reg(struct device *dev,
|
||||
@ -724,7 +832,7 @@ 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)
|
||||
{
|
||||
struct w83791d_data *data = w83791d_update_device(dev);
|
||||
struct w83791d_data *data = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%d\n", data->vrm);
|
||||
}
|
||||
|
||||
@ -749,17 +857,23 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
|
||||
#define IN_UNIT_ATTRS(X) \
|
||||
&sda_in_input[X].dev_attr.attr, \
|
||||
&sda_in_min[X].dev_attr.attr, \
|
||||
&sda_in_max[X].dev_attr.attr
|
||||
&sda_in_max[X].dev_attr.attr, \
|
||||
&sda_in_beep[X].dev_attr.attr, \
|
||||
&sda_in_alarm[X].dev_attr.attr
|
||||
|
||||
#define FAN_UNIT_ATTRS(X) \
|
||||
&sda_fan_input[X].dev_attr.attr, \
|
||||
&sda_fan_min[X].dev_attr.attr, \
|
||||
&sda_fan_div[X].dev_attr.attr
|
||||
&sda_fan_div[X].dev_attr.attr, \
|
||||
&sda_fan_beep[X].dev_attr.attr, \
|
||||
&sda_fan_alarm[X].dev_attr.attr
|
||||
|
||||
#define TEMP_UNIT_ATTRS(X) \
|
||||
&sda_temp_input[X].dev_attr.attr, \
|
||||
&sda_temp_max[X].dev_attr.attr, \
|
||||
&sda_temp_max_hyst[X].dev_attr.attr
|
||||
&sda_temp_max_hyst[X].dev_attr.attr, \
|
||||
&sda_temp_beep[X].dev_attr.attr, \
|
||||
&sda_temp_alarm[X].dev_attr.attr
|
||||
|
||||
static struct attribute *w83791d_attributes[] = {
|
||||
IN_UNIT_ATTRS(0),
|
||||
@ -1017,9 +1131,9 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
goto error3;
|
||||
|
||||
/* Everything is ready, now register the working device */
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto error4;
|
||||
}
|
||||
|
||||
@ -1051,7 +1165,7 @@ static int w83791d_detach_client(struct i2c_client *client)
|
||||
|
||||
/* main client */
|
||||
if (data) {
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &w83791d_group);
|
||||
}
|
||||
|
||||
|
@ -267,7 +267,7 @@ DIV_TO_REG(long val)
|
||||
|
||||
struct w83792d_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
enum chips type;
|
||||
|
||||
struct mutex update_lock;
|
||||
@ -540,6 +540,15 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
return sprintf(buf, "%d\n", data->alarms);
|
||||
}
|
||||
|
||||
static ssize_t show_alarm(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 w83792d_data *data = w83792d_update_device(dev);
|
||||
return sprintf(buf, "%d\n", (data->alarms >> nr) & 1);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_pwm(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -1015,6 +1024,25 @@ static SENSOR_DEVICE_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR,
|
||||
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 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(temp1_alarm, S_IRUGO, show_alarm, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 7);
|
||||
static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 8);
|
||||
static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 9);
|
||||
static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 10);
|
||||
static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 11);
|
||||
static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 12);
|
||||
static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_alarm, NULL, 15);
|
||||
static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19);
|
||||
static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20);
|
||||
static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21);
|
||||
static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22);
|
||||
static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 23);
|
||||
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);
|
||||
@ -1123,26 +1151,30 @@ static SENSOR_DEVICE_ATTR(fan6_div, S_IWUSR | S_IRUGO,
|
||||
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] = {
|
||||
static struct attribute *w83792d_attributes_fan[4][5] = {
|
||||
{
|
||||
&sensor_dev_attr_fan4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan4_min.dev_attr.attr,
|
||||
&sensor_dev_attr_fan4_div.dev_attr.attr,
|
||||
&sensor_dev_attr_fan4_alarm.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,
|
||||
&sensor_dev_attr_fan5_alarm.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,
|
||||
&sensor_dev_attr_fan6_alarm.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,
|
||||
&sensor_dev_attr_fan7_alarm.dev_attr.attr,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
@ -1182,6 +1214,15 @@ static struct attribute *w83792d_attributes[] = {
|
||||
&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_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,
|
||||
&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,
|
||||
@ -1191,6 +1232,9 @@ static struct attribute *w83792d_attributes[] = {
|
||||
&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_temp1_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_alarm.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,
|
||||
@ -1233,12 +1277,15 @@ static struct attribute *w83792d_attributes[] = {
|
||||
&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_fan1_alarm.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_fan2_alarm.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_fan3_alarm.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -1396,9 +1443,9 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
&w83792d_group_fan[3])))
|
||||
goto exit_remove_files;
|
||||
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_files;
|
||||
}
|
||||
|
||||
@ -1433,7 +1480,7 @@ w83792d_detach_client(struct i2c_client *client)
|
||||
|
||||
/* main client */
|
||||
if (data) {
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_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,
|
||||
|
@ -179,7 +179,7 @@ static inline s8 TEMP_TO_REG(long val, s8 min, s8 max)
|
||||
struct w83793_data {
|
||||
struct i2c_client client;
|
||||
struct i2c_client *lm75[2];
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
@ -1075,7 +1075,7 @@ static int w83793_detach_client(struct i2c_client *client)
|
||||
|
||||
/* main client */
|
||||
if (data) {
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
|
||||
device_remove_file(dev,
|
||||
@ -1434,9 +1434,9 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
}
|
||||
}
|
||||
|
||||
data->class_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->class_dev)) {
|
||||
err = PTR_ERR(data->class_dev);
|
||||
data->hwmon_dev = hwmon_device_register(dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ static struct i2c_driver w83l785ts_driver = {
|
||||
|
||||
struct w83l785ts_data {
|
||||
struct i2c_client client;
|
||||
struct class_device *class_dev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
@ -247,9 +247,9 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
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);
|
||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
@ -272,7 +272,7 @@ static int w83l785ts_detach_client(struct i2c_client *client)
|
||||
struct w83l785ts_data *data = i2c_get_clientdata(client);
|
||||
int err;
|
||||
|
||||
hwmon_device_unregister(data->class_dev);
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
device_remove_file(&client->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_remove_file(&client->dev,
|
||||
|
@ -83,7 +83,7 @@ struct ads7846 {
|
||||
|
||||
#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
|
||||
struct attribute_group *attr_group;
|
||||
struct class_device *hwmon;
|
||||
struct device *hwmon;
|
||||
#endif
|
||||
|
||||
u16 model;
|
||||
@ -369,7 +369,7 @@ static struct attribute_group ads7845_attr_group = {
|
||||
|
||||
static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
|
||||
{
|
||||
struct class_device *hwmon;
|
||||
struct device *hwmon;
|
||||
int err;
|
||||
|
||||
/* hwmon sensors need a reference voltage */
|
||||
|
@ -517,7 +517,7 @@ static char *next_cmd(char **cmds)
|
||||
****************************************************************************/
|
||||
|
||||
static struct platform_device *tpacpi_pdev;
|
||||
static struct class_device *tpacpi_hwmon;
|
||||
static struct device *tpacpi_hwmon;
|
||||
static struct input_dev *tpacpi_inputdev;
|
||||
|
||||
|
||||
|
@ -171,7 +171,7 @@ static int parse_strtoul(const char *buf, unsigned long max,
|
||||
|
||||
/* Device model */
|
||||
static struct platform_device *tpacpi_pdev;
|
||||
static struct class_device *tpacpi_hwmon;
|
||||
static struct device *tpacpi_hwmon;
|
||||
static struct platform_driver tpacpi_pdriver;
|
||||
static struct input_dev *tpacpi_inputdev;
|
||||
static int tpacpi_create_driver_attributes(struct device_driver *drv);
|
||||
|
@ -16,9 +16,9 @@
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
struct class_device *hwmon_device_register(struct device *dev);
|
||||
struct device *hwmon_device_register(struct device *dev);
|
||||
|
||||
void hwmon_device_unregister(struct class_device *cdev);
|
||||
void hwmon_device_unregister(struct device *dev);
|
||||
|
||||
/* Scale user input to sensible values */
|
||||
static inline int SENSORS_LIMIT(long value, long low, long high)
|
||||
|
Loading…
Reference in New Issue
Block a user