Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/i2c-2.6
This commit is contained in:
commit
4e93d3e885
|
@ -83,3 +83,13 @@ Why: Deprecated in favour of the new ioctl-based rawiso interface, which is
|
|||
more efficient. You should really be using libraw1394 for raw1394
|
||||
access anyway.
|
||||
Who: Jody McIntyre <scjody@steamballoon.com>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: i2c sysfs name change: in1_ref, vid deprecated in favour of cpu0_vid
|
||||
When: November 2005
|
||||
Files: drivers/i2c/chips/adm1025.c, drivers/i2c/chips/adm1026.c
|
||||
Why: Match the other drivers' name for the same function, duplicate names
|
||||
will be available until removal of old names.
|
||||
Who: Grant Coady <gcoady@gmail.com>
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ I suspect that this driver could be made to work for the following SiS
|
|||
chipsets as well: 635, and 635T. If anyone owns a board with those chips
|
||||
AND is willing to risk crashing & burning an otherwise well-behaved kernel
|
||||
in the name of progress... please contact me at <mhoffman@lightlink.com> or
|
||||
via the project's mailing list: <sensors@stimpy.netroedge.com>. Please
|
||||
via the project's mailing list: <lm-sensors@lm-sensors.org>. Please
|
||||
send bug reports and/or success stories as well.
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
Kernel driver adm1021
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Analog Devices ADM1021
|
||||
Prefix: 'adm1021'
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
* Analog Devices ADM1021A/ADM1023
|
||||
Prefix: 'adm1023'
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
* Genesys Logic GL523SM
|
||||
Prefix: 'gl523sm'
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
Datasheet:
|
||||
* Intel Xeon Processor
|
||||
Prefix: - any other - may require 'force_adm1021' parameter
|
||||
Addresses scanned: none
|
||||
Datasheet: Publicly available at Intel website
|
||||
* Maxim MAX1617
|
||||
Prefix: 'max1617'
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
* Maxim MAX1617A
|
||||
Prefix: 'max1617a'
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
* National Semiconductor LM84
|
||||
Prefix: 'lm84'
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
* Philips NE1617
|
||||
Prefix: 'max1617' (probably detected as a max1617)
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
Datasheet: Publicly available at the Philips website
|
||||
* Philips NE1617A
|
||||
Prefix: 'max1617' (probably detected as a max1617)
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
Datasheet: Publicly available at the Philips website
|
||||
* TI THMC10
|
||||
Prefix: 'thmc10'
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
Datasheet: Publicly available at the TI website
|
||||
* Onsemi MC1066
|
||||
Prefix: 'mc1066'
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
Datasheet: Publicly available at the Onsemi website
|
||||
|
||||
|
||||
Authors:
|
||||
Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>
|
||||
|
||||
Module Parameters
|
||||
-----------------
|
||||
|
||||
* read_only: int
|
||||
Don't set any values, read only mode
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The chips supported by this driver are very similar. The Maxim MAX1617 is
|
||||
the oldest; it has the problem that it is not very well detectable. The
|
||||
MAX1617A solves that. The ADM1021 is a straight clone of the MAX1617A.
|
||||
Ditto for the THMC10. From here on, we will refer to all these chips as
|
||||
ADM1021-clones.
|
||||
|
||||
The ADM1021 and MAX1617A reports a die code, which is a sort of revision
|
||||
code. This can help us pinpoint problems; it is not very useful
|
||||
otherwise.
|
||||
|
||||
ADM1021-clones implement two temperature sensors. One of them is internal,
|
||||
and measures the temperature of the chip itself; the other is external and
|
||||
is realised in the form of a transistor-like device. A special alarm
|
||||
indicates whether the remote sensor is connected.
|
||||
|
||||
Each sensor has its own low and high limits. When they are crossed, the
|
||||
corresponding alarm is set and remains on as long as the temperature stays
|
||||
out of range. Temperatures are measured in degrees Celsius. Measurements
|
||||
are possible between -65 and +127 degrees, with a resolution of one degree.
|
||||
|
||||
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!
|
||||
|
||||
This driver only updates its values each 1.5 seconds; reading it more often
|
||||
will do no harm, but will return 'old' values. It is possible to make
|
||||
ADM1021-clones do faster measurements, but there is really no good reason
|
||||
for that.
|
||||
|
||||
Xeon support
|
||||
------------
|
||||
|
||||
Some Xeon processors have real max1617, adm1021, or compatible chips
|
||||
within them, with two temperature sensors.
|
||||
|
||||
Other Xeons have chips with only one sensor.
|
||||
|
||||
If you have a Xeon, and the adm1021 module loads, and both temperatures
|
||||
appear valid, then things are good.
|
||||
|
||||
If the adm1021 module doesn't load, you should try this:
|
||||
modprobe adm1021 force_adm1021=BUS,ADDRESS
|
||||
ADDRESS can only be 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e.
|
||||
|
||||
If you have dual Xeons you may have appear to have two separate
|
||||
adm1021-compatible chips, or two single-temperature sensors, at distinct
|
||||
addresses.
|
|
@ -0,0 +1,51 @@
|
|||
Kernel driver adm1025
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Analog Devices ADM1025, ADM1025A
|
||||
Prefix: 'adm1025'
|
||||
Addresses scanned: I2C 0x2c - 0x2e
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
* Philips NE1619
|
||||
Prefix: 'ne1619'
|
||||
Addresses scanned: I2C 0x2c - 0x2d
|
||||
Datasheet: Publicly available at the Philips website
|
||||
|
||||
The NE1619 presents some differences with the original ADM1025:
|
||||
* Only two possible addresses (0x2c - 0x2d).
|
||||
* No temperature offset register, but we don't use it anyway.
|
||||
* No INT mode for pin 16. We don't play with it anyway.
|
||||
|
||||
Authors:
|
||||
Chen-Yuan Wu <gwu@esoft.com>,
|
||||
Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
(This is from Analog Devices.) The ADM1025 is a complete system hardware
|
||||
monitor for microprocessor-based systems, providing measurement and limit
|
||||
comparison of various system parameters. Five voltage measurement inputs
|
||||
are provided, for monitoring +2.5V, +3.3V, +5V and +12V power supplies and
|
||||
the processor core voltage. The ADM1025 can monitor a sixth power-supply
|
||||
voltage by measuring its own VCC. One input (two pins) is dedicated to a
|
||||
remote temperature-sensing diode and an on-chip temperature sensor allows
|
||||
ambient temperature to be monitored.
|
||||
|
||||
One specificity of this chip is that the pin 11 can be hardwired in two
|
||||
different manners. It can act as the +12V power-supply voltage analog
|
||||
input, or as the a fifth digital entry for the VID reading (bit 4). It's
|
||||
kind of strange since both are useful, and the reason for designing the
|
||||
chip that way is obscure at least to me. The bit 5 of the configuration
|
||||
register can be used to define how the chip is hardwired. Please note that
|
||||
it is not a choice you have to make as the user. The choice was already
|
||||
made by your motherboard's maker. If the configuration bit isn't set
|
||||
properly, you'll have a wrong +12V reading or a wrong VID reading. The way
|
||||
the driver handles that is to preserve this bit through the initialization
|
||||
process, assuming that the BIOS set it up properly beforehand. If it turns
|
||||
out not to be true in some cases, we'll provide a module parameter to force
|
||||
modes.
|
||||
|
||||
This driver also supports the ADM1025A, which differs from the ADM1025
|
||||
only in that it has "open-drain VID inputs while the ADM1025 has on-chip
|
||||
100k pull-ups on the VID inputs". It doesn't make any difference for us.
|
|
@ -0,0 +1,93 @@
|
|||
Kernel driver adm1026
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Analog Devices ADM1026
|
||||
Prefix: 'adm1026'
|
||||
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
http://www.analog.com/en/prod/0,,766_825_ADM1026,00.html
|
||||
|
||||
Authors:
|
||||
Philip Pokorny <ppokorny@penguincomputing.com> for Penguin Computing
|
||||
Justin Thiessen <jthiessen@penguincomputing.com>
|
||||
|
||||
Module Parameters
|
||||
-----------------
|
||||
|
||||
* gpio_input: int array (min = 1, max = 17)
|
||||
List of GPIO pins (0-16) to program as inputs
|
||||
* gpio_output: int array (min = 1, max = 17)
|
||||
List of GPIO pins (0-16) to program as outputs
|
||||
* gpio_inverted: int array (min = 1, max = 17)
|
||||
List of GPIO pins (0-16) to program as inverted
|
||||
* gpio_normal: int array (min = 1, max = 17)
|
||||
List of GPIO pins (0-16) to program as normal/non-inverted
|
||||
* gpio_fan: int array (min = 1, max = 8)
|
||||
List of GPIO pins (0-7) to program as fan tachs
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the Analog Devices ADM1026. Analog
|
||||
Devices calls it a "complete thermal system management controller."
|
||||
|
||||
The ADM1026 implements three (3) temperature sensors, 17 voltage sensors,
|
||||
16 general purpose digital I/O lines, eight (8) fan speed sensors (8-bit),
|
||||
an analog output and a PWM output along with limit, alarm and mask bits for
|
||||
all of the above. There is even 8k bytes of EEPROM memory on chip.
|
||||
|
||||
Temperatures are measured in degrees Celsius. There are two external
|
||||
sensor inputs and one internal sensor. Each sensor has a high and low
|
||||
limit. If the limit is exceeded, an interrupt (#SMBALERT) can be
|
||||
generated. The interrupts can be masked. In addition, there are over-temp
|
||||
limits for each sensor. If this limit is exceeded, the #THERM output will
|
||||
be asserted. The current temperature and limits have a resolution of 1
|
||||
degree.
|
||||
|
||||
Fan rotation speeds are reported in RPM (rotations per minute) but measured
|
||||
in counts of a 22.5kHz internal clock. Each fan has a high limit which
|
||||
corresponds to a minimum fan speed. If the limit is exceeded, an interrupt
|
||||
can be generated. Each fan can be programmed to divide the reference clock
|
||||
by 1, 2, 4 or 8. Not all RPM values can accurately be represented, so some
|
||||
rounding is done. With a divider of 8, the slowest measurable speed of a
|
||||
two pulse per revolution fan is 661 RPM.
|
||||
|
||||
There are 17 voltage sensors. An alarm is triggered if the voltage has
|
||||
crossed a programmable minimum or maximum limit. Note that minimum in this
|
||||
case always means 'closest to zero'; this is important for negative voltage
|
||||
measurements. Several inputs have integrated attenuators so they can measure
|
||||
higher voltages directly. 3.3V, 5V, 12V, -12V and battery voltage all have
|
||||
dedicated inputs. There are several inputs scaled to 0-3V full-scale range
|
||||
for SCSI terminator power. The remaining inputs are not scaled and have
|
||||
a 0-2.5V full-scale range. A 2.5V or 1.82V reference voltage is provided
|
||||
for negative voltage measurements.
|
||||
|
||||
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 hardware
|
||||
registers are read whenever any data is read (unless it is less than 2.0
|
||||
seconds since the last update). This means that you can easily miss
|
||||
once-only alarms.
|
||||
|
||||
The ADM1026 measures continuously. Analog inputs are measured about 4
|
||||
times a second. Fan speed measurement time depends on fan speed and
|
||||
divisor. It can take as long as 1.5 seconds to measure all fan speeds.
|
||||
|
||||
The ADM1026 has the ability to automatically control fan speed based on the
|
||||
temperature sensor inputs. Both the PWM output and the DAC output can be
|
||||
used to control fan speed. Usually only one of these two outputs will be
|
||||
used. Write the minimum PWM or DAC value to the appropriate control
|
||||
register. Then set the low temperature limit in the tmin values for each
|
||||
temperature sensor. The range of control is fixed at 20 °C, and the
|
||||
largest difference between current and tmin of the temperature sensors sets
|
||||
the control output. See the datasheet for several example circuits for
|
||||
controlling fan speed with the PWM and DAC outputs. The fan speed sensors
|
||||
do not have PWM compensation, so it is probably best to control the fan
|
||||
voltage from the power lead rather than on the ground lead.
|
||||
|
||||
The datasheet shows an example application with VID signals attached to
|
||||
GPIO lines. Unfortunately, the chip may not be connected to the VID lines
|
||||
in this way. The driver assumes that the chips *is* connected this way to
|
||||
get a VID voltage.
|
|
@ -0,0 +1,35 @@
|
|||
Kernel driver adm1031
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Analog Devices ADM1030
|
||||
Prefix: 'adm1030'
|
||||
Addresses scanned: I2C 0x2c to 0x2e
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
http://products.analog.com/products/info.asp?product=ADM1030
|
||||
|
||||
* Analog Devices ADM1031
|
||||
Prefix: 'adm1031'
|
||||
Addresses scanned: I2C 0x2c to 0x2e
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
http://products.analog.com/products/info.asp?product=ADM1031
|
||||
|
||||
Authors:
|
||||
Alexandre d'Alton <alex@alexdalton.org>
|
||||
Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The ADM1030 and ADM1031 are digital temperature sensors and fan controllers.
|
||||
They sense their own temperature as well as the temperature of up to one
|
||||
(ADM1030) or two (ADM1031) external diodes.
|
||||
|
||||
All temperature values are given in degrees Celsius. Resolution is 0.5
|
||||
degree for the local temperature, 0.125 degree for the remote temperatures.
|
||||
|
||||
Each temperature channel has its own high and low limits, plus a critical
|
||||
limit.
|
||||
|
||||
The ADM1030 monitors a single fan speed, while the ADM1031 monitors up to
|
||||
two. Each fan channel has its own low speed limit.
|
|
@ -0,0 +1,177 @@
|
|||
Kernel driver adm9240
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Analog Devices ADM9240
|
||||
Prefix: 'adm9240'
|
||||
Addresses scanned: I2C 0x2c - 0x2f
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
http://www.analog.com/UploadedFiles/Data_Sheets/79857778ADM9240_0.pdf
|
||||
|
||||
* Dallas Semiconductor DS1780
|
||||
Prefix: 'ds1780'
|
||||
Addresses scanned: I2C 0x2c - 0x2f
|
||||
Datasheet: Publicly available at the Dallas Semiconductor (Maxim) website
|
||||
http://pdfserv.maxim-ic.com/en/ds/DS1780.pdf
|
||||
|
||||
* National Semiconductor LM81
|
||||
Prefix: 'lm81'
|
||||
Addresses scanned: I2C 0x2c - 0x2f
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/ds.cgi/LM/LM81.pdf
|
||||
|
||||
Authors:
|
||||
Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>,
|
||||
Michiel Rook <michiel@grendelproject.nl>,
|
||||
Grant Coady <gcoady@gmail.com> with guidance
|
||||
from Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Interface
|
||||
---------
|
||||
The I2C addresses listed above assume BIOS has not changed the
|
||||
chip MSB 5-bit address. Each chip reports a unique manufacturer
|
||||
identification code as well as the chip revision/stepping level.
|
||||
|
||||
Description
|
||||
-----------
|
||||
[From ADM9240] The ADM9240 is a complete system hardware monitor for
|
||||
microprocessor-based systems, providing measurement and limit comparison
|
||||
of up to four power supplies and two processor core voltages, plus
|
||||
temperature, two fan speeds and chassis intrusion. Measured values can
|
||||
be read out via an I2C-compatible serial System Management Bus, and values
|
||||
for limit comparisons can be programmed in over the same serial bus. The
|
||||
high speed successive approximation ADC allows frequent sampling of all
|
||||
analog channels to ensure a fast interrupt response to any out-of-limit
|
||||
measurement.
|
||||
|
||||
The ADM9240, DS1780 and LM81 are register compatible, the following
|
||||
details are common to the three chips. Chip differences are described
|
||||
after this section.
|
||||
|
||||
|
||||
Measurements
|
||||
------------
|
||||
The measurement cycle
|
||||
|
||||
The adm9240 driver will take a measurement reading no faster than once
|
||||
each two seconds. User-space may read sysfs interface faster than the
|
||||
measurement update rate and will receive cached data from the most
|
||||
recent measurement.
|
||||
|
||||
ADM9240 has a very fast 320us temperature and voltage measurement cycle
|
||||
with independent fan speed measurement cycles counting alternating rising
|
||||
edges of the fan tacho inputs.
|
||||
|
||||
DS1780 measurement cycle is about once per second including fan speed.
|
||||
|
||||
LM81 measurement cycle is about once per 400ms including fan speed.
|
||||
The LM81 12-bit extended temperature measurement mode is not supported.
|
||||
|
||||
Temperature
|
||||
-----------
|
||||
On chip temperature is reported as degrees Celsius as 9-bit signed data
|
||||
with resolution of 0.5 degrees Celsius. High and low temperature limits
|
||||
are 8-bit signed data with resolution of one degree Celsius.
|
||||
|
||||
Temperature alarm is asserted once the temperature exceeds the high limit,
|
||||
and is cleared when the temperature falls below the temp1_max_hyst value.
|
||||
|
||||
Fan Speed
|
||||
---------
|
||||
Two fan tacho inputs are provided, the ADM9240 gates an internal 22.5kHz
|
||||
clock via a divider to an 8-bit counter. Fan speed (rpm) is calculated by:
|
||||
|
||||
rpm = (22500 * 60) / (count * divider)
|
||||
|
||||
Automatic fan clock divider
|
||||
|
||||
* User sets 0 to fan_min limit
|
||||
- low speed alarm is disabled
|
||||
- fan clock divider not changed
|
||||
- auto fan clock adjuster enabled for valid fan speed reading
|
||||
|
||||
* User sets fan_min limit too low
|
||||
- low speed alarm is enabled
|
||||
- fan clock divider set to max
|
||||
- fan_min set to register value 254 which corresponds
|
||||
to 664 rpm on adm9240
|
||||
- low speed alarm will be asserted if fan speed is
|
||||
less than minimum measurable speed
|
||||
- auto fan clock adjuster disabled
|
||||
|
||||
* User sets reasonable fan speed
|
||||
- low speed alarm is enabled
|
||||
- fan clock divider set to suit fan_min
|
||||
- auto fan clock adjuster enabled: adjusts fan_min
|
||||
|
||||
* User sets unreasonably high low fan speed limit
|
||||
- resolution of the low speed limit may be reduced
|
||||
- alarm will be asserted
|
||||
- auto fan clock adjuster enabled: adjusts fan_min
|
||||
|
||||
* fan speed may be displayed as zero until the auto fan clock divider
|
||||
adjuster brings fan speed clock divider back into chip measurement
|
||||
range, this will occur within a few measurement cycles.
|
||||
|
||||
Analog Output
|
||||
-------------
|
||||
An analog output provides a 0 to 1.25 volt signal intended for an external
|
||||
fan speed amplifier circuit. The analog output is set to maximum value on
|
||||
power up or reset. This doesn't do much on the test Intel SE440BX-2.
|
||||
|
||||
Voltage Monitor
|
||||
|
||||
Voltage (IN) measurement is internally scaled:
|
||||
|
||||
nr label nominal maximum resolution
|
||||
mV mV mV
|
||||
0 +2.5V 2500 3320 13.0
|
||||
1 Vccp1 2700 3600 14.1
|
||||
2 +3.3V 3300 4380 17.2
|
||||
3 +5V 5000 6640 26.0
|
||||
4 +12V 12000 15940 62.5
|
||||
5 Vccp2 2700 3600 14.1
|
||||
|
||||
The reading is an unsigned 8-bit value, nominal voltage measurement is
|
||||
represented by a reading of 192, being 3/4 of the measurement range.
|
||||
|
||||
An alarm is asserted for any voltage going below or above the set limits.
|
||||
|
||||
The driver reports and accepts voltage limits scaled to the above table.
|
||||
|
||||
VID Monitor
|
||||
-----------
|
||||
The chip has five inputs to read the 5-bit VID and reports the mV value
|
||||
based on detected CPU type.
|
||||
|
||||
Chassis Intrusion
|
||||
-----------------
|
||||
An alarm is asserted when the CI pin goes active high. The ADM9240
|
||||
Datasheet has an example of an external temperature sensor driving
|
||||
this pin. On an Intel SE440BX-2 the Chassis Intrusion header is
|
||||
connected to a normally open switch.
|
||||
|
||||
The ADM9240 provides an internal open drain on this line, and may output
|
||||
a 20 ms active low pulse to reset an external Chassis Intrusion latch.
|
||||
|
||||
Clear the CI latch by writing value 1 to the sysfs chassis_clear file.
|
||||
|
||||
Alarm flags reported as 16-bit word
|
||||
|
||||
bit label comment
|
||||
--- ------------- --------------------------
|
||||
0 +2.5 V_Error high or low limit exceeded
|
||||
1 VCCP_Error high or low limit exceeded
|
||||
2 +3.3 V_Error high or low limit exceeded
|
||||
3 +5 V_Error high or low limit exceeded
|
||||
4 Temp_Error temperature error
|
||||
6 FAN1_Error fan low limit exceeded
|
||||
7 FAN2_Error fan low limit exceeded
|
||||
8 +12 V_Error high or low limit exceeded
|
||||
9 VCCP2_Error high or low limit exceeded
|
||||
12 Chassis_Error CI pin went high
|
||||
|
||||
Remaining bits are reserved and thus undefined. It is important to note
|
||||
that alarm bits may be cleared on read, user-space may latch alarms and
|
||||
provide the end-user with a method to clear alarm memory.
|
|
@ -0,0 +1,72 @@
|
|||
Kernel driver asb100
|
||||
====================
|
||||
|
||||
Supported Chips:
|
||||
* Asus ASB100 and ASB100-A "Bach"
|
||||
Prefix: 'asb100'
|
||||
Addresses scanned: I2C 0x2d
|
||||
Datasheet: none released
|
||||
|
||||
Author: Mark M. Hoffman <mhoffman@lightlink.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the Asus ASB100 and ASB100-A "Bach".
|
||||
These are custom ASICs available only on Asus mainboards. Asus refuses to
|
||||
supply a datasheet for these chips. Thanks go to many people who helped
|
||||
investigate their hardware, including:
|
||||
|
||||
Vitaly V. Bursov
|
||||
Alexander van Kaam (author of MBM for Windows)
|
||||
Bertrik Sikken
|
||||
|
||||
The ASB100 implements seven voltage sensors, three fan rotation speed
|
||||
sensors, four temperature sensors, VID lines and alarms. In addition to
|
||||
these, the ASB100-A also implements a single PWM controller for fans 2 and
|
||||
3 (i.e. one setting controls both.) If you have a plain ASB100, the PWM
|
||||
controller will simply not work (or maybe it will for you... it doesn't for
|
||||
me).
|
||||
|
||||
Temperatures are measured and reported in degrees Celsius.
|
||||
|
||||
Fan speeds are reported in RPM (rotations per minute). An alarm is
|
||||
triggered if the rotation speed has dropped below a programmable limit.
|
||||
|
||||
Voltage sensors (also known as IN sensors) report values in volts.
|
||||
|
||||
The VID lines encode the core voltage value: the voltage level your
|
||||
processor should work with. This is hardcoded by the mainboard and/or
|
||||
processor itself. It is a value in volts.
|
||||
|
||||
Alarms: (TODO question marks indicate may or may not work)
|
||||
|
||||
0x0001 => in0 (?)
|
||||
0x0002 => in1 (?)
|
||||
0x0004 => in2
|
||||
0x0008 => in3
|
||||
0x0010 => temp1 (1)
|
||||
0x0020 => temp2
|
||||
0x0040 => fan1
|
||||
0x0080 => fan2
|
||||
0x0100 => in4
|
||||
0x0200 => in5 (?) (2)
|
||||
0x0400 => in6 (?) (2)
|
||||
0x0800 => fan3
|
||||
0x1000 => chassis switch
|
||||
0x2000 => temp3
|
||||
|
||||
Alarm Notes:
|
||||
|
||||
(1) This alarm will only trigger if the hysteresis value is 127C.
|
||||
I.e. it behaves the same as w83781d.
|
||||
|
||||
(2) The min and max registers for these values appear to
|
||||
be read-only or otherwise stuck at 0x00.
|
||||
|
||||
TODO:
|
||||
* Experiment with fan divisors > 8.
|
||||
* Experiment with temp. sensor types.
|
||||
* Are there really 13 voltage inputs? Probably not...
|
||||
* Cleanups, no doubt...
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
Kernel driver ds1621
|
||||
====================
|
||||
|
||||
Supported chips:
|
||||
* Dallas Semiconductor DS1621
|
||||
Prefix: 'ds1621'
|
||||
Addresses scanned: I2C 0x48 - 0x4f
|
||||
Datasheet: Publicly available at the Dallas Semiconductor website
|
||||
http://www.dalsemi.com/
|
||||
* Dallas Semiconductor DS1625
|
||||
Prefix: 'ds1621'
|
||||
Addresses scanned: I2C 0x48 - 0x4f
|
||||
Datasheet: Publicly available at the Dallas Semiconductor website
|
||||
http://www.dalsemi.com/
|
||||
|
||||
Authors:
|
||||
Christian W. Zuckschwerdt <zany@triq.net>
|
||||
valuable contributions by Jan M. Sendler <sendler@sendler.de>
|
||||
ported to 2.6 by Aurelien Jarno <aurelien@aurel32.net>
|
||||
with the help of Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Module Parameters
|
||||
------------------
|
||||
|
||||
* polarity int
|
||||
Output's polarity: 0 = active high, 1 = active low
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The DS1621 is a (one instance) digital thermometer and thermostat. It has
|
||||
both high and low temperature limits which can be user defined (i.e.
|
||||
programmed into non-volatile on-chip registers). Temperature range is -55
|
||||
degree Celsius to +125 in 0.5 increments. You may convert this into a
|
||||
Fahrenheit range of -67 to +257 degrees with 0.9 steps. If polarity
|
||||
parameter is not provided, original value is used.
|
||||
|
||||
As for the thermostat, behavior can also be programmed using the polarity
|
||||
toggle. On the one hand ("heater"), the thermostat output of the chip,
|
||||
Tout, will trigger when the low limit temperature is met or underrun and
|
||||
stays high until the high limit is met or exceeded. On the other hand
|
||||
("cooler"), vice versa. That way "heater" equals "active low", whereas
|
||||
"conditioner" equals "active high". Please note that the DS1621 data sheet
|
||||
is somewhat misleading in this point since setting the polarity bit does
|
||||
not simply invert Tout.
|
||||
|
||||
A second thing is that, during extensive testing, Tout showed a tolerance
|
||||
of up to +/- 0.5 degrees even when compared against precise temperature
|
||||
readings. Be sure to have a high vs. low temperature limit gap of al least
|
||||
1.0 degree Celsius to avoid Tout "bouncing", though!
|
||||
|
||||
As for alarms, you can read the alarm status of the DS1621 via the 'alarms'
|
||||
/sys file interface. The result consists mainly of bit 6 and 5 of the
|
||||
configuration register of the chip; bit 6 (0x40 or 64) is the high alarm
|
||||
bit and bit 5 (0x20 or 32) the low one. These bits are set when the high or
|
||||
low limits are met or exceeded and are reset by the module as soon as the
|
||||
respective temperature ranges are left.
|
||||
|
||||
The alarm registers are in no way suitable to find out about the actual
|
||||
status of Tout. They will only tell you about its history, whether or not
|
||||
any of the limits have ever been met or exceeded since last power-up or
|
||||
reset. Be aware: When testing, it showed that the status of Tout can change
|
||||
with neither of the alarms set.
|
||||
|
||||
Temperature conversion of the DS1621 takes up to 1000ms; internal access to
|
||||
non-volatile registers may last for 10ms or below.
|
||||
|
||||
High Accuracy Temperature Reading
|
||||
---------------------------------
|
||||
|
||||
As said before, the temperature issued via the 9-bit i2c-bus data is
|
||||
somewhat arbitrary. Internally, the temperature conversion is of a
|
||||
different kind that is explained (not so...) well in the DS1621 data sheet.
|
||||
To cut the long story short: Inside the DS1621 there are two oscillators,
|
||||
both of them biassed by a temperature coefficient.
|
||||
|
||||
Higher resolution of the temperature reading can be achieved using the
|
||||
internal projection, which means taking account of REG_COUNT and REG_SLOPE
|
||||
(the driver manages them):
|
||||
|
||||
Taken from Dallas Semiconductors App Note 068: 'Increasing Temperature
|
||||
Resolution on the DS1620' and App Note 105: 'High Resolution Temperature
|
||||
Measurement with Dallas Direct-to-Digital Temperature Sensors'
|
||||
|
||||
- Read the 9-bit temperature and strip the LSB (Truncate the .5 degs)
|
||||
- The resulting value is TEMP_READ.
|
||||
- Then, read REG_COUNT.
|
||||
- And then, REG_SLOPE.
|
||||
|
||||
TEMP = TEMP_READ - 0.25 + ((REG_SLOPE - REG_COUNT) / REG_SLOPE)
|
||||
|
||||
Note that this is what the DONE bit in the DS1621 configuration register is
|
||||
good for: Internally, one temperature conversion takes up to 1000ms. Before
|
||||
that conversion is complete you will not be able to read valid things out
|
||||
of REG_COUNT and REG_SLOPE. The DONE bit, as you may have guessed by now,
|
||||
tells you whether the conversion is complete ("done", in plain English) and
|
||||
thus, whether the values you read are good or not.
|
||||
|
||||
The DS1621 has two modes of operation: "Continuous" conversion, which can
|
||||
be understood as the default stand-alone mode where the chip gets the
|
||||
temperature and controls external devices via its Tout pin or tells other
|
||||
i2c's about it if they care. The other mode is called "1SHOT", that means
|
||||
that it only figures out about the temperature when it is explicitly told
|
||||
to do so; this can be seen as power saving mode.
|
||||
|
||||
Now if you want to read REG_COUNT and REG_SLOPE, you have to either stop
|
||||
the continuous conversions until the contents of these registers are valid,
|
||||
or, in 1SHOT mode, you have to have one conversion made.
|
|
@ -0,0 +1,96 @@
|
|||
Kernel driver eeprom
|
||||
====================
|
||||
|
||||
Supported chips:
|
||||
* Any EEPROM chip in the designated address range
|
||||
Prefix: 'eeprom'
|
||||
Addresses scanned: I2C 0x50 - 0x57
|
||||
Datasheets: Publicly available from:
|
||||
Atmel (www.atmel.com),
|
||||
Catalyst (www.catsemi.com),
|
||||
Fairchild (www.fairchildsemi.com),
|
||||
Microchip (www.microchip.com),
|
||||
Philips (www.semiconductor.philips.com),
|
||||
Rohm (www.rohm.com),
|
||||
ST (www.st.com),
|
||||
Xicor (www.xicor.com),
|
||||
and others.
|
||||
|
||||
Chip Size (bits) Address
|
||||
24C01 1K 0x50 (shadows at 0x51 - 0x57)
|
||||
24C01A 1K 0x50 - 0x57 (Typical device on DIMMs)
|
||||
24C02 2K 0x50 - 0x57
|
||||
24C04 4K 0x50, 0x52, 0x54, 0x56
|
||||
(additional data at 0x51, 0x53, 0x55, 0x57)
|
||||
24C08 8K 0x50, 0x54 (additional data at 0x51, 0x52,
|
||||
0x53, 0x55, 0x56, 0x57)
|
||||
24C16 16K 0x50 (additional data at 0x51 - 0x57)
|
||||
Sony 2K 0x57
|
||||
|
||||
Atmel 34C02B 2K 0x50 - 0x57, SW write protect at 0x30-37
|
||||
Catalyst 34FC02 2K 0x50 - 0x57, SW write protect at 0x30-37
|
||||
Catalyst 34RC02 2K 0x50 - 0x57, SW write protect at 0x30-37
|
||||
Fairchild 34W02 2K 0x50 - 0x57, SW write protect at 0x30-37
|
||||
Microchip 24AA52 2K 0x50 - 0x57, SW write protect at 0x30-37
|
||||
ST M34C02 2K 0x50 - 0x57, SW write protect at 0x30-37
|
||||
|
||||
|
||||
Authors:
|
||||
Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>,
|
||||
Jean Delvare <khali@linux-fr.org>,
|
||||
Greg Kroah-Hartman <greg@kroah.com>,
|
||||
IBM Corp.
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This is a simple EEPROM module meant to enable reading the first 256 bytes
|
||||
of an EEPROM (on a SDRAM DIMM for example). However, it will access serial
|
||||
EEPROMs on any I2C adapter. The supported devices are generically called
|
||||
24Cxx, and are listed above; however the numbering for these
|
||||
industry-standard devices may vary by manufacturer.
|
||||
|
||||
This module was a programming exercise to get used to the new project
|
||||
organization laid out by Frodo, but it should be at least completely
|
||||
effective for decoding the contents of EEPROMs on DIMMs.
|
||||
|
||||
DIMMS will typically contain a 24C01A or 24C02, or the 34C02 variants.
|
||||
The other devices will not be found on a DIMM because they respond to more
|
||||
than one address.
|
||||
|
||||
DDC Monitors may contain any device. Often a 24C01, which responds to all 8
|
||||
addresses, is found.
|
||||
|
||||
Recent Sony Vaio laptops have an EEPROM at 0x57. We couldn't get the
|
||||
specification, so it is guess work and far from being complete.
|
||||
|
||||
The Microchip 24AA52/24LCS52, ST M34C02, and others support an additional
|
||||
software write protect register at 0x30 - 0x37 (0x20 less than the memory
|
||||
location). The chip responds to "write quick" detection at this address but
|
||||
does not respond to byte reads. If this register is present, the lower 128
|
||||
bytes of the memory array are not write protected. Any byte data write to
|
||||
this address will write protect the memory array permanently, and the
|
||||
device will no longer respond at the 0x30-37 address. The eeprom driver
|
||||
does not support this register.
|
||||
|
||||
Lacking functionality:
|
||||
|
||||
* Full support for larger devices (24C04, 24C08, 24C16). These are not
|
||||
typically found on a PC. These devices will appear as separate devices at
|
||||
multiple addresses.
|
||||
|
||||
* Support for really large devices (24C32, 24C64, 24C128, 24C256, 24C512).
|
||||
These devices require two-byte address fields and are not supported.
|
||||
|
||||
* Enable Writing. Again, no technical reason why not, but making it easy
|
||||
to change the contents of the EEPROMs (on DIMMs anyway) also makes it easy
|
||||
to disable the DIMMs (potentially preventing the computer from booting)
|
||||
until the values are restored somehow.
|
||||
|
||||
Use:
|
||||
|
||||
After inserting the module (and any other required SMBus/i2c modules), you
|
||||
should have some EEPROM directories in /sys/bus/i2c/devices/* of names such
|
||||
as "0-0050". Inside each of these is a series of files, the eeprom file
|
||||
contains the binary data from EEPROM.
|
|
@ -0,0 +1,169 @@
|
|||
Kernel driver fscher
|
||||
====================
|
||||
|
||||
Supported chips:
|
||||
* Fujitsu-Siemens Hermes chip
|
||||
Prefix: 'fscher'
|
||||
Addresses scanned: I2C 0x73
|
||||
|
||||
Authors:
|
||||
Reinhard Nissl <rnissl@gmx.de> based on work
|
||||
from Hermann Jung <hej@odn.de>,
|
||||
Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the Fujitsu-Siemens Hermes chip. It is
|
||||
described in the 'Register Set Specification BMC Hermes based Systemboard'
|
||||
from Fujitsu-Siemens.
|
||||
|
||||
The Hermes chip implements a hardware-based system management, e.g. for
|
||||
controlling fan speed and core voltage. There is also a watchdog counter on
|
||||
the chip which can trigger an alarm and even shut the system down.
|
||||
|
||||
The chip provides three temperature values (CPU, motherboard and
|
||||
auxiliary), three voltage values (+12V, +5V and battery) and three fans
|
||||
(power supply, CPU and auxiliary).
|
||||
|
||||
Temperatures are measured in degrees Celsius. The resolution is 1 degree.
|
||||
|
||||
Fan rotation speeds are reported in RPM (rotations per minute). The value
|
||||
can be divided by a programmable divider (1, 2 or 4) which is stored on
|
||||
the chip.
|
||||
|
||||
Voltage sensors (also known as "in" sensors) report their values in volts.
|
||||
|
||||
All values are reported as final values from the driver. There is no need
|
||||
for further calculations.
|
||||
|
||||
|
||||
Detailed description
|
||||
--------------------
|
||||
|
||||
Below you'll find a single line description of all the bit values. With
|
||||
this information, you're able to decode e. g. alarms, wdog, etc. To make
|
||||
use of the watchdog, you'll need to set the watchdog time and enable the
|
||||
watchdog. After that it is necessary to restart the watchdog time within
|
||||
the specified period of time, or a system reset will occur.
|
||||
|
||||
* revision
|
||||
READING & 0xff = 0x??: HERMES revision identification
|
||||
|
||||
* alarms
|
||||
READING & 0x80 = 0x80: CPU throttling active
|
||||
READING & 0x80 = 0x00: CPU running at full speed
|
||||
|
||||
READING & 0x10 = 0x10: software event (see control:1)
|
||||
READING & 0x10 = 0x00: no software event
|
||||
|
||||
READING & 0x08 = 0x08: watchdog event (see wdog:2)
|
||||
READING & 0x08 = 0x00: no watchdog event
|
||||
|
||||
READING & 0x02 = 0x02: thermal event (see temp*:1)
|
||||
READING & 0x02 = 0x00: no thermal event
|
||||
|
||||
READING & 0x01 = 0x01: fan event (see fan*:1)
|
||||
READING & 0x01 = 0x00: no fan event
|
||||
|
||||
READING & 0x13 ! 0x00: ALERT LED is flashing
|
||||
|
||||
* control
|
||||
READING & 0x01 = 0x01: software event
|
||||
READING & 0x01 = 0x00: no software event
|
||||
|
||||
WRITING & 0x01 = 0x01: set software event
|
||||
WRITING & 0x01 = 0x00: clear software event
|
||||
|
||||
* watchdog_control
|
||||
READING & 0x80 = 0x80: power off on watchdog event while thermal event
|
||||
READING & 0x80 = 0x00: watchdog power off disabled (just system reset enabled)
|
||||
|
||||
READING & 0x40 = 0x40: watchdog timebase 60 seconds (see also wdog:1)
|
||||
READING & 0x40 = 0x00: watchdog timebase 2 seconds
|
||||
|
||||
READING & 0x10 = 0x10: watchdog enabled
|
||||
READING & 0x10 = 0x00: watchdog disabled
|
||||
|
||||
WRITING & 0x80 = 0x80: enable "power off on watchdog event while thermal event"
|
||||
WRITING & 0x80 = 0x00: disable "power off on watchdog event while thermal event"
|
||||
|
||||
WRITING & 0x40 = 0x40: set watchdog timebase to 60 seconds
|
||||
WRITING & 0x40 = 0x00: set watchdog timebase to 2 seconds
|
||||
|
||||
WRITING & 0x20 = 0x20: disable watchdog
|
||||
|
||||
WRITING & 0x10 = 0x10: enable watchdog / restart watchdog time
|
||||
|
||||
* watchdog_state
|
||||
READING & 0x02 = 0x02: watchdog system reset occurred
|
||||
READING & 0x02 = 0x00: no watchdog system reset occurred
|
||||
|
||||
WRITING & 0x02 = 0x02: clear watchdog event
|
||||
|
||||
* watchdog_preset
|
||||
READING & 0xff = 0x??: configured watch dog time in units (see wdog:3 0x40)
|
||||
|
||||
WRITING & 0xff = 0x??: configure watch dog time in units
|
||||
|
||||
* in* (0: +5V, 1: +12V, 2: onboard 3V battery)
|
||||
READING: actual voltage value
|
||||
|
||||
* temp*_status (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor)
|
||||
READING & 0x02 = 0x02: thermal event (overtemperature)
|
||||
READING & 0x02 = 0x00: no thermal event
|
||||
|
||||
READING & 0x01 = 0x01: sensor is working
|
||||
READING & 0x01 = 0x00: sensor is faulty
|
||||
|
||||
WRITING & 0x02 = 0x02: clear thermal event
|
||||
|
||||
* temp*_input (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor)
|
||||
READING: actual temperature value
|
||||
|
||||
* fan*_status (1: power supply fan, 2: CPU fan, 3: auxiliary fan)
|
||||
READING & 0x04 = 0x04: fan event (fan fault)
|
||||
READING & 0x04 = 0x00: no fan event
|
||||
|
||||
WRITING & 0x04 = 0x04: clear fan event
|
||||
|
||||
* fan*_div (1: power supply fan, 2: CPU fan, 3: auxiliary fan)
|
||||
Divisors 2,4 and 8 are supported, both for reading and writing
|
||||
|
||||
* fan*_pwm (1: power supply fan, 2: CPU fan, 3: auxiliary fan)
|
||||
READING & 0xff = 0x00: fan may be switched off
|
||||
READING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V)
|
||||
READING & 0xff = 0xff: fan must run at maximum speed (supply: 12V)
|
||||
READING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V)
|
||||
|
||||
WRITING & 0xff = 0x00: fan may be switched off
|
||||
WRITING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V)
|
||||
WRITING & 0xff = 0xff: fan must run at maximum speed (supply: 12V)
|
||||
WRITING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V)
|
||||
|
||||
* fan*_input (1: power supply fan, 2: CPU fan, 3: auxiliary fan)
|
||||
READING: actual RPM value
|
||||
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
* Measuring fan speed
|
||||
It seems that the chip counts "ripples" (typical fans produce 2 ripples per
|
||||
rotation while VERAX fans produce 18) in a 9-bit register. This register is
|
||||
read out every second, then the ripple prescaler (2, 4 or 8) is applied and
|
||||
the result is stored in the 8 bit output register. Due to the limitation of
|
||||
the counting register to 9 bits, it is impossible to measure a VERAX fan
|
||||
properly (even with a prescaler of 8). At its maximum speed of 3500 RPM the
|
||||
fan produces 1080 ripples per second which causes the counting register to
|
||||
overflow twice, leading to only 186 RPM.
|
||||
|
||||
* Measuring input voltages
|
||||
in2 ("battery") reports the voltage of the onboard lithium battery and not
|
||||
+3.3V from the power supply.
|
||||
|
||||
* Undocumented features
|
||||
Fujitsu-Siemens Computers has not documented all features of the chip so
|
||||
far. Their software, System Guard, shows that there are a still some
|
||||
features which cannot be controlled by this implementation.
|
|
@ -0,0 +1,74 @@
|
|||
Kernel driver gl518sm
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Genesys Logic GL518SM release 0x00
|
||||
Prefix: 'gl518sm'
|
||||
Addresses scanned: I2C 0x2c and 0x2d
|
||||
Datasheet: http://www.genesyslogic.com/pdf
|
||||
* Genesys Logic GL518SM release 0x80
|
||||
Prefix: 'gl518sm'
|
||||
Addresses scanned: I2C 0x2c and 0x2d
|
||||
Datasheet: http://www.genesyslogic.com/pdf
|
||||
|
||||
Authors:
|
||||
Frodo Looijaard <frodol@dds.nl>,
|
||||
Kyösti Mälkki <kmalkki@cc.hut.fi>
|
||||
Hong-Gunn Chew <hglinux@gunnet.org>
|
||||
Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
IMPORTANT:
|
||||
|
||||
For the revision 0x00 chip, the in0, in1, and in2 values (+5V, +3V,
|
||||
and +12V) CANNOT be read. This is a limitation of the chip, not the driver.
|
||||
|
||||
This driver supports the Genesys Logic GL518SM chip. There are at least
|
||||
two revision of this chip, which we call revision 0x00 and 0x80. Revision
|
||||
0x80 chips support the reading of all voltages and revision 0x00 only
|
||||
for VIN3.
|
||||
|
||||
The GL518SM implements one temperature sensor, two fan rotation speed
|
||||
sensors, and four voltage sensors. It can report alarms through the
|
||||
computer speakers.
|
||||
|
||||
Temperatures are measured in degrees Celsius. An alarm goes off while the
|
||||
temperature is above the over temperature limit, and has not yet dropped
|
||||
below the hysteresis limit. The alarm always reflects the current
|
||||
situation. Measurements are guaranteed between -10 degrees and +110
|
||||
degrees, with a accuracy of +/-3 degrees.
|
||||
|
||||
Rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||
triggered if the rotation speed has dropped below a programmable limit. In
|
||||
case when you have selected to turn fan1 off, no fan1 alarm is triggered.
|
||||
|
||||
Fan readings can be divided by a programmable divider (1, 2, 4 or 8) to
|
||||
give the readings more range or accuracy. Not all RPM values can
|
||||
accurately be represented, so some rounding is done. With a divider
|
||||
of 2, the lowest representable value is around 1900 RPM.
|
||||
|
||||
Voltage sensors (also known as VIN sensors) report their values in volts.
|
||||
An alarm is triggered if the voltage has crossed a programmable minimum or
|
||||
maximum limit. Note that minimum in this case always means 'closest to
|
||||
zero'; this is important for negative voltage measurements. The VDD input
|
||||
measures voltages between 0.000 and 5.865 volt, with a resolution of 0.023
|
||||
volt. The other inputs measure voltages between 0.000 and 4.845 volt, with
|
||||
a resolution of 0.019 volt. Note that revision 0x00 chips do not support
|
||||
reading the current voltage of any input except for VIN3; limit setting and
|
||||
alarms work fine, though.
|
||||
|
||||
When an alarm is triggered, 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.
|
||||
|
||||
If an alarm triggers, it will remain triggered until the hardware register
|
||||
is read at least once (except for temperature alarms). This means that the
|
||||
cause for the alarm may already have disappeared! Note that in the current
|
||||
implementation, all hardware registers are read whenever any data is read
|
||||
(unless it is less than 1.5 seconds since the last update). This means that
|
||||
you can easily miss once-only alarms.
|
||||
|
||||
The GL518SM only updates its values each 1.5 seconds; reading it more often
|
||||
will do no harm, but will return 'old' values.
|
|
@ -0,0 +1,96 @@
|
|||
Kernel driver it87
|
||||
==================
|
||||
|
||||
Supported chips:
|
||||
* IT8705F
|
||||
Prefix: 'it87'
|
||||
Addresses scanned: from Super I/O config space, or default ISA 0x290 (8 I/O ports)
|
||||
Datasheet: Publicly available at the ITE website
|
||||
http://www.ite.com.tw/
|
||||
* IT8712F
|
||||
Prefix: 'it8712'
|
||||
Addresses scanned: I2C 0x28 - 0x2f
|
||||
from Super I/O config space, or default ISA 0x290 (8 I/O ports)
|
||||
Datasheet: Publicly available at the ITE website
|
||||
http://www.ite.com.tw/
|
||||
* SiS950 [clone of IT8705F]
|
||||
Prefix: 'sis950'
|
||||
Addresses scanned: from Super I/O config space, or default ISA 0x290 (8 I/O ports)
|
||||
Datasheet: No longer be available
|
||||
|
||||
Author: Christophe Gauthron <chrisg@0-in.com>
|
||||
|
||||
|
||||
Module Parameters
|
||||
-----------------
|
||||
|
||||
* update_vbat: int
|
||||
|
||||
0 if vbat should report power on value, 1 if vbat should be updated after
|
||||
each read. Default is 0. On some boards the battery voltage is provided
|
||||
by either the battery or the onboard power supply. Only the first reading
|
||||
at power on will be the actual battery voltage (which the chip does
|
||||
automatically). On other boards the battery voltage is always fed to
|
||||
the chip so can be read at any time. Excessive reading may decrease
|
||||
battery life but no information is given in the datasheet.
|
||||
|
||||
* fix_pwm_polarity int
|
||||
|
||||
Force PWM polarity to active high (DANGEROUS). Some chips are
|
||||
misconfigured by BIOS - PWM values would be inverted. This option tries
|
||||
to fix this. Please contact your BIOS manufacturer and ask him for fix.
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the IT8705F, IT8712F and SiS950 chips.
|
||||
|
||||
This driver also supports IT8712F, which adds SMBus access, and a VID
|
||||
input, used to report the Vcore voltage of the Pentium processor.
|
||||
The IT8712F additionally features VID inputs.
|
||||
|
||||
These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
|
||||
joysticks and other miscellaneous stuff. For hardware monitoring, they
|
||||
include an 'environment controller' with 3 temperature sensors, 3 fan
|
||||
rotation speed sensors, 8 voltage sensors, and associated alarms.
|
||||
|
||||
Temperatures are measured in degrees Celsius. An alarm is triggered once
|
||||
when the Overtemperature Shutdown limit is crossed.
|
||||
|
||||
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||
triggered if the rotation speed has dropped below a programmable limit. Fan
|
||||
readings can be divided by a programmable divider (1, 2, 4 or 8) to give the
|
||||
readings more range or accuracy. Not all RPM values can accurately be
|
||||
represented, so some rounding is done. With a divider of 2, the lowest
|
||||
representable value is around 2600 RPM.
|
||||
|
||||
Voltage sensors (also known as IN sensors) report their values in volts. An
|
||||
alarm is triggered if the voltage has crossed a programmable minimum or
|
||||
maximum limit. Note that minimum in this case always means 'closest to
|
||||
zero'; this is important for negative voltage measurements. All voltage
|
||||
inputs can measure voltages between 0 and 4.08 volts, with a resolution of
|
||||
0.016 volt. The battery voltage in8 does not have limit registers.
|
||||
|
||||
The VID lines (IT8712F only) encode the core voltage value: the voltage
|
||||
level your processor should work with. This is hardcoded by the mainboard
|
||||
and/or processor itself. It is a value in volts.
|
||||
|
||||
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 hardware
|
||||
registers are read whenever any data is read (unless it is less than 1.5
|
||||
seconds since the last update). This means that you can easily miss
|
||||
once-only alarms.
|
||||
|
||||
The IT87xx only updates its values each 1.5 seconds; reading it more often
|
||||
will do no harm, but will return 'old' values.
|
||||
|
||||
To change sensor N to a thermistor, 'echo 2 > tempN_type' where N is 1, 2,
|
||||
or 3. To change sensor N to a thermal diode, 'echo 3 > tempN_type'.
|
||||
Give 0 for unused sensor. Any other value is invalid. To configure this at
|
||||
startup, consult lm_sensors's /etc/sensors.conf. (2 = thermistor;
|
||||
3 = thermal diode)
|
||||
|
||||
The fan speed control features are limited to manual PWM mode. Automatic
|
||||
"Smart Guardian" mode control handling is not implemented. However
|
||||
if you want to go for "manual mode" just write 1 to pwmN_enable.
|
|
@ -0,0 +1,57 @@
|
|||
Kernel driver lm63
|
||||
==================
|
||||
|
||||
Supported chips:
|
||||
* National Semiconductor LM63
|
||||
Prefix: 'lm63'
|
||||
Addresses scanned: I2C 0x4c
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/pf/LM/LM63.html
|
||||
|
||||
Author: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Thanks go to Tyan and especially Alex Buckingham for setting up a remote
|
||||
access to their S4882 test platform for this driver.
|
||||
http://www.tyan.com/
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The LM63 is a digital temperature sensor with integrated fan monitoring
|
||||
and control.
|
||||
|
||||
The LM63 is basically an LM86 with fan speed monitoring and control
|
||||
capabilities added. It misses some of the LM86 features though:
|
||||
- No low limit for local temperature.
|
||||
- No critical limit for local temperature.
|
||||
- Critical limit for remote temperature can be changed only once. We
|
||||
will consider that the critical limit is read-only.
|
||||
|
||||
The datasheet isn't very clear about what the tachometer reading is.
|
||||
|
||||
An explanation from National Semiconductor: The two lower bits of the read
|
||||
value have to be masked out. The value is still 16 bit in width.
|
||||
|
||||
All temperature values are given in degrees Celsius. Resolution is 1.0
|
||||
degree for the local temperature, 0.125 degree for the remote temperature.
|
||||
|
||||
The fan speed is measured using a tachometer. Contrary to most chips which
|
||||
store the value in an 8-bit register and have a selectable clock divider
|
||||
to make sure that the result will fit in the register, the LM63 uses 16-bit
|
||||
value for measuring the speed of the fan. It can measure fan speeds down to
|
||||
83 RPM, at least in theory.
|
||||
|
||||
Note that the pin used for fan monitoring is shared with an alert out
|
||||
function. Depending on how the board designer wanted to use the chip, fan
|
||||
speed monitoring will or will not be possible. The proper chip configuration
|
||||
is left to the BIOS, and the driver will blindly trust it.
|
||||
|
||||
A PWM output can be used to control the speed of the fan. The LM63 has two
|
||||
PWM modes: manual and automatic. Automatic mode is not fully implemented yet
|
||||
(you cannot define your custom PWM/temperature curve), and mode change isn't
|
||||
supported either.
|
||||
|
||||
The lm63 driver will not update its values more frequently than every
|
||||
second; reading them more often will do no harm, but will return 'old'
|
||||
values.
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
Kernel driver lm75
|
||||
==================
|
||||
|
||||
Supported chips:
|
||||
* National Semiconductor LM75
|
||||
Prefix: 'lm75'
|
||||
Addresses scanned: I2C 0x48 - 0x4f
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/
|
||||
* Dallas Semiconductor DS75
|
||||
Prefix: 'lm75'
|
||||
Addresses scanned: I2C 0x48 - 0x4f
|
||||
Datasheet: Publicly available at the Dallas Semiconductor website
|
||||
http://www.maxim-ic.com/
|
||||
* Dallas Semiconductor DS1775
|
||||
Prefix: 'lm75'
|
||||
Addresses scanned: I2C 0x48 - 0x4f
|
||||
Datasheet: Publicly available at the Dallas Semiconductor website
|
||||
http://www.maxim-ic.com/
|
||||
* Maxim MAX6625, MAX6626
|
||||
Prefix: 'lm75'
|
||||
Addresses scanned: I2C 0x48 - 0x4b
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
http://www.maxim-ic.com/
|
||||
* Microchip (TelCom) TCN75
|
||||
Prefix: 'lm75'
|
||||
Addresses scanned: I2C 0x48 - 0x4f
|
||||
Datasheet: Publicly available at the Microchip website
|
||||
http://www.microchip.com/
|
||||
|
||||
Author: Frodo Looijaard <frodol@dds.nl>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The LM75 implements one temperature sensor. Limits can be set through the
|
||||
Overtemperature Shutdown register and Hysteresis register. Each value can be
|
||||
set and read to half-degree accuracy.
|
||||
An alarm is issued (usually to a connected LM78) when the temperature
|
||||
gets higher then the Overtemperature Shutdown value; it stays on until
|
||||
the temperature falls below the Hysteresis value.
|
||||
All temperatures are in degrees Celsius, and are guaranteed within a
|
||||
range of -55 to +125 degrees.
|
||||
|
||||
The LM75 only updates its values each 1.5 seconds; reading it more often
|
||||
will do no harm, but will return 'old' values.
|
||||
|
||||
The LM75 is usually used in combination with LM78-like chips, to measure
|
||||
the temperature of the processor(s).
|
||||
|
||||
The DS75, DS1775, MAX6625, and MAX6626 are supported as well.
|
||||
They are not distinguished from an LM75. While most of these chips
|
||||
have three additional bits of accuracy (12 vs. 9 for the LM75),
|
||||
the additional bits are not supported. Not only that, but these chips will
|
||||
not be detected if not in 9-bit precision mode (use the force parameter if
|
||||
needed).
|
||||
|
||||
The TCN75 is supported as well, and is not distinguished from an LM75.
|
||||
|
||||
The LM75 is essentially an industry standard; there may be other
|
||||
LM75 clones not listed here, with or without various enhancements,
|
||||
that are supported.
|
||||
|
||||
The LM77 is not supported, contrary to what we pretended for a long time.
|
||||
Both chips are simply not compatible, value encoding differs.
|
|
@ -0,0 +1,22 @@
|
|||
Kernel driver lm77
|
||||
==================
|
||||
|
||||
Supported chips:
|
||||
* National Semiconductor LM77
|
||||
Prefix: 'lm77'
|
||||
Addresses scanned: I2C 0x48 - 0x4b
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/
|
||||
|
||||
Author: Andras BALI <drewie@freemail.hu>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The LM77 implements one temperature sensor. The temperature
|
||||
sensor incorporates a band-gap type temperature sensor,
|
||||
10-bit ADC, and a digital comparator with user-programmable upper
|
||||
and lower limit values.
|
||||
|
||||
Limits can be set through the Overtemperature Shutdown register and
|
||||
Hysteresis register.
|
|
@ -0,0 +1,82 @@
|
|||
Kernel driver lm78
|
||||
==================
|
||||
|
||||
Supported chips:
|
||||
* National Semiconductor LM78
|
||||
Prefix: 'lm78'
|
||||
Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/
|
||||
* National Semiconductor LM78-J
|
||||
Prefix: 'lm78-j'
|
||||
Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/
|
||||
* National Semiconductor LM79
|
||||
Prefix: 'lm79'
|
||||
Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/
|
||||
|
||||
Author: Frodo Looijaard <frodol@dds.nl>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the National Semiconductor LM78, LM78-J
|
||||
and LM79. They are described as 'Microprocessor System Hardware Monitors'.
|
||||
|
||||
There is almost no difference between the three supported chips. Functionally,
|
||||
the LM78 and LM78-J are exactly identical. The LM79 has one more VID line,
|
||||
which is used to report the lower voltages newer Pentium processors use.
|
||||
From here on, LM7* means either of these three types.
|
||||
|
||||
The LM7* implements one temperature sensor, three fan rotation speed sensors,
|
||||
seven voltage sensors, VID lines, alarms, and some miscellaneous stuff.
|
||||
|
||||
Temperatures are measured in degrees Celsius. An alarm is triggered once
|
||||
when the Overtemperature Shutdown limit is crossed; it is triggered again
|
||||
as soon as it drops below the Hysteresis value. A more useful behavior
|
||||
can be found by setting the Hysteresis value to +127 degrees Celsius; in
|
||||
this case, alarms are issued during all the time when the actual temperature
|
||||
is above the Overtemperature Shutdown value. Measurements are guaranteed
|
||||
between -55 and +125 degrees, with a resolution of 1 degree.
|
||||
|
||||
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||
triggered if the rotation speed has dropped below a programmable limit. Fan
|
||||
readings can be divided by a programmable divider (1, 2, 4 or 8) to give
|
||||
the readings more range or accuracy. Not all RPM values can accurately be
|
||||
represented, so some rounding is done. With a divider of 2, the lowest
|
||||
representable value is around 2600 RPM.
|
||||
|
||||
Voltage sensors (also known as IN sensors) report their values in volts.
|
||||
An alarm is triggered if the voltage has crossed a programmable minimum
|
||||
or maximum limit. Note that minimum in this case always means 'closest to
|
||||
zero'; this is important for negative voltage measurements. All voltage
|
||||
inputs can measure voltages between 0 and 4.08 volts, with a resolution
|
||||
of 0.016 volt.
|
||||
|
||||
The VID lines encode the core voltage value: the voltage level your processor
|
||||
should work with. This is hardcoded by the mainboard and/or processor itself.
|
||||
It is a value in volts. 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
|
||||
hardware registers are read whenever any data is read (unless it is less
|
||||
than 1.5 seconds since the last update). This means that you can easily
|
||||
miss once-only alarms.
|
||||
|
||||
The LM7* only updates its values each 1.5 seconds; reading it more often
|
||||
will do no harm, but will return 'old' values.
|
|
@ -0,0 +1,56 @@
|
|||
Kernel driver lm80
|
||||
==================
|
||||
|
||||
Supported chips:
|
||||
* National Semiconductor LM80
|
||||
Prefix: 'lm80'
|
||||
Addresses scanned: I2C 0x28 - 0x2f
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/
|
||||
|
||||
Authors:
|
||||
Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the National Semiconductor LM80.
|
||||
It is described as a 'Serial Interface ACPI-Compatible Microprocessor
|
||||
System Hardware Monitor'.
|
||||
|
||||
The LM80 implements one temperature sensor, two fan rotation speed sensors,
|
||||
seven voltage sensors, alarms, and some miscellaneous stuff.
|
||||
|
||||
Temperatures are measured in degrees Celsius. There are two sets of limits
|
||||
which operate independently. When the HOT Temperature Limit is crossed,
|
||||
this will cause an alarm that will be reasserted until the temperature
|
||||
drops below the HOT Hysteresis. The Overtemperature Shutdown (OS) limits
|
||||
should work in the same way (but this must be checked; the datasheet
|
||||
is unclear about this). Measurements are guaranteed between -55 and
|
||||
+125 degrees. The current temperature measurement has a resolution of
|
||||
0.0625 degrees; the limits have a resolution of 1 degree.
|
||||
|
||||
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||
triggered if the rotation speed has dropped below a programmable limit. Fan
|
||||
readings can be divided by a programmable divider (1, 2, 4 or 8) to give
|
||||
the readings more range or accuracy. Not all RPM values can accurately be
|
||||
represented, so some rounding is done. With a divider of 2, the lowest
|
||||
representable value is around 2600 RPM.
|
||||
|
||||
Voltage sensors (also known as IN sensors) report their values in volts.
|
||||
An alarm is triggered if the voltage has crossed a programmable minimum
|
||||
or maximum limit. Note that minimum in this case always means 'closest to
|
||||
zero'; this is important for negative voltage measurements. All voltage
|
||||
inputs can measure voltages between 0 and 2.55 volts, with a resolution
|
||||
of 0.01 volt.
|
||||
|
||||
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
|
||||
hardware registers are read whenever any data is read (unless it is less
|
||||
than 2.0 seconds since the last update). This means that you can easily
|
||||
miss once-only alarms.
|
||||
|
||||
The LM80 only updates its values each 1.5 seconds; reading it more often
|
||||
will do no harm, but will return 'old' values.
|
|
@ -0,0 +1,76 @@
|
|||
Kernel driver lm83
|
||||
==================
|
||||
|
||||
Supported chips:
|
||||
* National Semiconductor LM83
|
||||
Prefix: 'lm83'
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/pf/LM/LM83.html
|
||||
|
||||
|
||||
Author: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The LM83 is a digital temperature sensor. It senses its own temperature as
|
||||
well as the temperature of up to three external diodes. It is compatible
|
||||
with many other devices such as the LM84 and all other ADM1021 clones.
|
||||
The main difference between the LM83 and the LM84 in that the later can
|
||||
only sense the temperature of one external diode.
|
||||
|
||||
Using the adm1021 driver for a LM83 should work, but only two temperatures
|
||||
will be reported instead of four.
|
||||
|
||||
The LM83 is only found on a handful of motherboards. Both a confirmed
|
||||
list and an unconfirmed list follow. If you can confirm or infirm the
|
||||
fact that any of these motherboards do actually have an LM83, please
|
||||
contact us. Note that the LM90 can easily be misdetected as a LM83.
|
||||
|
||||
Confirmed motherboards:
|
||||
SBS P014
|
||||
|
||||
Unconfirmed motherboards:
|
||||
Gigabyte GA-8IK1100
|
||||
Iwill MPX2
|
||||
Soltek SL-75DRV5
|
||||
|
||||
The driver has been successfully tested by Magnus Forsström, who I'd
|
||||
like to thank here. More testers will be of course welcome.
|
||||
|
||||
The fact that the LM83 is only scarcely used can be easily explained.
|
||||
Most motherboards come with more than just temperature sensors for
|
||||
health monitoring. They also have voltage and fan rotation speed
|
||||
sensors. This means that temperature-only chips are usually used as
|
||||
secondary chips coupled with another chip such as an IT8705F or similar
|
||||
chip, which provides more features. Since systems usually need three
|
||||
temperature sensors (motherboard, processor, power supply) and primary
|
||||
chips provide some temperature sensors, the secondary chip, if needed,
|
||||
won't have to handle more than two temperatures. Thus, ADM1021 clones
|
||||
are sufficient, and there is no need for a four temperatures sensor
|
||||
chip such as the LM83. The only case where using an LM83 would make
|
||||
sense is on SMP systems, such as the above-mentioned Iwill MPX2,
|
||||
because you want an additional temperature sensor for each additional
|
||||
CPU.
|
||||
|
||||
On the SBS P014, this is different, since the LM83 is the only hardware
|
||||
monitoring chipset. One temperature sensor is used for the motherboard
|
||||
(actually measuring the LM83's own temperature), one is used for the
|
||||
CPU. The two other sensors must be used to measure the temperature of
|
||||
two other points of the motherboard. We suspect these points to be the
|
||||
north and south bridges, but this couldn't be confirmed.
|
||||
|
||||
All temperature values are given in degrees Celsius. Local temperature
|
||||
is given within a range of 0 to +85 degrees. Remote temperatures are
|
||||
given within a range of 0 to +125 degrees. Resolution is 1.0 degree,
|
||||
accuracy is guaranteed to 3.0 degrees (see the datasheet for more
|
||||
details).
|
||||
|
||||
Each sensor has its own high limit, but the critical limit is common to
|
||||
all four sensors. There is no hysteresis mechanism as found on most
|
||||
recent temperature sensors.
|
||||
|
||||
The lm83 driver will not update its values more frequently than every
|
||||
other second; reading them more often will do no harm, but will return
|
||||
'old' values.
|
|
@ -0,0 +1,221 @@
|
|||
Kernel driver lm85
|
||||
==================
|
||||
|
||||
Supported chips:
|
||||
* National Semiconductor LM85 (B and C versions)
|
||||
Prefix: 'lm85'
|
||||
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
|
||||
Datasheet: http://www.national.com/pf/LM/LM85.html
|
||||
* Analog Devices ADM1027
|
||||
Prefix: 'adm1027'
|
||||
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
|
||||
Datasheet: http://www.analog.com/en/prod/0,,766_825_ADM1027,00.html
|
||||
* Analog Devices ADT7463
|
||||
Prefix: 'adt7463'
|
||||
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
|
||||
Datasheet: http://www.analog.com/en/prod/0,,766_825_ADT7463,00.html
|
||||
* SMSC EMC6D100, SMSC EMC6D101
|
||||
Prefix: 'emc6d100'
|
||||
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
|
||||
Datasheet: http://www.smsc.com/main/tools/discontinued/6d100.pdf
|
||||
* SMSC EMC6D102
|
||||
Prefix: 'emc6d102'
|
||||
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
|
||||
Datasheet: http://www.smsc.com/main/catalog/emc6d102.html
|
||||
|
||||
Authors:
|
||||
Philip Pokorny <ppokorny@penguincomputing.com>,
|
||||
Frodo Looijaard <frodol@dds.nl>,
|
||||
Richard Barrington <rich_b_nz@clear.net.nz>,
|
||||
Margit Schubert-While <margitsw@t-online.de>,
|
||||
Justin Thiessen <jthiessen@penguincomputing.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the National Semiconductor LM85 and
|
||||
compatible chips including the Analog Devices ADM1027, ADT7463 and
|
||||
SMSC EMC6D10x chips family.
|
||||
|
||||
The LM85 uses the 2-wire interface compatible with the SMBUS 2.0
|
||||
specification. Using an analog to digital converter it measures three (3)
|
||||
temperatures and five (5) voltages. It has four (4) 16-bit counters for
|
||||
measuring fan speed. Five (5) digital inputs are provided for sampling the
|
||||
VID signals from the processor to the VRM. Lastly, there are three (3) PWM
|
||||
outputs that can be used to control fan speed.
|
||||
|
||||
The voltage inputs have internal scaling resistors so that the following
|
||||
voltage can be measured without external resistors:
|
||||
|
||||
2.5V, 3.3V, 5V, 12V, and CPU core voltage (2.25V)
|
||||
|
||||
The temperatures measured are one internal diode, and two remote diodes.
|
||||
Remote 1 is generally the CPU temperature. These inputs are designed to
|
||||
measure a thermal diode like the one in a Pentium 4 processor in a socket
|
||||
423 or socket 478 package. They can also measure temperature using a
|
||||
transistor like the 2N3904.
|
||||
|
||||
A sophisticated control system for the PWM outputs is designed into the
|
||||
LM85 that allows fan speed to be adjusted automatically based on any of the
|
||||
three temperature sensors. Each PWM output is individually adjustable and
|
||||
programmable. Once configured, the LM85 will adjust the PWM outputs in
|
||||
response to the measured temperatures without further host intervention.
|
||||
This feature can also be disabled for manual control of the PWM's.
|
||||
|
||||
Each of the measured inputs (voltage, temperature, fan speed) has
|
||||
corresponding high/low limit values. The LM85 will signal an ALARM if any
|
||||
measured value exceeds either limit.
|
||||
|
||||
The LM85 samples all inputs continuously. The lm85 driver will not read
|
||||
the registers more often than once a second. Further, configuration data is
|
||||
only read once each 5 minutes. There is twice as much config data as
|
||||
measurements, so this would seem to be a worthwhile optimization.
|
||||
|
||||
Special Features
|
||||
----------------
|
||||
|
||||
The LM85 has four fan speed monitoring modes. The ADM1027 has only two.
|
||||
Both have special circuitry to compensate for PWM interactions with the
|
||||
TACH signal from the fans. The ADM1027 can be configured to measure the
|
||||
speed of a two wire fan, but the input conditioning circuitry is different
|
||||
for 3-wire and 2-wire mode. For this reason, the 2-wire fan modes are not
|
||||
exposed to user control. The BIOS should initialize them to the correct
|
||||
mode. If you've designed your own ADM1027, you'll have to modify the
|
||||
init_client function and add an insmod parameter to set this up.
|
||||
|
||||
To smooth the response of fans to changes in temperature, the LM85 has an
|
||||
optional filter for smoothing temperatures. The ADM1027 has the same
|
||||
config option but uses it to rate limit the changes to fan speed instead.
|
||||
|
||||
The ADM1027 and ADT7463 have a 10-bit ADC and can therefore measure
|
||||
temperatures with 0.25 degC resolution. They also provide an offset to the
|
||||
temperature readings that is automatically applied during measurement.
|
||||
This offset can be used to zero out any errors due to traces and placement.
|
||||
The documentation says that the offset is in 0.25 degC steps, but in
|
||||
initial testing of the ADM1027 it was 1.00 degC steps. Analog Devices has
|
||||
confirmed this "bug". The ADT7463 is reported to work as described in the
|
||||
documentation. The current lm85 driver does not show the offset register.
|
||||
|
||||
The ADT7463 has a THERM asserted counter. This counter has a 22.76ms
|
||||
resolution and a range of 5.8 seconds. The driver implements a 32-bit
|
||||
accumulator of the counter value to extend the range to over a year. The
|
||||
counter will stay at it's max value until read.
|
||||
|
||||
See the vendor datasheets for more information. There is application note
|
||||
from National (AN-1260) with some additional information about the LM85.
|
||||
The Analog Devices datasheet is very detailed and describes a procedure for
|
||||
determining an optimal configuration for the automatic PWM control.
|
||||
|
||||
The SMSC EMC6D100 & EMC6D101 monitor external voltages, temperatures, and
|
||||
fan speeds. They use this monitoring capability to alert the system to out
|
||||
of limit conditions and can automatically control the speeds of multiple
|
||||
fans in a PC or embedded system. The EMC6D101, available in a 24-pin SSOP
|
||||
package, and the EMC6D100, available in a 28-pin SSOP package, are designed
|
||||
to be register compatible. The EMC6D100 offers all the features of the
|
||||
EMC6D101 plus additional voltage monitoring and system control features.
|
||||
Unfortunately it is not possible to distinguish between the package
|
||||
versions on register level so these additional voltage inputs may read
|
||||
zero. The EMC6D102 features addtional ADC bits thus extending precision
|
||||
of voltage and temperature channels.
|
||||
|
||||
|
||||
Hardware Configurations
|
||||
-----------------------
|
||||
|
||||
The LM85 can be jumpered for 3 different SMBus addresses. There are
|
||||
no other hardware configuration options for the LM85.
|
||||
|
||||
The lm85 driver detects both LM85B and LM85C revisions of the chip. See the
|
||||
datasheet for a complete description of the differences. Other than
|
||||
identifying the chip, the driver behaves no differently with regard to
|
||||
these two chips. The LM85B is recommended for new designs.
|
||||
|
||||
The ADM1027 and ADT7463 chips have an optional SMBALERT output that can be
|
||||
used to signal the chipset in case a limit is exceeded or the temperature
|
||||
sensors fail. Individual sensor interrupts can be masked so they won't
|
||||
trigger SMBALERT. The SMBALERT output if configured replaces one of the other
|
||||
functions (PWM2 or IN0). This functionality is not implemented in current
|
||||
driver.
|
||||
|
||||
The ADT7463 also has an optional THERM output/input which can be connected
|
||||
to the processor PROC_HOT output. If available, the autofan control
|
||||
dynamic Tmin feature can be enabled to keep the system temperature within
|
||||
spec (just?!) with the least possible fan noise.
|
||||
|
||||
Configuration Notes
|
||||
-------------------
|
||||
|
||||
Besides standard interfaces driver adds following:
|
||||
|
||||
* Temperatures and Zones
|
||||
|
||||
Each temperature sensor is associated with a Zone. There are three
|
||||
sensors and therefore three zones (# 1, 2 and 3). Each zone has the following
|
||||
temperature configuration points:
|
||||
|
||||
* temp#_auto_temp_off - temperature below which fans should be off or spinning very low.
|
||||
* temp#_auto_temp_min - temperature over which fans start to spin.
|
||||
* temp#_auto_temp_max - temperature when fans spin at full speed.
|
||||
* temp#_auto_temp_crit - temperature when all fans will run full speed.
|
||||
|
||||
* PWM Control
|
||||
|
||||
There are three PWM outputs. The LM85 datasheet suggests that the
|
||||
pwm3 output control both fan3 and fan4. Each PWM can be individually
|
||||
configured and assigned to a zone for it's control value. Each PWM can be
|
||||
configured individually according to the following options.
|
||||
|
||||
* pwm#_auto_pwm_min - this specifies the PWM value for temp#_auto_temp_off
|
||||
temperature. (PWM value from 0 to 255)
|
||||
|
||||
* pwm#_auto_pwm_freq - select base frequency of PWM output. You can select
|
||||
in range of 10.0 to 94.0 Hz in .1 Hz units.
|
||||
(Values 100 to 940).
|
||||
|
||||
The pwm#_auto_pwm_freq can be set to one of the following 8 values. Setting the
|
||||
frequency to a value not on this list, will result in the next higher frequency
|
||||
being selected. The actual device frequency may vary slightly from this
|
||||
specification as designed by the manufacturer. Consult the datasheet for more
|
||||
details. (PWM Frequency values: 100, 150, 230, 300, 380, 470, 620, 940)
|
||||
|
||||
* pwm#_auto_pwm_minctl - this flags selects for temp#_auto_temp_off temperature
|
||||
the bahaviour of fans. Write 1 to let fans spinning at
|
||||
pwm#_auto_pwm_min or write 0 to let them off.
|
||||
|
||||
NOTE: It has been reported that there is a bug in the LM85 that causes the flag
|
||||
to be associated with the zones not the PWMs. This contradicts all the
|
||||
published documentation. Setting pwm#_min_ctl in this case actually affects all
|
||||
PWMs controlled by zone '#'.
|
||||
|
||||
* PWM Controlling Zone selection
|
||||
|
||||
* pwm#_auto_channels - controls zone that is associated with PWM
|
||||
|
||||
Configuration choices:
|
||||
|
||||
Value Meaning
|
||||
------ ------------------------------------------------
|
||||
1 Controlled by Zone 1
|
||||
2 Controlled by Zone 2
|
||||
3 Controlled by Zone 3
|
||||
23 Controlled by higher temp of Zone 2 or 3
|
||||
123 Controlled by highest temp of Zone 1, 2 or 3
|
||||
0 PWM always 0% (off)
|
||||
-1 PWM always 100% (full on)
|
||||
-2 Manual control (write to 'pwm#' to set)
|
||||
|
||||
The National LM85's have two vendor specific configuration
|
||||
features. Tach. mode and Spinup Control. For more details on these,
|
||||
see the LM85 datasheet or Application Note AN-1260.
|
||||
|
||||
The Analog Devices ADM1027 has several vendor specific enhancements.
|
||||
The number of pulses-per-rev of the fans can be set, Tach monitoring
|
||||
can be optimized for PWM operation, and an offset can be applied to
|
||||
the temperatures to compensate for systemic errors in the
|
||||
measurements.
|
||||
|
||||
In addition to the ADM1027 features, the ADT7463 also has Tmin control
|
||||
and THERM asserted counts. Automatic Tmin control acts to adjust the
|
||||
Tmin value to maintain the measured temperature sensor at a specified
|
||||
temperature. There isn't much documentation on this feature in the
|
||||
ADT7463 data sheet. This is not supported by current driver.
|
|
@ -0,0 +1,73 @@
|
|||
Kernel driver lm87
|
||||
==================
|
||||
|
||||
Supported chips:
|
||||
* National Semiconductor LM87
|
||||
Prefix: 'lm87'
|
||||
Addresses scanned: I2C 0x2c - 0x2f
|
||||
Datasheet: http://www.national.com/pf/LM/LM87.html
|
||||
|
||||
Authors:
|
||||
Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>,
|
||||
Mark Studebaker <mdsxyz123@yahoo.com>,
|
||||
Stephen Rousset <stephen.rousset@rocketlogix.com>,
|
||||
Dan Eaton <dan.eaton@rocketlogix.com>,
|
||||
Jean Delvare <khali@linux-fr.org>,
|
||||
Original 2.6 port Jeff Oliver
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the National Semiconductor LM87.
|
||||
|
||||
The LM87 implements up to three temperature sensors, up to two fan
|
||||
rotation speed sensors, up to seven voltage sensors, alarms, and some
|
||||
miscellaneous stuff.
|
||||
|
||||
Temperatures are measured in degrees Celsius. Each input has a high
|
||||
and low alarm settings. A high limit produces an alarm when the value
|
||||
goes above it, and an alarm is also produced when the value goes below
|
||||
the low limit.
|
||||
|
||||
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||
triggered if the rotation speed has dropped below a programmable limit. Fan
|
||||
readings can be divided by a programmable divider (1, 2, 4 or 8) to give
|
||||
the readings more range or accuracy. Not all RPM values can accurately be
|
||||
represented, so some rounding is done. With a divider of 2, the lowest
|
||||
representable value is around 2600 RPM.
|
||||
|
||||
Voltage sensors (also known as IN sensors) report their values in
|
||||
volts. An alarm is triggered if the voltage has crossed a programmable
|
||||
minimum or maximum limit. Note that minimum in this case always means
|
||||
'closest to zero'; this is important for negative voltage measurements.
|
||||
|
||||
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
|
||||
hardware registers are read whenever any data is read (unless it is less
|
||||
than 1.0 seconds since the last update). This means that you can easily
|
||||
miss once-only alarms.
|
||||
|
||||
The lm87 driver only updates its values each 1.0 seconds; reading it more
|
||||
often will do no harm, but will return 'old' values.
|
||||
|
||||
|
||||
Hardware Configurations
|
||||
-----------------------
|
||||
|
||||
The LM87 has four pins which can serve one of two possible functions,
|
||||
depending on the hardware configuration.
|
||||
|
||||
Some functions share pins, so not all functions are available at the same
|
||||
time. Which are depends on the hardware setup. This driver assumes that
|
||||
the BIOS configured the chip correctly. In that respect, it differs from
|
||||
the original driver (from lm_sensors for Linux 2.4), which would force the
|
||||
LM87 to an arbitrary, compile-time chosen mode, regardless of the actual
|
||||
chipset wiring.
|
||||
|
||||
For reference, here is the list of exclusive functions:
|
||||
- in0+in5 (default) or temp3
|
||||
- fan1 (default) or in6
|
||||
- fan2 (default) or in7
|
||||
- VID lines (default) or IRQ lines (not handled by this driver)
|
|
@ -0,0 +1,121 @@
|
|||
Kernel driver lm90
|
||||
==================
|
||||
|
||||
Supported chips:
|
||||
* National Semiconductor LM90
|
||||
Prefix: 'lm90'
|
||||
Addresses scanned: I2C 0x4c
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/pf/LM/LM90.html
|
||||
* National Semiconductor LM89
|
||||
Prefix: 'lm99'
|
||||
Addresses scanned: I2C 0x4c and 0x4d
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/pf/LM/LM89.html
|
||||
* National Semiconductor LM99
|
||||
Prefix: 'lm99'
|
||||
Addresses scanned: I2C 0x4c and 0x4d
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/pf/LM/LM99.html
|
||||
* National Semiconductor LM86
|
||||
Prefix: 'lm86'
|
||||
Addresses scanned: I2C 0x4c
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
http://www.national.com/pf/LM/LM86.html
|
||||
* Analog Devices ADM1032
|
||||
Prefix: 'adm1032'
|
||||
Addresses scanned: I2C 0x4c
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
http://products.analog.com/products/info.asp?product=ADM1032
|
||||
* Analog Devices ADT7461
|
||||
Prefix: 'adt7461'
|
||||
Addresses scanned: I2C 0x4c
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
http://products.analog.com/products/info.asp?product=ADT7461
|
||||
Note: Only if in ADM1032 compatibility mode
|
||||
* Maxim MAX6657
|
||||
Prefix: 'max6657'
|
||||
Addresses scanned: I2C 0x4c
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
|
||||
* Maxim MAX6658
|
||||
Prefix: 'max6657'
|
||||
Addresses scanned: I2C 0x4c
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
|
||||
* Maxim MAX6659
|
||||
Prefix: 'max6657'
|
||||
Addresses scanned: I2C 0x4c, 0x4d (unsupported 0x4e)
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
|
||||
|
||||
|
||||
Author: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The LM90 is a digital temperature sensor. It senses its own temperature as
|
||||
well as the temperature of up to one external diode. It is compatible
|
||||
with many other devices such as the LM86, the LM89, the LM99, the ADM1032,
|
||||
the MAX6657, MAX6658 and the MAX6659 all of which are supported by this driver.
|
||||
Note that there is no easy way to differentiate between the last three
|
||||
variants. The extra address and features of the MAX6659 are not supported by
|
||||
this driver. Additionally, the ADT7461 is supported if found in ADM1032
|
||||
compatibility mode.
|
||||
|
||||
The specificity of this family of chipsets over the ADM1021/LM84
|
||||
family is that it features critical limits with hysteresis, and an
|
||||
increased resolution of the remote temperature measurement.
|
||||
|
||||
The different chipsets of the family are not strictly identical, although
|
||||
very similar. This driver doesn't handle any specific feature for now,
|
||||
but could if there ever was a need for it. For reference, here comes a
|
||||
non-exhaustive list of specific features:
|
||||
|
||||
LM90:
|
||||
* Filter and alert configuration register at 0xBF.
|
||||
* ALERT is triggered by temperatures over critical limits.
|
||||
|
||||
LM86 and LM89:
|
||||
* Same as LM90
|
||||
* Better external channel accuracy
|
||||
|
||||
LM99:
|
||||
* Same as LM89
|
||||
* External temperature shifted by 16 degrees down
|
||||
|
||||
ADM1032:
|
||||
* Consecutive alert register at 0x22.
|
||||
* Conversion averaging.
|
||||
* Up to 64 conversions/s.
|
||||
* ALERT is triggered by open remote sensor.
|
||||
|
||||
ADT7461
|
||||
* Extended temperature range (breaks compatibility)
|
||||
* Lower resolution for remote temperature
|
||||
|
||||
MAX6657 and MAX6658:
|
||||
* Remote sensor type selection
|
||||
|
||||
MAX6659
|
||||
* Selectable address
|
||||
* Second critical temperature limit
|
||||
* Remote sensor type selection
|
||||
|
||||
All temperature values are given in degrees Celsius. Resolution
|
||||
is 1.0 degree for the local temperature, 0.125 degree for the remote
|
||||
temperature.
|
||||
|
||||
Each sensor has its own high and low limits, plus a critical limit.
|
||||
Additionally, there is a relative hysteresis value common to both critical
|
||||
values. To make life easier to user-space applications, two absolute values
|
||||
are exported, one for each channel, but these values are of course linked.
|
||||
Only the local hysteresis can be set from user-space, and the same delta
|
||||
applies to the remote hysteresis.
|
||||
|
||||
The lm90 driver will not update its values more frequently than every
|
||||
other second; reading them more often will do no harm, but will return
|
||||
'old' values.
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
Kernel driver lm92
|
||||
==================
|
||||
|
||||
Supported chips:
|
||||
* National Semiconductor LM92
|
||||
Prefix: 'lm92'
|
||||
Addresses scanned: I2C 0x48 - 0x4b
|
||||
Datasheet: http://www.national.com/pf/LM/LM92.html
|
||||
* National Semiconductor LM76
|
||||
Prefix: 'lm92'
|
||||
Addresses scanned: none, force parameter needed
|
||||
Datasheet: http://www.national.com/pf/LM/LM76.html
|
||||
* Maxim MAX6633/MAX6634/MAX6635
|
||||
Prefix: 'lm92'
|
||||
Addresses scanned: I2C 0x48 - 0x4b
|
||||
MAX6633 with address in 0x40 - 0x47, 0x4c - 0x4f needs force parameter
|
||||
and MAX6634 with address in 0x4c - 0x4f needs force parameter
|
||||
Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074
|
||||
|
||||
Authors:
|
||||
Abraham van der Merwe <abraham@2d3d.co.za>
|
||||
Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the National Semiconductor LM92
|
||||
temperature sensor.
|
||||
|
||||
Each LM92 temperature sensor supports a single temperature sensor. There are
|
||||
alarms for high, low, and critical thresholds. There's also an hysteresis to
|
||||
control the thresholds for resetting alarms.
|
||||
|
||||
Support was added later for the LM76 and Maxim MAX6633/MAX6634/MAX6635,
|
||||
which are mostly compatible. They have not all been tested, so you
|
||||
may need to use the force parameter.
|
|
@ -0,0 +1,29 @@
|
|||
Kernel driver max1619
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Maxim MAX1619
|
||||
Prefix: 'max1619'
|
||||
Addresses scanned: I2C 0x18-0x1a, 0x29-0x2b, 0x4c-0x4e
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf
|
||||
|
||||
Authors:
|
||||
Alexey Fisher <fishor@mail.ru>,
|
||||
Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The MAX1619 is a digital temperature sensor. It senses its own temperature as
|
||||
well as the temperature of up to one external diode.
|
||||
|
||||
All temperature values are given in degrees Celsius. Resolution
|
||||
is 1.0 degree for the local temperature and for the remote temperature.
|
||||
|
||||
Only the external sensor has high and low limits.
|
||||
|
||||
The max1619 driver will not update its values more frequently than every
|
||||
other second; reading them more often will do no harm, but will return
|
||||
'old' values.
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
Kernel driver max6875
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Maxim max6874, max6875
|
||||
Prefixes: 'max6875'
|
||||
Addresses scanned: 0x50, 0x52
|
||||
Datasheets:
|
||||
http://pdfserv.maxim-ic.com/en/ds/MAX6874-MAX6875.pdf
|
||||
|
||||
Author: Ben Gardner <bgardner@wabtec.com>
|
||||
|
||||
|
||||
Module Parameters
|
||||
-----------------
|
||||
|
||||
* allow_write int
|
||||
Set to non-zero to enable write permission:
|
||||
*0: Read only
|
||||
1: Read and write
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The MAXIM max6875 is a EEPROM-programmable power-supply sequencer/supervisor.
|
||||
It provides timed outputs that can be used as a watchdog, if properly wired.
|
||||
It also provides 512 bytes of user EEPROM.
|
||||
|
||||
At reset, the max6875 reads the configuration eeprom into its configuration
|
||||
registers. The chip then begins to operate according to the values in the
|
||||
registers.
|
||||
|
||||
See the datasheet for details on how to program the EEPROM.
|
||||
|
||||
|
||||
Sysfs entries
|
||||
-------------
|
||||
|
||||
eeprom_user - 512 bytes of user-defined EEPROM space. Only writable if
|
||||
allow_write was set and register 0x43 is 0.
|
||||
|
||||
eeprom_config - 70 bytes of config EEPROM. Note that changes will not get
|
||||
loaded into register space until a power cycle or device reset.
|
||||
|
||||
reg_config - 70 bytes of register space. Any changes take affect immediately.
|
||||
|
||||
|
||||
General Remarks
|
||||
---------------
|
||||
|
||||
A typical application will require that the EEPROMs be programmed once and
|
||||
never altered afterwards.
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
Kernel driver pc87360
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* National Semiconductor PC87360, PC87363, PC87364, PC87365 and PC87366
|
||||
Prefixes: 'pc87360', 'pc87363', 'pc87364', 'pc87365', 'pc87366'
|
||||
Addresses scanned: none, address read from Super I/O config space
|
||||
Datasheets:
|
||||
http://www.national.com/pf/PC/PC87360.html
|
||||
http://www.national.com/pf/PC/PC87363.html
|
||||
http://www.national.com/pf/PC/PC87364.html
|
||||
http://www.national.com/pf/PC/PC87365.html
|
||||
http://www.national.com/pf/PC/PC87366.html
|
||||
|
||||
Authors: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Thanks to Sandeep Mehta, Tonko de Rooy and Daniel Ceregatti for testing.
|
||||
Thanks to Rudolf Marek for helping me investigate conversion issues.
|
||||
|
||||
|
||||
Module Parameters
|
||||
-----------------
|
||||
|
||||
* init int
|
||||
Chip initialization level:
|
||||
0: None
|
||||
*1: Forcibly enable internal voltage and temperature channels, except in9
|
||||
2: Forcibly enable all voltage and temperature channels, except in9
|
||||
3: Forcibly enable all voltage and temperature channels, including in9
|
||||
|
||||
Note that this parameter has no effect for the PC87360, PC87363 and PC87364
|
||||
chips.
|
||||
|
||||
Also note that for the PC87366, initialization levels 2 and 3 don't enable
|
||||
all temperature channels, because some of them share pins with each other,
|
||||
so they can't be used at the same time.
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The National Semiconductor PC87360 Super I/O chip contains monitoring and
|
||||
PWM control circuitry for two fans. The PC87363 chip is similar, and the
|
||||
PC87364 chip has monitoring and PWM control for a third fan.
|
||||
|
||||
The National Semiconductor PC87365 and PC87366 Super I/O chips are complete
|
||||
hardware monitoring chipsets, not only controlling and monitoring three fans,
|
||||
but also monitoring eleven voltage inputs and two (PC87365) or up to four
|
||||
(PC87366) temperatures.
|
||||
|
||||
Chip #vin #fan #pwm #temp devid
|
||||
|
||||
PC87360 - 2 2 - 0xE1
|
||||
PC87363 - 2 2 - 0xE8
|
||||
PC87364 - 3 3 - 0xE4
|
||||
PC87365 11 3 3 2 0xE5
|
||||
PC87366 11 3 3 3-4 0xE9
|
||||
|
||||
The driver assumes that no more than one chip is present, and one of the
|
||||
standard Super I/O addresses is used (0x2E/0x2F or 0x4E/0x4F)
|
||||
|
||||
Fan Monitoring
|
||||
--------------
|
||||
|
||||
Fan rotation speeds are reported in RPM (revolutions per minute). An alarm
|
||||
is triggered if the rotation speed has dropped below a programmable limit.
|
||||
A different alarm is triggered if the fan speed is too low to be measured.
|
||||
|
||||
Fan readings are affected by a programmable clock divider, giving the
|
||||
readings more range or accuracy. Usually, users have to learn how it works,
|
||||
but this driver implements dynamic clock divider selection, so you don't
|
||||
have to care no more.
|
||||
|
||||
For reference, here are a few values about clock dividers:
|
||||
|
||||
slowest accuracy highest
|
||||
measurable around 3000 accurate
|
||||
divider speed (RPM) RPM (RPM) speed (RPM)
|
||||
1 1882 18 6928
|
||||
2 941 37 4898
|
||||
4 470 74 3464
|
||||
8 235 150 2449
|
||||
|
||||
For the curious, here is how the values above were computed:
|
||||
* slowest measurable speed: clock/(255*divider)
|
||||
* accuracy around 3000 RPM: 3000^2/clock
|
||||
* highest accurate speed: sqrt(clock*100)
|
||||
The clock speed for the PC87360 family is 480 kHz. I arbitrarily chose 100
|
||||
RPM as the lowest acceptable accuracy.
|
||||
|
||||
As mentioned above, you don't have to care about this no more.
|
||||
|
||||
Note that not all RPM values can be represented, even when the best clock
|
||||
divider is selected. This is not only true for the measured speeds, but
|
||||
also for the programmable low limits, so don't be surprised if you try to
|
||||
set, say, fan1_min to 2900 and it finally reads 2909.
|
||||
|
||||
|
||||
Fan Control
|
||||
-----------
|
||||
|
||||
PWM (pulse width modulation) values range from 0 to 255, with 0 meaning
|
||||
that the fan is stopped, and 255 meaning that the fan goes at full speed.
|
||||
|
||||
Be extremely careful when changing PWM values. Low PWM values, even
|
||||
non-zero, can stop the fan, which may cause irreversible damage to your
|
||||
hardware if temperature increases too much. When changing PWM values, go
|
||||
step by step and keep an eye on temperatures.
|
||||
|
||||
One user reported problems with PWM. Changing PWM values would break fan
|
||||
speed readings. No explanation nor fix could be found.
|
||||
|
||||
|
||||
Temperature Monitoring
|
||||
----------------------
|
||||
|
||||
Temperatures are reported in degrees Celsius. Each temperature measured has
|
||||
associated low, high and overtemperature limits, each of which triggers an
|
||||
alarm when crossed.
|
||||
|
||||
The first two temperature channels are external. The third one (PC87366
|
||||
only) is internal.
|
||||
|
||||
The PC87366 has three additional temperature channels, based on
|
||||
thermistors (as opposed to thermal diodes for the first three temperature
|
||||
channels). For technical reasons, these channels are held by the VLM
|
||||
(voltage level monitor) logical device, not the TMS (temperature
|
||||
measurement) one. As a consequence, these temperatures are exported as
|
||||
voltages, and converted into temperatures in user-space.
|
||||
|
||||
Note that these three additional channels share their pins with the
|
||||
external thermal diode channels, so you (physically) can't use them all at
|
||||
the same time. Although it should be possible to mix the two sensor types,
|
||||
the documents from National Semiconductor suggest that motherboard
|
||||
manufacturers should choose one type and stick to it. So you will more
|
||||
likely have either channels 1 to 3 (thermal diodes) or 3 to 6 (internal
|
||||
thermal diode, and thermistors).
|
||||
|
||||
|
||||
Voltage Monitoring
|
||||
------------------
|
||||
|
||||
Voltages are reported relatively to a reference voltage, either internal or
|
||||
external. Some of them (in7:Vsb, in8:Vdd and in10:AVdd) are divided by two
|
||||
internally, you will have to compensate in sensors.conf. Others (in0 to in6)
|
||||
are likely to be divided externally. The meaning of each of these inputs as
|
||||
well as the values of the resistors used for division is left to the
|
||||
motherboard manufacturers, so you will have to document yourself and edit
|
||||
sensors.conf accordingly. National Semiconductor has a document with
|
||||
recommended resistor values for some voltages, but this still leaves much
|
||||
room for per motherboard specificities, unfortunately. Even worse,
|
||||
motherboard manufacturers don't seem to care about National Semiconductor's
|
||||
recommendations.
|
||||
|
||||
Each voltage measured has associated low and high limits, each of which
|
||||
triggers an alarm when crossed.
|
||||
|
||||
When available, VID inputs are used to provide the nominal CPU Core voltage.
|
||||
The driver will default to VRM 9.0, but this can be changed from user-space.
|
||||
The chipsets can handle two sets of VID inputs (on dual-CPU systems), but
|
||||
the driver will only export one for now. This may change later if there is
|
||||
a need.
|
||||
|
||||
|
||||
General Remarks
|
||||
---------------
|
||||
|
||||
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 all hardware registers are read whenever any
|
||||
data is read (unless it is less than 2 seconds since the last update, in
|
||||
which case cached values are returned instead). As a consequence, when
|
||||
a once-only alarm triggers, it may take 2 seconds for it to show, and 2
|
||||
more seconds for it to disappear.
|
||||
|
||||
Monitoring of in9 isn't enabled at lower init levels (<3) because that
|
||||
channel measures the battery voltage (Vbat). It is a known fact that
|
||||
repeatedly sampling the battery voltage reduces its lifetime. National
|
||||
Semiconductor smartly designed their chipset so that in9 is sampled only
|
||||
once every 1024 sampling cycles (that is every 34 minutes at the default
|
||||
sampling rate), so the effect is attenuated, but still present.
|
||||
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
The datasheets suggests that some values (fan mins, fan dividers)
|
||||
shouldn't be changed once the monitoring has started, but we ignore that
|
||||
recommendation. We'll reconsider if it actually causes trouble.
|
|
@ -0,0 +1,47 @@
|
|||
Kernel driver pca9539
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Philips PCA9539
|
||||
Prefix: 'pca9539'
|
||||
Addresses scanned: 0x74 - 0x77
|
||||
Datasheet:
|
||||
http://www.semiconductors.philips.com/acrobat/datasheets/PCA9539_2.pdf
|
||||
|
||||
Author: Ben Gardner <bgardner@wabtec.com>
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The Philips PCA9539 is a 16 bit low power I/O device.
|
||||
All 16 lines can be individually configured as an input or output.
|
||||
The input sense can also be inverted.
|
||||
The 16 lines are split between two bytes.
|
||||
|
||||
|
||||
Sysfs entries
|
||||
-------------
|
||||
|
||||
Each is a byte that maps to the 8 I/O bits.
|
||||
A '0' suffix is for bits 0-7, while '1' is for bits 8-15.
|
||||
|
||||
input[01] - read the current value
|
||||
output[01] - sets the output value
|
||||
direction[01] - direction of each bit: 1=input, 0=output
|
||||
invert[01] - toggle the input bit sense
|
||||
|
||||
input reads the actual state of the line and is always available.
|
||||
The direction defaults to input for all channels.
|
||||
|
||||
|
||||
General Remarks
|
||||
---------------
|
||||
|
||||
Note that each output, direction, and invert entry controls 8 lines.
|
||||
You should use the read, modify, write sequence.
|
||||
For example. to set output bit 0 of 1.
|
||||
val=$(cat output0)
|
||||
val=$(( $val | 1 ))
|
||||
echo $val > output0
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
Kernel driver pcf8574
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Philips PCF8574
|
||||
Prefix: 'pcf8574'
|
||||
Addresses scanned: I2C 0x20 - 0x27
|
||||
Datasheet: Publicly available at the Philips Semiconductors website
|
||||
http://www.semiconductors.philips.com/pip/PCF8574P.html
|
||||
|
||||
* Philips PCF8574A
|
||||
Prefix: 'pcf8574a'
|
||||
Addresses scanned: I2C 0x38 - 0x3f
|
||||
Datasheet: Publicly available at the Philips Semiconductors website
|
||||
http://www.semiconductors.philips.com/pip/PCF8574P.html
|
||||
|
||||
Authors:
|
||||
Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>,
|
||||
Dan Eaton <dan.eaton@rocketlogix.com>,
|
||||
Aurelien Jarno <aurelien@aurel32.net>,
|
||||
Jean Delvare <khali@linux-fr.org>,
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
The PCF8574(A) is an 8-bit I/O expander for the I2C bus produced by Philips
|
||||
Semiconductors. It is designed to provide a byte I2C interface to up to 16
|
||||
separate devices (8 x PCF8574 and 8 x PCF8574A).
|
||||
|
||||
This device consists of a quasi-bidirectional port. Each of the eight I/Os
|
||||
can be independently used as an input or output. To setup an I/O as an
|
||||
input, you have to write a 1 to the corresponding output.
|
||||
|
||||
For more informations see the datasheet.
|
||||
|
||||
|
||||
Accessing PCF8574(A) via /sys interface
|
||||
-------------------------------------
|
||||
|
||||
! Be careful !
|
||||
The PCF8574(A) is plainly impossible to detect ! Stupid chip.
|
||||
So every chip with address in the interval [20..27] and [38..3f] are
|
||||
detected as PCF8574(A). If you have other chips in this address
|
||||
range, the workaround is to load this module after the one
|
||||
for your others chips.
|
||||
|
||||
On detection (i.e. insmod, modprobe et al.), directories are being
|
||||
created for each detected PCF8574(A):
|
||||
|
||||
/sys/bus/i2c/devices/<0>-<1>/
|
||||
where <0> is the bus the chip was detected on (e. g. i2c-0)
|
||||
and <1> the chip address ([20..27] or [38..3f]):
|
||||
|
||||
(example: /sys/bus/i2c/devices/1-0020/)
|
||||
|
||||
Inside these directories, there are two files each:
|
||||
read and write (and one file with chip name).
|
||||
|
||||
The read file is read-only. Reading gives you the current I/O input
|
||||
if the corresponding output is set as 1, otherwise the current output
|
||||
value, that is to say 0.
|
||||
|
||||
The write file is read/write. Writing a value outputs it on the I/O
|
||||
port. Reading returns the last written value.
|
||||
|
||||
On module initialization the chip is configured as eight inputs (all
|
||||
outputs to 1), so you can connect any circuit to the PCF8574(A) without
|
||||
being afraid of short-circuit.
|
|
@ -0,0 +1,90 @@
|
|||
Kernel driver pcf8591
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Philips PCF8591
|
||||
Prefix: 'pcf8591'
|
||||
Addresses scanned: I2C 0x48 - 0x4f
|
||||
Datasheet: Publicly available at the Philips Semiconductor website
|
||||
http://www.semiconductors.philips.com/pip/PCF8591P.html
|
||||
|
||||
Authors:
|
||||
Aurelien Jarno <aurelien@aurel32.net>
|
||||
valuable contributions by Jan M. Sendler <sendler@sendler.de>,
|
||||
Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
The PCF8591 is an 8-bit A/D and D/A converter (4 analog inputs and one
|
||||
analog output) for the I2C bus produced by Philips Semiconductors. It
|
||||
is designed to provide a byte I2C interface to up to 4 separate devices.
|
||||
|
||||
The PCF8591 has 4 analog inputs programmable as single-ended or
|
||||
differential inputs :
|
||||
- mode 0 : four single ended inputs
|
||||
Pins AIN0 to AIN3 are single ended inputs for channels 0 to 3
|
||||
|
||||
- mode 1 : three differential inputs
|
||||
Pins AIN3 is the common negative differential input
|
||||
Pins AIN0 to AIN2 are positive differential inputs for channels 0 to 2
|
||||
|
||||
- mode 2 : single ended and differential mixed
|
||||
Pins AIN0 and AIN1 are single ended inputs for channels 0 and 1
|
||||
Pins AIN2 is the positive differential input for channel 3
|
||||
Pins AIN3 is the negative differential input for channel 3
|
||||
|
||||
- mode 3 : two differential inputs
|
||||
Pins AIN0 is the positive differential input for channel 0
|
||||
Pins AIN1 is the negative differential input for channel 0
|
||||
Pins AIN2 is the positive differential input for channel 1
|
||||
Pins AIN3 is the negative differential input for channel 1
|
||||
|
||||
See the datasheet for details.
|
||||
|
||||
Module parameters
|
||||
-----------------
|
||||
|
||||
* input_mode int
|
||||
|
||||
Analog input mode:
|
||||
0 = four single ended inputs
|
||||
1 = three differential inputs
|
||||
2 = single ended and differential mixed
|
||||
3 = two differential inputs
|
||||
|
||||
|
||||
Accessing PCF8591 via /sys interface
|
||||
-------------------------------------
|
||||
|
||||
! Be careful !
|
||||
The PCF8591 is plainly impossible to detect ! Stupid chip.
|
||||
So every chip with address in the interval [48..4f] is
|
||||
detected as PCF8591. If you have other chips in this address
|
||||
range, the workaround is to load this module after the one
|
||||
for your others chips.
|
||||
|
||||
On detection (i.e. insmod, modprobe et al.), directories are being
|
||||
created for each detected PCF8591:
|
||||
|
||||
/sys/bus/devices/<0>-<1>/
|
||||
where <0> is the bus the chip was detected on (e. g. i2c-0)
|
||||
and <1> the chip address ([48..4f])
|
||||
|
||||
Inside these directories, there are such files:
|
||||
in0, in1, in2, in3, out0_enable, out0_output, name
|
||||
|
||||
Name contains chip name.
|
||||
|
||||
The in0, in1, in2 and in3 files are RO. Reading gives the value of the
|
||||
corresponding channel. Depending on the current analog inputs configuration,
|
||||
files in2 and/or in3 do not exist. Values range are from 0 to 255 for single
|
||||
ended inputs and -128 to +127 for differential inputs (8-bit ADC).
|
||||
|
||||
The out0_enable file is RW. Reading gives "1" for analog output enabled and
|
||||
"0" for analog output disabled. Writing accepts "0" and "1" accordingly.
|
||||
|
||||
The out0_output file is RW. Writing a number between 0 and 255 (8-bit DAC), send
|
||||
the value to the digital-to-analog converter. Note that a voltage will
|
||||
only appears on AOUT pin if aout0_enable equals 1. Reading returns the last
|
||||
value written.
|
|
@ -0,0 +1,106 @@
|
|||
Kernel driver sis5595
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Silicon Integrated Systems Corp. SiS5595 Southbridge Hardware Monitor
|
||||
Prefix: 'sis5595'
|
||||
Addresses scanned: ISA in PCI-space encoded address
|
||||
Datasheet: Publicly available at the Silicon Integrated Systems Corp. site.
|
||||
|
||||
Authors:
|
||||
Kyösti Mälkki <kmalkki@cc.hut.fi>,
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>,
|
||||
Aurelien Jarno <aurelien@aurel32.net> 2.6 port
|
||||
|
||||
SiS southbridge has a LM78-like chip integrated on the same IC.
|
||||
This driver is a customized copy of lm78.c
|
||||
|
||||
Supports following revisions:
|
||||
Version PCI ID PCI Revision
|
||||
1 1039/0008 AF or less
|
||||
2 1039/0008 B0 or greater
|
||||
|
||||
Note: these chips contain a 0008 device which is incompatible with the
|
||||
5595. We recognize these by the presence of the listed
|
||||
"blacklist" PCI ID and refuse to load.
|
||||
|
||||
NOT SUPPORTED PCI ID BLACKLIST PCI ID
|
||||
540 0008 0540
|
||||
550 0008 0550
|
||||
5513 0008 5511
|
||||
5581 0008 5597
|
||||
5582 0008 5597
|
||||
5597 0008 5597
|
||||
630 0008 0630
|
||||
645 0008 0645
|
||||
730 0008 0730
|
||||
735 0008 0735
|
||||
|
||||
|
||||
Module Parameters
|
||||
-----------------
|
||||
force_addr=0xaddr Set the I/O base address. Useful for boards
|
||||
that don't set the address in the BIOS. Does not do a
|
||||
PCI force; the device must still be present in lspci.
|
||||
Don't use this unless the driver complains that the
|
||||
base address is not set.
|
||||
Example: 'modprobe sis5595 force_addr=0x290'
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The SiS5595 southbridge has integrated hardware monitor functions. It also
|
||||
has an I2C bus, but this driver only supports the hardware monitor. For the
|
||||
I2C bus driver see i2c-sis5595.
|
||||
|
||||
The SiS5595 implements zero or one temperature sensor, two fan speed
|
||||
sensors, four or five voltage sensors, and alarms.
|
||||
|
||||
On the first version of the chip, there are four voltage sensors and one
|
||||
temperature sensor.
|
||||
|
||||
On the second version of the chip, the temperature sensor (temp) and the
|
||||
fifth voltage sensor (in4) share a pin which is configurable, but not
|
||||
through the driver. Sorry. The driver senses the configuration of the pin,
|
||||
which was hopefully set by the BIOS.
|
||||
|
||||
Temperatures are measured in degrees Celsius. An alarm is triggered once
|
||||
when the max is crossed; it is also triggered when it drops below the min
|
||||
value. Measurements are guaranteed between -55 and +125 degrees, with a
|
||||
resolution of 1 degree.
|
||||
|
||||
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||
triggered if the rotation speed has dropped below a programmable limit. Fan
|
||||
readings can be divided by a programmable divider (1, 2, 4 or 8) to give
|
||||
the readings more range or accuracy. Not all RPM values can accurately be
|
||||
represented, so some rounding is done. With a divider of 2, the lowest
|
||||
representable value is around 2600 RPM.
|
||||
|
||||
Voltage sensors (also known as IN sensors) report their values in volts. An
|
||||
alarm is triggered if the voltage has crossed a programmable minimum or
|
||||
maximum limit. Note that minimum in this case always means 'closest to
|
||||
zero'; this is important for negative voltage measurements. All voltage
|
||||
inputs can measure voltages between 0 and 4.08 volts, with a resolution of
|
||||
0.016 volt.
|
||||
|
||||
In addition to the alarms described above, there is a BTI alarm, which gets
|
||||
triggered when an external chip has crossed its limits. Usually, this is
|
||||
connected to some LM75-like chip; if at least one crosses its limits, this
|
||||
bit gets set.
|
||||
|
||||
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 hardware
|
||||
registers are read whenever any data is read (unless it is less than 1.5
|
||||
seconds since the last update). This means that you can easily miss
|
||||
once-only alarms.
|
||||
|
||||
The SiS5595 only updates its values each 1.5 seconds; reading it more often
|
||||
will do no harm, but will return 'old' values.
|
||||
|
||||
Problems
|
||||
--------
|
||||
Some chips refuse to be enabled. We don't know why.
|
||||
The driver will recognize this and print a message in dmesg.
|
||||
|
|
@ -1,3 +1,15 @@
|
|||
Kernel driver smsc47b397
|
||||
========================
|
||||
|
||||
Supported chips:
|
||||
* SMSC LPC47B397-NC
|
||||
Prefix: 'smsc47b397'
|
||||
Addresses scanned: none, address read from Super I/O config space
|
||||
Datasheet: In this file
|
||||
|
||||
Authors: Mark M. Hoffman <mhoffman@lightlink.com>
|
||||
Utilitek Systems, Inc.
|
||||
|
||||
November 23, 2004
|
||||
|
||||
The following specification describes the SMSC LPC47B397-NC sensor chip
|
|
@ -0,0 +1,52 @@
|
|||
Kernel driver smsc47m1
|
||||
======================
|
||||
|
||||
Supported chips:
|
||||
* SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192
|
||||
Addresses scanned: none, address read from Super I/O config space
|
||||
Prefix: 'smsc47m1'
|
||||
Datasheets:
|
||||
http://www.smsc.com/main/datasheets/47b27x.pdf
|
||||
http://www.smsc.com/main/datasheets/47m10x.pdf
|
||||
http://www.smsc.com/main/tools/discontinued/47m13x.pdf
|
||||
http://www.smsc.com/main/datasheets/47m14x.pdf
|
||||
http://www.smsc.com/main/tools/discontinued/47m15x.pdf
|
||||
http://www.smsc.com/main/datasheets/47m192.pdf
|
||||
|
||||
Authors:
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>,
|
||||
With assistance from Bruce Allen <ballen@uwm.edu>, and his
|
||||
fan.c program: http://www.lsc-group.phys.uwm.edu/%7Eballen/driver/
|
||||
Gabriele Gorla <gorlik@yahoo.com>,
|
||||
Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The Standard Microsystems Corporation (SMSC) 47M1xx Super I/O chips
|
||||
contain monitoring and PWM control circuitry for two fans.
|
||||
|
||||
The 47M15x and 47M192 chips contain a full 'hardware monitoring block'
|
||||
in addition to the fan monitoring and control. The hardware monitoring
|
||||
block is not supported by the driver.
|
||||
|
||||
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||
triggered if the rotation speed has dropped below a programmable limit. Fan
|
||||
readings can be divided by a programmable divider (1, 2, 4 or 8) to give
|
||||
the readings more range or accuracy. Not all RPM values can accurately be
|
||||
represented, so some rounding is done. With a divider of 2, the lowest
|
||||
representable value is around 2600 RPM.
|
||||
|
||||
PWM values are from 0 to 255.
|
||||
|
||||
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
|
||||
hardware registers are read whenever any data is read (unless it is less
|
||||
than 1.5 seconds since the last update). This means that you can easily
|
||||
miss once-only alarms.
|
||||
|
||||
|
||||
**********************
|
||||
The lm_sensors project gratefully acknowledges the support of
|
||||
Intel in the development of this driver.
|
|
@ -0,0 +1,65 @@
|
|||
Kernel driver via686a
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Via VT82C686A, VT82C686B Southbridge Integrated Hardware Monitor
|
||||
Prefix: 'via686a'
|
||||
Addresses scanned: ISA in PCI-space encoded address
|
||||
Datasheet: On request through web form (http://www.via.com.tw/en/support/datasheets/)
|
||||
|
||||
Authors:
|
||||
Kyösti Mälkki <kmalkki@cc.hut.fi>,
|
||||
Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
Bob Dougherty <bobd@stanford.edu>
|
||||
(Some conversion-factor data were contributed by
|
||||
Jonathan Teh Soon Yew <j.teh@iname.com>
|
||||
and Alex van Kaam <darkside@chello.nl>.)
|
||||
|
||||
Module Parameters
|
||||
-----------------
|
||||
|
||||
force_addr=0xaddr Set the I/O base address. Useful for Asus A7V boards
|
||||
that don't set the address in the BIOS. Does not do a
|
||||
PCI force; the via686a must still be present in lspci.
|
||||
Don't use this unless the driver complains that the
|
||||
base address is not set.
|
||||
Example: 'modprobe via686a force_addr=0x6000'
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The driver does not distinguish between the chips and reports
|
||||
all as a 686A.
|
||||
|
||||
The Via 686a southbridge has integrated hardware monitor functionality.
|
||||
It also has an I2C bus, but this driver only supports the hardware monitor.
|
||||
For the I2C bus driver, see <file:Documentation/i2c/busses/i2c-viapro>
|
||||
|
||||
The Via 686a implements three temperature sensors, two fan rotation speed
|
||||
sensors, five voltage sensors and alarms.
|
||||
|
||||
Temperatures are measured in degrees Celsius. An alarm is triggered once
|
||||
when the Overtemperature Shutdown limit is crossed; it is triggered again
|
||||
as soon as it drops below the hysteresis value.
|
||||
|
||||
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||
triggered if the rotation speed has dropped below a programmable limit. Fan
|
||||
readings can be divided by a programmable divider (1, 2, 4 or 8) to give
|
||||
the readings more range or accuracy. Not all RPM values can accurately be
|
||||
represented, so some rounding is done. With a divider of 2, the lowest
|
||||
representable value is around 2600 RPM.
|
||||
|
||||
Voltage sensors (also known as IN sensors) report their values in volts.
|
||||
An alarm is triggered if the voltage has crossed a programmable minimum
|
||||
or maximum limit. Voltages are internally scalled, so each voltage channel
|
||||
has a different resolution and range.
|
||||
|
||||
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
|
||||
hardware registers are read whenever any data is read (unless it is less
|
||||
than 1.5 seconds since the last update). This means that you can easily
|
||||
miss once-only alarms.
|
||||
|
||||
The driver only updates its values each 1.5 seconds; reading it more often
|
||||
will do no harm, but will return 'old' values.
|
|
@ -0,0 +1,66 @@
|
|||
Kernel driver w83627hf
|
||||
======================
|
||||
|
||||
Supported chips:
|
||||
* Winbond W83627HF (ISA accesses ONLY)
|
||||
Prefix: 'w83627hf'
|
||||
Addresses scanned: ISA address retrieved from Super I/O registers
|
||||
Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf
|
||||
* Winbond W83627THF
|
||||
Prefix: 'w83627thf'
|
||||
Addresses scanned: ISA address retrieved from Super I/O registers
|
||||
Datasheet: http://www.winbond.com/PDF/sheet/w83627thf.pdf
|
||||
* Winbond W83697HF
|
||||
Prefix: 'w83697hf'
|
||||
Addresses scanned: ISA address retrieved from Super I/O registers
|
||||
Datasheet: http://www.winbond.com/PDF/sheet/697hf.pdf
|
||||
* Winbond W83637HF
|
||||
Prefix: 'w83637hf'
|
||||
Addresses scanned: ISA address retrieved from Super I/O registers
|
||||
Datasheet: http://www.winbond.com/PDF/sheet/w83637hf.pdf
|
||||
|
||||
Authors:
|
||||
Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>,
|
||||
Mark Studebaker <mdsxyz123@yahoo.com>,
|
||||
Bernhard C. Schrenk <clemy@clemy.org>
|
||||
|
||||
Module Parameters
|
||||
-----------------
|
||||
|
||||
* force_addr: int
|
||||
Initialize the ISA address of the sensors
|
||||
* force_i2c: int
|
||||
Initialize the I2C address of the sensors
|
||||
* init: int
|
||||
(default is 1)
|
||||
Use 'init=0' to bypass initializing the chip.
|
||||
Try this if your computer crashes when you load the module.
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for ISA accesses *only* for
|
||||
the Winbond W83627HF, W83627THF, W83697HF and W83637HF Super I/O chips.
|
||||
We will refer to them collectively as Winbond chips.
|
||||
|
||||
This driver supports ISA accesses, which should be more reliable
|
||||
than i2c accesses. Also, for Tyan boards which contain both a
|
||||
Super I/O chip and a second i2c-only Winbond chip (often a W83782D),
|
||||
using this driver will avoid i2c address conflicts and complex
|
||||
initialization that were required in the w83781d driver.
|
||||
|
||||
If you really want i2c accesses for these Super I/O chips,
|
||||
use the w83781d driver. However this is not the preferred method
|
||||
now that this ISA driver has been developed.
|
||||
|
||||
Technically, the w83627thf does not support a VID reading. However, it's
|
||||
possible or even likely that your mainboard maker has routed these signals
|
||||
to a specific set of general purpose IO pins (the Asus P4C800-E is one such
|
||||
board). The w83627thf driver now interprets these as VID. If the VID on
|
||||
your board doesn't work, first see doc/vid in the lm_sensors package. If
|
||||
that still doesn't help, email us at lm-sensors@lm-sensors.org.
|
||||
|
||||
For further information on this driver see the w83781d driver
|
||||
documentation.
|
||||
|
|
@ -0,0 +1,402 @@
|
|||
Kernel driver w83781d
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
* Winbond W83781D
|
||||
Prefix: 'w83781d'
|
||||
Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
|
||||
Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83781d.pdf
|
||||
* Winbond W83782D
|
||||
Prefix: 'w83782d'
|
||||
Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
|
||||
Datasheet: http://www.winbond.com/PDF/sheet/w83782d.pdf
|
||||
* Winbond W83783S
|
||||
Prefix: 'w83783s'
|
||||
Addresses scanned: I2C 0x2d
|
||||
Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83783s.pdf
|
||||
* Winbond W83627HF
|
||||
Prefix: 'w83627hf'
|
||||
Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
|
||||
Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf
|
||||
* Asus AS99127F
|
||||
Prefix: 'as99127f'
|
||||
Addresses scanned: I2C 0x28 - 0x2f
|
||||
Datasheet: Unavailable from Asus
|
||||
|
||||
Authors:
|
||||
Frodo Looijaard <frodol@dds.nl>,
|
||||
Philip Edelbrock <phil@netroedge.com>,
|
||||
Mark Studebaker <mdsxyz123@yahoo.com>
|
||||
|
||||
Module parameters
|
||||
-----------------
|
||||
|
||||
* init int
|
||||
(default 1)
|
||||
Use 'init=0' to bypass initializing the chip.
|
||||
Try this if your computer crashes when you load the module.
|
||||
|
||||
force_subclients=bus,caddr,saddr,saddr
|
||||
This is used to force the i2c addresses for subclients of
|
||||
a certain chip. Typical usage is `force_subclients=0,0x2d,0x4a,0x4b'
|
||||
to force the subclients of chip 0x2d on bus 0 to i2c addresses
|
||||
0x4a and 0x4b. This parameter is useful for certain Tyan boards.
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the Winbond W83781D, W83782D, W83783S,
|
||||
W83627HF chips, and the Asus AS99127F chips. We will refer to them
|
||||
collectively as W8378* chips.
|
||||
|
||||
There is quite some difference between these chips, but they are similar
|
||||
enough that it was sensible to put them together in one driver.
|
||||
The W83627HF chip is assumed to be identical to the ISA W83782D.
|
||||
The Asus chips are similar to an I2C-only W83782D.
|
||||
|
||||
Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA
|
||||
as99127f 7 3 0 3 0x31 0x12c3 yes no
|
||||
as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no
|
||||
w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes
|
||||
w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC)
|
||||
w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes
|
||||
w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no
|
||||
|
||||
Detection of these chips can sometimes be foiled because they can be in
|
||||
an internal state that allows no clean access. If you know the address
|
||||
of the chip, use a 'force' parameter; this will put them into a more
|
||||
well-behaved state first.
|
||||
|
||||
The W8378* implements temperature sensors (three on the W83781D and W83782D,
|
||||
two on the W83783S), three fan rotation speed sensors, voltage sensors
|
||||
(seven on the W83781D, nine on the W83782D and six on the W83783S), VID
|
||||
lines, alarms with beep warnings, and some miscellaneous stuff.
|
||||
|
||||
Temperatures are measured in degrees Celsius. There is always one main
|
||||
temperature sensor, and one (W83783S) or two (W83781D and W83782D) other
|
||||
sensors. An alarm is triggered for the main sensor once when the
|
||||
Overtemperature Shutdown limit is crossed; it is triggered again as soon as
|
||||
it drops below the Hysteresis value. A more useful behavior
|
||||
can be found by setting the Hysteresis value to +127 degrees Celsius; in
|
||||
this case, alarms are issued during all the time when the actual temperature
|
||||
is above the Overtemperature Shutdown value. The driver sets the
|
||||
hysteresis value for temp1 to 127 at initialization.
|
||||
|
||||
For the other temperature sensor(s), an alarm is triggered when the
|
||||
temperature gets higher then the Overtemperature Shutdown value; it stays
|
||||
on until the temperature falls below the Hysteresis value. But on the
|
||||
W83781D, there is only one alarm that functions for both other sensors!
|
||||
Temperatures are guaranteed within a range of -55 to +125 degrees. The
|
||||
main temperature sensors has a resolution of 1 degree; the other sensor(s)
|
||||
of 0.5 degree.
|
||||
|
||||
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||
triggered if the rotation speed has dropped below a programmable limit. Fan
|
||||
readings can be divided by a programmable divider (1, 2, 4 or 8 for the
|
||||
W83781D; 1, 2, 4, 8, 16, 32, 64 or 128 for the others) to give
|
||||
the readings more range or accuracy. Not all RPM values can accurately
|
||||
be represented, so some rounding is done. With a divider of 2, the lowest
|
||||
representable value is around 2600 RPM.
|
||||
|
||||
Voltage sensors (also known as IN sensors) report their values in volts.
|
||||
An alarm is triggered if the voltage has crossed a programmable minimum
|
||||
or maximum limit. Note that minimum in this case always means 'closest to
|
||||
zero'; this is important for negative voltage measurements. All voltage
|
||||
inputs can measure voltages between 0 and 4.08 volts, with a resolution
|
||||
of 0.016 volt.
|
||||
|
||||
The VID lines encode the core voltage value: the voltage level your processor
|
||||
should work with. This is hardcoded by the mainboard and/or processor itself.
|
||||
It is a value in volts. When it is unconnected, you will often find the
|
||||
value 3.50 V here.
|
||||
|
||||
The W83782D and W83783S temperature conversion machine understands about
|
||||
several kinds of temperature probes. You can program the so-called
|
||||
beta value in the sensor files. '1' is the PII/Celeron diode, '2' is the
|
||||
TN3904 transistor, and 3435 the default thermistor value. Other values
|
||||
are (not yet) supported.
|
||||
|
||||
In addition to the alarms described above, there is a CHAS alarm on the
|
||||
chips which triggers if your computer case is open.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
hardware registers are read whenever any data is read (unless it is less
|
||||
than 1.5 seconds since the last update). This means that you can easily
|
||||
miss once-only alarms.
|
||||
|
||||
The chips only update values each 1.5 seconds; reading them more often
|
||||
will do no harm, but will return 'old' values.
|
||||
|
||||
AS99127F PROBLEMS
|
||||
-----------------
|
||||
The as99127f support was developed without the benefit of a datasheet.
|
||||
In most cases it is treated as a w83781d (although revision 2 of the
|
||||
AS99127F looks more like a w83782d).
|
||||
This support will be BETA until a datasheet is released.
|
||||
One user has reported problems with fans stopping
|
||||
occasionally.
|
||||
|
||||
Note that the individual beep bits are inverted from the other chips.
|
||||
The driver now takes care of this so that user-space applications
|
||||
don't have to know about it.
|
||||
|
||||
Known problems:
|
||||
- Problems with diode/thermistor settings (supported?)
|
||||
- One user reports fans stopping under high server load.
|
||||
- Revision 2 seems to have 2 PWM registers but we don't know
|
||||
how to handle them. More details below.
|
||||
|
||||
These will not be fixed unless we get a datasheet.
|
||||
If you have problems, please lobby Asus to release a datasheet.
|
||||
Unfortunately several others have without success.
|
||||
Please do not send mail to us asking for better as99127f support.
|
||||
We have done the best we can without a datasheet.
|
||||
Please do not send mail to the author or the sensors group asking for
|
||||
a datasheet or ideas on how to convince Asus. We can't help.
|
||||
|
||||
|
||||
NOTES:
|
||||
-----
|
||||
783s has no in1 so that in[2-6] are compatible with the 781d/782d.
|
||||
|
||||
783s pin is programmable for -5V or temp1; defaults to -5V,
|
||||
no control in driver so temp1 doesn't work.
|
||||
|
||||
782d and 783s datasheets differ on which is pwm1 and which is pwm2.
|
||||
We chose to follow 782d.
|
||||
|
||||
782d and 783s pin is programmable for fan3 input or pwm2 output;
|
||||
defaults to fan3 input.
|
||||
If pwm2 is enabled (with echo 255 1 > pwm2), then
|
||||
fan3 will report 0.
|
||||
|
||||
782d has pwm1-2 for ISA, pwm1-4 for i2c. (pwm3-4 share pins with
|
||||
the ISA pins)
|
||||
|
||||
Data sheet updates:
|
||||
------------------
|
||||
- PWM clock registers:
|
||||
|
||||
000: master / 512
|
||||
001: master / 1024
|
||||
010: master / 2048
|
||||
011: master / 4096
|
||||
100: master / 8192
|
||||
|
||||
|
||||
Answers from Winbond tech support
|
||||
---------------------------------
|
||||
>
|
||||
> 1) In the W83781D data sheet section 7.2 last paragraph, it talks about
|
||||
> reprogramming the R-T table if the Beta of the thermistor is not
|
||||
> 3435K. The R-T table is described briefly in section 8.20.
|
||||
> What formulas do I use to program a new R-T table for a given Beta?
|
||||
>
|
||||
We are sorry that the calculation for R-T table value is
|
||||
confidential. If you have another Beta value of thermistor, we can help
|
||||
to calculate the R-T table for you. But you should give us real R-T
|
||||
Table which can be gotten by thermistor vendor. Therefore we will calculate
|
||||
them and obtain 32-byte data, and you can fill the 32-byte data to the
|
||||
register in Bank0.CR51 of W83781D.
|
||||
|
||||
|
||||
> 2) In the W83782D data sheet, it mentions that pins 38, 39, and 40 are
|
||||
> programmable to be either thermistor or Pentium II diode inputs.
|
||||
> How do I program them for diode inputs? I can't find any register
|
||||
> to program these to be diode inputs.
|
||||
--> You may program Bank0 CR[5Dh] and CR[59h] registers.
|
||||
|
||||
CR[5Dh] bit 1(VTIN1) bit 2(VTIN2) bit 3(VTIN3)
|
||||
|
||||
thermistor 0 0 0
|
||||
diode 1 1 1
|
||||
|
||||
|
||||
(error) CR[59h] bit 4(VTIN1) bit 2(VTIN2) bit 3(VTIN3)
|
||||
(right) CR[59h] bit 4(VTIN1) bit 5(VTIN2) bit 6(VTIN3)
|
||||
|
||||
PII thermal diode 1 1 1
|
||||
2N3904 diode 0 0 0
|
||||
|
||||
|
||||
Asus Clones
|
||||
-----------
|
||||
|
||||
We have no datasheets for the Asus clones (AS99127F and ASB100 Bach).
|
||||
Here are some very useful information that were given to us by Alex Van
|
||||
Kaam about how to detect these chips, and how to read their values. He
|
||||
also gives advice for another Asus chipset, the Mozart-2 (which we
|
||||
don't support yet). Thanks Alex!
|
||||
I reworded some parts and added personal comments.
|
||||
|
||||
# Detection:
|
||||
|
||||
AS99127F rev.1, AS99127F rev.2 and ASB100:
|
||||
- I2C address range: 0x29 - 0x2F
|
||||
- If register 0x58 holds 0x31 then we have an Asus (either ASB100 or
|
||||
AS99127F)
|
||||
- Which one depends on register 0x4F (manufacturer ID):
|
||||
0x06 or 0x94: ASB100
|
||||
0x12 or 0xC3: AS99127F rev.1
|
||||
0x5C or 0xA3: AS99127F rev.2
|
||||
Note that 0x5CA3 is Winbond's ID (WEC), which let us think Asus get their
|
||||
AS99127F rev.2 direct from Winbond. The other codes mean ATT and DVC,
|
||||
respectively. ATT could stand for Asustek something (although it would be
|
||||
very badly chosen IMHO), I don't know what DVC could stand for. Maybe
|
||||
these codes simply aren't meant to be decoded that way.
|
||||
|
||||
Mozart-2:
|
||||
- I2C address: 0x77
|
||||
- If register 0x58 holds 0x56 or 0x10 then we have a Mozart-2
|
||||
- Of the Mozart there are 3 types:
|
||||
0x58=0x56, 0x4E=0x94, 0x4F=0x36: Asus ASM58 Mozart-2
|
||||
0x58=0x56, 0x4E=0x94, 0x4F=0x06: Asus AS2K129R Mozart-2
|
||||
0x58=0x10, 0x4E=0x5C, 0x4F=0xA3: Asus ??? Mozart-2
|
||||
You can handle all 3 the exact same way :)
|
||||
|
||||
# Temperature sensors:
|
||||
|
||||
ASB100:
|
||||
- sensor 1: register 0x27
|
||||
- sensor 2 & 3 are the 2 LM75's on the SMBus
|
||||
- sensor 4: register 0x17
|
||||
Remark: I noticed that on Intel boards sensor 2 is used for the CPU
|
||||
and 4 is ignored/stuck, on AMD boards sensor 4 is the CPU and sensor 2 is
|
||||
either ignored or a socket temperature.
|
||||
|
||||
AS99127F (rev.1 and 2 alike):
|
||||
- sensor 1: register 0x27
|
||||
- sensor 2 & 3 are the 2 LM75's on the SMBus
|
||||
Remark: Register 0x5b is suspected to be temperature type selector. Bit 1
|
||||
would control temp1, bit 3 temp2 and bit 5 temp3.
|
||||
|
||||
Mozart-2:
|
||||
- sensor 1: register 0x27
|
||||
- sensor 2: register 0x13
|
||||
|
||||
# Fan sensors:
|
||||
|
||||
ASB100, AS99127F (rev.1 and 2 alike):
|
||||
- 3 fans, identical to the W83781D
|
||||
|
||||
Mozart-2:
|
||||
- 2 fans only, 1350000/RPM/div
|
||||
- fan 1: register 0x28, divisor on register 0xA1 (bits 4-5)
|
||||
- fan 2: register 0x29, divisor on register 0xA1 (bits 6-7)
|
||||
|
||||
# Voltages:
|
||||
|
||||
This is where there is a difference between AS99127F rev.1 and 2.
|
||||
Remark: The difference is similar to the difference between
|
||||
W83781D and W83782D.
|
||||
|
||||
ASB100:
|
||||
in0=r(0x20)*0.016
|
||||
in1=r(0x21)*0.016
|
||||
in2=r(0x22)*0.016
|
||||
in3=r(0x23)*0.016*1.68
|
||||
in4=r(0x24)*0.016*3.8
|
||||
in5=r(0x25)*(-0.016)*3.97
|
||||
in6=r(0x26)*(-0.016)*1.666
|
||||
|
||||
AS99127F rev.1:
|
||||
in0=r(0x20)*0.016
|
||||
in1=r(0x21)*0.016
|
||||
in2=r(0x22)*0.016
|
||||
in3=r(0x23)*0.016*1.68
|
||||
in4=r(0x24)*0.016*3.8
|
||||
in5=r(0x25)*(-0.016)*3.97
|
||||
in6=r(0x26)*(-0.016)*1.503
|
||||
|
||||
AS99127F rev.2:
|
||||
in0=r(0x20)*0.016
|
||||
in1=r(0x21)*0.016
|
||||
in2=r(0x22)*0.016
|
||||
in3=r(0x23)*0.016*1.68
|
||||
in4=r(0x24)*0.016*3.8
|
||||
in5=(r(0x25)*0.016-3.6)*5.14+3.6
|
||||
in6=(r(0x26)*0.016-3.6)*3.14+3.6
|
||||
|
||||
Mozart-2:
|
||||
in0=r(0x20)*0.016
|
||||
in1=255
|
||||
in2=r(0x22)*0.016
|
||||
in3=r(0x23)*0.016*1.68
|
||||
in4=r(0x24)*0.016*4
|
||||
in5=255
|
||||
in6=255
|
||||
|
||||
|
||||
# PWM
|
||||
|
||||
Additional info about PWM on the AS99127F (may apply to other Asus
|
||||
chips as well) by Jean Delvare as of 2004-04-09:
|
||||
|
||||
AS99127F revision 2 seems to have two PWM registers at 0x59 and 0x5A,
|
||||
and a temperature sensor type selector at 0x5B (which basically means
|
||||
that they swapped registers 0x59 and 0x5B when you compare with Winbond
|
||||
chips).
|
||||
Revision 1 of the chip also has the temperature sensor type selector at
|
||||
0x5B, but PWM registers have no effect.
|
||||
|
||||
We don't know exactly how the temperature sensor type selection works.
|
||||
Looks like bits 1-0 are for temp1, bits 3-2 for temp2 and bits 5-4 for
|
||||
temp3, although it is possible that only the most significant bit matters
|
||||
each time. So far, values other than 0 always broke the readings.
|
||||
|
||||
PWM registers seem to be split in two parts: bit 7 is a mode selector,
|
||||
while the other bits seem to define a value or threshold.
|
||||
|
||||
When bit 7 is clear, bits 6-0 seem to hold a threshold value. If the value
|
||||
is below a given limit, the fan runs at low speed. If the value is above
|
||||
the limit, the fan runs at full speed. We have no clue as to what the limit
|
||||
represents. Note that there seem to be some inertia in this mode, speed
|
||||
changes may need some time to trigger. Also, an hysteresis mechanism is
|
||||
suspected since walking through all the values increasingly and then
|
||||
decreasingly led to slightly different limits.
|
||||
|
||||
When bit 7 is set, bits 3-0 seem to hold a threshold value, while bits 6-4
|
||||
would not be significant. If the value is below a given limit, the fan runs
|
||||
at full speed, while if it is above the limit it runs at low speed (so this
|
||||
is the contrary of the other mode, in a way). Here again, we don't know
|
||||
what the limit is supposed to represent.
|
||||
|
||||
One remarkable thing is that the fans would only have two or three
|
||||
different speeds (transitional states left apart), not a whole range as
|
||||
you usually get with PWM.
|
||||
|
||||
As a conclusion, you can write 0x00 or 0x8F to the PWM registers to make
|
||||
fans run at low speed, and 0x7F or 0x80 to make them run at full speed.
|
||||
|
||||
Please contact us if you can figure out how it is supposed to work. As
|
||||
long as we don't know more, the w83781d driver doesn't handle PWM on
|
||||
AS99127F chips at all.
|
||||
|
||||
Additional info about PWM on the AS99127F rev.1 by Hector Martin:
|
||||
|
||||
I've been fiddling around with the (in)famous 0x59 register and
|
||||
found out the following values do work as a form of coarse pwm:
|
||||
|
||||
0x80 - seems to turn fans off after some time(1-2 minutes)... might be
|
||||
some form of auto-fan-control based on temp? hmm (Qfan? this mobo is an
|
||||
old ASUS, it isn't marketed as Qfan. Maybe some beta pre-attemp at Qfan
|
||||
that was dropped at the BIOS)
|
||||
0x81 - off
|
||||
0x82 - slightly "on-ner" than off, but my fans do not get to move. I can
|
||||
hear the high-pitched PWM sound that motors give off at too-low-pwm.
|
||||
0x83 - now they do move. Estimate about 70% speed or so.
|
||||
0x84-0x8f - full on
|
||||
|
||||
Changing the high nibble doesn't seem to do much except the high bit
|
||||
(0x80) must be set for PWM to work, else the current pwm doesn't seem to
|
||||
change.
|
||||
|
||||
My mobo is an ASUS A7V266-E. This behavior is similar to what I got
|
||||
with speedfan under Windows, where 0-15% would be off, 15-2x% (can't
|
||||
remember the exact value) would be 70% and higher would be full on.
|
|
@ -0,0 +1,39 @@
|
|||
Kernel driver w83l785ts
|
||||
=======================
|
||||
|
||||
Supported chips:
|
||||
* Winbond W83L785TS-S
|
||||
Prefix: 'w83l785ts'
|
||||
Addresses scanned: I2C 0x2e
|
||||
Datasheet: Publicly available at the Winbond USA website
|
||||
http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf
|
||||
|
||||
Authors:
|
||||
Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The W83L785TS-S is a digital temperature sensor. It senses the
|
||||
temperature of a single external diode. The high limit is
|
||||
theoretically defined as 85 or 100 degrees C through a combination
|
||||
of external resistors, so the user cannot change it. Values seen so
|
||||
far suggest that the two possible limits are actually 95 and 110
|
||||
degrees C. The datasheet is rather poor and obviously inaccurate
|
||||
on several points including this one.
|
||||
|
||||
All temperature values are given in degrees Celsius. Resolution
|
||||
is 1.0 degree. See the datasheet for details.
|
||||
|
||||
The w83l785ts driver will not update its values more frequently than
|
||||
every other second; reading them more often will do no harm, but will
|
||||
return 'old' values.
|
||||
|
||||
Known Issues
|
||||
------------
|
||||
|
||||
On some systems (Asus), the BIOS is known to interfere with the driver
|
||||
and cause read errors. The driver will retry a given number of times
|
||||
(5 by default) and then give up, returning the old value (or 0 if
|
||||
there is no old value). It seems to work well enough so that you should
|
||||
not notice anything. Thanks to James Bolt for helping test this feature.
|
|
@ -57,7 +57,7 @@ Technical changes:
|
|||
Documentation/i2c/sysfs-interface for the individual files. Also
|
||||
convert the units these files read and write to the specified ones.
|
||||
If you need to add a new type of file, please discuss it on the
|
||||
sensors mailing list <sensors@stimpy.netroedge.com> by providing a
|
||||
sensors mailing list <lm-sensors@lm-sensors.org> by providing a
|
||||
patch to the Documentation/i2c/sysfs-interface file.
|
||||
|
||||
* [Attach] For I2C drivers, the attach function should make sure
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
Introduction
|
||||
------------
|
||||
|
||||
Most mainboards have sensor chips to monitor system health (like temperatures,
|
||||
voltages, fans speed). They are often connected through an I2C bus, but some
|
||||
are also connected directly through the ISA bus.
|
||||
|
||||
The kernel drivers make the data from the sensor chips available in the /sys
|
||||
virtual filesystem. Userspace tools are then used to display or set or the
|
||||
data in a more friendly manner.
|
||||
|
||||
Lm-sensors
|
||||
----------
|
||||
|
||||
Core set of utilites that will allow you to obtain health information,
|
||||
setup monitoring limits etc. You can get them on their homepage
|
||||
http://www.lm-sensors.nu/ or as a package from your Linux distribution.
|
||||
|
||||
If from website:
|
||||
Get lmsensors from project web site. Please note, you need only userspace
|
||||
part, so compile with "make user_install" target.
|
||||
|
||||
General hints to get things working:
|
||||
|
||||
0) get lm-sensors userspace utils
|
||||
1) compile all drivers in I2C section as modules in your kernel
|
||||
2) run sensors-detect script, it will tell you what modules you need to load.
|
||||
3) load them and run "sensors" command, you should see some results.
|
||||
4) fix sensors.conf, labels, limits, fan divisors
|
||||
5) if any more problems consult FAQ, or documentation
|
||||
|
||||
Other utilites
|
||||
--------------
|
||||
|
||||
If you want some graphical indicators of system health look for applications
|
||||
like: gkrellm, ksensors, xsensors, wmtemp, wmsensors, wmgtemp, ksysguardd,
|
||||
hardware-monitor
|
||||
|
||||
If you are server administrator you can try snmpd or mrtgutils.
|
|
@ -171,45 +171,31 @@ The following lists are used internally:
|
|||
|
||||
normal_i2c: filled in by the module writer.
|
||||
A list of I2C addresses which should normally be examined.
|
||||
normal_i2c_range: filled in by the module writer.
|
||||
A list of pairs of I2C addresses, each pair being an inclusive range of
|
||||
addresses which should normally be examined.
|
||||
probe: insmod parameter.
|
||||
A list of pairs. The first value is a bus number (-1 for any I2C bus),
|
||||
the second is the address. These addresses are also probed, as if they
|
||||
were in the 'normal' list.
|
||||
probe_range: insmod parameter.
|
||||
A list of triples. The first value is a bus number (-1 for any I2C bus),
|
||||
the second and third are addresses. These form an inclusive range of
|
||||
addresses that are also probed, as if they were in the 'normal' list.
|
||||
ignore: insmod parameter.
|
||||
A list of pairs. The first value is a bus number (-1 for any I2C bus),
|
||||
the second is the I2C address. These addresses are never probed.
|
||||
This parameter overrules 'normal' and 'probe', but not the 'force' lists.
|
||||
ignore_range: insmod parameter.
|
||||
A list of triples. The first value is a bus number (-1 for any I2C bus),
|
||||
the second and third are addresses. These form an inclusive range of
|
||||
I2C addresses that are never probed.
|
||||
This parameter overrules 'normal' and 'probe', but not the 'force' lists.
|
||||
force: insmod parameter.
|
||||
A list of pairs. The first value is a bus number (-1 for any I2C bus),
|
||||
the second is the I2C address. A device is blindly assumed to be on
|
||||
the given address, no probing is done.
|
||||
|
||||
Fortunately, as a module writer, you just have to define the `normal'
|
||||
and/or `normal_range' parameters. The complete declaration could look
|
||||
like this:
|
||||
Fortunately, as a module writer, you just have to define the `normal_i2c'
|
||||
parameter. The complete declaration could look like this:
|
||||
|
||||
/* Scan 0x20 to 0x2f, 0x37, and 0x40 to 0x4f */
|
||||
static unsigned short normal_i2c[] = { 0x37,I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c_range[] = { 0x20, 0x2f, 0x40, 0x4f,
|
||||
I2C_CLIENT_END };
|
||||
/* Scan 0x37, and 0x48 to 0x4f */
|
||||
static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
|
||||
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
|
||||
|
||||
/* Magic definition of all other variables and things */
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
Note that you *have* to call the two defined variables `normal_i2c' and
|
||||
`normal_i2c_range', without any prefix!
|
||||
Note that you *have* to call the defined variable `normal_i2c',
|
||||
without any prefix!
|
||||
|
||||
|
||||
Probing classes (sensors)
|
||||
|
@ -223,39 +209,17 @@ The following lists are used internally. They are all lists of integers.
|
|||
|
||||
normal_i2c: filled in by the module writer. Terminated by SENSORS_I2C_END.
|
||||
A list of I2C addresses which should normally be examined.
|
||||
normal_i2c_range: filled in by the module writer. Terminated by
|
||||
SENSORS_I2C_END
|
||||
A list of pairs of I2C addresses, each pair being an inclusive range of
|
||||
addresses which should normally be examined.
|
||||
normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END.
|
||||
A list of ISA addresses which should normally be examined.
|
||||
normal_isa_range: filled in by the module writer. Terminated by
|
||||
SENSORS_ISA_END
|
||||
A list of triples. The first two elements are ISA addresses, being an
|
||||
range of addresses which should normally be examined. The third is the
|
||||
modulo parameter: only addresses which are 0 module this value relative
|
||||
to the first address of the range are actually considered.
|
||||
probe: insmod parameter. Initialize this list with SENSORS_I2C_END values.
|
||||
A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
|
||||
the ISA bus, -1 for any I2C bus), the second is the address. These
|
||||
addresses are also probed, as if they were in the 'normal' list.
|
||||
probe_range: insmod parameter. Initialize this list with SENSORS_I2C_END
|
||||
values.
|
||||
A list of triples. The first value is a bus number (SENSORS_ISA_BUS for
|
||||
the ISA bus, -1 for any I2C bus), the second and third are addresses.
|
||||
These form an inclusive range of addresses that are also probed, as
|
||||
if they were in the 'normal' list.
|
||||
ignore: insmod parameter. Initialize this list with SENSORS_I2C_END values.
|
||||
A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
|
||||
the ISA bus, -1 for any I2C bus), the second is the I2C address. These
|
||||
addresses are never probed. This parameter overrules 'normal' and
|
||||
'probe', but not the 'force' lists.
|
||||
ignore_range: insmod parameter. Initialize this list with SENSORS_I2C_END
|
||||
values.
|
||||
A list of triples. The first value is a bus number (SENSORS_ISA_BUS for
|
||||
the ISA bus, -1 for any I2C bus), the second and third are addresses.
|
||||
These form an inclusive range of I2C addresses that are never probed.
|
||||
This parameter overrules 'normal' and 'probe', but not the 'force' lists.
|
||||
|
||||
Also used is a list of pointers to sensors_force_data structures:
|
||||
force_data: insmod parameters. A list, ending with an element of which
|
||||
|
@ -269,16 +233,14 @@ Also used is a list of pointers to sensors_force_data structures:
|
|||
So we have a generic insmod variabled `force', and chip-specific variables
|
||||
`force_CHIPNAME'.
|
||||
|
||||
Fortunately, as a module writer, you just have to define the `normal'
|
||||
and/or `normal_range' parameters, and define what chip names are used.
|
||||
Fortunately, as a module writer, you just have to define the `normal_i2c'
|
||||
and `normal_isa' parameters, and define what chip names are used.
|
||||
The complete declaration could look like this:
|
||||
/* Scan i2c addresses 0x20 to 0x2f, 0x37, and 0x40 to 0x4f
|
||||
static unsigned short normal_i2c[] = {0x37,SENSORS_I2C_END};
|
||||
static unsigned short normal_i2c_range[] = {0x20,0x2f,0x40,0x4f,
|
||||
SENSORS_I2C_END};
|
||||
/* Scan i2c addresses 0x37, and 0x48 to 0x4f */
|
||||
static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
|
||||
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
|
||||
/* Scan ISA address 0x290 */
|
||||
static unsigned int normal_isa[] = {0x0290,SENSORS_ISA_END};
|
||||
static unsigned int normal_isa_range[] = {SENSORS_ISA_END};
|
||||
|
||||
/* Define chips foo and bar, as well as all module parameters and things */
|
||||
SENSORS_INSMOD_2(foo,bar);
|
||||
|
|
16
MAINTAINERS
16
MAINTAINERS
|
@ -194,7 +194,7 @@ S: Maintained
|
|||
ADM1025 HARDWARE MONITOR DRIVER
|
||||
P: Jean Delvare
|
||||
M: khali@linux-fr.org
|
||||
L: sensors@stimpy.netroedge.com
|
||||
L: lm-sensors@lm-sensors.org
|
||||
S: Maintained
|
||||
|
||||
ADT746X FAN DRIVER
|
||||
|
@ -242,7 +242,7 @@ S: Maintained
|
|||
ALI1563 I2C DRIVER
|
||||
P: Rudolf Marek
|
||||
M: r.marek@sh.cvut.cz
|
||||
L: sensors@stimpy.netroedge.com
|
||||
L: lm-sensors@lm-sensors.org
|
||||
S: Maintained
|
||||
|
||||
ALPHA PORT
|
||||
|
@ -1002,7 +1002,7 @@ P: Greg Kroah-Hartman
|
|||
M: greg@kroah.com
|
||||
P: Jean Delvare
|
||||
M: khali@linux-fr.org
|
||||
L: sensors@stimpy.netroedge.com
|
||||
L: lm-sensors@lm-sensors.org
|
||||
W: http://www.lm-sensors.nu/
|
||||
S: Maintained
|
||||
|
||||
|
@ -1430,13 +1430,13 @@ S: Supported
|
|||
LM83 HARDWARE MONITOR DRIVER
|
||||
P: Jean Delvare
|
||||
M: khali@linux-fr.org
|
||||
L: sensors@stimpy.netroedge.com
|
||||
L: lm-sensors@lm-sensors.org
|
||||
S: Maintained
|
||||
|
||||
LM90 HARDWARE MONITOR DRIVER
|
||||
P: Jean Delvare
|
||||
M: khali@linux-fr.org
|
||||
L: sensors@stimpy.netroedge.com
|
||||
L: lm-sensors@lm-sensors.org
|
||||
S: Maintained
|
||||
|
||||
LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP Dynamic Disks)
|
||||
|
@ -2075,7 +2075,7 @@ S: Maintained
|
|||
SMSC47M1 HARDWARE MONITOR DRIVER
|
||||
P: Jean Delvare
|
||||
M: khali@linux-fr.org
|
||||
L: sensors@stimpy.netroedge.com
|
||||
L: lm-sensors@lm-sensors.org
|
||||
S: Odd Fixes
|
||||
|
||||
SMB FILESYSTEM
|
||||
|
@ -2614,7 +2614,7 @@ S: Orphan
|
|||
W1 DALLAS'S 1-WIRE BUS
|
||||
P: Evgeniy Polyakov
|
||||
M: johnpol@2ka.mipt.ru
|
||||
L: sensors@stimpy.netroedge.com
|
||||
L: lm-sensors@lm-sensors.org
|
||||
S: Maintained
|
||||
|
||||
W83L51xD SD/MMC CARD INTERFACE DRIVER
|
||||
|
@ -2627,7 +2627,7 @@ S: Maintained
|
|||
W83L785TS HARDWARE MONITOR DRIVER
|
||||
P: Jean Delvare
|
||||
M: khali@linux-fr.org
|
||||
L: sensors@stimpy.netroedge.com
|
||||
L: lm-sensors@lm-sensors.org
|
||||
S: Odd Fixes
|
||||
|
||||
WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC)
|
||||
|
|
|
@ -185,6 +185,26 @@ mpc834x_sys_init_IRQ(void)
|
|||
ipic_set_default_priority();
|
||||
}
|
||||
|
||||
#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
|
||||
extern ulong ds1374_get_rtc_time(void);
|
||||
extern int ds1374_set_rtc_time(ulong);
|
||||
|
||||
static int __init
|
||||
mpc834x_rtc_hookup(void)
|
||||
{
|
||||
struct timespec tv;
|
||||
|
||||
ppc_md.get_rtc_time = ds1374_get_rtc_time;
|
||||
ppc_md.set_rtc_time = ds1374_set_rtc_time;
|
||||
|
||||
tv.tv_nsec = 0;
|
||||
tv.tv_sec = (ppc_md.get_rtc_time)();
|
||||
do_settimeofday(&tv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
late_initcall(mpc834x_rtc_hookup);
|
||||
#endif
|
||||
static __inline__ void
|
||||
mpc834x_sys_set_bat(void)
|
||||
{
|
||||
|
|
|
@ -26,11 +26,8 @@ static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END };
|
|||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_addr,
|
||||
.normal_i2c_range = ignore,
|
||||
.probe = ignore,
|
||||
.probe_range = ignore,
|
||||
.ignore = ignore,
|
||||
.ignore_range = ignore,
|
||||
.force = ignore,
|
||||
};
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ static int i2c_debug=0;
|
|||
/*
|
||||
* Generate a start condition on the i2c bus.
|
||||
*
|
||||
* returns after the start condition has occured
|
||||
* returns after the start condition has occurred
|
||||
*/
|
||||
static void pca_start(struct i2c_algo_pca_data *adap)
|
||||
{
|
||||
|
@ -64,7 +64,7 @@ static void pca_start(struct i2c_algo_pca_data *adap)
|
|||
/*
|
||||
* Generate a repeated start condition on the i2c bus
|
||||
*
|
||||
* return after the repeated start condition has occured
|
||||
* return after the repeated start condition has occurred
|
||||
*/
|
||||
static void pca_repeated_start(struct i2c_algo_pca_data *adap)
|
||||
{
|
||||
|
@ -82,7 +82,7 @@ static void pca_repeated_start(struct i2c_algo_pca_data *adap)
|
|||
* returns after the stop condition has been generated
|
||||
*
|
||||
* STOPs do not generate an interrupt or set the SI flag, since the
|
||||
* part returns the the idle state (0xf8). Hence we don't need to
|
||||
* part returns the idle state (0xf8). Hence we don't need to
|
||||
* pca_wait here.
|
||||
*/
|
||||
static void pca_stop(struct i2c_algo_pca_data *adap)
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
/* Ported for SiByte SOCs by Broadcom Corporation. */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
@ -7,7 +7,7 @@ menu "I2C Hardware Bus support"
|
|||
|
||||
config I2C_ALI1535
|
||||
tristate "ALI 1535"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the SMB
|
||||
Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB
|
||||
|
@ -31,7 +31,7 @@ config I2C_ALI1563
|
|||
|
||||
config I2C_ALI15X3
|
||||
tristate "ALI 15x3"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces.
|
||||
|
@ -41,7 +41,7 @@ config I2C_ALI15X3
|
|||
|
||||
config I2C_AMD756
|
||||
tristate "AMD 756/766/768/8111 and nVidia nForce"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the AMD
|
||||
756/766/768 mainboard I2C interfaces. The driver also includes
|
||||
|
@ -66,7 +66,7 @@ config I2C_AMD756_S4882
|
|||
|
||||
config I2C_AMD8111
|
||||
tristate "AMD 8111"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
second (SMBus 2.0) AMD 8111 mainboard I2C interface.
|
||||
|
@ -109,7 +109,7 @@ config I2C_HYDRA
|
|||
|
||||
config I2C_I801
|
||||
tristate "Intel 82801 (ICH)"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the Intel
|
||||
801 family of mainboard I2C interfaces. Specifically, the following
|
||||
|
@ -130,7 +130,7 @@ config I2C_I801
|
|||
|
||||
config I2C_I810
|
||||
tristate "Intel 810/815"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the Intel
|
||||
|
@ -183,7 +183,7 @@ config I2C_IOP3XX
|
|||
|
||||
config I2C_ISA
|
||||
tristate "ISA Bus support"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes to this option, support will be included for i2c
|
||||
interfaces that are on the ISA bus.
|
||||
|
@ -248,12 +248,11 @@ config I2C_MPC
|
|||
will be called i2c-mpc.
|
||||
|
||||
config I2C_NFORCE2
|
||||
tristate "Nvidia Nforce2"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
tristate "Nvidia nForce2, nForce3 and nForce4"
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the Nvidia
|
||||
Nforce2 family of mainboard I2C interfaces.
|
||||
This driver also supports the nForce3 Pro 150 MCP.
|
||||
nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-nforce2.
|
||||
|
@ -305,7 +304,7 @@ config I2C_PARPORT_LIGHT
|
|||
|
||||
config I2C_PROSAVAGE
|
||||
tristate "S3/VIA (Pro)Savage"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
|
@ -388,7 +387,7 @@ config SCx200_ACB
|
|||
|
||||
config I2C_SIS5595
|
||||
tristate "SiS 5595"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
SiS5595 SMBus (a subset of I2C) interface.
|
||||
|
@ -398,7 +397,7 @@ config I2C_SIS5595
|
|||
|
||||
config I2C_SIS630
|
||||
tristate "SiS 630/730"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
SiS630 and SiS730 SMBus (a subset of I2C) interface.
|
||||
|
@ -408,7 +407,7 @@ config I2C_SIS630
|
|||
|
||||
config I2C_SIS96X
|
||||
tristate "SiS 96x"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the SiS
|
||||
96x SMBus (a subset of I2C) interfaces. Specifically, the following
|
||||
|
@ -419,6 +418,7 @@ config I2C_SIS96X
|
|||
648/961
|
||||
650/961
|
||||
735
|
||||
745
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sis96x.
|
||||
|
@ -449,7 +449,7 @@ config I2C_VIA
|
|||
|
||||
config I2C_VIAPRO
|
||||
tristate "VIA 82C596/82C686/823x"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the VIA
|
||||
82C596/82C686/823x I2C interfaces. Specifically, the following
|
||||
|
@ -467,7 +467,7 @@ config I2C_VIAPRO
|
|||
|
||||
config I2C_VOODOO3
|
||||
tristate "Voodoo 3"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
|
||||
/* Note: we assume there can only be one ALI1535, with one SMBus interface */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -60,7 +60,6 @@
|
|||
|
||||
/* Note: we assume there can only be one ALI15X3, with one SMBus interface */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
* the Free Software Foundation version 2.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
/* Partialy rewriten by Oleg I. Vdovikin for mmapped support of
|
||||
for Alpha Processor Inc. UP-2000(+) boards */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
* version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
|
||||
/* Note: we assume there can only be one I801, with one SMBus interface */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
i815 1132
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
@ -695,7 +695,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
|
|||
|
||||
dev->irq = iic_force_poll ? -1 : ocp->def->irq;
|
||||
if (dev->irq >= 0){
|
||||
/* Disable interrupts until we finish intialization,
|
||||
/* Disable interrupts until we finish initialization,
|
||||
assumes level-sensitive IRQ setup...
|
||||
*/
|
||||
iic_interrupt_mode(dev, 0);
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#ifndef __I2C_IBM_IIC_H_
|
||||
#define __I2C_IBM_IIC_H_
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
struct iic_regs {
|
||||
|
|
|
@ -85,7 +85,7 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
|
|||
u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE;
|
||||
|
||||
/*
|
||||
* Everytime unit enable is asserted, GPOD needs to be cleared
|
||||
* Every time unit enable is asserted, GPOD needs to be cleared
|
||||
* on IOP321 to avoid data corruption on the bus.
|
||||
*/
|
||||
#ifdef CONFIG_ARCH_IOP321
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
the SMBus and the ISA bus very much easier. See lm78.c for an example
|
||||
of this. */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
|
||||
Frodo Looijaard <frodol@dds.nl> */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
@ -26,11 +26,6 @@
|
|||
* 'enabled' to drive the GPIOs.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#ifdef CONFIG_I2C_DEBUG_BUS
|
||||
#define DEBUG 1
|
||||
#endif
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
|
|
|
@ -26,11 +26,6 @@
|
|||
* that is passed as the platform_data to this driver.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#ifdef CONFIG_I2C_DEBUG_BUS
|
||||
#define DEBUG 1
|
||||
#endif
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
sound driver to be happy
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ioport.h>
|
||||
|
|
|
@ -325,7 +325,7 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp)
|
|||
if (i2c->irq != OCP_IRQ_NA)
|
||||
{
|
||||
if ((result = request_irq(ocp->def->irq, mpc_i2c_isr,
|
||||
0, "i2c-mpc", i2c)) < 0) {
|
||||
SA_SHIRQ, "i2c-mpc", i2c)) < 0) {
|
||||
printk(KERN_ERR
|
||||
"i2c-mpc - failed to attach interrupt\n");
|
||||
goto fail_irq;
|
||||
|
@ -333,6 +333,9 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp)
|
|||
} else
|
||||
i2c->irq = 0;
|
||||
|
||||
mpc_i2c_setclock(i2c);
|
||||
ocp_set_drvdata(ocp, i2c);
|
||||
|
||||
i2c->adap = mpc_ops;
|
||||
i2c_set_adapdata(&i2c->adap, i2c);
|
||||
|
||||
|
@ -341,8 +344,6 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp)
|
|||
goto fail_add;
|
||||
}
|
||||
|
||||
mpc_i2c_setclock(i2c);
|
||||
ocp_set_drvdata(ocp, i2c);
|
||||
return result;
|
||||
|
||||
fail_add:
|
||||
|
@ -358,8 +359,8 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp)
|
|||
static void __devexit mpc_i2c_remove(struct ocp_device *ocp)
|
||||
{
|
||||
struct mpc_i2c *i2c = ocp_get_drvdata(ocp);
|
||||
ocp_set_drvdata(ocp, NULL);
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
ocp_set_drvdata(ocp, NULL);
|
||||
|
||||
if (ocp->def->irq != OCP_IRQ_NA)
|
||||
free_irq(i2c->irq, i2c);
|
||||
|
@ -424,12 +425,15 @@ static int fsl_i2c_probe(struct device *device)
|
|||
|
||||
if (i2c->irq != 0)
|
||||
if ((result = request_irq(i2c->irq, mpc_i2c_isr,
|
||||
0, "fsl-i2c", i2c)) < 0) {
|
||||
SA_SHIRQ, "i2c-mpc", i2c)) < 0) {
|
||||
printk(KERN_ERR
|
||||
"i2c-mpc - failed to attach interrupt\n");
|
||||
goto fail_irq;
|
||||
}
|
||||
|
||||
mpc_i2c_setclock(i2c);
|
||||
dev_set_drvdata(device, i2c);
|
||||
|
||||
i2c->adap = mpc_ops;
|
||||
i2c_set_adapdata(&i2c->adap, i2c);
|
||||
i2c->adap.dev.parent = &pdev->dev;
|
||||
|
@ -438,8 +442,6 @@ static int fsl_i2c_probe(struct device *device)
|
|||
goto fail_add;
|
||||
}
|
||||
|
||||
mpc_i2c_setclock(i2c);
|
||||
dev_set_drvdata(device, i2c);
|
||||
return result;
|
||||
|
||||
fail_add:
|
||||
|
@ -456,8 +458,8 @@ static int fsl_i2c_remove(struct device *device)
|
|||
{
|
||||
struct mpc_i2c *i2c = dev_get_drvdata(device);
|
||||
|
||||
dev_set_drvdata(device, NULL);
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
dev_set_drvdata(device, NULL);
|
||||
|
||||
if (i2c->irq != 0)
|
||||
free_irq(i2c->irq, i2c);
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
|
||||
/* Note: we assume there can only be one nForce2, with two SMBus interfaces */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* ------------------------------------------------------------------------ */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* ------------------------------------------------------------------------ */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -131,7 +130,7 @@ static int parport_getsda(void *data)
|
|||
/* Encapsulate the functions above in the correct structure.
|
||||
Note that this is only a template, from which the real structures are
|
||||
copied. The attaching code will set getscl to NULL for adapters that
|
||||
cannot read SCL back, and will also make the the data field point to
|
||||
cannot read SCL back, and will also make the data field point to
|
||||
the parallel port structure. */
|
||||
static struct i2c_algo_bit_data parport_algo_data = {
|
||||
.setsda = parport_setsda,
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/pci.h>
|
||||
|
|
|
@ -54,7 +54,6 @@
|
|||
* (Additional documentation needed :(
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
* changed to eliminate RPXLite references.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
|
@ -533,7 +534,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int
|
|||
/* s3c24xx_i2c_xfer
|
||||
*
|
||||
* first port of call from the i2c bus code when an message needs
|
||||
* transfering across the i2c bus.
|
||||
* transferring across the i2c bus.
|
||||
*/
|
||||
|
||||
static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
it easier to add later.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c-algo-sibyte.h>
|
||||
#include <asm/sibyte/sb1250_regs.h>
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
* Add adapter resets
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
We assume there can only be one SiS96x with one SMBus interface.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#define DEBUG 1
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
/* This interfaces to the I2C bus of the Voodoo3 to gain access to
|
||||
the BT869 and possibly other I2C devices. */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# I2C Sensor device configuration
|
||||
# I2C Sensor and "other" chip configuration
|
||||
#
|
||||
|
||||
menu "Hardware Sensors Chip support"
|
||||
|
@ -11,7 +11,7 @@ config I2C_SENSOR
|
|||
|
||||
config SENSORS_ADM1021
|
||||
tristate "Analog Devices ADM1021 and compatibles"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
depends on I2C
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for Analog Devices ADM1021
|
||||
|
@ -29,6 +29,7 @@ config SENSORS_ADM1025
|
|||
help
|
||||
If you say yes here you get support for Analog Devices ADM1025
|
||||
and Philips NE1619 sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adm1025.
|
||||
|
||||
|
@ -38,6 +39,8 @@ config SENSORS_ADM1026
|
|||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for Analog Devices ADM1026
|
||||
sensor chip.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adm1026.
|
||||
|
||||
|
@ -48,9 +51,21 @@ config SENSORS_ADM1031
|
|||
help
|
||||
If you say yes here you get support for Analog Devices ADM1031
|
||||
and ADM1030 sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adm1031.
|
||||
|
||||
config SENSORS_ADM9240
|
||||
tristate "Analog Devices ADM9240 and compatibles"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for Analog Devices ADM9240,
|
||||
Dallas DS1780, National Semiconductor LM81 sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adm9240.
|
||||
|
||||
config SENSORS_ASB100
|
||||
tristate "Asus ASB100 Bach"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
|
@ -62,6 +77,19 @@ config SENSORS_ASB100
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called asb100.
|
||||
|
||||
config SENSORS_ATXP1
|
||||
tristate "Attansic ATXP1 VID controller"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for the Attansic ATXP1 VID
|
||||
controller.
|
||||
|
||||
If your board have such a chip, you are able to control your CPU
|
||||
core and other voltages.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called atxp1.
|
||||
|
||||
config SENSORS_DS1621
|
||||
tristate "Dallas Semiconductor DS1621 and DS1625"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
|
@ -97,7 +125,7 @@ config SENSORS_FSCPOS
|
|||
|
||||
config SENSORS_GL518SM
|
||||
tristate "Genesys Logic GL518SM"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
depends on I2C
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for Genesys Logic GL518SM
|
||||
|
@ -119,7 +147,7 @@ config SENSORS_GL520SM
|
|||
|
||||
config SENSORS_IT87
|
||||
tristate "ITE IT87xx and compatibles"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
depends on I2C
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for ITE IT87xx sensor chips
|
||||
|
@ -143,7 +171,7 @@ config SENSORS_LM63
|
|||
|
||||
config SENSORS_LM75
|
||||
tristate "National Semiconductor LM75 and compatibles"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
depends on I2C
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for National Semiconductor LM75
|
||||
|
@ -174,8 +202,7 @@ config SENSORS_LM78
|
|||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for National Semiconductor LM78,
|
||||
LM78-J and LM79. This can also be built as a module which can be
|
||||
inserted and removed while the kernel is running.
|
||||
LM78-J and LM79.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called lm78.
|
||||
|
@ -208,7 +235,7 @@ config SENSORS_LM85
|
|||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for National Semiconductor LM85
|
||||
sensor chips and clones: ADT7463 and ADM1027.
|
||||
sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called lm85.
|
||||
|
@ -307,14 +334,14 @@ config SENSORS_SMSC47M1
|
|||
help
|
||||
If you say yes here you get support for the integrated fan
|
||||
monitoring and control capabilities of the SMSC LPC47B27x,
|
||||
LPC47M10x, LPC47M13x and LPC47M14x chips.
|
||||
LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called smsc47m1.
|
||||
|
||||
config SENSORS_VIA686A
|
||||
tristate "VIA686A"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
select I2C_SENSOR
|
||||
select I2C_ISA
|
||||
help
|
||||
|
@ -326,7 +353,7 @@ config SENSORS_VIA686A
|
|||
|
||||
config SENSORS_W83781D
|
||||
tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
depends on I2C
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for the Winbond W8378x series
|
||||
|
@ -360,22 +387,47 @@ config SENSORS_W83627HF
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called w83627hf.
|
||||
|
||||
config SENSORS_W83627EHF
|
||||
tristate "Winbond W83627EHF"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
select I2C_SENSOR
|
||||
select I2C_ISA
|
||||
help
|
||||
If you say yes here you get preliminary support for the hardware
|
||||
monitoring functionality of the Winbond W83627EHF Super-I/O chip.
|
||||
Only fan and temperature inputs are supported at the moment, while
|
||||
the chip does much more than that.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called w83627ehf.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Other I2C Chip support"
|
||||
depends on I2C
|
||||
|
||||
config SENSORS_DS1337
|
||||
tristate "Dallas Semiconductor DS1337 Real Time Clock"
|
||||
tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for Dallas Semiconductor
|
||||
DS1337 real-time clock chips.
|
||||
DS1337 and DS1339 real-time clock chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ds1337.
|
||||
|
||||
config SENSORS_DS1374
|
||||
tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for Dallas Semiconductor
|
||||
DS1374 real-time clock chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ds1374.
|
||||
|
||||
config SENSORS_EEPROM
|
||||
tristate "EEPROM reader"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
|
@ -399,6 +451,16 @@ config SENSORS_PCF8574
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called pcf8574.
|
||||
|
||||
config SENSORS_PCA9539
|
||||
tristate "Philips PCA9539 16-bit I/O port"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for the Philips PCA9539
|
||||
16-bit I/O port.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called pca9539.
|
||||
|
||||
config SENSORS_PCF8591
|
||||
tristate "Philips PCF8591"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
|
@ -431,6 +493,23 @@ config ISP1301_OMAP
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called isp1301_omap.
|
||||
|
||||
# NOTE: This isn't really OMAP-specific, except for the current
|
||||
# interface location in <include/asm-arm/arch-omap/tps65010.h>
|
||||
# and having mostly OMAP-specific board support
|
||||
config TPS65010
|
||||
tristate "TPS6501x Power Management chips"
|
||||
depends on I2C && ARCH_OMAP
|
||||
default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
|
||||
help
|
||||
If you say yes here you get support for the TPS6501x series of
|
||||
Power Management chips. These include voltage regulators,
|
||||
lithium ion/polymer battery charging, and other features that
|
||||
are often used in portable devices like cell phones and cameras.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tps65010.
|
||||
|
||||
|
||||
config SENSORS_M41T00
|
||||
tristate "ST M41T00 RTC chip"
|
||||
depends on I2C && PPC32
|
||||
|
@ -440,4 +519,16 @@ config SENSORS_M41T00
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called m41t00.
|
||||
|
||||
config SENSORS_MAX6875
|
||||
tristate "MAXIM MAX6875 Power supply supervisor"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for the MAX6875
|
||||
EEPROM-Programmable, Hex/Quad, Power-Suppy Sequencers/Supervisors.
|
||||
|
||||
This provides a interface to program the EEPROM and reset the chip.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max6875.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Makefile for the kernel hardware sensors chip drivers.
|
||||
# Makefile for sensor and "other" I2C chip drivers.
|
||||
#
|
||||
|
||||
# asb100, then w83781d go first, as they can override other drivers' addresses.
|
||||
|
@ -11,7 +11,10 @@ obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
|
|||
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
|
||||
obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
|
||||
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
|
||||
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
|
||||
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
|
||||
obj-$(CONFIG_SENSORS_DS1337) += ds1337.o
|
||||
obj-$(CONFIG_SENSORS_DS1374) += ds1374.o
|
||||
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
|
||||
obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o
|
||||
obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
|
||||
|
@ -30,8 +33,10 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o
|
|||
obj-$(CONFIG_SENSORS_LM90) += lm90.o
|
||||
obj-$(CONFIG_SENSORS_LM92) += lm92.o
|
||||
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
|
||||
obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
|
||||
obj-$(CONFIG_SENSORS_M41T00) += m41t00.o
|
||||
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
|
||||
obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
|
||||
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
|
||||
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
|
||||
obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o
|
||||
|
@ -39,8 +44,11 @@ obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
|
|||
obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
|
||||
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
|
||||
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
|
||||
obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
|
||||
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
|
||||
|
||||
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
|
||||
obj-$(CONFIG_TPS65010) += tps65010.o
|
||||
|
||||
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -103,8 +102,6 @@ struct adm1021_data {
|
|||
u8 remote_temp_hyst;
|
||||
u8 remote_temp_input;
|
||||
u8 alarms;
|
||||
/* special values for ADM1021 only */
|
||||
u8 die_code;
|
||||
/* Special values for ADM1023 only */
|
||||
u8 remote_temp_prec;
|
||||
u8 remote_temp_os_prec;
|
||||
|
@ -156,7 +153,6 @@ static ssize_t show_##value(struct device *dev, struct device_attribute *attr, c
|
|||
return sprintf(buf, "%d\n", data->value); \
|
||||
}
|
||||
show2(alarms);
|
||||
show2(die_code);
|
||||
|
||||
#define set(value, reg) \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
|
||||
|
@ -183,7 +179,6 @@ static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remot
|
|||
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 DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
static DEVICE_ATTR(die_code, S_IRUGO, show_die_code, NULL);
|
||||
|
||||
|
||||
static int adm1021_attach_adapter(struct i2c_adapter *adapter)
|
||||
|
@ -307,8 +302,6 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
device_create_file(&new_client->dev, &dev_attr_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
if (data->type == adm1021)
|
||||
device_create_file(&new_client->dev, &dev_attr_die_code);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -371,8 +364,6 @@ static struct adm1021_data *adm1021_update_device(struct device *dev)
|
|||
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;
|
||||
if (data->type == adm1021)
|
||||
data->die_code = adm1021_read_value(client, ADM1021_REG_DIE_CODE);
|
||||
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);
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -287,7 +286,9 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char
|
|||
struct adm1025_data *data = adm1025_update_device(dev);
|
||||
return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
|
||||
}
|
||||
/* in1_ref is deprecated in favour of cpu0_vid, remove after 2005-11-11 */
|
||||
static DEVICE_ATTR(in1_ref, S_IRUGO, show_vid, NULL);
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
|
||||
|
||||
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
@ -437,7 +438,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
/* in1_ref is deprecated, remove after 2005-11-11 */
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_ref);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
device_create_file(&new_client->dev, &dev_attr_vrm);
|
||||
|
||||
/* Pin 11 is either in4 (+12V) or VID4 */
|
||||
|
|
|
@ -23,15 +23,14 @@
|
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/i2c-sysfs.h>
|
||||
#include <linux/i2c-vid.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
|
||||
|
@ -1225,8 +1224,9 @@ static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, c
|
|||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm));
|
||||
}
|
||||
|
||||
/* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */
|
||||
static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL);
|
||||
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)
|
||||
{
|
||||
|
@ -1666,7 +1666,9 @@ int adm1026_detect(struct i2c_adapter *adapter, int address,
|
|||
device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable);
|
||||
/* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */
|
||||
device_create_file(&new_client->dev, &dev_attr_vid);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
device_create_file(&new_client->dev, &dev_attr_vrm);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarm_mask);
|
||||
|
|
|
@ -440,7 +440,7 @@ pwm_reg(2);
|
|||
|
||||
/*
|
||||
* That function checks the cases where the fan reading is not
|
||||
* relevent. It is used to provide 0 as fan reading when the fan is
|
||||
* relevant. It is used to provide 0 as fan reading when the fan is
|
||||
* not supposed to run
|
||||
*/
|
||||
static int trust_fan_readings(struct adm1031_data *data, int chan)
|
||||
|
|
|
@ -0,0 +1,791 @@
|
|||
/*
|
||||
* adm9240.c Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
*
|
||||
* Copyright (C) 1999 Frodo Looijaard <frodol@dds.nl>
|
||||
* Philip Edelbrock <phil@netroedge.com>
|
||||
* Copyright (C) 2003 Michiel Rook <michiel@grendelproject.nl>
|
||||
* Copyright (C) 2005 Grant Coady <gcoady@gmail.com> with valuable
|
||||
* guidance from Jean Delvare
|
||||
*
|
||||
* Driver supports Analog Devices ADM9240
|
||||
* Dallas Semiconductor DS1780
|
||||
* National Semiconductor LM81
|
||||
*
|
||||
* ADM9240 is the reference, DS1780 and LM81 are register compatibles
|
||||
*
|
||||
* Voltage Six inputs are scaled by chip, VID also reported
|
||||
* Temperature Chip temperature to 0.5'C, maximum and max_hysteris
|
||||
* Fans 2 fans, low speed alarm, automatic fan clock divider
|
||||
* Alarms 16-bit map of active alarms
|
||||
* Analog Out 0..1250 mV output
|
||||
*
|
||||
* Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear'
|
||||
*
|
||||
* Test hardware: Intel SE440BX-2 desktop motherboard --Grant
|
||||
*
|
||||
* LM81 extended temp reading not implemented
|
||||
*
|
||||
* 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/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/i2c-vid.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
I2C_CLIENT_END };
|
||||
|
||||
static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
|
||||
|
||||
/* Insmod parameters */
|
||||
SENSORS_INSMOD_3(adm9240, ds1780, lm81);
|
||||
|
||||
/* ADM9240 registers */
|
||||
#define ADM9240_REG_MAN_ID 0x3e
|
||||
#define ADM9240_REG_DIE_REV 0x3f
|
||||
#define ADM9240_REG_CONFIG 0x40
|
||||
|
||||
#define ADM9240_REG_IN(nr) (0x20 + (nr)) /* 0..5 */
|
||||
#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2)
|
||||
#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2)
|
||||
#define ADM9240_REG_FAN(nr) (0x28 + (nr)) /* 0..1 */
|
||||
#define ADM9240_REG_FAN_MIN(nr) (0x3b + (nr))
|
||||
#define ADM9240_REG_INT(nr) (0x41 + (nr))
|
||||
#define ADM9240_REG_INT_MASK(nr) (0x43 + (nr))
|
||||
#define ADM9240_REG_TEMP 0x27
|
||||
#define ADM9240_REG_TEMP_HIGH 0x39
|
||||
#define ADM9240_REG_TEMP_HYST 0x3a
|
||||
#define ADM9240_REG_ANALOG_OUT 0x19
|
||||
#define ADM9240_REG_CHASSIS_CLEAR 0x46
|
||||
#define ADM9240_REG_VID_FAN_DIV 0x47
|
||||
#define ADM9240_REG_I2C_ADDR 0x48
|
||||
#define ADM9240_REG_VID4 0x49
|
||||
#define ADM9240_REG_TEMP_CONF 0x4b
|
||||
|
||||
/* generalised scaling with integer rounding */
|
||||
static inline int SCALE(long val, int mul, int div)
|
||||
{
|
||||
if (val < 0)
|
||||
return (val * mul - div / 2) / div;
|
||||
else
|
||||
return (val * mul + div / 2) / div;
|
||||
}
|
||||
|
||||
/* adm9240 internally scales voltage measurements */
|
||||
static const u16 nom_mv[] = { 2500, 2700, 3300, 5000, 12000, 2700 };
|
||||
|
||||
static inline unsigned int IN_FROM_REG(u8 reg, int n)
|
||||
{
|
||||
return SCALE(reg, nom_mv[n], 192);
|
||||
}
|
||||
|
||||
static inline u8 IN_TO_REG(unsigned long val, int n)
|
||||
{
|
||||
return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
|
||||
}
|
||||
|
||||
/* temperature range: -40..125, 127 disables temperature alarm */
|
||||
static inline s8 TEMP_TO_REG(long val)
|
||||
{
|
||||
return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127);
|
||||
}
|
||||
|
||||
/* two fans, each with low fan speed limit */
|
||||
static inline unsigned int FAN_FROM_REG(u8 reg, u8 div)
|
||||
{
|
||||
if (!reg) /* error */
|
||||
return -1;
|
||||
|
||||
if (reg == 255)
|
||||
return 0;
|
||||
|
||||
return SCALE(1350000, 1, reg * div);
|
||||
}
|
||||
|
||||
/* analog out 0..1250mV */
|
||||
static inline u8 AOUT_TO_REG(unsigned long val)
|
||||
{
|
||||
return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255);
|
||||
}
|
||||
|
||||
static inline unsigned int AOUT_FROM_REG(u8 reg)
|
||||
{
|
||||
return SCALE(reg, 1250, 255);
|
||||
}
|
||||
|
||||
static int adm9240_attach_adapter(struct i2c_adapter *adapter);
|
||||
static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind);
|
||||
static void adm9240_init_client(struct i2c_client *client);
|
||||
static int adm9240_detach_client(struct i2c_client *client);
|
||||
static struct adm9240_data *adm9240_update_device(struct device *dev);
|
||||
|
||||
/* driver data */
|
||||
static struct i2c_driver adm9240_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "adm9240",
|
||||
.id = I2C_DRIVERID_ADM9240,
|
||||
.flags = I2C_DF_NOTIFY,
|
||||
.attach_adapter = adm9240_attach_adapter,
|
||||
.detach_client = adm9240_detach_client,
|
||||
};
|
||||
|
||||
/* per client data */
|
||||
struct adm9240_data {
|
||||
enum chips type;
|
||||
struct i2c_client client;
|
||||
struct semaphore update_lock;
|
||||
char valid;
|
||||
unsigned long last_updated_measure;
|
||||
unsigned long last_updated_config;
|
||||
|
||||
u8 in[6]; /* ro in0_input */
|
||||
u8 in_max[6]; /* rw in0_max */
|
||||
u8 in_min[6]; /* rw in0_min */
|
||||
u8 fan[2]; /* ro fan1_input */
|
||||
u8 fan_min[2]; /* rw fan1_min */
|
||||
u8 fan_div[2]; /* rw fan1_div, read-only accessor */
|
||||
s16 temp; /* ro temp1_input, 9-bit sign-extended */
|
||||
s8 temp_high; /* rw temp1_max */
|
||||
s8 temp_hyst; /* rw temp1_max_hyst */
|
||||
u16 alarms; /* ro alarms */
|
||||
u8 aout; /* rw aout_output */
|
||||
u8 vid; /* ro vid */
|
||||
u8 vrm; /* -- vrm set on startup, no accessor */
|
||||
};
|
||||
|
||||
/* i2c byte read/write interface */
|
||||
static int adm9240_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
/*** sysfs accessors ***/
|
||||
|
||||
/* temperature */
|
||||
#define show_temp(value, scale) \
|
||||
static ssize_t show_##value(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct adm9240_data *data = adm9240_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", data->value * scale); \
|
||||
}
|
||||
show_temp(temp_high, 1000);
|
||||
show_temp(temp_hyst, 1000);
|
||||
show_temp(temp, 500); /* 0.5'C per bit */
|
||||
|
||||
#define set_temp(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 adm9240_data *data = adm9240_update_device(dev); \
|
||||
long temp = simple_strtoul(buf, NULL, 10); \
|
||||
\
|
||||
down(&data->update_lock); \
|
||||
data->value = TEMP_TO_REG(temp); \
|
||||
adm9240_write_value(client, reg, data->value); \
|
||||
up(&data->update_lock); \
|
||||
return count; \
|
||||
}
|
||||
|
||||
set_temp(temp_high, ADM9240_REG_TEMP_HIGH);
|
||||
set_temp(temp_hyst, ADM9240_REG_TEMP_HYST);
|
||||
|
||||
static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
|
||||
show_temp_high, set_temp_high);
|
||||
static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
|
||||
show_temp_hyst, set_temp_hyst);
|
||||
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
|
||||
|
||||
/* voltage */
|
||||
static ssize_t show_in(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr));
|
||||
}
|
||||
|
||||
static ssize_t show_in_min(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr));
|
||||
}
|
||||
|
||||
static ssize_t show_in_max(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr));
|
||||
}
|
||||
|
||||
static ssize_t set_in_min(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
down(&data->update_lock);
|
||||
data->in_min[nr] = IN_TO_REG(val, nr);
|
||||
adm9240_write_value(client, ADM9240_REG_IN_MIN(nr), data->in_min[nr]);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t set_in_max(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
down(&data->update_lock);
|
||||
data->in_max[nr] = IN_TO_REG(val, nr);
|
||||
adm9240_write_value(client, ADM9240_REG_IN_MAX(nr), data->in_max[nr]);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
#define show_in_offset(offset) \
|
||||
static ssize_t show_in##offset(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_in(dev, buf, offset); \
|
||||
} \
|
||||
static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \
|
||||
static ssize_t show_in##offset##_min(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_in_min(dev, buf, offset); \
|
||||
} \
|
||||
static ssize_t show_in##offset##_max(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_in_max(dev, buf, offset); \
|
||||
} \
|
||||
static ssize_t \
|
||||
set_in##offset##_min(struct device *dev, \
|
||||
struct device_attribute *attr, const char *buf, \
|
||||
size_t count) \
|
||||
{ \
|
||||
return set_in_min(dev, buf, count, offset); \
|
||||
} \
|
||||
static ssize_t \
|
||||
set_in##offset##_max(struct device *dev, \
|
||||
struct device_attribute *attr, const char *buf, \
|
||||
size_t count) \
|
||||
{ \
|
||||
return set_in_max(dev, buf, count, offset); \
|
||||
} \
|
||||
static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_in##offset##_min, set_in##offset##_min); \
|
||||
static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
|
||||
show_in##offset##_max, set_in##offset##_max);
|
||||
|
||||
show_in_offset(0);
|
||||
show_in_offset(1);
|
||||
show_in_offset(2);
|
||||
show_in_offset(3);
|
||||
show_in_offset(4);
|
||||
show_in_offset(5);
|
||||
|
||||
/* fans */
|
||||
static ssize_t show_fan(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
|
||||
1 << data->fan_div[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
|
||||
1 << data->fan_div[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", 1 << data->fan_div[nr]);
|
||||
}
|
||||
|
||||
/* write new fan div, callers must hold data->update_lock */
|
||||
static void adm9240_write_fan_div(struct i2c_client *client, int nr,
|
||||
u8 fan_div)
|
||||
{
|
||||
u8 reg, old, shift = (nr + 2) * 2;
|
||||
|
||||
reg = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV);
|
||||
old = (reg >> shift) & 3;
|
||||
reg &= ~(3 << shift);
|
||||
reg |= (fan_div << shift);
|
||||
adm9240_write_value(client, ADM9240_REG_VID_FAN_DIV, reg);
|
||||
dev_dbg(&client->dev, "fan%d clock divider changed from %u "
|
||||
"to %u\n", nr + 1, 1 << old, 1 << fan_div);
|
||||
}
|
||||
|
||||
/*
|
||||
* set fan speed low limit:
|
||||
*
|
||||
* - value is zero: disable fan speed low limit alarm
|
||||
*
|
||||
* - value is below fan speed measurement range: enable fan speed low
|
||||
* limit alarm to be asserted while fan speed too slow to measure
|
||||
*
|
||||
* - otherwise: select fan clock divider to suit fan speed low limit,
|
||||
* measurement code may adjust registers to ensure fan speed reading
|
||||
*/
|
||||
static ssize_t set_fan_min(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
u8 new_div;
|
||||
|
||||
down(&data->update_lock);
|
||||
|
||||
if (!val) {
|
||||
data->fan_min[nr] = 255;
|
||||
new_div = data->fan_div[nr];
|
||||
|
||||
dev_dbg(&client->dev, "fan%u low limit set disabled\n",
|
||||
nr + 1);
|
||||
|
||||
} else if (val < 1350000 / (8 * 254)) {
|
||||
new_div = 3;
|
||||
data->fan_min[nr] = 254;
|
||||
|
||||
dev_dbg(&client->dev, "fan%u low limit set minimum %u\n",
|
||||
nr + 1, FAN_FROM_REG(254, 1 << new_div));
|
||||
|
||||
} else {
|
||||
unsigned int new_min = 1350000 / val;
|
||||
|
||||
new_div = 0;
|
||||
while (new_min > 192 && new_div < 3) {
|
||||
new_div++;
|
||||
new_min /= 2;
|
||||
}
|
||||
if (!new_min) /* keep > 0 */
|
||||
new_min++;
|
||||
|
||||
data->fan_min[nr] = new_min;
|
||||
|
||||
dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n",
|
||||
nr + 1, FAN_FROM_REG(new_min, 1 << new_div));
|
||||
}
|
||||
|
||||
if (new_div != data->fan_div[nr]) {
|
||||
data->fan_div[nr] = new_div;
|
||||
adm9240_write_fan_div(client, nr, new_div);
|
||||
}
|
||||
adm9240_write_value(client, ADM9240_REG_FAN_MIN(nr),
|
||||
data->fan_min[nr]);
|
||||
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
#define show_fan_offset(offset) \
|
||||
static ssize_t show_fan_##offset (struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_fan(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t show_fan_##offset##_div (struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_fan_div(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t show_fan_##offset##_min (struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_fan_min(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_fan_##offset##_min (struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_fan_min(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
|
||||
show_fan_##offset, NULL); \
|
||||
static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
|
||||
show_fan_##offset##_div, NULL); \
|
||||
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_fan_##offset##_min, set_fan_##offset##_min);
|
||||
|
||||
show_fan_offset(1);
|
||||
show_fan_offset(2);
|
||||
|
||||
/* alarms */
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
/* vid */
|
||||
static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
|
||||
}
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
|
||||
|
||||
/* analog output */
|
||||
static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout));
|
||||
}
|
||||
|
||||
static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtol(buf, NULL, 10);
|
||||
|
||||
down(&data->update_lock);
|
||||
data->aout = AOUT_TO_REG(val);
|
||||
adm9240_write_value(client, ADM9240_REG_ANALOG_OUT, data->aout);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
|
||||
|
||||
/* chassis_clear */
|
||||
static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
unsigned long val = simple_strtol(buf, NULL, 10);
|
||||
|
||||
if (val == 1) {
|
||||
adm9240_write_value(client, ADM9240_REG_CHASSIS_CLEAR, 0x80);
|
||||
dev_dbg(&client->dev, "chassis intrusion latch cleared\n");
|
||||
}
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear);
|
||||
|
||||
|
||||
/*** sensor chip detect and driver install ***/
|
||||
|
||||
static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
struct i2c_client *new_client;
|
||||
struct adm9240_data *data;
|
||||
int err = 0;
|
||||
const char *name = "";
|
||||
u8 man_id, die_rev;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
goto exit;
|
||||
|
||||
if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
memset(data, 0, sizeof(struct adm9240_data));
|
||||
|
||||
new_client = &data->client;
|
||||
i2c_set_clientdata(new_client, data);
|
||||
new_client->addr = address;
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = &adm9240_driver;
|
||||
new_client->flags = 0;
|
||||
|
||||
if (kind == 0) {
|
||||
kind = adm9240;
|
||||
}
|
||||
|
||||
if (kind < 0) {
|
||||
|
||||
/* verify chip: reg address should match i2c address */
|
||||
if (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR)
|
||||
!= address) {
|
||||
dev_err(&adapter->dev, "detect fail: address match, "
|
||||
"0x%02x\n", address);
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
/* check known chip manufacturer */
|
||||
man_id = adm9240_read_value(new_client, ADM9240_REG_MAN_ID);
|
||||
|
||||
if (man_id == 0x23) {
|
||||
kind = adm9240;
|
||||
} else if (man_id == 0xda) {
|
||||
kind = ds1780;
|
||||
} else if (man_id == 0x01) {
|
||||
kind = lm81;
|
||||
} else {
|
||||
dev_err(&adapter->dev, "detect fail: unknown manuf, "
|
||||
"0x%02x\n", man_id);
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
/* successful detect, print chip info */
|
||||
die_rev = adm9240_read_value(new_client, ADM9240_REG_DIE_REV);
|
||||
dev_info(&adapter->dev, "found %s revision %u\n",
|
||||
man_id == 0x23 ? "ADM9240" :
|
||||
man_id == 0xda ? "DS1780" : "LM81", die_rev);
|
||||
}
|
||||
|
||||
/* either forced or detected chip kind */
|
||||
if (kind == adm9240) {
|
||||
name = "adm9240";
|
||||
} else if (kind == ds1780) {
|
||||
name = "ds1780";
|
||||
} else if (kind == lm81) {
|
||||
name = "lm81";
|
||||
}
|
||||
|
||||
/* fill in the remaining client fields and attach */
|
||||
strlcpy(new_client->name, name, I2C_NAME_SIZE);
|
||||
data->type = kind;
|
||||
init_MUTEX(&data->update_lock);
|
||||
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
goto exit_free;
|
||||
|
||||
adm9240_init_client(new_client);
|
||||
|
||||
/* populate sysfs filesystem */
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
device_create_file(&new_client->dev, &dev_attr_aout_output);
|
||||
device_create_file(&new_client->dev, &dev_attr_chassis_clear);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
|
||||
return 0;
|
||||
exit_free:
|
||||
kfree(new_client);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adm9240_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
||||
return 0;
|
||||
return i2c_detect(adapter, &addr_data, adm9240_detect);
|
||||
}
|
||||
|
||||
static int adm9240_detach_client(struct i2c_client *client)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = i2c_detach_client(client))) {
|
||||
dev_err(&client->dev, "Client deregistration failed, "
|
||||
"client not detached.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adm9240_init_client(struct i2c_client *client)
|
||||
{
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG);
|
||||
u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3;
|
||||
|
||||
data->vrm = i2c_which_vrm(); /* need this to report vid as mV */
|
||||
|
||||
dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10,
|
||||
data->vrm % 10);
|
||||
|
||||
if (conf & 1) { /* measurement cycle running: report state */
|
||||
|
||||
dev_info(&client->dev, "status: config 0x%02x mode %u\n",
|
||||
conf, mode);
|
||||
|
||||
} else { /* cold start: open limits before starting chip */
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
adm9240_write_value(client,
|
||||
ADM9240_REG_IN_MIN(i), 0);
|
||||
adm9240_write_value(client,
|
||||
ADM9240_REG_IN_MAX(i), 255);
|
||||
}
|
||||
adm9240_write_value(client, ADM9240_REG_FAN_MIN(0), 255);
|
||||
adm9240_write_value(client, ADM9240_REG_FAN_MIN(1), 255);
|
||||
adm9240_write_value(client, ADM9240_REG_TEMP_HIGH, 127);
|
||||
adm9240_write_value(client, ADM9240_REG_TEMP_HYST, 127);
|
||||
|
||||
/* start measurement cycle */
|
||||
adm9240_write_value(client, ADM9240_REG_CONFIG, 1);
|
||||
|
||||
dev_info(&client->dev, "cold start: config was 0x%02x "
|
||||
"mode %u\n", conf, mode);
|
||||
}
|
||||
}
|
||||
|
||||
static struct adm9240_data *adm9240_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
int i;
|
||||
|
||||
down(&data->update_lock);
|
||||
|
||||
/* minimum measurement cycle: 1.75 seconds */
|
||||
if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4))
|
||||
|| !data->valid) {
|
||||
|
||||
for (i = 0; i < 6; i++) /* read voltages */
|
||||
{
|
||||
data->in[i] = adm9240_read_value(client,
|
||||
ADM9240_REG_IN(i));
|
||||
}
|
||||
data->alarms = adm9240_read_value(client,
|
||||
ADM9240_REG_INT(0)) |
|
||||
adm9240_read_value(client,
|
||||
ADM9240_REG_INT(1)) << 8;
|
||||
|
||||
/* read temperature: assume temperature changes less than
|
||||
* 0.5'C per two measurement cycles thus ignore possible
|
||||
* but unlikely aliasing error on lsb reading. --Grant */
|
||||
data->temp = ((adm9240_read_value(client,
|
||||
ADM9240_REG_TEMP) << 8) |
|
||||
adm9240_read_value(client,
|
||||
ADM9240_REG_TEMP_CONF)) / 128;
|
||||
|
||||
for (i = 0; i < 2; i++) /* read fans */
|
||||
{
|
||||
data->fan[i] = adm9240_read_value(client,
|
||||
ADM9240_REG_FAN(i));
|
||||
|
||||
/* adjust fan clock divider on overflow */
|
||||
if (data->valid && data->fan[i] == 255 &&
|
||||
data->fan_div[i] < 3) {
|
||||
|
||||
adm9240_write_fan_div(client, i,
|
||||
++data->fan_div[i]);
|
||||
|
||||
/* adjust fan_min if active, but not to 0 */
|
||||
if (data->fan_min[i] < 255 &&
|
||||
data->fan_min[i] >= 2)
|
||||
data->fan_min[i] /= 2;
|
||||
}
|
||||
}
|
||||
data->last_updated_measure = jiffies;
|
||||
}
|
||||
|
||||
/* minimum config reading cycle: 300 seconds */
|
||||
if (time_after(jiffies, data->last_updated_config + (HZ * 300))
|
||||
|| !data->valid) {
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
data->in_min[i] = adm9240_read_value(client,
|
||||
ADM9240_REG_IN_MIN(i));
|
||||
data->in_max[i] = adm9240_read_value(client,
|
||||
ADM9240_REG_IN_MAX(i));
|
||||
}
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
data->fan_min[i] = adm9240_read_value(client,
|
||||
ADM9240_REG_FAN_MIN(i));
|
||||
}
|
||||
data->temp_high = adm9240_read_value(client,
|
||||
ADM9240_REG_TEMP_HIGH);
|
||||
data->temp_hyst = adm9240_read_value(client,
|
||||
ADM9240_REG_TEMP_HYST);
|
||||
|
||||
/* read fan divs and 5-bit VID */
|
||||
i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV);
|
||||
data->fan_div[0] = (i >> 4) & 3;
|
||||
data->fan_div[1] = (i >> 6) & 3;
|
||||
data->vid = i & 0x0f;
|
||||
data->vid |= (adm9240_read_value(client,
|
||||
ADM9240_REG_VID4) & 1) << 4;
|
||||
/* read analog out */
|
||||
data->aout = adm9240_read_value(client,
|
||||
ADM9240_REG_ANALOG_OUT);
|
||||
|
||||
data->last_updated_config = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
up(&data->update_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init sensors_adm9240_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adm9240_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_adm9240_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adm9240_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Michiel Rook <michiel@grendelproject.nl>, "
|
||||
"Grant Coady <gcoady@gmail.com> and others");
|
||||
MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_adm9240_init);
|
||||
module_exit(sensors_adm9240_exit);
|
||||
|
|
@ -42,6 +42,7 @@
|
|||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/i2c-vid.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include "lm75.h"
|
||||
|
||||
/*
|
||||
|
@ -168,8 +169,6 @@ static int ASB100_PWM_FROM_REG(u8 reg)
|
|||
return reg * 16;
|
||||
}
|
||||
|
||||
#define ALARMS_FROM_REG(val) (val)
|
||||
|
||||
#define DIV_FROM_REG(val) (1 << (val))
|
||||
|
||||
/* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
|
||||
|
@ -556,7 +555,7 @@ device_create_file(&client->dev, &dev_attr_vrm);
|
|||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct asb100_data *data = asb100_update_device(dev);
|
||||
return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms));
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
|
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
atxp1.c - kernel module for setting CPU VID and general purpose
|
||||
I/Os using the Attansic ATXP1 chip.
|
||||
|
||||
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/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/i2c-vid.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
|
||||
MODULE_VERSION("0.6.2");
|
||||
MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
|
||||
|
||||
#define ATXP1_VID 0x00
|
||||
#define ATXP1_CVID 0x01
|
||||
#define ATXP1_GPIO1 0x06
|
||||
#define ATXP1_GPIO2 0x0a
|
||||
#define ATXP1_VIDENA 0x20
|
||||
#define ATXP1_VIDMASK 0x1f
|
||||
#define ATXP1_GPIO1MASK 0x0f
|
||||
|
||||
static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END };
|
||||
static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
|
||||
|
||||
SENSORS_INSMOD_1(atxp1);
|
||||
|
||||
static int atxp1_attach_adapter(struct i2c_adapter * adapter);
|
||||
static int atxp1_detach_client(struct i2c_client * client);
|
||||
static struct atxp1_data * atxp1_update_device(struct device *dev);
|
||||
static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind);
|
||||
|
||||
static struct i2c_driver atxp1_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "atxp1",
|
||||
.flags = I2C_DF_NOTIFY,
|
||||
.attach_adapter = atxp1_attach_adapter,
|
||||
.detach_client = atxp1_detach_client,
|
||||
};
|
||||
|
||||
struct atxp1_data {
|
||||
struct i2c_client client;
|
||||
struct semaphore update_lock;
|
||||
unsigned long last_updated;
|
||||
u8 valid;
|
||||
struct {
|
||||
u8 vid; /* VID output register */
|
||||
u8 cpu_vid; /* VID input from CPU */
|
||||
u8 gpio1; /* General purpose I/O register 1 */
|
||||
u8 gpio2; /* General purpose I/O register 2 */
|
||||
} reg;
|
||||
u8 vrm; /* Detected CPU VRM */
|
||||
};
|
||||
|
||||
static struct atxp1_data * atxp1_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct atxp1_data *data;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = i2c_get_clientdata(client);
|
||||
|
||||
down(&data->update_lock);
|
||||
|
||||
if ((jiffies - data->last_updated > HZ) ||
|
||||
(jiffies < data->last_updated) ||
|
||||
!data->valid) {
|
||||
|
||||
/* Update local register data */
|
||||
data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID);
|
||||
data->reg.cpu_vid = i2c_smbus_read_byte_data(client, ATXP1_CVID);
|
||||
data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1);
|
||||
data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2);
|
||||
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
up(&data->update_lock);
|
||||
|
||||
return(data);
|
||||
}
|
||||
|
||||
/* sys file functions for cpu0_vid */
|
||||
static ssize_t atxp1_showvcore(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int size;
|
||||
struct atxp1_data *data;
|
||||
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, data->vrm));
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct atxp1_data *data;
|
||||
struct i2c_client *client;
|
||||
char vid;
|
||||
char cvid;
|
||||
unsigned int vcore;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
vcore = simple_strtoul(buf, NULL, 10);
|
||||
vcore /= 25;
|
||||
vcore *= 25;
|
||||
|
||||
/* Calculate VID */
|
||||
vid = vid_to_reg(vcore, data->vrm);
|
||||
|
||||
if (vid < 0) {
|
||||
dev_err(dev, "VID calculation failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If output enabled, use control register value. Otherwise original CPU VID */
|
||||
if (data->reg.vid & ATXP1_VIDENA)
|
||||
cvid = data->reg.vid & ATXP1_VIDMASK;
|
||||
else
|
||||
cvid = data->reg.cpu_vid;
|
||||
|
||||
/* Nothing changed, aborting */
|
||||
if (vid == cvid)
|
||||
return count;
|
||||
|
||||
dev_info(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid);
|
||||
|
||||
/* Write every 25 mV step to increase stability */
|
||||
if (cvid > vid) {
|
||||
for (; cvid >= vid; cvid--) {
|
||||
i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (; cvid <= vid; cvid++) {
|
||||
i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA);
|
||||
}
|
||||
}
|
||||
|
||||
data->valid = 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* CPU core reference voltage
|
||||
unit: millivolt
|
||||
*/
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, atxp1_storevcore);
|
||||
|
||||
/* sys file functions for GPIO1 */
|
||||
static ssize_t atxp1_showgpio1(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int size;
|
||||
struct atxp1_data *data;
|
||||
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t atxp1_storegpio1(struct device *dev, struct device_attribute *attr, const char*buf, size_t count)
|
||||
{
|
||||
struct atxp1_data *data;
|
||||
struct i2c_client *client;
|
||||
unsigned int value;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
value = simple_strtoul(buf, NULL, 16);
|
||||
|
||||
value &= ATXP1_GPIO1MASK;
|
||||
|
||||
if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) {
|
||||
dev_info(dev, "Writing 0x%x to GPIO1.\n", value);
|
||||
|
||||
i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value);
|
||||
|
||||
data->valid = 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* GPIO1 data register
|
||||
unit: Four bit as hex (e.g. 0x0f)
|
||||
*/
|
||||
static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1);
|
||||
|
||||
/* sys file functions for GPIO2 */
|
||||
static ssize_t atxp1_showgpio2(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int size;
|
||||
struct atxp1_data *data;
|
||||
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
size = sprintf(buf, "0x%02x\n", data->reg.gpio2);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct atxp1_data *data;
|
||||
struct i2c_client *client;
|
||||
unsigned int value;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
value = simple_strtoul(buf, NULL, 16) & 0xff;
|
||||
|
||||
if (value != data->reg.gpio2) {
|
||||
dev_info(dev, "Writing 0x%x to GPIO1.\n", value);
|
||||
|
||||
i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value);
|
||||
|
||||
data->valid = 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* GPIO2 data register
|
||||
unit: Eight bit as hex (e.g. 0xff)
|
||||
*/
|
||||
static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
|
||||
|
||||
|
||||
static int atxp1_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
return i2c_detect(adapter, &addr_data, &atxp1_detect);
|
||||
};
|
||||
|
||||
static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
struct i2c_client * new_client;
|
||||
struct atxp1_data * data;
|
||||
int err = 0;
|
||||
u8 temp;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
goto exit;
|
||||
|
||||
if (!(data = kmalloc(sizeof(struct atxp1_data), GFP_KERNEL))) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memset(data, 0, sizeof(struct atxp1_data));
|
||||
new_client = &data->client;
|
||||
i2c_set_clientdata(new_client, data);
|
||||
|
||||
new_client->addr = address;
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = &atxp1_driver;
|
||||
new_client->flags = 0;
|
||||
|
||||
/* Detect ATXP1, checking if vendor ID registers are all zero */
|
||||
if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) &&
|
||||
(i2c_smbus_read_byte_data(new_client, 0x3f) == 0) &&
|
||||
(i2c_smbus_read_byte_data(new_client, 0xfe) == 0) &&
|
||||
(i2c_smbus_read_byte_data(new_client, 0xff) == 0) )) {
|
||||
|
||||
/* No vendor ID, now checking if registers 0x10,0x11 (non-existent)
|
||||
* showing the same as register 0x00 */
|
||||
temp = i2c_smbus_read_byte_data(new_client, 0x00);
|
||||
|
||||
if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
|
||||
(i2c_smbus_read_byte_data(new_client, 0x11) == temp) ))
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
/* Get VRM */
|
||||
data->vrm = i2c_which_vrm();
|
||||
|
||||
if ((data->vrm != 90) && (data->vrm != 91)) {
|
||||
dev_err(&new_client->dev, "Not supporting VRM %d.%d\n",
|
||||
data->vrm / 10, data->vrm % 10);
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
strncpy(new_client->name, "atxp1", I2C_NAME_SIZE);
|
||||
|
||||
data->valid = 0;
|
||||
|
||||
init_MUTEX(&data->update_lock);
|
||||
|
||||
err = i2c_attach_client(new_client);
|
||||
|
||||
if (err)
|
||||
{
|
||||
dev_err(&new_client->dev, "Attach client error.\n");
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_gpio1);
|
||||
device_create_file(&new_client->dev, &dev_attr_gpio2);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
|
||||
dev_info(&new_client->dev, "Using VRM: %d.%d\n",
|
||||
data->vrm / 10, data->vrm % 10);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
return err;
|
||||
};
|
||||
|
||||
static int atxp1_detach_client(struct i2c_client * client)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
|
||||
if (err)
|
||||
dev_err(&client->dev, "Failed to detach client.\n");
|
||||
else
|
||||
kfree(i2c_get_clientdata(client));
|
||||
|
||||
return err;
|
||||
};
|
||||
|
||||
static int __init atxp1_init(void)
|
||||
{
|
||||
return i2c_add_driver(&atxp1_driver);
|
||||
};
|
||||
|
||||
static void __exit atxp1_exit(void)
|
||||
{
|
||||
i2c_del_driver(&atxp1_driver);
|
||||
};
|
||||
|
||||
module_init(atxp1_init);
|
||||
module_exit(atxp1_exit);
|
|
@ -3,17 +3,16 @@
|
|||
*
|
||||
* Copyright (C) 2005 James Chapman <jchapman@katalix.com>
|
||||
*
|
||||
* based on linux/drivers/acron/char/pcf8583.c
|
||||
* based on linux/drivers/acorn/char/pcf8583.c
|
||||
* Copyright (C) 2000 Russell King
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Driver for Dallas Semiconductor DS1337 real time clock chip
|
||||
* Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -69,13 +68,11 @@ static struct i2c_driver ds1337_driver = {
|
|||
struct ds1337_data {
|
||||
struct i2c_client client;
|
||||
struct list_head list;
|
||||
int id;
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal variables
|
||||
*/
|
||||
static int ds1337_id;
|
||||
static LIST_HEAD(ds1337_clients);
|
||||
|
||||
static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value)
|
||||
|
@ -95,7 +92,6 @@ static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value)
|
|||
*/
|
||||
static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
|
||||
{
|
||||
struct ds1337_data *data = i2c_get_clientdata(client);
|
||||
int result;
|
||||
u8 buf[7];
|
||||
u8 val;
|
||||
|
@ -103,9 +99,7 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
|
|||
u8 offs = 0;
|
||||
|
||||
if (!dt) {
|
||||
dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n",
|
||||
__FUNCTION__);
|
||||
|
||||
dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -119,98 +113,86 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
|
|||
msg[1].len = sizeof(buf);
|
||||
msg[1].buf = &buf[0];
|
||||
|
||||
result = client->adapter->algo->master_xfer(client->adapter,
|
||||
&msg[0], 2);
|
||||
result = i2c_transfer(client->adapter, msg, 2);
|
||||
|
||||
dev_dbg(&client->adapter->dev,
|
||||
"%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
__FUNCTION__, result, buf[0], buf[1], buf[2], buf[3],
|
||||
buf[4], buf[5], buf[6]);
|
||||
|
||||
if (result >= 0) {
|
||||
dt->tm_sec = BCD_TO_BIN(buf[0]);
|
||||
dt->tm_min = BCD_TO_BIN(buf[1]);
|
||||
if (result == 2) {
|
||||
dt->tm_sec = BCD2BIN(buf[0]);
|
||||
dt->tm_min = BCD2BIN(buf[1]);
|
||||
val = buf[2] & 0x3f;
|
||||
dt->tm_hour = BCD_TO_BIN(val);
|
||||
dt->tm_wday = BCD_TO_BIN(buf[3]) - 1;
|
||||
dt->tm_mday = BCD_TO_BIN(buf[4]);
|
||||
dt->tm_hour = BCD2BIN(val);
|
||||
dt->tm_wday = BCD2BIN(buf[3]) - 1;
|
||||
dt->tm_mday = BCD2BIN(buf[4]);
|
||||
val = buf[5] & 0x7f;
|
||||
dt->tm_mon = BCD_TO_BIN(val);
|
||||
dt->tm_year = 1900 + BCD_TO_BIN(buf[6]);
|
||||
dt->tm_mon = BCD2BIN(val) - 1;
|
||||
dt->tm_year = BCD2BIN(buf[6]);
|
||||
if (buf[5] & 0x80)
|
||||
dt->tm_year += 100;
|
||||
|
||||
dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, "
|
||||
dev_dbg(&client->dev, "%s: secs=%d, mins=%d, "
|
||||
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
__FUNCTION__, dt->tm_sec, dt->tm_min,
|
||||
dt->tm_hour, dt->tm_mday,
|
||||
dt->tm_mon, dt->tm_year, dt->tm_wday);
|
||||
} else {
|
||||
dev_err(&client->adapter->dev, "ds1337[%d]: error reading "
|
||||
"data! %d\n", data->id, result);
|
||||
result = -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
dev_err(&client->dev, "error reading data! %d\n", result);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt)
|
||||
{
|
||||
struct ds1337_data *data = i2c_get_clientdata(client);
|
||||
int result;
|
||||
u8 buf[8];
|
||||
u8 val;
|
||||
struct i2c_msg msg[1];
|
||||
|
||||
if (!dt) {
|
||||
dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n",
|
||||
__FUNCTION__);
|
||||
|
||||
dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, hours=%d, "
|
||||
dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
|
||||
"mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__,
|
||||
dt->tm_sec, dt->tm_min, dt->tm_hour,
|
||||
dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday);
|
||||
|
||||
buf[0] = 0; /* reg offset */
|
||||
buf[1] = BIN_TO_BCD(dt->tm_sec);
|
||||
buf[2] = BIN_TO_BCD(dt->tm_min);
|
||||
buf[3] = BIN_TO_BCD(dt->tm_hour) | (1 << 6);
|
||||
buf[4] = BIN_TO_BCD(dt->tm_wday) + 1;
|
||||
buf[5] = BIN_TO_BCD(dt->tm_mday);
|
||||
buf[6] = BIN_TO_BCD(dt->tm_mon);
|
||||
if (dt->tm_year >= 2000) {
|
||||
val = dt->tm_year - 2000;
|
||||
buf[1] = BIN2BCD(dt->tm_sec);
|
||||
buf[2] = BIN2BCD(dt->tm_min);
|
||||
buf[3] = BIN2BCD(dt->tm_hour) | (1 << 6);
|
||||
buf[4] = BIN2BCD(dt->tm_wday) + 1;
|
||||
buf[5] = BIN2BCD(dt->tm_mday);
|
||||
buf[6] = BIN2BCD(dt->tm_mon) + 1;
|
||||
val = dt->tm_year;
|
||||
if (val >= 100) {
|
||||
val -= 100;
|
||||
buf[6] |= (1 << 7);
|
||||
} else {
|
||||
val = dt->tm_year - 1900;
|
||||
}
|
||||
buf[7] = BIN_TO_BCD(val);
|
||||
buf[7] = BIN2BCD(val);
|
||||
|
||||
msg[0].addr = client->addr;
|
||||
msg[0].flags = 0;
|
||||
msg[0].len = sizeof(buf);
|
||||
msg[0].buf = &buf[0];
|
||||
|
||||
result = client->adapter->algo->master_xfer(client->adapter,
|
||||
&msg[0], 1);
|
||||
if (result < 0) {
|
||||
dev_err(&client->adapter->dev, "ds1337[%d]: error "
|
||||
"writing data! %d\n", data->id, result);
|
||||
result = -EIO;
|
||||
} else {
|
||||
result = 0;
|
||||
}
|
||||
result = i2c_transfer(client->adapter, msg, 1);
|
||||
if (result == 1)
|
||||
return 0;
|
||||
|
||||
return result;
|
||||
dev_err(&client->dev, "error writing data! %d\n", result);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int ds1337_command(struct i2c_client *client, unsigned int cmd,
|
||||
void *arg)
|
||||
{
|
||||
dev_dbg(&client->adapter->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
|
||||
dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case DS1337_GET_DATE:
|
||||
|
@ -228,7 +210,7 @@ static int ds1337_command(struct i2c_client *client, unsigned int cmd,
|
|||
* Public API for access to specific device. Useful for low-level
|
||||
* RTC access from kernel code.
|
||||
*/
|
||||
int ds1337_do_command(int id, int cmd, void *arg)
|
||||
int ds1337_do_command(int bus, int cmd, void *arg)
|
||||
{
|
||||
struct list_head *walk;
|
||||
struct list_head *tmp;
|
||||
|
@ -236,7 +218,7 @@ int ds1337_do_command(int id, int cmd, void *arg)
|
|||
|
||||
list_for_each_safe(walk, tmp, &ds1337_clients) {
|
||||
data = list_entry(walk, struct ds1337_data, list);
|
||||
if (data->id == id)
|
||||
if (data->client.adapter->nr == bus)
|
||||
return ds1337_command(&data->client, cmd, arg);
|
||||
}
|
||||
|
||||
|
@ -346,7 +328,6 @@ static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
ds1337_init_client(new_client);
|
||||
|
||||
/* Add client to local list */
|
||||
data->id = ds1337_id++;
|
||||
list_add(&data->list, &ds1337_clients);
|
||||
|
||||
return 0;
|
||||
|
@ -398,5 +379,7 @@ MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
|
|||
MODULE_DESCRIPTION("DS1337 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
EXPORT_SYMBOL_GPL(ds1337_do_command);
|
||||
|
||||
module_init(ds1337_init);
|
||||
module_exit(ds1337_exit);
|
||||
|
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* drivers/i2c/chips/ds1374.c
|
||||
*
|
||||
* I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock
|
||||
*
|
||||
* Author: Randy Vinson <rvinson@mvista.com>
|
||||
*
|
||||
* Based on the m41t00.c by Mark Greer <mgreer@mvista.com>
|
||||
*
|
||||
* 2005 (c) MontaVista Software, Inc. This file is licensed under
|
||||
* the terms of the GNU General Public License version 2. This program
|
||||
* is licensed "as is" without any warranty of any kind, whether express
|
||||
* or implied.
|
||||
*/
|
||||
/*
|
||||
* This i2c client/driver wedges between the drivers/char/genrtc.c RTC
|
||||
* interface and the SMBus interface of the i2c subsystem.
|
||||
* It would be more efficient to use i2c msgs/i2c_transfer directly but, as
|
||||
* recommened in .../Documentation/i2c/writing-clients section
|
||||
* "Sending and receiving", using SMBus level communication is preferred.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/bcd.h>
|
||||
|
||||
#define DS1374_REG_TOD0 0x00
|
||||
#define DS1374_REG_TOD1 0x01
|
||||
#define DS1374_REG_TOD2 0x02
|
||||
#define DS1374_REG_TOD3 0x03
|
||||
#define DS1374_REG_WDALM0 0x04
|
||||
#define DS1374_REG_WDALM1 0x05
|
||||
#define DS1374_REG_WDALM2 0x06
|
||||
#define DS1374_REG_CR 0x07
|
||||
#define DS1374_REG_SR 0x08
|
||||
#define DS1374_REG_SR_OSF 0x80
|
||||
#define DS1374_REG_TCR 0x09
|
||||
|
||||
#define DS1374_DRV_NAME "ds1374"
|
||||
|
||||
static DECLARE_MUTEX(ds1374_mutex);
|
||||
|
||||
static struct i2c_driver ds1374_driver;
|
||||
static struct i2c_client *save_client;
|
||||
|
||||
static unsigned short ignore[] = { I2C_CLIENT_END };
|
||||
static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END };
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_addr,
|
||||
.probe = ignore,
|
||||
.ignore = ignore,
|
||||
.force = ignore,
|
||||
};
|
||||
|
||||
static ulong ds1374_read_rtc(void)
|
||||
{
|
||||
ulong time = 0;
|
||||
int reg = DS1374_REG_WDALM0;
|
||||
|
||||
while (reg--) {
|
||||
s32 tmp;
|
||||
if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) {
|
||||
dev_warn(&save_client->dev,
|
||||
"can't read from rtc chip\n");
|
||||
return 0;
|
||||
}
|
||||
time = (time << 8) | (tmp & 0xff);
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
static void ds1374_write_rtc(ulong time)
|
||||
{
|
||||
int reg;
|
||||
|
||||
for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) {
|
||||
if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff)
|
||||
< 0) {
|
||||
dev_warn(&save_client->dev,
|
||||
"can't write to rtc chip\n");
|
||||
break;
|
||||
}
|
||||
time = time >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void ds1374_check_rtc_status(void)
|
||||
{
|
||||
s32 tmp;
|
||||
|
||||
tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR);
|
||||
if (tmp < 0) {
|
||||
dev_warn(&save_client->dev,
|
||||
"can't read status from rtc chip\n");
|
||||
return;
|
||||
}
|
||||
if (tmp & DS1374_REG_SR_OSF) {
|
||||
dev_warn(&save_client->dev,
|
||||
"oscillator discontinuity flagged, time unreliable\n");
|
||||
tmp &= ~DS1374_REG_SR_OSF;
|
||||
tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR,
|
||||
tmp & 0xff);
|
||||
if (tmp < 0)
|
||||
dev_warn(&save_client->dev,
|
||||
"can't clear discontinuity notification\n");
|
||||
}
|
||||
}
|
||||
|
||||
ulong ds1374_get_rtc_time(void)
|
||||
{
|
||||
ulong t1, t2;
|
||||
int limit = 10; /* arbitrary retry limit */
|
||||
|
||||
down(&ds1374_mutex);
|
||||
|
||||
/*
|
||||
* Since the reads are being performed one byte at a time using
|
||||
* the SMBus vs a 4-byte i2c transfer, there is a chance that a
|
||||
* carry will occur during the read. To detect this, 2 reads are
|
||||
* performed and compared.
|
||||
*/
|
||||
do {
|
||||
t1 = ds1374_read_rtc();
|
||||
t2 = ds1374_read_rtc();
|
||||
} while (t1 != t2 && limit--);
|
||||
|
||||
up(&ds1374_mutex);
|
||||
|
||||
if (t1 != t2) {
|
||||
dev_warn(&save_client->dev,
|
||||
"can't get consistent time from rtc chip\n");
|
||||
t1 = 0;
|
||||
}
|
||||
|
||||
return t1;
|
||||
}
|
||||
|
||||
static void ds1374_set_tlet(ulong arg)
|
||||
{
|
||||
ulong t1, t2;
|
||||
int limit = 10; /* arbitrary retry limit */
|
||||
|
||||
t1 = *(ulong *) arg;
|
||||
|
||||
down(&ds1374_mutex);
|
||||
|
||||
/*
|
||||
* Since the writes are being performed one byte at a time using
|
||||
* the SMBus vs a 4-byte i2c transfer, there is a chance that a
|
||||
* carry will occur during the write. To detect this, the write
|
||||
* value is read back and compared.
|
||||
*/
|
||||
do {
|
||||
ds1374_write_rtc(t1);
|
||||
t2 = ds1374_read_rtc();
|
||||
} while (t1 != t2 && limit--);
|
||||
|
||||
up(&ds1374_mutex);
|
||||
|
||||
if (t1 != t2)
|
||||
dev_warn(&save_client->dev,
|
||||
"can't confirm time set from rtc chip\n");
|
||||
}
|
||||
|
||||
ulong new_time;
|
||||
|
||||
DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, (ulong) & new_time);
|
||||
|
||||
int ds1374_set_rtc_time(ulong nowtime)
|
||||
{
|
||||
new_time = nowtime;
|
||||
|
||||
if (in_interrupt())
|
||||
tasklet_schedule(&ds1374_tasklet);
|
||||
else
|
||||
ds1374_set_tlet((ulong) & new_time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*****************************************************************************
|
||||
*
|
||||
* Driver Interface
|
||||
*
|
||||
*****************************************************************************
|
||||
*/
|
||||
static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
int rc;
|
||||
|
||||
client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(client, 0, sizeof(struct i2c_client));
|
||||
strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE);
|
||||
client->flags = I2C_DF_NOTIFY;
|
||||
client->addr = addr;
|
||||
client->adapter = adap;
|
||||
client->driver = &ds1374_driver;
|
||||
|
||||
if ((rc = i2c_attach_client(client)) != 0) {
|
||||
kfree(client);
|
||||
return rc;
|
||||
}
|
||||
|
||||
save_client = client;
|
||||
|
||||
ds1374_check_rtc_status();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ds1374_attach(struct i2c_adapter *adap)
|
||||
{
|
||||
return i2c_probe(adap, &addr_data, ds1374_probe);
|
||||
}
|
||||
|
||||
static int ds1374_detach(struct i2c_client *client)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((rc = i2c_detach_client(client)) == 0) {
|
||||
kfree(i2c_get_clientdata(client));
|
||||
tasklet_kill(&ds1374_tasklet);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct i2c_driver ds1374_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DS1374_DRV_NAME,
|
||||
.id = I2C_DRIVERID_DS1374,
|
||||
.flags = I2C_DF_NOTIFY,
|
||||
.attach_adapter = ds1374_attach,
|
||||
.detach_client = ds1374_detach,
|
||||
};
|
||||
|
||||
static int __init ds1374_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ds1374_driver);
|
||||
}
|
||||
|
||||
static void __exit ds1374_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ds1374_driver);
|
||||
}
|
||||
|
||||
module_init(ds1374_init);
|
||||
module_exit(ds1374_exit);
|
||||
|
||||
MODULE_AUTHOR("Randy Vinson <rvinson@mvista.com>");
|
||||
MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -121,7 +121,7 @@ static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
|
|||
static void ds1621_init_client(struct i2c_client *client)
|
||||
{
|
||||
int reg = ds1621_read_value(client, DS1621_REG_CONF);
|
||||
/* switch to continous conversion mode */
|
||||
/* switch to continuous conversion mode */
|
||||
reg &= ~ DS1621_REG_CONFIG_1SHOT;
|
||||
|
||||
/* setup output polarity */
|
||||
|
@ -303,7 +303,7 @@ static struct ds1621_data *ds1621_update_client(struct device *dev)
|
|||
data->temp_max = ds1621_read_value(client,
|
||||
DS1621_REG_TEMP_MAX);
|
||||
|
||||
/* reset alarms if neccessary */
|
||||
/* reset alarms if necessary */
|
||||
new_conf = data->conf;
|
||||
if (data->temp < data->temp_min)
|
||||
new_conf &= ~DS1621_ALARM_TEMP_LOW;
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
* and Philip Edelbrock <phil@netroedge.com>
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
* 2004-01-31 Code review and approval. (Jean Delvare)
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
@ -145,7 +145,6 @@ static inline void notresponding(struct isp1301 *isp)
|
|||
static unsigned short normal_i2c[] = {
|
||||
ISP_BASE, ISP_BASE + 1,
|
||||
I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
|
||||
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
type at module load time.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -39,6 +38,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/i2c-vid.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
|
@ -173,8 +173,6 @@ static inline u8 FAN_TO_REG(long rpm, int div)
|
|||
((val)+500)/1000),-128,127))
|
||||
#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000)
|
||||
|
||||
#define ALARMS_FROM_REG(val) (val)
|
||||
|
||||
#define PWM_TO_REG(val) ((val) >> 1)
|
||||
#define PWM_FROM_REG(val) (((val)&0x7f) << 1)
|
||||
|
||||
|
@ -241,27 +239,42 @@ static struct i2c_driver it87_driver = {
|
|||
.detach_client = it87_detach_client,
|
||||
};
|
||||
|
||||
static ssize_t show_in(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_in(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_in_min(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_in_max(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
|
||||
}
|
||||
|
||||
static ssize_t set_in_min(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
|
@ -273,9 +286,12 @@ static ssize_t set_in_min(struct device *dev, const char *buf,
|
|||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_in_max(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
|
@ -289,38 +305,14 @@ static ssize_t set_in_max(struct device *dev, const char *buf,
|
|||
}
|
||||
|
||||
#define show_in_offset(offset) \
|
||||
static ssize_t \
|
||||
show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_in(dev, buf, offset); \
|
||||
} \
|
||||
static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);
|
||||
static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
|
||||
show_in, NULL, offset);
|
||||
|
||||
#define limit_in_offset(offset) \
|
||||
static ssize_t \
|
||||
show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_in_min(dev, buf, offset); \
|
||||
} \
|
||||
static ssize_t \
|
||||
show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_in_max(dev, buf, offset); \
|
||||
} \
|
||||
static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_in_min(dev, buf, count, offset); \
|
||||
} \
|
||||
static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_in_max(dev, buf, count, offset); \
|
||||
} \
|
||||
static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_in##offset##_min, set_in##offset##_min); \
|
||||
static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
|
||||
show_in##offset##_max, set_in##offset##_max);
|
||||
static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_in_min, set_in_min, offset); \
|
||||
static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
|
||||
show_in_max, set_in_max, offset);
|
||||
|
||||
show_in_offset(0);
|
||||
limit_in_offset(0);
|
||||
|
@ -341,24 +333,39 @@ limit_in_offset(7);
|
|||
show_in_offset(8);
|
||||
|
||||
/* 3 temperatures */
|
||||
static ssize_t show_temp(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
|
||||
}
|
||||
static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr]));
|
||||
}
|
||||
static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr]));
|
||||
}
|
||||
static ssize_t set_temp_max(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
|
@ -369,9 +376,12 @@ static ssize_t set_temp_max(struct device *dev, const char *buf,
|
|||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_temp_min(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
|
@ -383,42 +393,23 @@ static ssize_t set_temp_min(struct device *dev, const char *buf,
|
|||
return count;
|
||||
}
|
||||
#define show_temp_offset(offset) \
|
||||
static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_temp(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t \
|
||||
show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_temp_max(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t \
|
||||
show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_temp_min(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_temp_max(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_temp_min(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL); \
|
||||
static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
|
||||
show_temp_##offset##_max, set_temp_##offset##_max); \
|
||||
static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_temp_##offset##_min, set_temp_##offset##_min);
|
||||
static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
|
||||
show_temp, NULL, offset - 1); \
|
||||
static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
|
||||
show_temp_max, set_temp_max, offset - 1); \
|
||||
static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_temp_min, set_temp_min, offset - 1);
|
||||
|
||||
show_temp_offset(1);
|
||||
show_temp_offset(2);
|
||||
show_temp_offset(3);
|
||||
|
||||
static ssize_t show_sensor(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_sensor(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
u8 reg = data->sensor; /* In case the value is updated while we use it */
|
||||
|
||||
|
@ -428,9 +419,12 @@ static ssize_t show_sensor(struct device *dev, char *buf, int nr)
|
|||
return sprintf(buf, "2\n"); /* thermistor */
|
||||
return sprintf(buf, "0\n"); /* disabled */
|
||||
}
|
||||
static ssize_t set_sensor(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
|
@ -453,53 +447,67 @@ static ssize_t set_sensor(struct device *dev, const char *buf,
|
|||
return count;
|
||||
}
|
||||
#define show_sensor_offset(offset) \
|
||||
static ssize_t show_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_sensor(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_sensor_##offset (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_sensor(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
|
||||
show_sensor_##offset, set_sensor_##offset);
|
||||
static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
|
||||
show_sensor, set_sensor, offset - 1);
|
||||
|
||||
show_sensor_offset(1);
|
||||
show_sensor_offset(2);
|
||||
show_sensor_offset(3);
|
||||
|
||||
/* 3 Fans */
|
||||
static ssize_t show_fan(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr],
|
||||
DIV_FROM_REG(data->fan_div[nr])));
|
||||
}
|
||||
static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf,"%d\n",
|
||||
FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])));
|
||||
}
|
||||
static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
|
||||
}
|
||||
static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf,"%d\n", (data->fan_main_ctrl & (1 << nr)) ? 1 : 0);
|
||||
}
|
||||
static ssize_t show_pwm(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]);
|
||||
}
|
||||
static ssize_t set_fan_min(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
|
@ -510,9 +518,12 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
|
|||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_fan_div(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
|
@ -550,9 +561,12 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
|
|||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_pwm_enable(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_pwm_enable(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
|
@ -581,9 +595,12 @@ static ssize_t set_pwm_enable(struct device *dev, const char *buf,
|
|||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_pwm(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
|
@ -600,63 +617,22 @@ static ssize_t set_pwm(struct device *dev, const char *buf,
|
|||
}
|
||||
|
||||
#define show_fan_offset(offset) \
|
||||
static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_fan(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_fan_min(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_fan_div(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_fan_min(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_fan_div(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL); \
|
||||
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_fan_##offset##_min, set_fan_##offset##_min); \
|
||||
static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
|
||||
show_fan_##offset##_div, set_fan_##offset##_div);
|
||||
static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
|
||||
show_fan, NULL, offset - 1); \
|
||||
static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_fan_min, set_fan_min, offset - 1); \
|
||||
static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
|
||||
show_fan_div, set_fan_div, offset - 1);
|
||||
|
||||
show_fan_offset(1);
|
||||
show_fan_offset(2);
|
||||
show_fan_offset(3);
|
||||
|
||||
#define show_pwm_offset(offset) \
|
||||
static ssize_t show_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_pwm_enable(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t show_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_pwm(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_pwm_enable(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_pwm(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
|
||||
show_pwm##offset##_enable, \
|
||||
set_pwm##offset##_enable); \
|
||||
static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
|
||||
show_pwm##offset , set_pwm##offset );
|
||||
static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
|
||||
show_pwm_enable, set_pwm_enable, offset - 1); \
|
||||
static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
|
||||
show_pwm, set_pwm, offset - 1);
|
||||
|
||||
show_pwm_offset(1);
|
||||
show_pwm_offset(2);
|
||||
|
@ -666,7 +642,7 @@ show_pwm_offset(3);
|
|||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms));
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
|
@ -864,60 +840,60 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
it87_init_client(new_client, data);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in7_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in8_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in7_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in7_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_type);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_type);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_type);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_div);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
if (enable_pwm_interface) {
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm3_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm3);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr);
|
||||
}
|
||||
|
||||
if (data->type == it8712) {
|
||||
|
@ -954,7 +930,7 @@ static int it87_detach_client(struct i2c_client *client)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* The SMBus locks itself, but ISA access must be locked explicitely!
|
||||
/* The SMBus locks itself, but ISA access must be locked explicitly!
|
||||
We don't want to lock the whole ISA bus, so we lock each client
|
||||
separately.
|
||||
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
|
||||
|
@ -974,7 +950,7 @@ static int it87_read_value(struct i2c_client *client, u8 reg)
|
|||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
/* The SMBus locks itself, but ISA access muse be locked explicitely!
|
||||
/* The SMBus locks itself, but ISA access muse be locked explicitly!
|
||||
We don't want to lock the whole ISA bus, so we lock each client
|
||||
separately.
|
||||
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* lm63.c - driver for the National Semiconductor LM63 temperature sensor
|
||||
* with integrated fan control
|
||||
* Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
|
||||
* Copyright (C) 2004-2005 Jean Delvare <khali@linux-fr.org>
|
||||
* Based on the lm90 driver.
|
||||
*
|
||||
* The LM63 is a sensor chip made by National Semiconductor. It measures
|
||||
|
@ -37,13 +37,13 @@
|
|||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
|
||||
/*
|
||||
* Addresses to scan
|
||||
|
@ -99,9 +99,9 @@ SENSORS_INSMOD_1(lm63);
|
|||
* Conversions and various macros
|
||||
* For tachometer counts, the LM63 uses 16-bit values.
|
||||
* For local temperature and high limit, remote critical limit and hysteresis
|
||||
* value, it uses signed 8-bit values with LSB = 1 degree Celcius.
|
||||
* value, it uses signed 8-bit values with LSB = 1 degree Celsius.
|
||||
* For remote temperature, low and high limits, it uses signed 11-bit values
|
||||
* with LSB = 0.125 degree Celcius, left-justified in 16-bit registers.
|
||||
* with LSB = 0.125 degree Celsius, left-justified in 16-bit registers.
|
||||
*/
|
||||
|
||||
#define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \
|
||||
|
@ -158,16 +158,16 @@ struct lm63_data {
|
|||
|
||||
/* registers values */
|
||||
u8 config, config_fan;
|
||||
u16 fan1_input;
|
||||
u16 fan1_low;
|
||||
u16 fan[2]; /* 0: input
|
||||
1: low limit */
|
||||
u8 pwm1_freq;
|
||||
u8 pwm1_value;
|
||||
s8 temp1_input;
|
||||
s8 temp1_high;
|
||||
s16 temp2_input;
|
||||
s16 temp2_high;
|
||||
s16 temp2_low;
|
||||
s8 temp2_crit;
|
||||
s8 temp8[3]; /* 0: local input
|
||||
1: local high limit
|
||||
2: remote critical limit */
|
||||
s16 temp11[3]; /* 0: remote input
|
||||
1: remote low limit
|
||||
2: remote high limit */
|
||||
u8 temp2_crit_hyst;
|
||||
u8 alarms;
|
||||
};
|
||||
|
@ -176,33 +176,33 @@ struct lm63_data {
|
|||
* Sysfs callback functions and files
|
||||
*/
|
||||
|
||||
#define show_fan(value) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct lm63_data *data = lm63_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->value)); \
|
||||
static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index]));
|
||||
}
|
||||
show_fan(fan1_input);
|
||||
show_fan(fan1_low);
|
||||
|
||||
static ssize_t set_fan1_low(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm63_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
down(&data->update_lock);
|
||||
data->fan1_low = FAN_TO_REG(val);
|
||||
data->fan[1] = FAN_TO_REG(val);
|
||||
i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB,
|
||||
data->fan1_low & 0xFF);
|
||||
data->fan[1] & 0xFF);
|
||||
i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB,
|
||||
data->fan1_low >> 8);
|
||||
data->fan[1] >> 8);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy,
|
||||
char *buf)
|
||||
{
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ?
|
||||
|
@ -210,7 +210,8 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char
|
|||
(2 * data->pwm1_freq));
|
||||
}
|
||||
|
||||
static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm63_data *data = i2c_get_clientdata(client);
|
||||
|
@ -229,77 +230,83 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy,
|
||||
char *buf)
|
||||
{
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
|
||||
}
|
||||
|
||||
#define show_temp8(value) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct lm63_data *data = lm63_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->value)); \
|
||||
static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index]));
|
||||
}
|
||||
#define show_temp11(value) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct lm63_data *data = lm63_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->value)); \
|
||||
}
|
||||
show_temp8(temp1_input);
|
||||
show_temp8(temp1_high);
|
||||
show_temp11(temp2_input);
|
||||
show_temp11(temp2_high);
|
||||
show_temp11(temp2_low);
|
||||
show_temp8(temp2_crit);
|
||||
|
||||
#define set_temp8(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 lm63_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
\
|
||||
down(&data->update_lock); \
|
||||
data->value = TEMP8_TO_REG(val); \
|
||||
i2c_smbus_write_byte_data(client, reg, data->value); \
|
||||
up(&data->update_lock); \
|
||||
return count; \
|
||||
static ssize_t set_temp8(struct device *dev, struct device_attribute *dummy,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm63_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
|
||||
down(&data->update_lock);
|
||||
data->temp8[1] = TEMP8_TO_REG(val);
|
||||
i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
#define set_temp11(value, reg_msb, reg_lsb) \
|
||||
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 lm63_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
\
|
||||
down(&data->update_lock); \
|
||||
data->value = TEMP11_TO_REG(val); \
|
||||
i2c_smbus_write_byte_data(client, reg_msb, data->value >> 8); \
|
||||
i2c_smbus_write_byte_data(client, reg_lsb, data->value & 0xff); \
|
||||
up(&data->update_lock); \
|
||||
return count; \
|
||||
|
||||
static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index]));
|
||||
}
|
||||
|
||||
static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
static const u8 reg[4] = {
|
||||
LM63_REG_REMOTE_LOW_MSB,
|
||||
LM63_REG_REMOTE_LOW_LSB,
|
||||
LM63_REG_REMOTE_HIGH_MSB,
|
||||
LM63_REG_REMOTE_HIGH_LSB,
|
||||
};
|
||||
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm63_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
int nr = attr->index;
|
||||
|
||||
down(&data->update_lock);
|
||||
data->temp11[nr] = TEMP11_TO_REG(val);
|
||||
i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
|
||||
data->temp11[nr] >> 8);
|
||||
i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
|
||||
data->temp11[nr] & 0xff);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
set_temp8(temp1_high, LM63_REG_LOCAL_HIGH);
|
||||
set_temp11(temp2_high, LM63_REG_REMOTE_HIGH_MSB, LM63_REG_REMOTE_HIGH_LSB);
|
||||
set_temp11(temp2_low, LM63_REG_REMOTE_LOW_MSB, LM63_REG_REMOTE_LOW_LSB);
|
||||
|
||||
/* Hysteresis register holds a relative value, while we want to present
|
||||
an absolute to user-space */
|
||||
static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
|
||||
char *buf)
|
||||
{
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp2_crit)
|
||||
return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2])
|
||||
- TEMP8_FROM_REG(data->temp2_crit_hyst));
|
||||
}
|
||||
|
||||
/* And now the other way around, user-space provides an absolute
|
||||
hysteresis value and we have to store a relative one */
|
||||
static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm63_data *data = i2c_get_clientdata(client);
|
||||
|
@ -307,36 +314,37 @@ static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *
|
|||
long hyst;
|
||||
|
||||
down(&data->update_lock);
|
||||
hyst = TEMP8_FROM_REG(data->temp2_crit) - val;
|
||||
hyst = TEMP8_FROM_REG(data->temp8[2]) - val;
|
||||
i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
|
||||
HYST_TO_REG(hyst));
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
|
||||
char *buf)
|
||||
{
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan1_input, NULL);
|
||||
static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan1_low,
|
||||
set_fan1_low);
|
||||
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
|
||||
set_fan, 1);
|
||||
|
||||
static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1);
|
||||
static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
|
||||
|
||||
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL);
|
||||
static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_high,
|
||||
set_temp1_high);
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8,
|
||||
set_temp8, 1);
|
||||
|
||||
static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp2_input, NULL);
|
||||
static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp2_low,
|
||||
set_temp2_low);
|
||||
static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp2_high,
|
||||
set_temp2_high);
|
||||
static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp2_crit, NULL);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
|
||||
set_temp11, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
|
||||
set_temp11, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2);
|
||||
static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
|
||||
set_temp2_crit_hyst);
|
||||
|
||||
|
@ -430,17 +438,25 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||
|
||||
/* Register sysfs hooks */
|
||||
if (data->config & 0x04) { /* tachometer enabled */
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_min.dev_attr);
|
||||
}
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
|
||||
|
@ -511,11 +527,11 @@ static struct lm63_data *lm63_update_device(struct device *dev)
|
|||
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
|
||||
if (data->config & 0x04) { /* tachometer enabled */
|
||||
/* order matters for fan1_input */
|
||||
data->fan1_input = i2c_smbus_read_byte_data(client,
|
||||
data->fan[0] = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_TACH_COUNT_LSB) & 0xFC;
|
||||
data->fan1_input |= i2c_smbus_read_byte_data(client,
|
||||
data->fan[0] |= i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_TACH_COUNT_MSB) << 8;
|
||||
data->fan1_low = (i2c_smbus_read_byte_data(client,
|
||||
data->fan[1] = (i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_TACH_LIMIT_LSB) & 0xFC)
|
||||
| (i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_TACH_LIMIT_MSB) << 8);
|
||||
|
@ -528,25 +544,25 @@ static struct lm63_data *lm63_update_device(struct device *dev)
|
|||
data->pwm1_value = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_PWM_VALUE);
|
||||
|
||||
data->temp1_input = i2c_smbus_read_byte_data(client,
|
||||
data->temp8[0] = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_LOCAL_TEMP);
|
||||
data->temp1_high = i2c_smbus_read_byte_data(client,
|
||||
data->temp8[1] = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_LOCAL_HIGH);
|
||||
|
||||
/* order matters for temp2_input */
|
||||
data->temp2_input = i2c_smbus_read_byte_data(client,
|
||||
data->temp11[0] = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_TEMP_MSB) << 8;
|
||||
data->temp2_input |= i2c_smbus_read_byte_data(client,
|
||||
data->temp11[0] |= i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_TEMP_LSB);
|
||||
data->temp2_high = (i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_HIGH_MSB) << 8)
|
||||
| i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_HIGH_LSB);
|
||||
data->temp2_low = (i2c_smbus_read_byte_data(client,
|
||||
data->temp11[1] = (i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_LOW_MSB) << 8)
|
||||
| i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_LOW_LSB);
|
||||
data->temp2_crit = i2c_smbus_read_byte_data(client,
|
||||
data->temp11[2] = (i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_HIGH_MSB) << 8)
|
||||
| i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_HIGH_LSB);
|
||||
data->temp8[2] = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_TCRIT);
|
||||
data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_TCRIT_HYST);
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue