Merge branch 'release' of git://lm-sensors.org/kernel/mhoffman/hwmon-2.6

* 'release' of git://lm-sensors.org/kernel/mhoffman/hwmon-2.6: (44 commits)
  i2c: Delete the i2c-isa pseudo bus driver
  hwmon: refuse to load abituguru driver on non-Abit boards
  hwmon: fix Abit Uguru3 driver detection on some motherboards
  hwmon/w83627ehf: Be quiet when no chip is found
  hwmon/w83627ehf: No need to initialize fan_min
  hwmon/w83627ehf: Export the thermal sensor types
  hwmon/w83627ehf: Enable VBAT monitoring
  hwmon/w83627ehf: Add support for the VID inputs
  hwmon/w83627ehf: Fix timing issues
  hwmon/w83627ehf: Add error messages for two error cases
  hwmon/w83627ehf: Convert to a platform driver
  hwmon/w83627ehf: Update the Kconfig entry
  make coretemp_device_remove() static
  hwmon: Add LM93 support
  hwmon: Improve the pwmN_enable documentation
  hwmon/smsc47b397: Don't report missing fans as spinning at 82 RPM
  hwmon: Add support for newer uGuru's
  hwmon/f71805f: Add temperature-tracking fan control mode
  hwmon/w83627ehf: Preserve speed reading when changing fan min
  hwmon: fix detection of abituguru volt inputs
  ...

Manual fixup of trivial conflict in MAINTAINERS file
This commit is contained in:
Linus Torvalds 2007-07-19 14:24:57 -07:00
commit 40b42f1ebf
57 changed files with 8803 additions and 1715 deletions

View file

@ -164,15 +164,6 @@ Who: Kay Sievers <kay.sievers@suse.de>
---------------------------
What: i2c-isa
When: December 2006
Why: i2c-isa is a non-sense and doesn't fit in the device driver
model. Drivers relying on it are better implemented as platform
drivers.
Who: Jean Delvare <khali@linux-fr.org>
---------------------------
What: i2c_adapter.list
When: July 2007
Why: Superfluous, this list duplicates the one maintained by the driver

View file

@ -2,7 +2,7 @@ Kernel driver abituguru
=======================
Supported chips:
* Abit uGuru revision 1-3 (Hardware Monitor part only)
* Abit uGuru revision 1 & 2 (Hardware Monitor part only)
Prefix: 'abituguru'
Addresses scanned: ISA 0x0E0
Datasheet: Not available, this driver is based on reverse engineering.
@ -20,8 +20,8 @@ Supported chips:
uGuru 2.1.0.0 ~ 2.1.2.8 (AS8, AV8, AA8, AG8, AA8XE, AX8)
uGuru 2.2.0.0 ~ 2.2.0.6 (AA8 Fatal1ty)
uGuru 2.3.0.0 ~ 2.3.0.9 (AN8)
uGuru 3.0.0.0 ~ 3.0.1.2 (AW8, AL8, NI8)
uGuru 4.xxxxx? (AT8 32X) (2)
uGuru 3.0.0.0 ~ 3.0.x.x (AW8, AL8, AT8, NI8 SLI, AT8 32X, AN8 32X,
AW9D-MAX) (2)
1) For revisions 2 and 3 uGuru's the driver can autodetect the
sensortype (Volt or Temp) for bank1 sensors, for revision 1 uGuru's
this doesnot always work. For these uGuru's the autodection can
@ -30,8 +30,9 @@ Supported chips:
bank1_types=1,1,0,0,0,0,0,2,0,0,0,0,2,0,0,1
You may also need to specify the fan_sensors option for these boards
fan_sensors=5
2) The current version of the abituguru driver is known to NOT work
on these Motherboards
2) There is a seperate abituguru3 driver for these motherboards,
the abituguru (without the 3 !) driver will not work on these
motherboards (and visa versa)!
Authors:
Hans de Goede <j.w.r.degoede@hhs.nl>,
@ -43,8 +44,10 @@ Module Parameters
-----------------
* force: bool Force detection. Note this parameter only causes the
detection to be skipped, if the uGuru can't be read
the module initialization (insmod) will still fail.
detection to be skipped, and thus the insmod to
succeed. If the uGuru can't be read the actual hwmon
driver will not load and thus no hwmon device will get
registered.
* bank1_types: int[] Bank1 sensortype autodetection override:
-1 autodetect (default)
0 volt sensor
@ -69,13 +72,15 @@ dmesg | grep abituguru
Description
-----------
This driver supports the hardware monitoring features of the Abit uGuru chip
found on Abit uGuru featuring motherboards (most modern Abit motherboards).
This driver supports the hardware monitoring features of the first and
second revision of the Abit uGuru chip found on Abit uGuru featuring
motherboards (most modern Abit motherboards).
The uGuru chip in reality is a Winbond W83L950D in disguise (despite Abit
claiming it is "a new microprocessor designed by the ABIT Engineers").
Unfortunatly this doesn't help since the W83L950D is a generic
microcontroller with a custom Abit application running on it.
The first and second revision of the uGuru chip in reality is a Winbond
W83L950D in disguise (despite Abit claiming it is "a new microprocessor
designed by the ABIT Engineers"). Unfortunatly this doesn't help since the
W83L950D is a generic microcontroller with a custom Abit application running
on it.
Despite Abit not releasing any information regarding the uGuru, Olle
Sandberg <ollebull@gmail.com> has managed to reverse engineer the sensor part

View file

@ -0,0 +1,65 @@
Kernel driver abituguru3
========================
Supported chips:
* Abit uGuru revision 3 (Hardware Monitor part, reading only)
Prefix: 'abituguru3'
Addresses scanned: ISA 0x0E0
Datasheet: Not available, this driver is based on reverse engineering.
Note:
The uGuru is a microcontroller with onboard firmware which programs
it to behave as a hwmon IC. There are many different revisions of the
firmware and thus effectivly many different revisions of the uGuru.
Below is an incomplete list with which revisions are used for which
Motherboards:
uGuru 1.00 ~ 1.24 (AI7, KV8-MAX3, AN7)
uGuru 2.0.0.0 ~ 2.0.4.2 (KV8-PRO)
uGuru 2.1.0.0 ~ 2.1.2.8 (AS8, AV8, AA8, AG8, AA8XE, AX8)
uGuru 2.3.0.0 ~ 2.3.0.9 (AN8)
uGuru 3.0.0.0 ~ 3.0.x.x (AW8, AL8, AT8, NI8 SLI, AT8 32X, AN8 32X,
AW9D-MAX)
The abituguru3 driver is only for revison 3.0.x.x motherboards,
this driver will not work on older motherboards. For older
motherboards use the abituguru (without the 3 !) driver.
Authors:
Hans de Goede <j.w.r.degoede@hhs.nl>,
(Initial reverse engineering done by Louis Kruger)
Module Parameters
-----------------
* force: bool Force detection. Note this parameter only causes the
detection to be skipped, and thus the insmod to
succeed. If the uGuru can't be read the actual hwmon
driver will not load and thus no hwmon device will get
registered.
* verbose: bool Should the driver be verbose?
0/off/false normal output
1/on/true + verbose error reporting (default)
Default: 1 (the driver is still in the testing phase)
Description
-----------
This driver supports the hardware monitoring features of the third revision of
the Abit uGuru chip, found on recent Abit uGuru featuring motherboards.
The 3rd revision of the uGuru chip in reality is a Winbond W83L951G.
Unfortunatly this doesn't help since the W83L951G is a generic microcontroller
with a custom Abit application running on it.
Despite Abit not releasing any information regarding the uGuru revision 3,
Louis Kruger has managed to reverse engineer the sensor part of the uGuru.
Without his work this driver would not have been possible.
Known Issues
------------
The voltage and frequency control parts of the Abit uGuru are not supported,
neither is writing any of the sensor settings and writing / reading the
fanspeed control registers (FanEQ)
If you encounter any problems please mail me <j.w.r.degoede@hhs.nl> and
include the output of: "dmesg | grep abituguru"

257
Documentation/hwmon/dme1737 Normal file
View file

@ -0,0 +1,257 @@
Kernel driver dme1737
=====================
Supported chips:
* SMSC DME1737 and compatibles (like Asus A8000)
Prefix: 'dme1737'
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
Datasheet: Provided by SMSC upon request and under NDA
Authors:
Juerg Haefliger <juergh@gmail.com>
Module Parameters
-----------------
* force_start: bool Enables the monitoring of voltage, fan and temp inputs
and PWM output control functions. Using this parameter
shouldn't be required since the BIOS usually takes care
of this.
Note that there is no need to use this parameter if the driver loads without
complaining. The driver will say so if it is necessary.
Description
-----------
This driver implements support for the hardware monitoring capabilities of the
SMSC DME1737 and Asus A8000 (which are the same) Super-I/O chips. This chip
features monitoring of 3 temp sensors temp[1-3] (2 remote diodes and 1
internal), 7 voltages in[0-6] (6 external and 1 internal) and 6 fan speeds
fan[1-6]. Additionally, the chip implements 5 PWM outputs pwm[1-3,5-6] for
controlling fan speeds both manually and automatically.
Fan[3-6] and pwm[3,5-6] are optional features and their availability is
dependent on the configuration of the chip. The driver will detect which
features are present during initialization and create the sysfs attributes
accordingly.
Voltage Monitoring
------------------
The voltage inputs are sampled with 12-bit resolution and have internal
scaling resistors. The values returned by the driver therefore reflect true
millivolts and don't need scaling. The voltage inputs are mapped as follows
(the last column indicates the input ranges):
in0: +5VTR (+5V standby) 0V - 6.64V
in1: Vccp (processor core) 0V - 3V
in2: VCC (internal +3.3V) 0V - 4.38V
in3: +5V 0V - 6.64V
in4: +12V 0V - 16V
in5: VTR (+3.3V standby) 0V - 4.38V
in6: Vbat (+3.0V) 0V - 4.38V
Each voltage input has associated min and max limits which trigger an alarm
when crossed.
Temperature Monitoring
----------------------
Temperatures are measured with 12-bit resolution and reported in millidegree
Celsius. The chip also features offsets for all 3 temperature inputs which -
when programmed - get added to the input readings. The chip does all the
scaling by itself and the driver therefore reports true temperatures that don't
need any user-space adjustments. The temperature inputs are mapped as follows
(the last column indicates the input ranges):
temp1: Remote diode 1 (3904 type) temperature -127C - +127C
temp2: DME1737 internal temperature -127C - +127C
temp3: Remote diode 2 (3904 type) temperature -127C - +127C
Each temperature input has associated min and max limits which trigger an alarm
when crossed. Additionally, each temperature input has a fault attribute that
returns 1 when a faulty diode or an unconnected input is detected and 0
otherwise.
Fan Monitoring
--------------
Fan RPMs are measured with 16-bit resolution. The chip provides inputs for 6
fan tachometers. All 6 inputs have an associated min limit which triggers an
alarm when crossed. Fan inputs 1-4 provide type attributes that need to be set
to the number of pulses per fan revolution that the connected tachometer
generates. Supported values are 1, 2, and 4. Fan inputs 5-6 only support fans
that generate 2 pulses per revolution. Fan inputs 5-6 also provide a max
attribute that needs to be set to the maximum attainable RPM (fan at 100% duty-
cycle) of the input. The chip adjusts the sampling rate based on this value.
PWM Output Control
------------------
This chip features 5 PWM outputs. PWM outputs 1-3 are associated with fan
inputs 1-3 and PWM outputs 5-6 are associated with fan inputs 5-6. PWM outputs
1-3 can be configured to operate either in manual or automatic mode by setting
the appropriate enable attribute accordingly. PWM outputs 5-6 can only operate
in manual mode, their enable attributes are therefore read-only. When set to
manual mode, the fan speed is set by writing the duty-cycle value to the
appropriate PWM attribute. In automatic mode, the PWM attribute returns the
current duty-cycle as set by the fan controller in the chip. All PWM outputs
support the setting of the output frequency via the freq attribute.
In automatic mode, the chip supports the setting of the PWM ramp rate which
defines how fast the PWM output is adjusting to changes of the associated
temperature input. Associating PWM outputs to temperature inputs is done via
temperature zones. The chip features 3 zones whose assignments to temperature
inputs is static and determined during initialization. These assignments can
be retrieved via the zone[1-3]_auto_channels_temp attributes. Each PWM output
is assigned to one (or hottest of multiple) temperature zone(s) through the
pwm[1-3]_auto_channels_zone attributes. Each PWM output has 3 distinct output
duty-cycles: full, low, and min. Full is internally hard-wired to 255 (100%)
and low and min can be programmed via pwm[1-3]_auto_point1_pwm and
pwm[1-3]_auto_pwm_min, respectively. The thermal thresholds of the zones are
programmed via zone[1-3]_auto_point[1-3]_temp and
zone[1-3]_auto_point1_temp_hyst:
pwm[1-3]_auto_point2_pwm full-speed duty-cycle (255, i.e., 100%)
pwm[1-3]_auto_point1_pwm low-speed duty-cycle
pwm[1-3]_auto_pwm_min min-speed duty-cycle
zone[1-3]_auto_point3_temp full-speed temp (all outputs)
zone[1-3]_auto_point2_temp full-speed temp
zone[1-3]_auto_point1_temp low-speed temp
zone[1-3]_auto_point1_temp_hyst min-speed temp
The chip adjusts the output duty-cycle linearly in the range of auto_point1_pwm
to auto_point2_pwm if the temperature of the associated zone is between
auto_point1_temp and auto_point2_temp. If the temperature drops below the
auto_point1_temp_hyst value, the output duty-cycle is set to the auto_pwm_min
value which only supports two values: 0 or auto_point1_pwm. That means that the
fan either turns completely off or keeps spinning with the low-speed
duty-cycle. If any of the temperatures rise above the auto_point3_temp value,
all PWM outputs are set to 100% duty-cycle.
Following is another representation of how the chip sets the output duty-cycle
based on the temperature of the associated thermal zone:
Duty-Cycle Duty-Cycle
Temperature Rising Temp Falling Temp
----------- ----------- ------------
full-speed full-speed full-speed
< linearly adjusted duty-cycle >
low-speed low-speed low-speed
min-speed low-speed
min-speed min-speed min-speed
min-speed min-speed
Sysfs Attributes
----------------
Following is a list of all sysfs attributes that the driver provides, their
permissions and a short description:
Name Perm Description
---- ---- -----------
cpu0_vid RO CPU core reference voltage in
millivolts.
vrm RW Voltage regulator module version
number.
in[0-6]_input RO Measured voltage in millivolts.
in[0-6]_min RW Low limit for voltage input.
in[0-6]_max RW High limit for voltage input.
in[0-6]_alarm RO Voltage input alarm. Returns 1 if
voltage input is or went outside the
associated min-max range, 0 otherwise.
temp[1-3]_input RO Measured temperature in millidegree
Celsius.
temp[1-3]_min RW Low limit for temp input.
temp[1-3]_max RW High limit for temp input.
temp[1-3]_offset RW Offset for temp input. This value will
be added by the chip to the measured
temperature.
temp[1-3]_alarm RO Alarm for temp input. Returns 1 if temp
input is or went outside the associated
min-max range, 0 otherwise.
temp[1-3]_fault RO Temp input fault. Returns 1 if the chip
detects a faulty thermal diode or an
unconnected temp input, 0 otherwise.
zone[1-3]_auto_channels_temp RO Temperature zone to temperature input
mapping. This attribute is a bitfield
and supports the following values:
1: temp1
2: temp2
4: temp3
zone[1-3]_auto_point1_temp_hyst RW Auto PWM temp point1 hysteresis. The
output of the corresponding PWM is set
to the pwm_auto_min value if the temp
falls below the auto_point1_temp_hyst
value.
zone[1-3]_auto_point[1-3]_temp RW Auto PWM temp points. Auto_point1 is
the low-speed temp, auto_point2 is the
full-speed temp, and auto_point3 is the
temp at which all PWM outputs are set
to full-speed (100% duty-cycle).
fan[1-6]_input RO Measured fan speed in RPM.
fan[1-6]_min RW Low limit for fan input.
fan[1-6]_alarm RO Alarm for fan input. Returns 1 if fan
input is or went below the associated
min value, 0 otherwise.
fan[1-4]_type RW Type of attached fan. Expressed in
number of pulses per revolution that
the fan generates. Supported values are
1, 2, and 4.
fan[5-6]_max RW Max attainable RPM at 100% duty-cycle.
Required for chip to adjust the
sampling rate accordingly.
pmw[1-3,5-6] RO/RW Duty-cycle of PWM output. Supported
values are 0-255 (0%-100%). Only
writeable if the associated PWM is in
manual mode.
pwm[1-3]_enable RW Enable of PWM outputs 1-3. Supported
values are:
0: turned off (output @ 100%)
1: manual mode
2: automatic mode
pwm[5-6]_enable RO Enable of PWM outputs 5-6. Always
returns 1 since these 2 outputs are
hard-wired to manual mode.
pmw[1-3,5-6]_freq RW Frequency of PWM output. Supported
values are in the range 11Hz-30000Hz
(default is 25000Hz).
pmw[1-3]_ramp_rate RW Ramp rate of PWM output. Determines how
fast the PWM duty-cycle will change
when the PWM is in automatic mode.
Expressed in ms per PWM step. Supported
values are in the range 0ms-206ms
(default is 0, which means the duty-
cycle changes instantly).
pwm[1-3]_auto_channels_zone RW PWM output to temperature zone mapping.
This attribute is a bitfield and
supports the following values:
1: zone1
2: zone2
4: zone3
6: highest of zone[2-3]
7: highest of zone[1-3]
pwm[1-3]_auto_pwm_min RW Auto PWM min pwm. Minimum PWM duty-
cycle. Supported values are 0 or
auto_point1_pwm.
pwm[1-3]_auto_point1_pwm RW Auto PWM pwm point. Auto_point1 is the
low-speed duty-cycle.
pwm[1-3]_auto_point2_pwm RO Auto PWM pwm point. Auto_point2 is the
full-speed duty-cycle which is hard-
wired to 255 (100% duty-cycle).

View file

@ -5,11 +5,11 @@ Supported chips:
* Fintek F71805F/FG
Prefix: 'f71805f'
Addresses scanned: none, address read from Super I/O config space
Datasheet: Provided by Fintek on request
Datasheet: Available from the Fintek website
* Fintek F71872F/FG
Prefix: 'f71872f'
Addresses scanned: none, address read from Super I/O config space
Datasheet: Provided by Fintek on request
Datasheet: Available from the Fintek website
Author: Jean Delvare <khali@linux-fr.org>
@ -128,7 +128,9 @@ it.
When the PWM method is used, you can select the operating frequency,
from 187.5 kHz (default) to 31 Hz. The best frequency depends on the
fan model. As a rule of thumb, lower frequencies seem to give better
control, but may generate annoying high-pitch noise. Fintek recommends
control, but may generate annoying high-pitch noise. So a frequency just
above the audible range, such as 25 kHz, may be a good choice; if this
doesn't give you good linear control, try reducing it. Fintek recommends
not going below 1 kHz, as the fan tachometers get confused by lower
frequencies as well.
@ -136,16 +138,23 @@ When the DC method is used, Fintek recommends not going below 5 V, which
corresponds to a pwm value of 106 for the driver. The driver doesn't
enforce this limit though.
Three different fan control modes are supported:
Three different fan control modes are supported; the mode number is written
to the pwm<n>_enable file.
* Manual mode
You ask for a specific PWM duty cycle or DC voltage.
* 1: Manual mode
You ask for a specific PWM duty cycle or DC voltage by writing to the
pwm<n> file.
* Fan speed mode
You ask for a specific fan speed. This mode assumes that pwm1
corresponds to fan1, pwm2 to fan2 and pwm3 to fan3.
* 2: Temperature mode
You define 3 temperature/fan speed trip points using the
pwm<n>_auto_point<m>_temp and _fan files. These define a staircase
relationship between temperature and fan speed with two additional points
interpolated between the values that you define. When the temperature
is below auto_point1_temp the fan is switched off.
* Temperature mode
You define 3 temperature/fan speed trip points, and the fan speed is
adjusted depending on the measured temperature, using interpolation.
This mode is not yet supported by the driver.
* 3: Fan speed mode
You ask for a specific fan speed by writing to the fan<n>_target file.
Both of the automatic modes require that pwm1 corresponds to fan1, pwm2 to
fan2 and pwm3 to fan3. Temperature mode also requires that temp1 corresponds
to pwm1 and fan1, etc.

View file

@ -12,11 +12,12 @@ Supported chips:
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Publicly available at the ITE website
http://www.ite.com.tw/
* IT8716F
* IT8716F/IT8726F
Prefix: 'it8716'
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Publicly available at the ITE website
http://www.ite.com.tw/product_info/file/pc/IT8716F_V0.3.ZIP
http://www.ite.com.tw/product_info/file/pc/IT8726F_V0.3.pdf
* IT8718F
Prefix: 'it8718'
Addresses scanned: from Super I/O config space (8 I/O ports)
@ -68,7 +69,7 @@ Description
-----------
This driver implements support for the IT8705F, IT8712F, IT8716F,
IT8718F and SiS950 chips.
IT8718F, IT8726F and SiS950 chips.
These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
joysticks and other miscellaneous stuff. For hardware monitoring, they
@ -97,6 +98,10 @@ clock divider mess) but not compatible with the older chips and
revisions. For now, the driver only uses the 16-bit mode on the
IT8716F and IT8718F.
The IT8726F is just bit enhanced IT8716F with additional hardware
for AMD power sequencing. Therefore the chip will appear as IT8716F
to userspace applications.
Temperatures are measured in degrees Celsius. An alarm is triggered once
when the Overtemperature Shutdown limit is crossed.

View file

@ -48,6 +48,18 @@ Supported chips:
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
* Maxim MAX6680
Prefix: 'max6680'
Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
0x4c, 0x4d and 0x4e
Datasheet: Publicly available at the Maxim website
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370
* Maxim MAX6681
Prefix: 'max6680'
Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
0x4c, 0x4d and 0x4e
Datasheet: Publicly available at the Maxim website
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370
Author: Jean Delvare <khali@linux-fr.org>
@ -59,11 +71,15 @@ 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 MAX6657, MAX6658, MAX6659, MAX6680 and the MAX6681 all of which are
supported by this driver.
Note that there is no easy way to differentiate between the MAX6657,
MAX6658 and MAX6659 variants. The extra address and features of the
MAX6659 are not supported by this driver. The MAX6680 and MAX6681 only
differ in their pinout, therefore they obviously can't (and don't need to)
be distinguished. 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
@ -93,18 +109,22 @@ ADM1032:
* ALERT is triggered by open remote sensor.
* SMBus PEC support for Write Byte and Receive Byte transactions.
ADT7461
ADT7461:
* Extended temperature range (breaks compatibility)
* Lower resolution for remote temperature
MAX6657 and MAX6658:
* Remote sensor type selection
MAX6659
MAX6659:
* Selectable address
* Second critical temperature limit
* Remote sensor type selection
MAX6680 and MAX6681:
* Selectable address
* 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.
@ -141,7 +161,7 @@ SMBus Read Byte, and PEC will work properly.
Additionally, the ADM1032 doesn't support SMBus Send Byte with PEC.
Instead, it will try to write the PEC value to the register (because the
SMBus Send Byte transaction with PEC is similar to a Write Byte transaction
without PEC), which is not what we want. Thus, PEC is explicitely disabled
without PEC), which is not what we want. Thus, PEC is explicitly disabled
on SMBus Send Byte transactions in the lm90 driver.
PEC on byte data transactions represents a significant increase in bandwidth

412
Documentation/hwmon/lm93 Normal file
View file

@ -0,0 +1,412 @@
Kernel driver lm93
==================
Supported chips:
* National Semiconductor LM93
Prefix 'lm93'
Addresses scanned: I2C 0x2c-0x2e
Datasheet: http://www.national.com/ds.cgi/LM/LM93.pdf
Author:
Mark M. Hoffman <mhoffman@lightlink.com>
Ported to 2.6 by Eric J. Bowersox <ericb@aspsys.com>
Adapted to 2.6.20 by Carsten Emde <ce@osadl.org>
Modified for mainline integration by Hans J. Koch <hjk@linutronix.de>
Module Parameters
-----------------
(specific to LM93)
* init: integer
Set to non-zero to force some initializations (default is 0).
* disable_block: integer
A "0" allows SMBus block data transactions if the host supports them. A "1"
disables SMBus block data transactions. The default is 0.
* vccp_limit_type: integer array (2)
Configures in7 and in8 limit type, where 0 means absolute and non-zero
means relative. "Relative" here refers to "Dynamic Vccp Monitoring using
VID" from the datasheet. It greatly simplifies the interface to allow
only one set of limits (absolute or relative) to be in operation at a
time (even though the hardware is capable of enabling both). There's
not a compelling use case for enabling both at once, anyway. The default
is "0,0".
* vid_agtl: integer
A "0" configures the VID pins for V(ih) = 2.1V min, V(il) = 0.8V max.
A "1" configures the VID pins for V(ih) = 0.8V min, V(il) = 0.4V max.
(The latter setting is referred to as AGTL+ Compatible in the datasheet.)
I.e. this parameter controls the VID pin input thresholds; if your VID
inputs are not working, try changing this. The default value is "0".
(common among sensor drivers)
* force: short array (min = 1, max = 48)
List of adapter,address pairs to assume to be present. Autodetection
of the target device will still be attempted. Use one of the more
specific force directives below if this doesn't detect the device.
* force_lm93: short array (min = 1, max = 48)
List of adapter,address pairs which are unquestionably assumed to contain
a 'lm93' chip
* ignore: short array (min = 1, max = 48)
List of adapter,address pairs not to scan
* ignore_range: short array (min = 1, max = 48)
List of adapter,start-addr,end-addr triples not to scan
* probe: short array (min = 1, max = 48)
List of adapter,address pairs to scan additionally
* probe_range: short array (min = 1, max = 48)
List of adapter,start-addr,end-addr triples to scan additionally
Hardware Description
--------------------
(from the datasheet)
The LM93, hardware monitor, has a two wire digital interface compatible with
SMBus 2.0. Using an 8-bit ADC, the LM93 measures the temperature of two remote
diode connected transistors as well as its own die and 16 power supply
voltages. To set fan speed, the LM93 has two PWM outputs that are each
controlled by up to four temperature zones. The fancontrol algorithm is lookup
table based. The LM93 includes a digital filter that can be invoked to smooth
temperature readings for better control of fan speed. The LM93 has four
tachometer inputs to measure fan speed. Limit and status registers for all
measured values are included. The LM93 builds upon the functionality of
previous motherboard management ASICs and uses some of the LM85 s features
(i.e. smart tachometer mode). It also adds measurement and control support
for dynamic Vccp monitoring and PROCHOT. It is designed to monitor a dual
processor Xeon class motherboard with a minimum of external components.
Driver Description
------------------
This driver implements support for the National Semiconductor LM93.
User Interface
--------------
#PROCHOT:
The LM93 can monitor two #PROCHOT signals. The results are found in the
sysfs files prochot1, prochot2, prochot1_avg, prochot2_avg, prochot1_max,
and prochot2_max. prochot1_max and prochot2_max contain the user limits
for #PROCHOT1 and #PROCHOT2, respectively. prochot1 and prochot2 contain
the current readings for the most recent complete time interval. The
value of prochot1_avg and prochot2_avg is something like a 2 period
exponential moving average (but not quite - check the datasheet). Note
that this third value is calculated by the chip itself. All values range
from 0-255 where 0 indicates no throttling, and 255 indicates > 99.6%.
The monitoring intervals for the two #PROCHOT signals is also configurable.
These intervals can be found in the sysfs files prochot1_interval and
prochot2_interval. The values in these files specify the intervals for
#P1_PROCHOT and #P2_PROCHOT, respectively. Selecting a value not in this
list will cause the driver to use the next largest interval. The available
intervals are:
#PROCHOT intervals: 0.73, 1.46, 2.9, 5.8, 11.7, 23.3, 46.6, 93.2, 186, 372
It is possible to configure the LM93 to logically short the two #PROCHOT
signals. I.e. when #P1_PROCHOT is asserted, the LM93 will automatically
assert #P2_PROCHOT, and vice-versa. This mode is enabled by writing a
non-zero integer to the sysfs file prochot_short.
The LM93 can also override the #PROCHOT pins by driving a PWM signal onto
one or both of them. When overridden, the signal has a period of 3.56 mS,
a minimum pulse width of 5 clocks (at 22.5kHz => 6.25% duty cycle), and
a maximum pulse width of 80 clocks (at 22.5kHz => 99.88% duty cycle).
The sysfs files prochot1_override and prochot2_override contain boolean
intgers which enable or disable the override function for #P1_PROCHOT and
#P2_PROCHOT, respectively. The sysfs file prochot_override_duty_cycle
contains a value controlling the duty cycle for the PWM signal used when
the override function is enabled. This value ranges from 0 to 15, with 0
indicating minimum duty cycle and 15 indicating maximum.
#VRD_HOT:
The LM93 can monitor two #VRD_HOT signals. The results are found in the
sysfs files vrdhot1 and vrdhot2. There is one value per file: a boolean for
which 1 indicates #VRD_HOT is asserted and 0 indicates it is negated. These
files are read-only.
Smart Tach Mode:
(from the datasheet)
If a fan is driven using a low-side drive PWM, the tachometer
output of the fan is corrupted. The LM93 includes smart tachometer
circuitry that allows an accurate tachometer reading to be
achieved despite the signal corruption. In smart tach mode all
four signals are measured within 4 seconds.
Smart tach mode is enabled by the driver by writing 1 or 2 (associating the
the fan tachometer with a pwm) to the sysfs file fan<n>_smart_tach. A zero
will disable the function for that fan. Note that Smart tach mode cannot be
enabled if the PWM output frequency is 22500 Hz (see below).
Manual PWM:
The LM93 has a fixed or override mode for the two PWM outputs (although, there
are still some conditions that will override even this mode - see section
15.10.6 of the datasheet for details.) The sysfs files pwm1_override
and pwm2_override are used to enable this mode; each is a boolean integer
where 0 disables and 1 enables the manual control mode. The sysfs files pwm1
and pwm2 are used to set the manual duty cycle; each is an integer (0-255)
where 0 is 0% duty cycle, and 255 is 100%. Note that the duty cycle values
are constrained by the hardware. Selecting a value which is not available
will cause the driver to use the next largest value. Also note: when manual
PWM mode is disabled, the value of pwm1 and pwm2 indicates the current duty
cycle chosen by the h/w.
PWM Output Frequency:
The LM93 supports several different frequencies for the PWM output channels.
The sysfs files pwm1_freq and pwm2_freq are used to select the frequency. The
frequency values are constrained by the hardware. Selecting a value which is
not available will cause the driver to use the next largest value. Also note
that this parameter has implications for the Smart Tach Mode (see above).
PWM Output Frequencies: 12, 36, 48, 60, 72, 84, 96, 22500 (h/w default)
Automatic PWM:
The LM93 is capable of complex automatic fan control, with many different
points of configuration. To start, each PWM output can be bound to any
combination of eight control sources. The final PWM is the largest of all
individual control sources to which the PWM output is bound.
The eight control sources are: temp1-temp4 (aka "zones" in the datasheet),
#PROCHOT 1 & 2, and #VRDHOT 1 & 2. The bindings are expressed as a bitmask
in the sysfs files pwm<n>_auto_channels, where a "1" enables the binding, and
a "0" disables it. The h/w default is 0x0f (all temperatures bound).
0x01 - Temp 1
0x02 - Temp 2
0x04 - Temp 3
0x08 - Temp 4
0x10 - #PROCHOT 1
0x20 - #PROCHOT 2
0x40 - #VRDHOT 1
0x80 - #VRDHOT 2
The function y = f(x) takes a source temperature x to a PWM output y. This
function of the LM93 is derived from a base temperature and a table of 12
temperature offsets. The base temperature is expressed in degrees C in the
sysfs files temp<n>_auto_base. The offsets are expressed in cumulative
degrees C, with the value of offset <i> for temperature value <n> being
contained in the file temp<n>_auto_offset<i>. E.g. if the base temperature
is 40C:
offset # temp<n>_auto_offset<i> range pwm
1 0 - 25.00%
2 0 - 28.57%
3 1 40C - 41C 32.14%
4 1 41C - 42C 35.71%
5 2 42C - 44C 39.29%
6 2 44C - 46C 42.86%
7 2 48C - 50C 46.43%
8 2 50C - 52C 50.00%
9 2 52C - 54C 53.57%
10 2 54C - 56C 57.14%
11 2 56C - 58C 71.43%
12 2 58C - 60C 85.71%
> 60C 100.00%
Valid offsets are in the range 0C <= x <= 7.5C in 0.5C increments.
There is an independent base temperature for each temperature channel. Note,
however, there are only two tables of offsets: one each for temp[12] and
temp[34]. Therefore, any change to e.g. temp1_auto_offset<i> will also
affect temp2_auto_offset<i>.
The LM93 can also apply hysteresis to the offset table, to prevent unwanted
oscillation between two steps in the offsets table. These values are found in
the sysfs files temp<n>_auto_offset_hyst. The value in this file has the
same representation as in temp<n>_auto_offset<i>.
If a temperature reading falls below the base value for that channel, the LM93
will use the minimum PWM value. These values are found in the sysfs files
temp<n>_auto_pwm_min. Note, there are only two minimums: one each for temp[12]
and temp[34]. Therefore, any change to e.g. temp1_auto_pwm_min will also
affect temp2_auto_pwm_min.
PWM Spin-Up Cycle:
A spin-up cycle occurs when a PWM output is commanded from 0% duty cycle to
some value > 0%. The LM93 supports a minimum duty cycle during spin-up. These
values are found in the sysfs files pwm<n>_auto_spinup_min. The value in this
file has the same representation as other PWM duty cycle values. The
duration of the spin-up cycle is also configurable. These values are found in
the sysfs files pwm<n>_auto_spinup_time. The value in this file is
the spin-up time in seconds. The available spin-up times are constrained by
the hardware. Selecting a value which is not available will cause the driver
to use the next largest value.
Spin-up Durations: 0 (disabled, h/w default), 0.1, 0.25, 0.4, 0.7, 1.0,
2.0, 4.0
#PROCHOT and #VRDHOT PWM Ramping:
If the #PROCHOT or #VRDHOT signals are asserted while bound to a PWM output
channel, the LM93 will ramp the PWM output up to 100% duty cycle in discrete
steps. The duration of each step is configurable. There are two files, with
one value each in seconds: pwm_auto_prochot_ramp and pwm_auto_vrdhot_ramp.
The available ramp times are constrained by the hardware. Selecting a value
which is not available will cause the driver to use the next largest value.
Ramp Times: 0 (disabled, h/w default) to 0.75 in 0.05 second intervals
Fan Boost:
For each temperature channel, there is a boost temperature: if the channel
exceeds this limit, the LM93 will immediately drive both PWM outputs to 100%.
This limit is expressed in degrees C in the sysfs files temp<n>_auto_boost.
There is also a hysteresis temperature for this function: after the boost
limit is reached, the temperature channel must drop below this value before
the boost function is disabled. This temperature is also expressed in degrees
C in the sysfs files temp<n>_auto_boost_hyst.
GPIO Pins:
The LM93 can monitor the logic level of four dedicated GPIO pins as well as the
four tach input pins. GPIO0-GPIO3 correspond to (fan) tach 1-4, respectively.
All eight GPIOs are read by reading the bitmask in the sysfs file gpio. The
LSB is GPIO0, and the MSB is GPIO7.
LM93 Unique sysfs Files
-----------------------
file description
-------------------------------------------------------------
prochot<n> current #PROCHOT %
prochot<n>_avg moving average #PROCHOT %
prochot<n>_max limit #PROCHOT %
prochot_short enable or disable logical #PROCHOT pin short
prochot<n>_override force #PROCHOT assertion as PWM
prochot_override_duty_cycle
duty cycle for the PWM signal used when
#PROCHOT is overridden
prochot<n>_interval #PROCHOT PWM sampling interval
vrdhot<n> 0 means negated, 1 means asserted
fan<n>_smart_tach enable or disable smart tach mode
pwm<n>_auto_channels select control sources for PWM outputs
pwm<n>_auto_spinup_min minimum duty cycle during spin-up
pwm<n>_auto_spinup_time duration of spin-up
pwm_auto_prochot_ramp ramp time per step when #PROCHOT asserted
pwm_auto_vrdhot_ramp ramp time per step when #VRDHOT asserted
temp<n>_auto_base temperature channel base
temp<n>_auto_offset[1-12]
temperature channel offsets
temp<n>_auto_offset_hyst
temperature channel offset hysteresis
temp<n>_auto_boost temperature channel boost (PWMs to 100%) limit
temp<n>_auto_boost_hyst temperature channel boost hysteresis
gpio input state of 8 GPIO pins; read-only
Sample Configuration File
-------------------------
Here is a sample LM93 chip config for sensors.conf:
---------- cut here ----------
chip "lm93-*"
# VOLTAGE INPUTS
# labels and scaling based on datasheet recommendations
label in1 "+12V1"
compute in1 @ * 12.945, @ / 12.945
set in1_min 12 * 0.90
set in1_max 12 * 1.10
label in2 "+12V2"
compute in2 @ * 12.945, @ / 12.945
set in2_min 12 * 0.90
set in2_max 12 * 1.10
label in3 "+12V3"
compute in3 @ * 12.945, @ / 12.945
set in3_min 12 * 0.90
set in3_max 12 * 1.10
label in4 "FSB_Vtt"
label in5 "3GIO"
label in6 "ICH_Core"
label in7 "Vccp1"
label in8 "Vccp2"
label in9 "+3.3V"
set in9_min 3.3 * 0.90
set in9_max 3.3 * 1.10
label in10 "+5V"
set in10_min 5.0 * 0.90
set in10_max 5.0 * 1.10
label in11 "SCSI_Core"
label in12 "Mem_Core"
label in13 "Mem_Vtt"
label in14 "Gbit_Core"
# Assuming R1/R2 = 4.1143, and 3.3V reference
# -12V = (4.1143 + 1) * (@ - 3.3) + 3.3
label in15 "-12V"
compute in15 @ * 5.1143 - 13.57719, (@ + 13.57719) / 5.1143
set in15_min -12 * 0.90
set in15_max -12 * 1.10
label in16 "+3.3VSB"
set in16_min 3.3 * 0.90
set in16_max 3.3 * 1.10
# TEMPERATURE INPUTS
label temp1 "CPU1"
label temp2 "CPU2"
label temp3 "LM93"
# TACHOMETER INPUTS
label fan1 "Fan1"
set fan1_min 3000
label fan2 "Fan2"
set fan2_min 3000
label fan3 "Fan3"
set fan3_min 3000
label fan4 "Fan4"
set fan4_min 3000
# PWM OUTPUTS
label pwm1 "CPU1"
label pwm2 "CPU2"

View file

@ -4,6 +4,7 @@ Kernel driver smsc47b397
Supported chips:
* SMSC LPC47B397-NC
* SMSC SCH5307-NS
* SMSC SCH5317
Prefix: 'smsc47b397'
Addresses scanned: none, address read from Super I/O config space
Datasheet: In this file
@ -18,8 +19,8 @@ The following specification describes the SMSC LPC47B397-NC[1] sensor chip
provided by Craig Kelly (In-Store Broadcast Network) and edited/corrected
by Mark M. Hoffman <mhoffman@lightlink.com>.
[1] And SMSC SCH5307-NS, which has a different device ID but is otherwise
compatible.
[1] And SMSC SCH5307-NS and SCH5317, which have different device IDs but are
otherwise compatible.
* * * * *
@ -131,7 +132,7 @@ OUT DX,AL
The registers of interest for identifying the SIO on the dc7100 are Device ID
(0x20) and Device Rev (0x21).
The Device ID will read 0x6F (for SCH5307-NS, 0x81)
The Device ID will read 0x6F (0x81 for SCH5307-NS, and 0x85 for SCH5317)
The Device Rev currently reads 0x01
Obtaining the HWM Base Address.

View file

@ -172,11 +172,10 @@ pwm[1-*] Pulse width modulation fan control.
255 is max or 100%.
pwm[1-*]_enable
Switch PWM on and off.
Not always present even if pwmN is.
0: turn off
1: turn on in manual mode
2+: turn on in automatic mode
Fan speed control method:
0: no fan speed control (i.e. fan at full speed)
1: manual fan speed control enabled (using pwm[1-*])
2+: automatic fan speed control enabled
Check individual chip documentation files for automatic mode
details.
RW
@ -343,9 +342,9 @@ to notify open diodes, unconnected fans etc. where the hardware
supports it. When this boolean has value 1, the measurement for that
channel should not be trusted.
in[0-*]_input_fault
fan[1-*]_input_fault
temp[1-*]_input_fault
in[0-*]_fault
fan[1-*]_fault
temp[1-*]_fault
Input fault condition
0: no fault occured
1: fault condition

View file

@ -22,9 +22,9 @@ This driver implements support for the Winbond W83627EHF, W83627EHG, and
W83627DHG super I/O chips. We will refer to them collectively as Winbond chips.
The chips implement three temperature sensors, five fan rotation
speed sensors, ten analog voltage sensors (only nine for the 627DHG), alarms
with beep warnings (control unimplemented), and some automatic fan regulation
strategies (plus manual fan control mode).
speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
VID (6 pins), alarms with beep warnings (control unimplemented), and
some automatic fan regulation strategies (plus manual fan control mode).
Temperatures are measured in degrees Celsius and measurement resolution is 1
degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when

View file

@ -607,6 +607,12 @@ W: http://sourceforge.net/projects/acpi4asus
W: http://xf.iksaif.net/acpi4asus
S: Maintained
ASUS ASB100 HARDWARE MONITOR DRIVER
P: Mark M. Hoffman
M: mhoffman@lightlink.com
L: lm-sensors@lm-sensors.org
S: Maintained
ASUS LAPTOP EXTRAS DRIVER
P: Corentin Chary
M: corentincj@iksaif.net
@ -1273,6 +1279,12 @@ M: shannon.nelson@intel.com
L: linux-kernel@vger.kernel.org
S: Maintained
DME1737 HARDWARE MONITOR DRIVER
P: Juerg Haefliger
M: juergh@gmail.com
L: lm-sensors@lm-sensors.org
S: Maintained
DOCBOOK FOR DOCUMENTATION
P: Randy Dunlap
M: rdunlap@xenotime.net
@ -1623,11 +1635,11 @@ W: http://gigaset307x.sourceforge.net/
S: Maintained
HARDWARE MONITORING
P: Jean Delvare
M: khali@linux-fr.org
P: Mark M. Hoffman
M: mhoffman@lightlink.com
L: lm-sensors@lm-sensors.org
W: http://www.lm-sensors.org/
T: quilt http://khali.linux-fr.org/devel/linux-2.6/jdelvare-hwmon/
T: git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git
S: Maintained
HARDWARE RANDOM NUMBER GENERATOR CORE
@ -1763,6 +1775,12 @@ P: William Irwin
M: wli@holomorphy.com
S: Maintained
I2C/SMBUS STUB DRIVER
P: Mark M. Hoffman
M: mhoffman@lightlink.com
L: lm-sensors@lm-sensors.org
S: Maintained
I2C SUBSYSTEM
P: Jean Delvare
M: khali@linux-fr.org
@ -3292,6 +3310,12 @@ W: http://www.brownhat.org/sis900.html
L: netdev@vger.kernel.org
S: Maintained
SIS 96X I2C/SMBUS DRIVER
P: Mark M. Hoffman
M: mhoffman@lightlink.com
L: lm-sensors@lm-sensors.org
S: Maintained
SIS FRAMEBUFFER DRIVER
P: Thomas Winischhofer
M: thomas@winischhofer.net
@ -3309,6 +3333,12 @@ P: Nicolas Pitre
M: nico@cam.org
S: Maintained
SMSC47B397 HARDWARE MONITOR DRIVER
P: Mark M. Hoffman
M: mhoffman@lightlink.com
L: lm-sensors@lm-sensors.org
S: Maintained
SOFTMAC LAYER (IEEE 802.11)
P: Johannes Berg
M: johannes@sipsolutions.net

View file

@ -708,7 +708,6 @@ CONFIG_I2C_ALGOPCF=m
# I2C Hardware Bus support
#
CONFIG_I2C_ELEKTOR=m
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_STUB is not set

View file

@ -536,7 +536,6 @@ CONFIG_I2C_ALGOBIT=y
# I2C Hardware Bus support
#
# CONFIG_I2C_ELEKTOR is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PCA_ISA is not set

View file

@ -748,7 +748,6 @@ CONFIG_I2C=m
# CONFIG_I2C_ELEKTOR is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PARPORT_LIGHT is not set

View file

@ -698,7 +698,6 @@ CONFIG_I2C_ALGOBIT=y
# I2C Hardware Bus support
#
# CONFIG_I2C_ELEKTOR is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_STUB is not set
# CONFIG_I2C_PCA_ISA is not set

View file

@ -735,7 +735,6 @@ CONFIG_I2C_CHARDEV=m
# I2C Hardware Bus support
#
CONFIG_I2C_AT91=m
CONFIG_I2C_ISA=m
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_STUB is not set

View file

@ -558,7 +558,6 @@ CONFIG_I2C_ALGOBIT=y
#
# I2C Hardware Bus support
#
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_STUB is not set

View file

@ -826,7 +826,6 @@ CONFIG_I2C_ALGOBIT=m
# I2C Hardware Bus support
#
# CONFIG_I2C_ELEKTOR is not set
CONFIG_I2C_ISA=m
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PARPORT_LIGHT is not set

View file

@ -699,7 +699,6 @@ CONFIG_I2C_ALGOPCF=m
# I2C Hardware Bus support
#
CONFIG_I2C_ELEKTOR=m
CONFIG_I2C_ISA=m
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PARPORT_LIGHT is not set

View file

@ -531,7 +531,6 @@ CONFIG_I2C_CHARDEV=m
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PIIX4 is not set

View file

@ -452,7 +452,6 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_ISA is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set

View file

@ -413,7 +413,6 @@ CONFIG_I2C_CHARDEV=y
#
# I2C Hardware Bus support
#
# CONFIG_I2C_ISA is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PCA_ISA is not set

View file

@ -518,7 +518,6 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_ISA is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set

View file

@ -489,7 +489,6 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_ISA is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set

View file

@ -710,7 +710,6 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_MPC is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set

View file

@ -661,7 +661,6 @@ CONFIG_I2C_ALGOBIT=m
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_MPC is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT is not set

View file

@ -461,7 +461,6 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_IBM_IIC is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PIIX4 is not set

View file

@ -29,17 +29,34 @@ config HWMON_VID
default n
config SENSORS_ABITUGURU
tristate "Abit uGuru"
tristate "Abit uGuru (rev 1 & 2)"
depends on EXPERIMENTAL
help
If you say yes here you get support for the Abit uGuru chips
sensor part. The voltage and frequency control parts of the Abit
uGuru are not supported. The Abit uGuru chip can be found on Abit
uGuru featuring motherboards (most modern Abit motherboards).
If you say yes here you get support for the sensor part of the first
and second revision of the Abit uGuru chip. The voltage and frequency
control parts of the Abit uGuru are not supported. The Abit uGuru
chip can be found on Abit uGuru featuring motherboards (most modern
Abit motherboards from before end 2005). For more info and a list
of which motherboards have which revision see
Documentation/hwmon/abituguru
This driver can also be built as a module. If so, the module
will be called abituguru.
config SENSORS_ABITUGURU3
tristate "Abit uGuru (rev 3)"
depends on HWMON && EXPERIMENTAL
help
If you say yes here you get support for the sensor part of the
third revision of the Abit uGuru chip. Only reading the sensors
and their settings is supported. The third revision of the Abit
uGuru chip can be found on recent Abit motherboards (since end
2005). For more info and a list of which motherboards have which
revision see Documentation/hwmon/abituguru3
This driver can also be built as a module. If so, the module
will be called abituguru3.
config SENSORS_AD7418
tristate "Analog Devices AD7416, AD7417 and AD7418"
depends on I2C && EXPERIMENTAL
@ -250,12 +267,10 @@ config SENSORS_CORETEMP
config SENSORS_IT87
tristate "ITE IT87xx and compatibles"
depends on I2C
select I2C_ISA
select HWMON_VID
help
If you say yes here you get support for ITE IT8705F, IT8712F,
IT8716F and IT8718F sensor chips, and the SiS960 clone.
IT8716F, IT8718F and IT8726F sensor chips, and the SiS960 clone.
This driver can also be built as a module. If so, the module
will be called it87.
@ -365,8 +380,8 @@ config SENSORS_LM90
depends on I2C
help
If you say yes here you get support for National Semiconductor LM90,
LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
MAX6658 sensor chips.
LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657,
MAX6658, MAX6659, MAX6680 and MAX6681 sensor chips.
The Analog Devices ADT7461 sensor chip is also supported, but only
if found in ADM1032 compatibility mode.
@ -384,6 +399,17 @@ config SENSORS_LM92
This driver can also be built as a module. If so, the module
will be called lm92.
config SENSORS_LM93
tristate "National Semiconductor LM93 and compatibles"
depends on HWMON && I2C
select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM93
sensor chips.
This driver can also be built as a module. If so, the module
will be called lm93.
config SENSORS_MAX1619
tristate "Maxim MAX1619 sensor chip"
depends on I2C
@ -405,8 +431,6 @@ config SENSORS_MAX6650
config SENSORS_PC87360
tristate "National Semiconductor PC87360 family"
depends on I2C && EXPERIMENTAL
select I2C_ISA
select HWMON_VID
help
If you say yes here you get access to the hardware monitoring
@ -433,8 +457,7 @@ config SENSORS_PC87427
config SENSORS_SIS5595
tristate "Silicon Integrated Systems Corp. SiS5595"
depends on I2C && PCI && EXPERIMENTAL
select I2C_ISA
depends on PCI
help
If you say yes here you get support for the integrated sensors in
SiS5595 South Bridges.
@ -442,6 +465,18 @@ config SENSORS_SIS5595
This driver can also be built as a module. If so, the module
will be called sis5595.
config SENSORS_DME1737
tristate "SMSC DME1737 and compatibles"
depends on I2C && EXPERIMENTAL
select HWMON_VID
help
If you say yes here you get support for the hardware monitoring
and fan control features of the SMSC DME1737 (and compatibles
like the Asus A8000) Super-I/O chip.
This driver can also be built as a module. If so, the module
will be called dme1737.
config SENSORS_SMSC47M1
tristate "SMSC LPC47M10x and compatibles"
help
@ -487,8 +522,7 @@ config SENSORS_SMSC47B397
config SENSORS_VIA686A
tristate "VIA686A"
depends on I2C && PCI
select I2C_ISA
depends on PCI
help
If you say yes here you get support for the integrated sensors in
Via 686A/B South Bridges.
@ -509,9 +543,8 @@ config SENSORS_VT1211
config SENSORS_VT8231
tristate "VIA VT8231"
depends on I2C && PCI && EXPERIMENTAL
depends on PCI
select HWMON_VID
select I2C_ISA
help
If you say yes here then you get support for the integrated sensors
in the VIA VT8231 device.
@ -584,17 +617,16 @@ config SENSORS_W83627HF
will be called w83627hf.
config SENSORS_W83627EHF
tristate "Winbond W83627EHF"
depends on I2C && EXPERIMENTAL
select I2C_ISA
tristate "Winbond W83627EHF/DHG"
select HWMON_VID
help
If you say yes here you get preliminary support for the hardware
If you say yes here you get 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 also supports the W83627EHG, which is the lead-free
version of the W83627EHF.
version of the W83627EHF, and the W83627DHG, which is a similar
chip suited for specific Intel processors that use PECI such as
the Core 2 Duo.
This driver can also be built as a module. If so, the module
will be called w83627ehf.

View file

@ -14,6 +14,7 @@ obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
@ -25,6 +26,7 @@ obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_AMS) += ams/
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
@ -45,6 +47,7 @@ obj-$(CONFIG_SENSORS_LM85) += lm85.o
obj-$(CONFIG_SENSORS_LM87) += lm87.o
obj-$(CONFIG_SENSORS_LM90) += lm90.o
obj-$(CONFIG_SENSORS_LM92) += lm92.o
obj-$(CONFIG_SENSORS_LM93) += lm93.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o

View file

@ -16,9 +16,9 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
This driver supports the sensor part of the custom Abit uGuru chip found
on Abit uGuru motherboards. Note: because of lack of specs the CPU / RAM /
etc voltage & frequency control is not supported!
This driver supports the sensor part of the first and second revision of
the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because
of lack of specs the CPU/RAM voltage & frequency control is not supported!
*/
#include <linux/module.h>
#include <linux/sched.h>
@ -31,6 +31,7 @@
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/dmi.h>
#include <asm/io.h>
/* Banks */
@ -418,7 +419,7 @@ static int __devinit
abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
u8 sensor_addr)
{
u8 val, buf[3];
u8 val, test_flag, buf[3];
int i, ret = -ENODEV; /* error is the most common used retval :| */
/* If overriden by the user return the user selected type */
@ -436,7 +437,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
return -ENODEV;
/* Test val is sane / usable for sensor type detection. */
if ((val < 10u) || (val > 240u)) {
if ((val < 10u) || (val > 250u)) {
printk(KERN_WARNING ABIT_UGURU_NAME
": bank1-sensor: %d reading (%d) too close to limits, "
"unable to determine sensor type, skipping sensor\n",
@ -449,10 +450,20 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr);
/* Volt sensor test, enable volt low alarm, set min value ridicously
high. If its a volt sensor this should always give us an alarm. */
buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
buf[1] = 245;
buf[2] = 250;
high, or vica versa if the reading is very high. If its a volt
sensor this should always give us an alarm. */
if (val <= 240u) {
buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
buf[1] = 245;
buf[2] = 250;
test_flag = ABIT_UGURU_VOLT_LOW_ALARM_FLAG;
} else {
buf[0] = ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE;
buf[1] = 5;
buf[2] = 10;
test_flag = ABIT_UGURU_VOLT_HIGH_ALARM_FLAG;
}
if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
buf, 3) != 3)
goto abituguru_detect_bank1_sensor_type_exit;
@ -469,13 +480,13 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
sensor_addr, buf, 3,
ABIT_UGURU_MAX_RETRIES) != 3)
goto abituguru_detect_bank1_sensor_type_exit;
if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) {
if (buf[0] & test_flag) {
ABIT_UGURU_DEBUG(2, " found volt sensor\n");
ret = ABIT_UGURU_IN_SENSOR;
goto abituguru_detect_bank1_sensor_type_exit;
} else
ABIT_UGURU_DEBUG(2, " alarm raised during volt "
"sensor test, but volt low flag not set\n");
"sensor test, but volt range flag not set\n");
} else
ABIT_UGURU_DEBUG(2, " alarm not raised during volt sensor "
"test\n");
@ -1287,6 +1298,7 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
device_remove_file(&pdev->dev,
&abituguru_sysfs_attr[i].dev_attr);
platform_set_drvdata(pdev, NULL);
kfree(data);
return res;
}
@ -1296,13 +1308,13 @@ static int __devexit abituguru_remove(struct platform_device *pdev)
int i;
struct abituguru_data *data = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
device_remove_file(&pdev->dev,
&abituguru_sysfs_attr[i].dev_attr);
platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
@ -1436,6 +1448,15 @@ static int __init abituguru_init(void)
int address, err;
struct resource res = { .flags = IORESOURCE_IO };
#ifdef CONFIG_DMI
char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
/* safety check, refuse to load on non Abit motherboards */
if (!force && (!board_vendor ||
strcmp(board_vendor, "http://www.abit.com.tw/")))
return -ENODEV;
#endif
address = abituguru_detect();
if (address < 0)
return address;

1140
drivers/hwmon/abituguru3.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -318,7 +318,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
}
#ifdef CONFIG_HOTPLUG_CPU
void coretemp_device_remove(unsigned int cpu)
static void coretemp_device_remove(unsigned int cpu)
{
struct pdev_entry *p, *n;
mutex_lock(&pdev_list_mutex);

2080
drivers/hwmon/dme1737.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -27,6 +27,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
@ -52,9 +53,11 @@ MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low")
#define DS1621_REG_CONFIG_DONE 0x80
/* The DS1621 registers */
#define DS1621_REG_TEMP 0xAA /* word, RO */
#define DS1621_REG_TEMP_MIN 0xA2 /* word, RW */
#define DS1621_REG_TEMP_MAX 0xA1 /* word, RW */
static const u8 DS1621_REG_TEMP[3] = {
0xAA, /* input, word, RO */
0xA2, /* min, word, RW */
0xA1, /* max, word, RW */
};
#define DS1621_REG_CONF 0xAC /* byte, RW */
#define DS1621_COM_START 0xEE /* no data */
#define DS1621_COM_STOP 0x22 /* no data */
@ -63,10 +66,7 @@ MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low")
#define DS1621_ALARM_TEMP_HIGH 0x40
#define DS1621_ALARM_TEMP_LOW 0x20
/* Conversions. Rounding and limit checking is only done on the TO_REG
variants. Note that you should be a bit careful with which arguments
these macros are called: arguments may be evaluated more than once.
Fixing this is just not worth it. */
/* Conversions */
#define ALARMS_FROM_REG(val) ((val) & \
(DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW))
@ -78,7 +78,7 @@ struct ds1621_data {
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
u16 temp, temp_min, temp_max; /* Register values, word */
u16 temp[3]; /* Register values, word */
u8 conf; /* Register encoding, combined */
};
@ -101,7 +101,7 @@ static struct i2c_driver ds1621_driver = {
/* All registers are word-sized, except for the configuration register.
DS1621 uses a high-byte first convention, which is exactly opposite to
the usual practice. */
the SMBus standard. */
static int ds1621_read_value(struct i2c_client *client, u8 reg)
{
if (reg == DS1621_REG_CONF)
@ -110,9 +110,6 @@ static int ds1621_read_value(struct i2c_client *client, u8 reg)
return swab16(i2c_smbus_read_word_data(client, reg));
}
/* All registers are word-sized, except for the configuration register.
DS1621 uses a high-byte first convention, which is exactly opposite to
the usual practice. */
static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
{
if (reg == DS1621_REG_CONF)
@ -139,50 +136,61 @@ static void ds1621_init_client(struct i2c_client *client)
i2c_smbus_write_byte(client, DS1621_COM_START);
}
#define show(value) \
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
struct ds1621_data *data = ds1621_update_client(dev); \
return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \
static ssize_t show_temp(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ds1621_data *data = ds1621_update_client(dev);
return sprintf(buf, "%d\n",
LM75_TEMP_FROM_REG(data->temp[attr->index]));
}
show(temp);
show(temp_min);
show(temp_max);
static ssize_t set_temp(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct ds1621_data *data = ds1621_update_client(dev);
u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));
#define set_temp(suffix, value, reg) \
static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \
size_t count) \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct ds1621_data *data = ds1621_update_client(dev); \
u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); \
\
mutex_lock(&data->update_lock); \
data->value = val; \
ds1621_write_value(client, reg, data->value); \
mutex_unlock(&data->update_lock); \
return count; \
mutex_lock(&data->update_lock);
data->temp[attr->index] = val;
ds1621_write_value(client, DS1621_REG_TEMP[attr->index],
data->temp[attr->index]);
mutex_unlock(&data->update_lock);
return count;
}
set_temp(min, temp_min, DS1621_REG_TEMP_MIN);
set_temp(max, temp_max, DS1621_REG_TEMP_MAX);
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 *da,
char *buf)
{
struct ds1621_data *data = ds1621_update_client(dev);
return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf));
}
static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ds1621_data *data = ds1621_update_client(dev);
return sprintf(buf, "%d\n", !!(data->conf & attr->index));
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL);
static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min);
static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1);
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2);
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
DS1621_ALARM_TEMP_LOW);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
DS1621_ALARM_TEMP_HIGH);
static struct attribute *ds1621_attributes[] = {
&dev_attr_temp1_input.attr,
&dev_attr_temp1_min.attr,
&dev_attr_temp1_max.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
NULL
};
@ -204,9 +212,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
int kind)
{
int conf, temp;
struct i2c_client *new_client;
struct i2c_client *client;
struct ds1621_data *data;
int err = 0;
int i, err = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
| I2C_FUNC_SMBUS_WORD_DATA
@ -221,55 +229,44 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
goto exit;
}
new_client = &data->client;
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &ds1621_driver;
new_client->flags = 0;
client = &data->client;
i2c_set_clientdata(client, data);
client->addr = address;
client->adapter = adapter;
client->driver = &ds1621_driver;
/* Now, we do the remaining detection. It is lousy. */
if (kind < 0) {
/* The NVB bit should be low if no EEPROM write has been
requested during the latest 10ms, which is highly
improbable in our case. */
conf = ds1621_read_value(new_client, DS1621_REG_CONF);
conf = ds1621_read_value(client, DS1621_REG_CONF);
if (conf & DS1621_REG_CONFIG_NVB)
goto exit_free;
/* The 7 lowest bits of a temperature should always be 0. */
temp = ds1621_read_value(new_client, DS1621_REG_TEMP);
if (temp & 0x007f)
goto exit_free;
temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MIN);
if (temp & 0x007f)
goto exit_free;
temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MAX);
if (temp & 0x007f)
goto exit_free;
for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
if (temp & 0x007f)
goto exit_free;
}
}
/* Determine the chip type - only one kind supported! */
if (kind <= 0)
kind = ds1621;
/* Fill in remaining client fields and put it into the global list */
strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE);
data->valid = 0;
strlcpy(client->name, "ds1621", I2C_NAME_SIZE);
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
if ((err = i2c_attach_client(client)))
goto exit_free;
/* Initialize the DS1621 chip */
ds1621_init_client(new_client);
ds1621_init_client(client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &ds1621_group)))
if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
goto exit_detach;
data->class_dev = hwmon_device_register(&new_client->dev);
data->class_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto exit_remove_files;
@ -278,9 +275,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
return 0;
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &ds1621_group);
sysfs_remove_group(&client->dev.kobj, &ds1621_group);
exit_detach:
i2c_detach_client(new_client);
i2c_detach_client(client);
exit_free:
kfree(data);
exit:
@ -314,23 +311,21 @@ static struct ds1621_data *ds1621_update_client(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
int i;
dev_dbg(&client->dev, "Starting ds1621 update\n");
data->conf = ds1621_read_value(client, DS1621_REG_CONF);
data->temp = ds1621_read_value(client, DS1621_REG_TEMP);
data->temp_min = ds1621_read_value(client,
DS1621_REG_TEMP_MIN);
data->temp_max = ds1621_read_value(client,
DS1621_REG_TEMP_MAX);
for (i = 0; i < ARRAY_SIZE(data->temp); i++)
data->temp[i] = ds1621_read_value(client,
DS1621_REG_TEMP[i]);
/* reset alarms if necessary */
new_conf = data->conf;
if (data->temp > data->temp_min)
if (data->temp[0] > data->temp[1]) /* input > min */
new_conf &= ~DS1621_ALARM_TEMP_LOW;
if (data->temp < data->temp_max)
if (data->temp[0] < data->temp[2]) /* input < max */
new_conf &= ~DS1621_ALARM_TEMP_HIGH;
if (data->conf != new_conf)
ds1621_write_value(client, DS1621_REG_CONF,

View file

@ -127,6 +127,13 @@ superio_exit(int base)
#define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr))
#define F71805F_REG_TEMP_HYST(nr) (0x55 + 2 * (nr))
#define F71805F_REG_TEMP_MODE 0x01
/* pwm/fan pwmnr from 0 to 2, auto point apnr from 0 to 2 */
/* map Fintek numbers to our numbers as follows: 9->0, 5->1, 1->2 */
#define F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr) \
(0xA0 + 0x10 * (pwmnr) + (2 - (apnr)))
#define F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr) \
(0xA4 + 0x10 * (pwmnr) + \
2 * (2 - (apnr)))
#define F71805F_REG_START 0x00
/* status nr from 0 to 2 */
@ -144,6 +151,11 @@ superio_exit(int base)
* Data structures and manipulation thereof
*/
struct f71805f_auto_point {
u8 temp[3];
u16 fan[3];
};
struct f71805f_data {
unsigned short addr;
const char *name;
@ -170,6 +182,7 @@ struct f71805f_data {
u8 temp_hyst[3];
u8 temp_mode;
unsigned long alarms;
struct f71805f_auto_point auto_points[3];
};
struct f71805f_sio_data {
@ -312,7 +325,7 @@ static void f71805f_write16(struct f71805f_data *data, u8 reg, u16 val)
static struct f71805f_data *f71805f_update_device(struct device *dev)
{
struct f71805f_data *data = dev_get_drvdata(dev);
int nr;
int nr, apnr;
mutex_lock(&data->update_lock);
@ -342,6 +355,18 @@ static struct f71805f_data *f71805f_update_device(struct device *dev)
F71805F_REG_TEMP_HYST(nr));
}
data->temp_mode = f71805f_read8(data, F71805F_REG_TEMP_MODE);
for (nr = 0; nr < 3; nr++) {
for (apnr = 0; apnr < 3; apnr++) {
data->auto_points[nr].temp[apnr] =
f71805f_read8(data,
F71805F_REG_PWM_AUTO_POINT_TEMP(nr,
apnr));
data->auto_points[nr].fan[apnr] =
f71805f_read16(data,
F71805F_REG_PWM_AUTO_POINT_FAN(nr,
apnr));
}
}
data->last_limits = jiffies;
}
@ -705,6 +730,70 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute
return count;
}
static ssize_t show_pwm_auto_point_temp(struct device *dev,
struct device_attribute *devattr,
char* buf)
{
struct f71805f_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
int pwmnr = attr->nr;
int apnr = attr->index;
return sprintf(buf, "%ld\n",
temp_from_reg(data->auto_points[pwmnr].temp[apnr]));
}
static ssize_t set_pwm_auto_point_temp(struct device *dev,
struct device_attribute *devattr,
const char* buf, size_t count)
{
struct f71805f_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
int pwmnr = attr->nr;
int apnr = attr->index;
unsigned long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->auto_points[pwmnr].temp[apnr] = temp_to_reg(val);
f71805f_write8(data, F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr),
data->auto_points[pwmnr].temp[apnr]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t show_pwm_auto_point_fan(struct device *dev,
struct device_attribute *devattr,
char* buf)
{
struct f71805f_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
int pwmnr = attr->nr;
int apnr = attr->index;
return sprintf(buf, "%ld\n",
fan_from_reg(data->auto_points[pwmnr].fan[apnr]));
}
static ssize_t set_pwm_auto_point_fan(struct device *dev,
struct device_attribute *devattr,
const char* buf, size_t count)
{
struct f71805f_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
int pwmnr = attr->nr;
int apnr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->auto_points[pwmnr].fan[apnr] = fan_to_reg(val);
f71805f_write16(data, F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr),
data->auto_points[pwmnr].fan[apnr]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
char *buf)
{
@ -932,6 +1021,63 @@ static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO | S_IWUSR,
show_pwm_freq, set_pwm_freq, 2);
static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2);
static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR,
show_pwm_auto_point_temp, set_pwm_auto_point_temp,
0, 0);
static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_fan, S_IRUGO | S_IWUSR,
show_pwm_auto_point_fan, set_pwm_auto_point_fan,
0, 0);
static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR,
show_pwm_auto_point_temp, set_pwm_auto_point_temp,
0, 1);
static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_fan, S_IRUGO | S_IWUSR,
show_pwm_auto_point_fan, set_pwm_auto_point_fan,
0, 1);
static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR,
show_pwm_auto_point_temp, set_pwm_auto_point_temp,
0, 2);
static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_fan, S_IRUGO | S_IWUSR,
show_pwm_auto_point_fan, set_pwm_auto_point_fan,
0, 2);
static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR,
show_pwm_auto_point_temp, set_pwm_auto_point_temp,
1, 0);
static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_fan, S_IRUGO | S_IWUSR,
show_pwm_auto_point_fan, set_pwm_auto_point_fan,
1, 0);
static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR,
show_pwm_auto_point_temp, set_pwm_auto_point_temp,
1, 1);
static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_fan, S_IRUGO | S_IWUSR,
show_pwm_auto_point_fan, set_pwm_auto_point_fan,
1, 1);
static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR,
show_pwm_auto_point_temp, set_pwm_auto_point_temp,
1, 2);
static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_fan, S_IRUGO | S_IWUSR,
show_pwm_auto_point_fan, set_pwm_auto_point_fan,
1, 2);
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR,
show_pwm_auto_point_temp, set_pwm_auto_point_temp,
2, 0);
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_fan, S_IRUGO | S_IWUSR,
show_pwm_auto_point_fan, set_pwm_auto_point_fan,
2, 0);
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR,
show_pwm_auto_point_temp, set_pwm_auto_point_temp,
2, 1);
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_fan, S_IRUGO | S_IWUSR,
show_pwm_auto_point_fan, set_pwm_auto_point_fan,
2, 1);
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
show_pwm_auto_point_temp, set_pwm_auto_point_temp,
2, 2);
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_fan, S_IRUGO | S_IWUSR,
show_pwm_auto_point_fan, set_pwm_auto_point_fan,
2, 2);
static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
@ -1014,6 +1160,25 @@ static struct attribute *f71805f_attributes[] = {
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp3_type.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point1_fan.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point2_fan.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point3_fan.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point1_fan.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point2_fan.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point3_fan.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point1_fan.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point2_fan.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point3_fan.dev_attr.attr,
&sensor_dev_attr_in0_alarm.dev_attr.attr,
&sensor_dev_attr_in1_alarm.dev_attr.attr,
&sensor_dev_attr_in2_alarm.dev_attr.attr,
@ -1242,12 +1407,12 @@ static int __devexit f71805f_remove(struct platform_device *pdev)
struct resource *res;
int i;
platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
for (i = 0; i < 4; i++)
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
platform_set_drvdata(pdev, NULL);
kfree(data);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@ -1290,15 +1455,12 @@ static int __init f71805f_device_add(unsigned short address,
goto exit_device_put;
}
pdev->dev.platform_data = kmalloc(sizeof(struct f71805f_sio_data),
GFP_KERNEL);
if (!pdev->dev.platform_data) {
err = -ENOMEM;
err = platform_device_add_data(pdev, sio_data,
sizeof(struct f71805f_sio_data));
if (err) {
printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
goto exit_device_put;
}
memcpy(pdev->dev.platform_data, sio_data,
sizeof(struct f71805f_sio_data));
err = platform_device_add(pdev);
if (err) {

File diff suppressed because it is too large Load diff

View file

@ -364,7 +364,7 @@ static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
/* Individual alarm files */
static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
@ -383,7 +383,7 @@ static struct attribute *lm63_attributes[] = {
&dev_attr_temp2_crit_hyst.attr,
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_input_fault.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,

View file

@ -223,14 +223,14 @@ static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8);
/* Individual alarm files */
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
static SENSOR_DEVICE_ATTR(temp4_input_fault, S_IRUGO, show_alarm, NULL, 10);
static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL, 10);
static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 12);
static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 13);
static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 13);
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15);
/* Raw alarm file for compatibility */
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
@ -245,7 +245,7 @@ static struct attribute *lm83_attributes[] = {
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_input_fault.dev_attr.attr,
&sensor_dev_attr_temp3_fault.dev_attr.attr,
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
@ -266,9 +266,9 @@ static struct attribute *lm83_attributes_opt[] = {
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_input_fault.dev_attr.attr,
&sensor_dev_attr_temp4_fault.dev_attr.attr,
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_input_fault.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
NULL
};

View file

@ -43,6 +43,13 @@
* variants. The extra address and features of the MAX6659 are not
* supported by this driver.
*
* This driver also supports the MAX6680 and MAX6681, two other sensor
* chips made by Maxim. These are quite similar to the other Maxim
* chips. Complete datasheet can be obtained at:
* http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370
* The MAX6680 and MAX6681 only differ in the pinout so they can be
* treated identically.
*
* This driver also supports the ADT7461 chip from Analog Devices but
* only in its "compatability mode". If an ADT7461 chip is found but
* is configured in non-compatible mode (where its temperature
@ -84,20 +91,25 @@
/*
* Addresses to scan
* Address is fully defined internally and cannot be changed except for
* MAX6659.
* MAX6659, MAX6680 and MAX6681.
* LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6657 and MAX6658
* have address 0x4c.
* ADM1032-2, ADT7461-2, LM89-1, and LM99-1 have address 0x4d.
* MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported).
* MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
* 0x4c, 0x4d or 0x4e.
*/
static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END };
static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
0x29, 0x2a, 0x2b,
0x4c, 0x4d, 0x4e,
I2C_CLIENT_END };
/*
* Insmod parameters
*/
I2C_CLIENT_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680);
/*
* The LM90 registers
@ -359,7 +371,7 @@ static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4);
/* Individual alarm files */
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
@ -381,7 +393,7 @@ static struct attribute *lm90_attributes[] = {
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_input_fault.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
@ -429,7 +441,7 @@ static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec);
*/
/* The ADM1032 supports PEC but not on write byte transactions, so we need
to explicitely ask for a transaction without PEC. */
to explicitly ask for a transaction without PEC. */
static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value)
{
return i2c_smbus_xfer(client->adapter, client->addr,
@ -525,7 +537,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
&reg_convrate) < 0)
goto exit_free;
if (man_id == 0x01) { /* National Semiconductor */
if ((address == 0x4C || address == 0x4D)
&& man_id == 0x01) { /* National Semiconductor */
u8 reg_config2;
if (lm90_read_reg(new_client, LM90_REG_R_CONFIG2,
@ -548,7 +561,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
}
}
} else
if (man_id == 0x41) { /* Analog Devices */
if ((address == 0x4C || address == 0x4D)
&& man_id == 0x41) { /* Analog Devices */
if ((chip_id & 0xF0) == 0x40 /* ADM1032 */
&& (reg_config1 & 0x3F) == 0x00
&& reg_convrate <= 0x0A) {
@ -562,18 +576,30 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
} else
if (man_id == 0x4D) { /* Maxim */
/*
* The Maxim variants do NOT have a chip_id register.
* Reading from that address will return the last read
* value, which in our case is those of the man_id
* register. Likewise, the config1 register seems to
* lack a low nibble, so the value will be those of the
* previous read, so in our case those of the man_id
* register.
* The MAX6657, MAX6658 and MAX6659 do NOT have a
* chip_id register. Reading from that address will
* return the last read value, which in our case is
* those of the man_id register. Likewise, the config1
* register seems to lack a low nibble, so the value
* will be those of the previous read, so in our case
* those of the man_id register.
*/
if (chip_id == man_id
&& (address == 0x4F || address == 0x4D)
&& (reg_config1 & 0x1F) == (man_id & 0x0F)
&& reg_convrate <= 0x09) {
kind = max6657;
} else
/* The chip_id register of the MAX6680 and MAX6681
* holds the revision of the chip.
* the lowest bit of the config1 register is unused
* and should return zero when read, so should the
* second to last bit of config1 (software reset)
*/
if (chip_id == 0x01
&& (reg_config1 & 0x03) == 0x00
&& reg_convrate <= 0x07) {
kind = max6680;
}
}
@ -599,6 +625,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
name = "lm86";
} else if (kind == max6657) {
name = "max6657";
} else if (kind == max6680) {
name = "max6680";
} else if (kind == adt7461) {
name = "adt7461";
}
@ -646,7 +674,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
static void lm90_init_client(struct i2c_client *client)
{
u8 config;
u8 config, config_orig;
struct lm90_data *data = i2c_get_clientdata(client);
/*
* Start the conversions.
@ -657,9 +686,20 @@ static void lm90_init_client(struct i2c_client *client)
dev_warn(&client->dev, "Initialization failed!\n");
return;
}
if (config & 0x40)
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
config & 0xBF); /* run */
config_orig = config;
/*
* Put MAX6680/MAX8881 into extended resolution (bit 0x10,
* 0.125 degree resolution) and range (0x08, extend range
* to -64 degree) mode for the remote temperature sensor.
*/
if (data->kind == max6680) {
config |= 0x18;
}
config &= 0xBF; /* run */
if (config != config_orig) /* Only write if changed */
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
}
static int lm90_detach_client(struct i2c_client *client)

2655
drivers/hwmon/lm93.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
/*
* pc87360.c - Part of lm_sensors, Linux kernel modules
* for hardware monitoring
* Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
* Copyright (C) 2004, 2007 Jean Delvare <khali@linux-fr.org>
*
* Copied from smsc47m1.c:
* Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
@ -37,8 +37,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/i2c-isa.h>
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
@ -47,12 +46,10 @@
#include <asm/io.h>
static u8 devid;
static unsigned short address;
static struct platform_device *pdev;
static unsigned short extra_isa[3];
static u8 confreg[4];
enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 };
static int init = 1;
module_param(init, int, 0);
MODULE_PARM_DESC(init,
@ -178,11 +175,11 @@ static inline u8 PWM_TO_REG(int val, int inv)
((val) + 500) / 1000)
/*
* Client data (each client gets its own)
* Device data
*/
struct pc87360_data {
struct i2c_client client;
const char *name;
struct class_device *class_dev;
struct mutex lock;
struct mutex update_lock;
@ -222,27 +219,28 @@ struct pc87360_data {
* Functions declaration
*/
static int pc87360_detect(struct i2c_adapter *adapter);
static int pc87360_detach_client(struct i2c_client *client);
static int pc87360_probe(struct platform_device *pdev);
static int pc87360_remove(struct platform_device *pdev);
static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
u8 reg);
static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
u8 reg, u8 value);
static void pc87360_init_client(struct i2c_client *client, int use_thermistors);
static void pc87360_init_device(struct platform_device *pdev,
int use_thermistors);
static struct pc87360_data *pc87360_update_device(struct device *dev);
/*
* Driver data (common to all clients)
* Driver data
*/
static struct i2c_driver pc87360_driver = {
static struct platform_driver pc87360_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "pc87360",
},
.attach_adapter = pc87360_detect,
.detach_client = pc87360_detach_client,
.probe = pc87360_probe,
.remove = __devexit_p(pc87360_remove),
};
/*
@ -281,8 +279,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *devattr,
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = dev_get_drvdata(dev);
long fan_min = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@ -347,8 +344,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, con
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@ -410,8 +406,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr,
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@ -425,8 +420,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr,
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@ -511,8 +505,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char
}
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = dev_get_drvdata(dev);
data->vrm = simple_strtoul(buf, NULL, 10);
return count;
}
@ -584,8 +577,7 @@ static ssize_t set_therm_min(struct device *dev, struct device_attribute *devatt
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@ -599,8 +591,7 @@ static ssize_t set_therm_max(struct device *dev, struct device_attribute *devatt
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@ -614,8 +605,7 @@ static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devat
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@ -715,8 +705,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *devattr
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@ -730,8 +719,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@ -745,8 +733,7 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *devatt
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@ -818,6 +805,14 @@ static const struct attribute_group pc8736x_temp_group = {
.attrs = pc8736x_temp_attr_array,
};
static ssize_t show_name(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct pc87360_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", data->name);
}
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
/*
* Device detection, registration and update
*/
@ -912,28 +907,18 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses
return 0;
}
static int pc87360_detect(struct i2c_adapter *adapter)
static int __devinit pc87360_probe(struct platform_device *pdev)
{
int i;
struct i2c_client *client;
struct pc87360_data *data;
int err = 0;
const char *name = "pc87360";
int use_thermistors = 0;
struct device *dev;
struct device *dev = &pdev->dev;
if (!(data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL)))
return -ENOMEM;
client = &data->client;
dev = &client->dev;
i2c_set_clientdata(client, data);
client->addr = address;
mutex_init(&data->lock);
client->adapter = adapter;
client->driver = &pc87360_driver;
client->flags = 0;
data->fannr = 2;
data->innr = 0;
data->tempnr = 0;
@ -960,15 +945,17 @@ static int pc87360_detect(struct i2c_adapter *adapter)
break;
}
strlcpy(client->name, name, sizeof(client->name));
data->name = name;
data->valid = 0;
mutex_init(&data->lock);
mutex_init(&data->update_lock);
platform_set_drvdata(pdev, data);
for (i = 0; i < 3; i++) {
if (((data->address[i] = extra_isa[i]))
&& !request_region(extra_isa[i], PC87360_EXTENT,
pc87360_driver.driver.name)) {
dev_err(&client->dev, "Region 0x%x-0x%x already "
dev_err(dev, "Region 0x%x-0x%x already "
"in use!\n", extra_isa[i],
extra_isa[i]+PC87360_EXTENT-1);
for (i--; i >= 0; i--)
@ -982,9 +969,6 @@ static int pc87360_detect(struct i2c_adapter *adapter)
if (data->fannr)
data->fan_conf = confreg[0] | (confreg[1] << 8);
if ((err = i2c_attach_client(client)))
goto ERROR2;
/* Use the correct reference voltage
Unless both the VLM and the TMS logical devices agree to
use an external Vref, the internal one is used. */
@ -996,7 +980,7 @@ static int pc87360_detect(struct i2c_adapter *adapter)
PC87365_REG_TEMP_CONFIG);
}
data->in_vref = (i&0x02) ? 3025 : 2966;
dev_dbg(&client->dev, "Using %s reference voltage\n",
dev_dbg(dev, "Using %s reference voltage\n",
(i&0x02) ? "external" : "internal");
data->vid_conf = confreg[3];
@ -1015,18 +999,18 @@ static int pc87360_detect(struct i2c_adapter *adapter)
if (devid == 0xe9 && data->address[1]) /* PC87366 */
use_thermistors = confreg[2] & 0x40;
pc87360_init_client(client, use_thermistors);
pc87360_init_device(pdev, use_thermistors);
}
/* Register all-or-nothing sysfs groups */
if (data->innr &&
(err = sysfs_create_group(&client->dev.kobj,
(err = sysfs_create_group(&dev->kobj,
&pc8736x_vin_group)))
goto ERROR3;
if (data->innr == 14 &&
(err = sysfs_create_group(&client->dev.kobj,
(err = sysfs_create_group(&dev->kobj,
&pc8736x_therm_group)))
goto ERROR3;
@ -1067,7 +1051,10 @@ static int pc87360_detect(struct i2c_adapter *adapter)
goto ERROR3;
}
data->class_dev = hwmon_device_register(&client->dev);
if ((err = device_create_file(dev, &dev_attr_name)))
goto ERROR3;
data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto ERROR3;
@ -1075,14 +1062,12 @@ static int pc87360_detect(struct i2c_adapter *adapter)
return 0;
ERROR3:
device_remove_file(dev, &dev_attr_name);
/* can still remove groups whose members were added individually */
sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
i2c_detach_client(client);
ERROR2:
sysfs_remove_group(&dev->kobj, &pc8736x_temp_group);
sysfs_remove_group(&dev->kobj, &pc8736x_fan_group);
sysfs_remove_group(&dev->kobj, &pc8736x_therm_group);
sysfs_remove_group(&dev->kobj, &pc8736x_vin_group);
for (i = 0; i < 3; i++) {
if (data->address[i]) {
release_region(data->address[i], PC87360_EXTENT);
@ -1093,20 +1078,18 @@ static int pc87360_detect(struct i2c_adapter *adapter)
return err;
}
static int pc87360_detach_client(struct i2c_client *client)
static int __devexit pc87360_remove(struct platform_device *pdev)
{
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = platform_get_drvdata(pdev);
int i;
hwmon_device_unregister(data->class_dev);
sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
if ((i = i2c_detach_client(client)))
return i;
device_remove_file(&pdev->dev, &dev_attr_name);
sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group);
sysfs_remove_group(&pdev->dev.kobj, &pc8736x_fan_group);
sysfs_remove_group(&pdev->dev.kobj, &pc8736x_therm_group);
sysfs_remove_group(&pdev->dev.kobj, &pc8736x_vin_group);
for (i = 0; i < 3; i++) {
if (data->address[i]) {
@ -1144,9 +1127,10 @@ static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
mutex_unlock(&(data->lock));
}
static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
static void pc87360_init_device(struct platform_device *pdev,
int use_thermistors)
{
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = platform_get_drvdata(pdev);
int i, nr;
const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 };
const u8 init_temp[3] = { 2, 2, 1 };
@ -1155,7 +1139,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
if (init >= 2 && data->innr) {
reg = pc87360_read_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONVRATE);
dev_info(&client->dev, "VLM conversion set to "
dev_info(&pdev->dev, "VLM conversion set to "
"1s period, 160us delay\n");
pc87360_write_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONVRATE,
@ -1169,7 +1153,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_IN, i,
PC87365_REG_IN_STATUS);
if (!(reg & 0x01)) {
dev_dbg(&client->dev, "Forcibly "
dev_dbg(&pdev->dev, "Forcibly "
"enabling in%d\n", i);
pc87360_write_value(data, LD_IN, i,
PC87365_REG_IN_STATUS,
@ -1193,7 +1177,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_TEMP, i,
PC87365_REG_TEMP_STATUS);
if (!(reg & 0x01)) {
dev_dbg(&client->dev, "Forcibly "
dev_dbg(&pdev->dev, "Forcibly "
"enabling temp%d\n", i+1);
pc87360_write_value(data, LD_TEMP, i,
PC87365_REG_TEMP_STATUS,
@ -1210,7 +1194,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_TEMP,
(i-11)/2, PC87365_REG_TEMP_STATUS);
if (reg & 0x01) {
dev_dbg(&client->dev, "Skipping "
dev_dbg(&pdev->dev, "Skipping "
"temp%d, pin already in use "
"by temp%d\n", i-7, (i-11)/2);
continue;
@ -1220,7 +1204,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_IN, i,
PC87365_REG_IN_STATUS);
if (!(reg & 0x01)) {
dev_dbg(&client->dev, "Forcibly "
dev_dbg(&pdev->dev, "Forcibly "
"enabling temp%d\n", i-7);
pc87360_write_value(data, LD_IN, i,
PC87365_REG_TEMP_STATUS,
@ -1234,7 +1218,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONFIG);
if (reg & 0x01) {
dev_dbg(&client->dev, "Forcibly "
dev_dbg(&pdev->dev, "Forcibly "
"enabling monitoring (VLM)\n");
pc87360_write_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONFIG,
@ -1246,7 +1230,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_TEMP, NO_BANK,
PC87365_REG_TEMP_CONFIG);
if (reg & 0x01) {
dev_dbg(&client->dev, "Forcibly enabling "
dev_dbg(&pdev->dev, "Forcibly enabling "
"monitoring (TMS)\n");
pc87360_write_value(data, LD_TEMP, NO_BANK,
PC87365_REG_TEMP_CONFIG,
@ -1268,9 +1252,9 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
}
}
static void pc87360_autodiv(struct i2c_client *client, int nr)
static void pc87360_autodiv(struct device *dev, int nr)
{
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = dev_get_drvdata(dev);
u8 old_min = data->fan_min[nr];
/* Increase clock divider if needed and possible */
@ -1280,7 +1264,7 @@ static void pc87360_autodiv(struct i2c_client *client, int nr)
data->fan_status[nr] += 0x20;
data->fan_min[nr] >>= 1;
data->fan[nr] >>= 1;
dev_dbg(&client->dev, "Increasing "
dev_dbg(dev, "Increasing "
"clock divider to %d for fan %d\n",
FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1);
}
@ -1292,7 +1276,7 @@ static void pc87360_autodiv(struct i2c_client *client, int nr)
data->fan_status[nr] -= 0x20;
data->fan_min[nr] <<= 1;
data->fan[nr] <<= 1;
dev_dbg(&client->dev, "Decreasing "
dev_dbg(dev, "Decreasing "
"clock divider to %d for fan %d\n",
FAN_DIV_FROM_REG(data->fan_status[nr]),
nr+1);
@ -1309,14 +1293,13 @@ static void pc87360_autodiv(struct i2c_client *client, int nr)
static struct pc87360_data *pc87360_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct pc87360_data *data = i2c_get_clientdata(client);
struct pc87360_data *data = dev_get_drvdata(dev);
u8 i;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
dev_dbg(&client->dev, "Data update\n");
dev_dbg(dev, "Data update\n");
/* Fans */
for (i = 0; i < data->fannr; i++) {
@ -1330,7 +1313,7 @@ static struct pc87360_data *pc87360_update_device(struct device *dev)
LD_FAN, NO_BANK,
PC87360_REG_FAN_MIN(i));
/* Change clock divider if needed */
pc87360_autodiv(client, i);
pc87360_autodiv(dev, i);
/* Clear bits and write new divider */
pc87360_write_value(data, LD_FAN, NO_BANK,
PC87360_REG_FAN_STATUS(i),
@ -1418,9 +1401,53 @@ static struct pc87360_data *pc87360_update_device(struct device *dev)
return data;
}
static int __init pc87360_device_add(unsigned short address)
{
struct resource res = {
.name = "pc87360",
.flags = IORESOURCE_IO,
};
int err, i;
pdev = platform_device_alloc("pc87360", address);
if (!pdev) {
err = -ENOMEM;
printk(KERN_ERR "pc87360: Device allocation failed\n");
goto exit;
}
for (i = 0; i < 3; i++) {
if (!extra_isa[i])
continue;
res.start = extra_isa[i];
res.end = extra_isa[i] + PC87360_EXTENT - 1;
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
printk(KERN_ERR "pc87360: Device resource[%d] "
"addition failed (%d)\n", i, err);
goto exit_device_put;
}
}
err = platform_device_add(pdev);
if (err) {
printk(KERN_ERR "pc87360: Device addition failed (%d)\n",
err);
goto exit_device_put;
}
return 0;
exit_device_put:
platform_device_put(pdev);
exit:
return err;
}
static int __init pc87360_init(void)
{
int i;
int err, i;
unsigned short address = 0;
if (pc87360_find(0x2e, &devid, extra_isa)
&& pc87360_find(0x4e, &devid, extra_isa)) {
@ -1443,12 +1470,27 @@ static int __init pc87360_init(void)
return -ENODEV;
}
return i2c_isa_add_driver(&pc87360_driver);
err = platform_driver_register(&pc87360_driver);
if (err)
goto exit;
/* Sets global pdev as a side effect */
err = pc87360_device_add(address);
if (err)
goto exit_driver;
return 0;
exit_driver:
platform_driver_unregister(&pc87360_driver);
exit:
return err;
}
static void __exit pc87360_exit(void)
{
i2c_isa_del_driver(&pc87360_driver);
platform_device_unregister(pdev);
platform_driver_unregister(&pc87360_driver);
}

View file

@ -484,7 +484,6 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
struct resource *res;
int i;
platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
device_remove_file(&pdev->dev, &dev_attr_name);
for (i = 0; i < 8; i++) {
@ -492,6 +491,7 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
continue;
sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
}
platform_set_drvdata(pdev, NULL);
kfree(data);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);

View file

@ -54,9 +54,9 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/i2c.h>
#include <linux/i2c-isa.h>
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/jiffies.h>
@ -72,17 +72,13 @@ module_param(force_addr, ushort, 0);
MODULE_PARM_DESC(force_addr,
"Initialize the base address of the sensors");
/* Device address
Note that we can't determine the ISA address until we have initialized
our module */
static unsigned short address;
static struct platform_device *pdev;
/* Many SIS5595 constants specified below */
/* Length of ISA address segment */
#define SIS5595_EXTENT 8
/* PCI Config Registers */
#define SIS5595_REVISION_REG 0x08
#define SIS5595_BASE_REG 0x68
#define SIS5595_PIN_REG 0x7A
#define SIS5595_ENABLE_REG 0x7B
@ -165,7 +161,8 @@ static inline u8 DIV_TO_REG(int val)
/* For each registered chip, we need to keep some data in memory.
The structure is dynamically allocated. */
struct sis5595_data {
struct i2c_client client;
unsigned short addr;
const char *name;
struct class_device *class_dev;
struct mutex lock;
@ -189,102 +186,88 @@ struct sis5595_data {
static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */
static int sis5595_detect(struct i2c_adapter *adapter);
static int sis5595_detach_client(struct i2c_client *client);
static int sis5595_probe(struct platform_device *pdev);
static int sis5595_remove(struct platform_device *pdev);
static int sis5595_read_value(struct i2c_client *client, u8 reg);
static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value);
static int sis5595_read_value(struct sis5595_data *data, u8 reg);
static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value);
static struct sis5595_data *sis5595_update_device(struct device *dev);
static void sis5595_init_client(struct i2c_client *client);
static void sis5595_init_device(struct sis5595_data *data);
static struct i2c_driver sis5595_driver = {
static struct platform_driver sis5595_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "sis5595",
},
.attach_adapter = sis5595_detect,
.detach_client = sis5595_detach_client,
.probe = sis5595_probe,
.remove = __devexit_p(sis5595_remove),
};
/* 4 Voltages */
static ssize_t show_in(struct device *dev, char *buf, int nr)
static ssize_t show_in(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
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 *da,
char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
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 *da,
char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
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 *da,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct sis5595_data *data = i2c_get_clientdata(client);
struct sis5595_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[nr] = IN_TO_REG(val);
sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
sis5595_write_value(data, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
mutex_unlock(&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 *da,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct sis5595_data *data = i2c_get_clientdata(client);
struct sis5595_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[nr] = IN_TO_REG(val);
sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
sis5595_write_value(data, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
mutex_unlock(&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);
static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
show_in, NULL, offset); \
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);
show_in_offset(1);
@ -307,13 +290,12 @@ static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr,
static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct sis5595_data *data = i2c_get_clientdata(client);
struct sis5595_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_over = TEMP_TO_REG(val);
sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over);
sis5595_write_value(data, SIS5595_REG_TEMP_OVER, data->temp_over);
mutex_unlock(&data->update_lock);
return count;
}
@ -326,13 +308,12 @@ static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr,
static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct sis5595_data *data = i2c_get_clientdata(client);
struct sis5595_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_hyst = TEMP_TO_REG(val);
sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst);
sis5595_write_value(data, SIS5595_REG_TEMP_HYST, data->temp_hyst);
mutex_unlock(&data->update_lock);
return count;
}
@ -344,37 +325,47 @@ static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
show_temp_hyst, set_temp_hyst);
/* 2 Fans */
static ssize_t show_fan(struct device *dev, char *buf, int nr)
static ssize_t show_fan(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
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 *da,
char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[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 *da,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct sis5595_data *data = i2c_get_clientdata(client);
struct sis5595_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
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 *da,
char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
}
@ -382,11 +373,12 @@ static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
determined in part by the fan divisor. This follows the principle of
least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
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 *da,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct sis5595_data *data = i2c_get_clientdata(client);
struct sis5595_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
unsigned long min;
unsigned long val = simple_strtoul(buf, NULL, 10);
int reg;
@ -394,7 +386,7 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
mutex_lock(&data->update_lock);
min = FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr]));
reg = sis5595_read_value(client, SIS5595_REG_FANDIV);
reg = sis5595_read_value(data, SIS5595_REG_FANDIV);
switch (val) {
case 1: data->fan_div[nr] = 0; break;
@ -402,7 +394,7 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
case 4: data->fan_div[nr] = 2; break;
case 8: data->fan_div[nr] = 3; break;
default:
dev_err(&client->dev, "fan_div value %ld not "
dev_err(dev, "fan_div value %ld not "
"supported. Choose one of 1, 2, 4 or 8!\n", val);
mutex_unlock(&data->update_lock);
return -EINVAL;
@ -416,55 +408,25 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
break;
}
sis5595_write_value(client, SIS5595_REG_FANDIV, reg);
sis5595_write_value(data, SIS5595_REG_FANDIV, reg);
data->fan_min[nr] =
FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&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##_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 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 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);
static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
return set_fan_div(dev, buf, count, 0) ;
}
static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
return set_fan_div(dev, buf, count, 1) ;
}
static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
show_fan_1_div, set_fan_1_div);
static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
show_fan_2_div, set_fan_2_div);
/* Alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
{
@ -473,28 +435,37 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static struct attribute *sis5595_attributes[] = {
&dev_attr_in0_input.attr,
&dev_attr_in0_min.attr,
&dev_attr_in0_max.attr,
&dev_attr_in1_input.attr,
&dev_attr_in1_min.attr,
&dev_attr_in1_max.attr,
&dev_attr_in2_input.attr,
&dev_attr_in2_min.attr,
&dev_attr_in2_max.attr,
&dev_attr_in3_input.attr,
&dev_attr_in3_min.attr,
&dev_attr_in3_max.attr,
static ssize_t show_name(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sis5595_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", data->name);
}
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
&dev_attr_fan1_input.attr,
&dev_attr_fan1_min.attr,
&dev_attr_fan1_div.attr,
&dev_attr_fan2_input.attr,
&dev_attr_fan2_min.attr,
&dev_attr_fan2_div.attr,
static struct attribute *sis5595_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_min.dev_attr.attr,
&sensor_dev_attr_in1_max.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in2_min.dev_attr.attr,
&sensor_dev_attr_in2_max.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in3_min.dev_attr.attr,
&sensor_dev_attr_in3_max.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_name.attr,
NULL
};
@ -503,9 +474,9 @@ static const struct attribute_group sis5595_group = {
};
static struct attribute *sis5595_attributes_opt[] = {
&dev_attr_in4_input.attr,
&dev_attr_in4_min.attr,
&dev_attr_in4_max.attr,
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in4_min.dev_attr.attr,
&sensor_dev_attr_in4_max.dev_attr.attr,
&dev_attr_temp1_input.attr,
&dev_attr_temp1_max.attr,
@ -518,68 +489,35 @@ static const struct attribute_group sis5595_group_opt = {
};
/* This is called when the module is loaded */
static int sis5595_detect(struct i2c_adapter *adapter)
static int __devinit sis5595_probe(struct platform_device *pdev)
{
int err = 0;
int i;
struct i2c_client *new_client;
struct sis5595_data *data;
struct resource *res;
char val;
u16 a;
if (force_addr)
address = force_addr & ~(SIS5595_EXTENT - 1);
/* Reserve the ISA region */
if (!request_region(address, SIS5595_EXTENT,
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!request_region(res->start, SIS5595_EXTENT,
sis5595_driver.driver.name)) {
err = -EBUSY;
goto exit;
}
if (force_addr) {
dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address);
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(s_bridge, SIS5595_BASE_REG, address))
goto exit_release;
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a))
goto exit_release;
if ((a & ~(SIS5595_EXTENT - 1)) != address)
/* doesn't work for some chips? */
goto exit_release;
}
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) {
goto exit_release;
}
if ((val & 0x80) == 0) {
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG,
val | 0x80))
goto exit_release;
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
goto exit_release;
if ((val & 0x80) == 0)
/* doesn't work for some chips! */
goto exit_release;
}
if (!(data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit_release;
}
new_client = &data->client;
new_client->addr = address;
mutex_init(&data->lock);
i2c_set_clientdata(new_client, data);
new_client->adapter = adapter;
new_client->driver = &sis5595_driver;
new_client->flags = 0;
mutex_init(&data->update_lock);
data->addr = res->start;
data->name = "sis5595";
platform_set_drvdata(pdev, data);
/* Check revision and pin registers to determine whether 4 or 5 voltages */
pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision));
pci_read_config_byte(s_bridge, PCI_REVISION_ID, &data->revision);
/* 4 voltages, 1 temp */
data->maxins = 3;
if (data->revision >= REV2MIN) {
@ -589,47 +527,37 @@ static int sis5595_detect(struct i2c_adapter *adapter)
data->maxins = 4;
}
/* Fill in the remaining client fields and put it into the global list */
strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE);
data->valid = 0;
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto exit_free;
/* Initialize the SIS5595 chip */
sis5595_init_client(new_client);
sis5595_init_device(data);
/* A few vars need to be filled upon startup */
for (i = 0; i < 2; i++) {
data->fan_min[i] = sis5595_read_value(new_client,
data->fan_min[i] = sis5595_read_value(data,
SIS5595_REG_FAN_MIN(i));
}
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &sis5595_group)))
goto exit_detach;
if ((err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group)))
goto exit_free;
if (data->maxins == 4) {
if ((err = device_create_file(&new_client->dev,
&dev_attr_in4_input))
|| (err = device_create_file(&new_client->dev,
&dev_attr_in4_min))
|| (err = device_create_file(&new_client->dev,
&dev_attr_in4_max)))
if ((err = device_create_file(&pdev->dev,
&sensor_dev_attr_in4_input.dev_attr))
|| (err = device_create_file(&pdev->dev,
&sensor_dev_attr_in4_min.dev_attr))
|| (err = device_create_file(&pdev->dev,
&sensor_dev_attr_in4_max.dev_attr)))
goto exit_remove_files;
} else {
if ((err = device_create_file(&new_client->dev,
if ((err = device_create_file(&pdev->dev,
&dev_attr_temp1_input))
|| (err = device_create_file(&new_client->dev,
|| (err = device_create_file(&pdev->dev,
&dev_attr_temp1_max))
|| (err = device_create_file(&new_client->dev,
|| (err = device_create_file(&pdev->dev,
&dev_attr_temp1_max_hyst)))
goto exit_remove_files;
}
data->class_dev = hwmon_device_register(&new_client->dev);
data->class_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto exit_remove_files;
@ -638,32 +566,26 @@ static int sis5595_detect(struct i2c_adapter *adapter)
return 0;
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &sis5595_group);
sysfs_remove_group(&new_client->dev.kobj, &sis5595_group_opt);
exit_detach:
i2c_detach_client(new_client);
sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
exit_free:
kfree(data);
exit_release:
release_region(address, SIS5595_EXTENT);
release_region(res->start, SIS5595_EXTENT);
exit:
return err;
}
static int sis5595_detach_client(struct i2c_client *client)
static int __devexit sis5595_remove(struct platform_device *pdev)
{
struct sis5595_data *data = i2c_get_clientdata(client);
int err;
struct sis5595_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->class_dev);
sysfs_remove_group(&client->dev.kobj, &sis5595_group);
sysfs_remove_group(&client->dev.kobj, &sis5595_group_opt);
if ((err = i2c_detach_client(client)))
return err;
release_region(client->addr, SIS5595_EXTENT);
sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
release_region(data->addr, SIS5595_EXTENT);
platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
@ -671,41 +593,37 @@ static int sis5595_detach_client(struct i2c_client *client)
/* ISA access must be locked explicitly. */
static int sis5595_read_value(struct i2c_client *client, u8 reg)
static int sis5595_read_value(struct sis5595_data *data, u8 reg)
{
int res;
struct sis5595_data *data = i2c_get_clientdata(client);
mutex_lock(&data->lock);
outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET);
outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET);
mutex_unlock(&data->lock);
return res;
}
static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value)
static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value)
{
struct sis5595_data *data = i2c_get_clientdata(client);
mutex_lock(&data->lock);
outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET);
outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET);
mutex_unlock(&data->lock);
return 0;
}
/* Called when we have found a new SIS5595. */
static void sis5595_init_client(struct i2c_client *client)
static void __devinit sis5595_init_device(struct sis5595_data *data)
{
u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG);
u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG);
if (!(config & 0x01))
sis5595_write_value(client, SIS5595_REG_CONFIG,
sis5595_write_value(data, SIS5595_REG_CONFIG,
(config & 0xf7) | 0x01);
}
static struct sis5595_data *sis5595_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct sis5595_data *data = i2c_get_clientdata(client);
struct sis5595_data *data = dev_get_drvdata(dev);
int i;
mutex_lock(&data->update_lock);
@ -715,35 +633,35 @@ static struct sis5595_data *sis5595_update_device(struct device *dev)
for (i = 0; i <= data->maxins; i++) {
data->in[i] =
sis5595_read_value(client, SIS5595_REG_IN(i));
sis5595_read_value(data, SIS5595_REG_IN(i));
data->in_min[i] =
sis5595_read_value(client,
sis5595_read_value(data,
SIS5595_REG_IN_MIN(i));
data->in_max[i] =
sis5595_read_value(client,
sis5595_read_value(data,
SIS5595_REG_IN_MAX(i));
}
for (i = 0; i < 2; i++) {
data->fan[i] =
sis5595_read_value(client, SIS5595_REG_FAN(i));
sis5595_read_value(data, SIS5595_REG_FAN(i));
data->fan_min[i] =
sis5595_read_value(client,
sis5595_read_value(data,
SIS5595_REG_FAN_MIN(i));
}
if (data->maxins == 3) {
data->temp =
sis5595_read_value(client, SIS5595_REG_TEMP);
sis5595_read_value(data, SIS5595_REG_TEMP);
data->temp_over =
sis5595_read_value(client, SIS5595_REG_TEMP_OVER);
sis5595_read_value(data, SIS5595_REG_TEMP_OVER);
data->temp_hyst =
sis5595_read_value(client, SIS5595_REG_TEMP_HYST);
sis5595_read_value(data, SIS5595_REG_TEMP_HYST);
}
i = sis5595_read_value(client, SIS5595_REG_FANDIV);
i = sis5595_read_value(data, SIS5595_REG_FANDIV);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = i >> 6;
data->alarms =
sis5595_read_value(client, SIS5595_REG_ALARM1) |
(sis5595_read_value(client, SIS5595_REG_ALARM2) << 8);
sis5595_read_value(data, SIS5595_REG_ALARM1) |
(sis5595_read_value(data, SIS5595_REG_ALARM2) << 8);
data->last_updated = jiffies;
data->valid = 1;
}
@ -774,10 +692,50 @@ static int blacklist[] __devinitdata = {
PCI_DEVICE_ID_SI_5598,
0 };
static int __devinit sis5595_device_add(unsigned short address)
{
struct resource res = {
.start = address,
.end = address + SIS5595_EXTENT - 1,
.name = "sis5595",
.flags = IORESOURCE_IO,
};
int err;
pdev = platform_device_alloc("sis5595", address);
if (!pdev) {
err = -ENOMEM;
printk(KERN_ERR "sis5595: Device allocation failed\n");
goto exit;
}
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
printk(KERN_ERR "sis5595: Device resource addition failed "
"(%d)\n", err);
goto exit_device_put;
}
err = platform_device_add(pdev);
if (err) {
printk(KERN_ERR "sis5595: Device addition failed (%d)\n",
err);
goto exit_device_put;
}
return 0;
exit_device_put:
platform_device_put(pdev);
exit:
return err;
}
static int __devinit sis5595_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
u16 val;
u16 address;
u8 enable;
int *i;
for (i = blacklist; *i != 0; i++) {
@ -790,27 +748,68 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
}
}
force_addr &= ~(SIS5595_EXTENT - 1);
if (force_addr) {
dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", force_addr);
pci_write_config_word(dev, SIS5595_BASE_REG, force_addr);
}
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_word(dev, SIS5595_BASE_REG, &val))
pci_read_config_word(dev, SIS5595_BASE_REG, &address)) {
dev_err(&dev->dev, "Failed to read ISA address\n");
return -ENODEV;
}
address = val & ~(SIS5595_EXTENT - 1);
if (address == 0 && force_addr == 0) {
address &= ~(SIS5595_EXTENT - 1);
if (!address) {
dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
return -ENODEV;
}
if (force_addr && address != force_addr) {
/* doesn't work for some chips? */
dev_err(&dev->dev, "Failed to force ISA address\n");
return -ENODEV;
}
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable)) {
dev_err(&dev->dev, "Failed to read enable register\n");
return -ENODEV;
}
if (!(enable & 0x80)) {
if ((PCIBIOS_SUCCESSFUL !=
pci_write_config_byte(dev, SIS5595_ENABLE_REG,
enable | 0x80))
|| (PCIBIOS_SUCCESSFUL !=
pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable))
|| (!(enable & 0x80))) {
/* doesn't work for some chips! */
dev_err(&dev->dev, "Failed to enable HWM device\n");
return -ENODEV;
}
}
if (platform_driver_register(&sis5595_driver)) {
dev_dbg(&dev->dev, "Failed to register sis5595 driver\n");
goto exit;
}
s_bridge = pci_dev_get(dev);
if (i2c_isa_add_driver(&sis5595_driver)) {
pci_dev_put(s_bridge);
s_bridge = NULL;
}
/* Sets global pdev as a side effect */
if (sis5595_device_add(address))
goto exit_unregister;
/* Always return failure here. This is to allow other drivers to bind
* to this pci device. We don't really want to have control over the
* pci device, we only wanted to read as few register values from it.
*/
return -ENODEV;
exit_unregister:
pci_dev_put(dev);
platform_driver_unregister(&sis5595_driver);
exit:
return -ENODEV;
}
static struct pci_driver sis5595_pci_driver = {
@ -828,7 +827,8 @@ static void __exit sm_sis5595_exit(void)
{
pci_unregister_driver(&sis5595_pci_driver);
if (s_bridge != NULL) {
i2c_isa_del_driver(&sis5595_driver);
platform_device_unregister(pdev);
platform_driver_unregister(&sis5595_driver);
pci_dev_put(s_bridge);
s_bridge = NULL;
}

View file

@ -174,6 +174,8 @@ static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
REG: count of 90kHz pulses / revolution */
static int fan_from_reg(u16 reg)
{
if (reg == 0 || reg == 0xffff)
return 0;
return 90000 * 60 / reg;
}
@ -333,7 +335,7 @@ static int __init smsc47b397_find(unsigned short *addr)
superio_enter();
id = superio_inb(SUPERIO_REG_DEVID);
if ((id != 0x6f) && (id != 0x81)) {
if ((id != 0x6f) && (id != 0x81) && (id != 0x85)) {
superio_exit();
return -ENODEV;
}
@ -346,7 +348,8 @@ static int __init smsc47b397_find(unsigned short *addr)
printk(KERN_INFO DRVNAME ": found SMSC %s "
"(base address 0x%04x, revision %u)\n",
id == 0x81 ? "SCH5307-NS" : "LPC47B397-NC", *addr, rev);
id == 0x81 ? "SCH5307-NS" : id == 0x85 ? "SCH5317" :
"LPC47B397-NC", *addr, rev);
superio_exit();
return 0;

View file

@ -597,6 +597,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
error_remove_files:
sysfs_remove_group(&dev->kobj, &smsc47m1_group);
error_free:
platform_set_drvdata(pdev, NULL);
kfree(data);
error_release:
release_region(res->start, SMSC_EXTENT);
@ -608,12 +609,12 @@ static int __devexit smsc47m1_remove(struct platform_device *pdev)
struct smsc47m1_data *data = platform_get_drvdata(pdev);
struct resource *res;
platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
release_region(res->start, SMSC_EXTENT);
platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
@ -693,15 +694,12 @@ static int __init smsc47m1_device_add(unsigned short address,
goto exit_device_put;
}
pdev->dev.platform_data = kmalloc(sizeof(struct smsc47m1_sio_data),
GFP_KERNEL);
if (!pdev->dev.platform_data) {
err = -ENOMEM;
err = platform_device_add_data(pdev, sio_data,
sizeof(struct smsc47m1_sio_data));
if (err) {
printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
goto exit_device_put;
}
memcpy(pdev->dev.platform_data, sio_data,
sizeof(struct smsc47m1_sio_data));
err = platform_device_add(pdev);
if (err) {

View file

@ -31,6 +31,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/sysfs.h>
#include <linux/mutex.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
@ -97,7 +98,7 @@ static inline int TEMP_FROM_REG(s8 val)
struct smsc47m192_data {
struct i2c_client client;
struct class_device *class_dev;
struct semaphore update_lock;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@ -164,11 +165,11 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
struct smsc47m192_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
down(&data->update_lock);
mutex_lock(&data->update_lock);
data->in_min[nr] = IN_TO_REG(val, nr);
i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MIN(nr),
data->in_min[nr]);
up(&data->update_lock);
mutex_unlock(&data->update_lock);
return count;
}
@ -181,11 +182,11 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
struct smsc47m192_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
down(&data->update_lock);
mutex_lock(&data->update_lock);
data->in_max[nr] = IN_TO_REG(val, nr);
i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MAX(nr),
data->in_max[nr]);
up(&data->update_lock);
mutex_unlock(&data->update_lock);
return count;
}
@ -243,11 +244,11 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
struct smsc47m192_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
down(&data->update_lock);
mutex_lock(&data->update_lock);
data->temp_min[nr] = TEMP_TO_REG(val);
i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[nr],
data->temp_min[nr]);
up(&data->update_lock);
mutex_unlock(&data->update_lock);
return count;
}
@ -260,11 +261,11 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
struct smsc47m192_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
down(&data->update_lock);
mutex_lock(&data->update_lock);
data->temp_max[nr] = TEMP_TO_REG(val);
i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MAX[nr],
data->temp_max[nr]);
up(&data->update_lock);
mutex_unlock(&data->update_lock);
return count;
}
@ -287,7 +288,7 @@ static ssize_t set_temp_offset(struct device *dev, struct device_attribute
u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
long val = simple_strtol(buf, NULL, 10);
down(&data->update_lock);
mutex_lock(&data->update_lock);
data->temp_offset[nr] = TEMP_TO_REG(val);
if (nr>1)
i2c_smbus_write_byte_data(client,
@ -303,7 +304,7 @@ static ssize_t set_temp_offset(struct device *dev, struct device_attribute
} else if ((sfr & 0x10) == (nr==0 ? 0x10 : 0))
i2c_smbus_write_byte_data(client,
SMSC47M192_REG_TEMP_OFFSET(nr), 0);
up(&data->update_lock);
mutex_unlock(&data->update_lock);
return count;
}
@ -360,8 +361,8 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0x0010);
static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0x0020);
static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0x0040);
static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 0x4000);
static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 0x8000);
static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 0x4000);
static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 0x8000);
static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0x0001);
static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0x0002);
static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 0x0004);
@ -411,13 +412,13 @@ static struct attribute *smsc47m192_attributes[] = {
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_offset.dev_attr.attr,
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_input_fault.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_offset.dev_attr.attr,
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_input_fault.dev_attr.attr,
&sensor_dev_attr_temp3_fault.dev_attr.attr,
&dev_attr_cpu0_vid.attr,
&dev_attr_vrm.attr,
@ -531,7 +532,7 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
/* Fill in the remaining client fields and put into the global list */
strlcpy(client->name, "smsc47m192", I2C_NAME_SIZE);
data->vrm = vid_which_vrm();
init_MUTEX(&data->update_lock);
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(client)))
@ -594,7 +595,7 @@ static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
struct smsc47m192_data *data = i2c_get_clientdata(client);
int i, config;
down(&data->update_lock);
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
@ -645,7 +646,7 @@ static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
data->valid = 1;
}
up(&data->update_lock);
mutex_unlock(&data->update_lock);
return data;
}

View file

@ -34,9 +34,9 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/i2c-isa.h>
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/mutex.h>
@ -51,10 +51,7 @@ module_param(force_addr, ushort, 0);
MODULE_PARM_DESC(force_addr,
"Initialize the base address of the sensors");
/* Device address
Note that we can't determine the ISA address until we have initialized
our module */
static unsigned short address;
static struct platform_device *pdev;
/*
The Via 686a southbridge has a LM78-like chip integrated on the same IC.
@ -295,7 +292,8 @@ static inline long TEMP_FROM_REG10(u16 val)
/* For each registered chip, we need to keep some data in memory.
The structure is dynamically allocated. */
struct via686a_data {
struct i2c_client client;
unsigned short addr;
const char *name;
struct class_device *class_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@ -315,98 +313,85 @@ struct via686a_data {
static struct pci_dev *s_bridge; /* pointer to the (only) via686a */
static int via686a_detect(struct i2c_adapter *adapter);
static int via686a_detach_client(struct i2c_client *client);
static int via686a_probe(struct platform_device *pdev);
static int via686a_remove(struct platform_device *pdev);
static inline int via686a_read_value(struct i2c_client *client, u8 reg)
static inline int via686a_read_value(struct via686a_data *data, u8 reg)
{
return (inb_p(client->addr + reg));
return inb_p(data->addr + reg);
}
static inline void via686a_write_value(struct i2c_client *client, u8 reg,
static inline void via686a_write_value(struct via686a_data *data, u8 reg,
u8 value)
{
outb_p(value, client->addr + reg);
outb_p(value, data->addr + reg);
}
static struct via686a_data *via686a_update_device(struct device *dev);
static void via686a_init_client(struct i2c_client *client);
static void via686a_init_device(struct via686a_data *data);
/* following are the sysfs callback functions */
/* 7 voltage sensors */
static ssize_t show_in(struct device *dev, char *buf, int nr) {
static ssize_t show_in(struct device *dev, struct device_attribute *da,
char *buf) {
struct via686a_data *data = via686a_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], 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 *da,
char *buf) {
struct via686a_data *data = via686a_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], 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 *da,
char *buf) {
struct via686a_data *data = via686a_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
return sprintf(buf, "%ld\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 via686a_data *data = i2c_get_clientdata(client);
static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
const char *buf, size_t count) {
struct via686a_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[nr] = IN_TO_REG(val, nr);
via686a_write_value(client, VIA686A_REG_IN_MIN(nr),
via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
data->in_min[nr]);
mutex_unlock(&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 via686a_data *data = i2c_get_clientdata(client);
static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
const char *buf, size_t count) {
struct via686a_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[nr] = IN_TO_REG(val, nr);
via686a_write_value(client, VIA686A_REG_IN_MAX(nr),
via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
data->in_max[nr]);
mutex_unlock(&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 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##_input, S_IRUGO, show_in##offset, NULL);\
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##_input, S_IRUGO, \
show_in, NULL, offset); \
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);
show_in_offset(1);
@ -415,150 +400,128 @@ show_in_offset(3);
show_in_offset(4);
/* 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 *da,
char *buf) {
struct via686a_data *data = via686a_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
}
static ssize_t show_temp_over(struct device *dev, char *buf, int nr) {
static ssize_t show_temp_over(struct device *dev, struct device_attribute *da,
char *buf) {
struct via686a_data *data = via686a_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
}
static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) {
static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da,
char *buf) {
struct via686a_data *data = via686a_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
}
static ssize_t set_temp_over(struct device *dev, const char *buf,
size_t count, int nr) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
const char *buf, size_t count) {
struct via686a_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_over[nr] = TEMP_TO_REG(val);
via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr],
via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
data->temp_over[nr]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t set_temp_hyst(struct device *dev, const char *buf,
size_t count, int nr) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
const char *buf, size_t count) {
struct via686a_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_hyst[nr] = TEMP_TO_REG(val);
via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr],
via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
data->temp_hyst[nr]);
mutex_unlock(&data->update_lock);
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##_over (struct device *dev, struct device_attribute *attr, char *buf) \
{ \
return show_temp_over(dev, buf, offset - 1); \
} \
static ssize_t \
show_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, char *buf) \
{ \
return show_temp_hyst(dev, buf, offset - 1); \
} \
static ssize_t set_temp_##offset##_over (struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
return set_temp_over(dev, buf, count, offset - 1); \
} \
static ssize_t set_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
return set_temp_hyst(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##_over, set_temp_##offset##_over); \
static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
show_temp_##offset##_hyst, set_temp_##offset##_hyst);
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_over, set_temp_over, offset - 1); \
static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
show_temp_hyst, set_temp_hyst, offset - 1);
show_temp_offset(1);
show_temp_offset(2);
show_temp_offset(3);
/* 2 Fans */
static ssize_t show_fan(struct device *dev, char *buf, int nr) {
static ssize_t show_fan(struct device *dev, struct device_attribute *da,
char *buf) {
struct via686a_data *data = via686a_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
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 *da,
char *buf) {
struct via686a_data *data = via686a_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
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 *da,
char *buf) {
struct via686a_data *data = via686a_update_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
}
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 via686a_data *data = i2c_get_clientdata(client);
static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
const char *buf, size_t count) {
struct via686a_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t set_fan_div(struct device *dev, const char *buf,
size_t count, int nr) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
const char *buf, size_t count) {
struct via686a_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
int nr = attr->index;
int val = simple_strtol(buf, NULL, 10);
int old;
mutex_lock(&data->update_lock);
old = via686a_read_value(client, VIA686A_REG_FANDIV);
old = via686a_read_value(data, VIA686A_REG_FANDIV);
data->fan_div[nr] = DIV_TO_REG(val);
old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
via686a_write_value(client, VIA686A_REG_FANDIV, old);
via686a_write_value(data, VIA686A_REG_FANDIV, old);
mutex_unlock(&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##_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);
@ -570,41 +533,50 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static ssize_t show_name(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct via686a_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", data->name);
}
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static struct attribute *via686a_attributes[] = {
&dev_attr_in0_input.attr,
&dev_attr_in1_input.attr,
&dev_attr_in2_input.attr,
&dev_attr_in3_input.attr,
&dev_attr_in4_input.attr,
&dev_attr_in0_min.attr,
&dev_attr_in1_min.attr,
&dev_attr_in2_min.attr,
&dev_attr_in3_min.attr,
&dev_attr_in4_min.attr,
&dev_attr_in0_max.attr,
&dev_attr_in1_max.attr,
&dev_attr_in2_max.attr,
&dev_attr_in3_max.attr,
&dev_attr_in4_max.attr,
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
&sensor_dev_attr_in1_min.dev_attr.attr,
&sensor_dev_attr_in2_min.dev_attr.attr,
&sensor_dev_attr_in3_min.dev_attr.attr,
&sensor_dev_attr_in4_min.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
&sensor_dev_attr_in1_max.dev_attr.attr,
&sensor_dev_attr_in2_max.dev_attr.attr,
&sensor_dev_attr_in3_max.dev_attr.attr,
&sensor_dev_attr_in4_max.dev_attr.attr,
&dev_attr_temp1_input.attr,
&dev_attr_temp2_input.attr,
&dev_attr_temp3_input.attr,
&dev_attr_temp1_max.attr,
&dev_attr_temp2_max.attr,
&dev_attr_temp3_max.attr,
&dev_attr_temp1_max_hyst.attr,
&dev_attr_temp2_max_hyst.attr,
&dev_attr_temp3_max_hyst.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
&dev_attr_fan1_input.attr,
&dev_attr_fan2_input.attr,
&dev_attr_fan1_min.attr,
&dev_attr_fan2_min.attr,
&dev_attr_fan1_div.attr,
&dev_attr_fan2_div.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_name.attr,
NULL
};
@ -612,58 +584,29 @@ static const struct attribute_group via686a_group = {
.attrs = via686a_attributes,
};
/* The driver. I choose to use type i2c_driver, as at is identical to both
smbus_driver and isa_driver, and clients could be of either kind */
static struct i2c_driver via686a_driver = {
static struct platform_driver via686a_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "via686a",
},
.attach_adapter = via686a_detect,
.detach_client = via686a_detach_client,
.probe = via686a_probe,
.remove = __devexit_p(via686a_remove),
};
/* This is called when the module is loaded */
static int via686a_detect(struct i2c_adapter *adapter)
static int __devinit via686a_probe(struct platform_device *pdev)
{
struct i2c_client *new_client;
struct via686a_data *data;
int err = 0;
const char client_name[] = "via686a";
u16 val;
/* 8231 requires multiple of 256, we enforce that on 686 as well */
if (force_addr) {
address = force_addr & 0xFF00;
dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n",
address);
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(s_bridge, VIA686A_BASE_REG, address))
return -ENODEV;
}
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val))
return -ENODEV;
if (!(val & 0x0001)) {
if (force_addr) {
dev_info(&adapter->dev, "enabling sensors\n");
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(s_bridge, VIA686A_ENABLE_REG,
val | 0x0001))
return -ENODEV;
} else {
dev_warn(&adapter->dev, "sensors disabled - enable "
"with force_addr=0x%x\n", address);
return -ENODEV;
}
}
struct resource *res;
int err;
/* Reserve the ISA region */
if (!request_region(address, VIA686A_EXTENT,
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!request_region(res->start, VIA686A_EXTENT,
via686a_driver.driver.name)) {
dev_err(&adapter->dev, "region 0x%x already in use!\n",
address);
dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
(unsigned long)res->start, (unsigned long)res->end);
return -ENODEV;
}
@ -672,30 +615,19 @@ static int via686a_detect(struct i2c_adapter *adapter)
goto exit_release;
}
new_client = &data->client;
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &via686a_driver;
new_client->flags = 0;
/* Fill in the remaining client fields and put into the global list */
strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
data->valid = 0;
platform_set_drvdata(pdev, data);
data->addr = res->start;
data->name = "via686a";
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto exit_free;
/* Initialize the VIA686A chip */
via686a_init_client(new_client);
via686a_init_device(data);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &via686a_group)))
goto exit_detach;
if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group)))
goto exit_free;
data->class_dev = hwmon_device_register(&new_client->dev);
data->class_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto exit_remove_files;
@ -704,51 +636,46 @@ static int via686a_detect(struct i2c_adapter *adapter)
return 0;
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &via686a_group);
exit_detach:
i2c_detach_client(new_client);
sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
exit_free:
kfree(data);
exit_release:
release_region(address, VIA686A_EXTENT);
release_region(res->start, VIA686A_EXTENT);
return err;
}
static int via686a_detach_client(struct i2c_client *client)
static int __devexit via686a_remove(struct platform_device *pdev)
{
struct via686a_data *data = i2c_get_clientdata(client);
int err;
struct via686a_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->class_dev);
sysfs_remove_group(&client->dev.kobj, &via686a_group);
sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
if ((err = i2c_detach_client(client)))
return err;
release_region(client->addr, VIA686A_EXTENT);
release_region(data->addr, VIA686A_EXTENT);
platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
}
static void via686a_init_client(struct i2c_client *client)
static void __devinit via686a_init_device(struct via686a_data *data)
{
u8 reg;
/* Start monitoring */
reg = via686a_read_value(client, VIA686A_REG_CONFIG);
via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F);
reg = via686a_read_value(data, VIA686A_REG_CONFIG);
via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
/* Configure temp interrupt mode for continuous-interrupt operation */
via686a_write_value(client, VIA686A_REG_TEMP_MODE,
via686a_read_value(client, VIA686A_REG_TEMP_MODE) &
!(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS));
reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
via686a_write_value(data, VIA686A_REG_TEMP_MODE,
(reg & ~VIA686A_TEMP_MODE_MASK)
| VIA686A_TEMP_MODE_CONTINUOUS);
}
static struct via686a_data *via686a_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
struct via686a_data *data = dev_get_drvdata(dev);
int i;
mutex_lock(&data->update_lock);
@ -757,27 +684,27 @@ static struct via686a_data *via686a_update_device(struct device *dev)
|| !data->valid) {
for (i = 0; i <= 4; i++) {
data->in[i] =
via686a_read_value(client, VIA686A_REG_IN(i));
data->in_min[i] = via686a_read_value(client,
via686a_read_value(data, VIA686A_REG_IN(i));
data->in_min[i] = via686a_read_value(data,
VIA686A_REG_IN_MIN
(i));
data->in_max[i] =
via686a_read_value(client, VIA686A_REG_IN_MAX(i));
via686a_read_value(data, VIA686A_REG_IN_MAX(i));
}
for (i = 1; i <= 2; i++) {
data->fan[i - 1] =
via686a_read_value(client, VIA686A_REG_FAN(i));
data->fan_min[i - 1] = via686a_read_value(client,
via686a_read_value(data, VIA686A_REG_FAN(i));
data->fan_min[i - 1] = via686a_read_value(data,
VIA686A_REG_FAN_MIN(i));
}
for (i = 0; i <= 2; i++) {
data->temp[i] = via686a_read_value(client,
data->temp[i] = via686a_read_value(data,
VIA686A_REG_TEMP[i]) << 2;
data->temp_over[i] =
via686a_read_value(client,
via686a_read_value(data,
VIA686A_REG_TEMP_OVER[i]);
data->temp_hyst[i] =
via686a_read_value(client,
via686a_read_value(data,
VIA686A_REG_TEMP_HYST[i]);
}
/* add in lower 2 bits
@ -785,23 +712,23 @@ static struct via686a_data *via686a_update_device(struct device *dev)
temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
*/
data->temp[0] |= (via686a_read_value(client,
data->temp[0] |= (via686a_read_value(data,
VIA686A_REG_TEMP_LOW1)
& 0xc0) >> 6;
data->temp[1] |=
(via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
(via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
0x30) >> 4;
data->temp[2] |=
(via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
(via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
0xc0) >> 6;
i = via686a_read_value(client, VIA686A_REG_FANDIV);
i = via686a_read_value(data, VIA686A_REG_FANDIV);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = i >> 6;
data->alarms =
via686a_read_value(client,
via686a_read_value(data,
VIA686A_REG_ALARM1) |
(via686a_read_value(client, VIA686A_REG_ALARM2) << 8);
(via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
data->last_updated = jiffies;
data->valid = 1;
}
@ -818,32 +745,102 @@ static struct pci_device_id via686a_pci_ids[] = {
MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
static int __devinit via686a_device_add(unsigned short address)
{
struct resource res = {
.start = address,
.end = address + VIA686A_EXTENT - 1,
.name = "via686a",
.flags = IORESOURCE_IO,
};
int err;
pdev = platform_device_alloc("via686a", address);
if (!pdev) {
err = -ENOMEM;
printk(KERN_ERR "via686a: Device allocation failed\n");
goto exit;
}
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
printk(KERN_ERR "via686a: Device resource addition failed "
"(%d)\n", err);
goto exit_device_put;
}
err = platform_device_add(pdev);
if (err) {
printk(KERN_ERR "via686a: Device addition failed (%d)\n",
err);
goto exit_device_put;
}
return 0;
exit_device_put:
platform_device_put(pdev);
exit:
return err;
}
static int __devinit via686a_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
u16 val;
u16 address, val;
if (force_addr) {
address = force_addr & ~(VIA686A_EXTENT - 1);
dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
return -ENODEV;
}
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_word(dev, VIA686A_BASE_REG, &val))
return -ENODEV;
address = val & ~(VIA686A_EXTENT - 1);
if (address == 0 && force_addr == 0) {
if (address == 0) {
dev_err(&dev->dev, "base address not set - upgrade BIOS "
"or use force_addr=0xaddr\n");
return -ENODEV;
}
s_bridge = pci_dev_get(dev);
if (i2c_isa_add_driver(&via686a_driver)) {
pci_dev_put(s_bridge);
s_bridge = NULL;
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
return -ENODEV;
if (!(val & 0x0001)) {
if (!force_addr) {
dev_warn(&dev->dev, "Sensors disabled, enable "
"with force_addr=0x%x\n", address);
return -ENODEV;
}
dev_warn(&dev->dev, "Enabling sensors\n");
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(dev, VIA686A_ENABLE_REG,
val | 0x0001))
return -ENODEV;
}
if (platform_driver_register(&via686a_driver))
goto exit;
/* Sets global pdev as a side effect */
if (via686a_device_add(address))
goto exit_unregister;
/* Always return failure here. This is to allow other drivers to bind
* to this pci device. We don't really want to have control over the
* pci device, we only wanted to read as few register values from it.
*/
s_bridge = pci_dev_get(dev);
return -ENODEV;
exit_unregister:
platform_driver_unregister(&via686a_driver);
exit:
return -ENODEV;
}
@ -862,7 +859,8 @@ static void __exit sm_via686a_exit(void)
{
pci_unregister_driver(&via686a_pci_driver);
if (s_bridge != NULL) {
i2c_isa_del_driver(&via686a_driver);
platform_device_unregister(pdev);
platform_driver_unregister(&via686a_driver);
pci_dev_put(s_bridge);
s_bridge = NULL;
}

View file

@ -29,8 +29,7 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/i2c-isa.h>
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
@ -42,10 +41,7 @@ static int force_addr;
module_param(force_addr, int, 0);
MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors");
/* Device address
Note that we can't determine the ISA address until we have initialized
our module */
static unsigned short isa_address;
static struct platform_device *pdev;
#define VT8231_EXTENT 0x80
#define VT8231_BASE_REG 0x70
@ -148,7 +144,9 @@ static inline u8 FAN_TO_REG(long rpm, int div)
#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : 1310720 / ((val) * (div)))
struct vt8231_data {
struct i2c_client client;
unsigned short addr;
const char *name;
struct mutex update_lock;
struct class_device *class_dev;
char valid; /* !=0 if following fields are valid */
@ -168,20 +166,20 @@ struct vt8231_data {
};
static struct pci_dev *s_bridge;
static int vt8231_detect(struct i2c_adapter *adapter);
static int vt8231_detach_client(struct i2c_client *client);
static int vt8231_probe(struct platform_device *pdev);
static int vt8231_remove(struct platform_device *pdev);
static struct vt8231_data *vt8231_update_device(struct device *dev);
static void vt8231_init_client(struct i2c_client *client);
static void vt8231_init_device(struct vt8231_data *data);
static inline int vt8231_read_value(struct i2c_client *client, u8 reg)
static inline int vt8231_read_value(struct vt8231_data *data, u8 reg)
{
return inb_p(client->addr + reg);
return inb_p(data->addr + reg);
}
static inline void vt8231_write_value(struct i2c_client *client, u8 reg,
static inline void vt8231_write_value(struct vt8231_data *data, u8 reg,
u8 value)
{
outb_p(value, client->addr + reg);
outb_p(value, data->addr + reg);
}
/* following are the sysfs callback functions */
@ -220,13 +218,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct vt8231_data *data = i2c_get_clientdata(client);
struct vt8231_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
vt8231_write_value(client, regvoltmin[nr], data->in_min[nr]);
vt8231_write_value(data, regvoltmin[nr], data->in_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@ -236,13 +233,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct vt8231_data *data = i2c_get_clientdata(client);
struct vt8231_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
vt8231_write_value(client, regvoltmax[nr], data->in_max[nr]);
vt8231_write_value(data, regvoltmax[nr], data->in_max[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@ -278,14 +274,13 @@ static ssize_t show_in5_max(struct device *dev, struct device_attribute *attr,
static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct vt8231_data *data = i2c_get_clientdata(client);
struct vt8231_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
0, 255);
vt8231_write_value(client, regvoltmin[5], data->in_min[5]);
vt8231_write_value(data, regvoltmin[5], data->in_min[5]);
mutex_unlock(&data->update_lock);
return count;
}
@ -293,14 +288,13 @@ static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr,
static ssize_t set_in5_max(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct vt8231_data *data = i2c_get_clientdata(client);
struct vt8231_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
0, 255);
vt8231_write_value(client, regvoltmax[5], data->in_max[5]);
vt8231_write_value(data, regvoltmax[5], data->in_max[5]);
mutex_unlock(&data->update_lock);
return count;
}
@ -348,26 +342,24 @@ static ssize_t show_temp0_min(struct device *dev, struct device_attribute *attr,
static ssize_t set_temp0_max(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct vt8231_data *data = i2c_get_clientdata(client);
struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_max[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
vt8231_write_value(client, regtempmax[0], data->temp_max[0]);
vt8231_write_value(data, regtempmax[0], data->temp_max[0]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t set_temp0_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct vt8231_data *data = i2c_get_clientdata(client);
struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_min[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
vt8231_write_value(client, regtempmin[0], data->temp_min[0]);
vt8231_write_value(data, regtempmin[0], data->temp_min[0]);
mutex_unlock(&data->update_lock);
return count;
}
@ -404,13 +396,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct vt8231_data *data = i2c_get_clientdata(client);
struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_max[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
vt8231_write_value(client, regtempmax[nr], data->temp_max[nr]);
vt8231_write_value(data, regtempmax[nr], data->temp_max[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@ -419,13 +410,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct vt8231_data *data = i2c_get_clientdata(client);
struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_min[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
vt8231_write_value(client, regtempmin[nr], data->temp_min[nr]);
vt8231_write_value(data, regtempmin[nr], data->temp_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@ -486,13 +476,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct i2c_client *client = to_i2c_client(dev);
struct vt8231_data *data = i2c_get_clientdata(client);
struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
vt8231_write_value(data, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@ -500,12 +489,11 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct vt8231_data *data = i2c_get_clientdata(client);
struct vt8231_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
unsigned long val = simple_strtoul(buf, NULL, 10);
int nr = sensor_attr->index;
int old = vt8231_read_value(client, VT8231_REG_FANDIV);
int old = vt8231_read_value(data, VT8231_REG_FANDIV);
long min = FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr]));
@ -516,7 +504,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
case 4: data->fan_div[nr] = 2; break;
case 8: data->fan_div[nr] = 3; break;
default:
dev_err(&client->dev, "fan_div value %ld not supported."
dev_err(dev, "fan_div value %ld not supported."
"Choose one of 1, 2, 4 or 8!\n", val);
mutex_unlock(&data->update_lock);
return -EINVAL;
@ -524,10 +512,10 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
/* Correct the fan minimum speed */
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
vt8231_write_value(data, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
vt8231_write_value(client, VT8231_REG_FANDIV, old);
vt8231_write_value(data, VT8231_REG_FANDIV, old);
mutex_unlock(&data->update_lock);
return count;
}
@ -551,9 +539,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
struct vt8231_data *data = vt8231_update_device(dev);
return sprintf(buf, "%d\n", data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static ssize_t show_name(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct vt8231_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", data->name);
}
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static struct attribute *vt8231_attributes_temps[6][4] = {
{
&dev_attr_temp1_input.attr,
@ -648,6 +643,7 @@ static struct attribute *vt8231_attributes[] = {
&sensor_dev_attr_fan1_div.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_name.attr,
NULL
};
@ -655,13 +651,13 @@ static const struct attribute_group vt8231_group = {
.attrs = vt8231_attributes,
};
static struct i2c_driver vt8231_driver = {
static struct platform_driver vt8231_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "vt8231",
},
.attach_adapter = vt8231_detect,
.detach_client = vt8231_detach_client,
.probe = vt8231_probe,
.remove = __devexit_p(vt8231_remove),
};
static struct pci_device_id vt8231_pci_ids[] = {
@ -680,40 +676,18 @@ static struct pci_driver vt8231_pci_driver = {
.probe = vt8231_pci_probe,
};
int vt8231_detect(struct i2c_adapter *adapter)
int vt8231_probe(struct platform_device *pdev)
{
struct i2c_client *client;
struct resource *res;
struct vt8231_data *data;
int err = 0, i;
u16 val;
/* 8231 requires multiple of 256 */
if (force_addr) {
isa_address = force_addr & 0xFF00;
dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n",
isa_address);
if (PCIBIOS_SUCCESSFUL != pci_write_config_word(s_bridge,
VT8231_BASE_REG, isa_address))
return -ENODEV;
}
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_word(s_bridge, VT8231_ENABLE_REG, &val))
return -ENODEV;
if (!(val & 0x0001)) {
dev_warn(&adapter->dev, "enabling sensors\n");
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(s_bridge, VT8231_ENABLE_REG,
val | 0x0001))
return -ENODEV;
}
/* Reserve the ISA region */
if (!request_region(isa_address, VT8231_EXTENT,
vt8231_pci_driver.name)) {
dev_err(&adapter->dev, "region 0x%x already in use!\n",
isa_address);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!request_region(res->start, VT8231_EXTENT,
vt8231_driver.driver.name)) {
dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
(unsigned long)res->start, (unsigned long)res->end);
return -ENODEV;
}
@ -722,33 +696,23 @@ int vt8231_detect(struct i2c_adapter *adapter)
goto exit_release;
}
client = &data->client;
i2c_set_clientdata(client, data);
client->addr = isa_address;
client->adapter = adapter;
client->driver = &vt8231_driver;
/* Fill in the remaining client fields and put into the global list */
strlcpy(client->name, "vt8231", I2C_NAME_SIZE);
platform_set_drvdata(pdev, data);
data->addr = res->start;
data->name = "vt8231";
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(client)))
goto exit_free;
vt8231_init_client(client);
vt8231_init_device(data);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&client->dev.kobj, &vt8231_group)))
goto exit_detach;
if ((err = sysfs_create_group(&pdev->dev.kobj, &vt8231_group)))
goto exit_free;
/* Must update device information to find out the config field */
data->uch_config = vt8231_read_value(client, VT8231_REG_UCH_CONFIG);
data->uch_config = vt8231_read_value(data, VT8231_REG_UCH_CONFIG);
for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) {
if (ISTEMP(i, data->uch_config)) {
if ((err = sysfs_create_group(&client->dev.kobj,
if ((err = sysfs_create_group(&pdev->dev.kobj,
&vt8231_group_temps[i])))
goto exit_remove_files;
}
@ -756,13 +720,13 @@ int vt8231_detect(struct i2c_adapter *adapter)
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) {
if (ISVOLT(i, data->uch_config)) {
if ((err = sysfs_create_group(&client->dev.kobj,
if ((err = sysfs_create_group(&pdev->dev.kobj,
&vt8231_group_volts[i])))
goto exit_remove_files;
}
}
data->class_dev = hwmon_device_register(&client->dev);
data->class_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto exit_remove_files;
@ -771,56 +735,52 @@ int vt8231_detect(struct i2c_adapter *adapter)
exit_remove_files:
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
sysfs_remove_group(&client->dev.kobj, &vt8231_group);
exit_detach:
i2c_detach_client(client);
exit_free:
platform_set_drvdata(pdev, NULL);
kfree(data);
exit_release:
release_region(isa_address, VT8231_EXTENT);
release_region(res->start, VT8231_EXTENT);
return err;
}
static int vt8231_detach_client(struct i2c_client *client)
static int vt8231_remove(struct platform_device *pdev)
{
struct vt8231_data *data = i2c_get_clientdata(client);
int err, i;
struct vt8231_data *data = platform_get_drvdata(pdev);
int i;
hwmon_device_unregister(data->class_dev);
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
sysfs_remove_group(&client->dev.kobj, &vt8231_group);
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
if ((err = i2c_detach_client(client))) {
return err;
}
release_region(client->addr, VT8231_EXTENT);
release_region(data->addr, VT8231_EXTENT);
platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
}
static void vt8231_init_client(struct i2c_client *client)
static void vt8231_init_device(struct vt8231_data *data)
{
vt8231_write_value(client, VT8231_REG_TEMP1_CONFIG, 0);
vt8231_write_value(client, VT8231_REG_TEMP2_CONFIG, 0);
vt8231_write_value(data, VT8231_REG_TEMP1_CONFIG, 0);
vt8231_write_value(data, VT8231_REG_TEMP2_CONFIG, 0);
}
static struct vt8231_data *vt8231_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct vt8231_data *data = i2c_get_clientdata(client);
struct vt8231_data *data = dev_get_drvdata(dev);
int i;
u16 low;
@ -830,41 +790,41 @@ static struct vt8231_data *vt8231_update_device(struct device *dev)
|| !data->valid) {
for (i = 0; i < 6; i++) {
if (ISVOLT(i, data->uch_config)) {
data->in[i] = vt8231_read_value(client,
data->in[i] = vt8231_read_value(data,
regvolt[i]);
data->in_min[i] = vt8231_read_value(client,
data->in_min[i] = vt8231_read_value(data,
regvoltmin[i]);
data->in_max[i] = vt8231_read_value(client,
data->in_max[i] = vt8231_read_value(data,
regvoltmax[i]);
}
}
for (i = 0; i < 2; i++) {
data->fan[i] = vt8231_read_value(client,
data->fan[i] = vt8231_read_value(data,
VT8231_REG_FAN(i));
data->fan_min[i] = vt8231_read_value(client,
data->fan_min[i] = vt8231_read_value(data,
VT8231_REG_FAN_MIN(i));
}
low = vt8231_read_value(client, VT8231_REG_TEMP_LOW01);
low = vt8231_read_value(data, VT8231_REG_TEMP_LOW01);
low = (low >> 6) | ((low & 0x30) >> 2)
| (vt8231_read_value(client, VT8231_REG_TEMP_LOW25) << 4);
| (vt8231_read_value(data, VT8231_REG_TEMP_LOW25) << 4);
for (i = 0; i < 6; i++) {
if (ISTEMP(i, data->uch_config)) {
data->temp[i] = (vt8231_read_value(client,
data->temp[i] = (vt8231_read_value(data,
regtemp[i]) << 2)
| ((low >> (2 * i)) & 0x03);
data->temp_max[i] = vt8231_read_value(client,
data->temp_max[i] = vt8231_read_value(data,
regtempmax[i]);
data->temp_min[i] = vt8231_read_value(client,
data->temp_min[i] = vt8231_read_value(data,
regtempmin[i]);
}
}
i = vt8231_read_value(client, VT8231_REG_FANDIV);
i = vt8231_read_value(data, VT8231_REG_FANDIV);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = i >> 6;
data->alarms = vt8231_read_value(client, VT8231_REG_ALARM1) |
(vt8231_read_value(client, VT8231_REG_ALARM2) << 8);
data->alarms = vt8231_read_value(data, VT8231_REG_ALARM1) |
(vt8231_read_value(data, VT8231_REG_ALARM2) << 8);
/* Set alarm flags correctly */
if (!data->fan[0] && data->fan_min[0]) {
@ -888,33 +848,102 @@ static struct vt8231_data *vt8231_update_device(struct device *dev)
return data;
}
static int __devinit vt8231_device_add(unsigned short address)
{
struct resource res = {
.start = address,
.end = address + VT8231_EXTENT - 1,
.name = "vt8231",
.flags = IORESOURCE_IO,
};
int err;
pdev = platform_device_alloc("vt8231", address);
if (!pdev) {
err = -ENOMEM;
printk(KERN_ERR "vt8231: Device allocation failed\n");
goto exit;
}
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
printk(KERN_ERR "vt8231: Device resource addition failed "
"(%d)\n", err);
goto exit_device_put;
}
err = platform_device_add(pdev);
if (err) {
printk(KERN_ERR "vt8231: Device addition failed (%d)\n",
err);
goto exit_device_put;
}
return 0;
exit_device_put:
platform_device_put(pdev);
exit:
return err;
}
static int __devinit vt8231_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
u16 val;
u16 address, val;
if (force_addr) {
address = force_addr & 0xff00;
dev_warn(&dev->dev, "Forcing ISA address 0x%x\n",
address);
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(dev, VT8231_BASE_REG, address | 1))
return -ENODEV;
}
if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_BASE_REG,
&val))
return -ENODEV;
isa_address = val & ~(VT8231_EXTENT - 1);
if (isa_address == 0 && force_addr == 0) {
address = val & ~(VT8231_EXTENT - 1);
if (address == 0) {
dev_err(&dev->dev, "base address not set -\
upgrade BIOS or use force_addr=0xaddr\n");
return -ENODEV;
}
s_bridge = pci_dev_get(dev);
if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_ENABLE_REG,
&val))
return -ENODEV;
if (i2c_isa_add_driver(&vt8231_driver)) {
pci_dev_put(s_bridge);
s_bridge = NULL;
if (!(val & 0x0001)) {
dev_warn(&dev->dev, "enabling sensors\n");
if (PCIBIOS_SUCCESSFUL !=
pci_write_config_word(dev, VT8231_ENABLE_REG,
val | 0x0001))
return -ENODEV;
}
if (platform_driver_register(&vt8231_driver))
goto exit;
/* Sets global pdev as a side effect */
if (vt8231_device_add(address))
goto exit_unregister;
/* Always return failure here. This is to allow other drivers to bind
* to this pci device. We don't really want to have control over the
* pci device, we only wanted to read as few register values from it.
*/
/* We do, however, mark ourselves as using the PCI device to stop it
getting unloaded. */
s_bridge = pci_dev_get(dev);
return -ENODEV;
exit_unregister:
platform_driver_unregister(&vt8231_driver);
exit:
return -ENODEV;
}
@ -927,7 +956,8 @@ static void __exit sm_vt8231_exit(void)
{
pci_unregister_driver(&vt8231_pci_driver);
if (s_bridge != NULL) {
i2c_isa_del_driver(&vt8231_driver);
platform_device_unregister(pdev);
platform_driver_unregister(&vt8231_driver);
pci_dev_put(s_bridge);
s_bridge = NULL;
}

File diff suppressed because it is too large Load diff

View file

@ -220,6 +220,18 @@ static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])
#define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */
#define W83637HF_REG_PWM_FREQ1 0x00 /* 697HF/687THF too */
#define W83637HF_REG_PWM_FREQ2 0x02 /* 697HF/687THF too */
#define W83637HF_REG_PWM_FREQ3 0x10 /* 687THF too */
static const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1,
W83637HF_REG_PWM_FREQ2,
W83637HF_REG_PWM_FREQ3 };
#define W83627HF_BASE_PWM_FREQ 46870
#define W83781D_REG_I2C_ADDR 0x48
#define W83781D_REG_I2C_SUBADDR 0x4A
@ -267,6 +279,49 @@ static int TEMP_FROM_REG(u8 reg)
#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
{
unsigned long freq;
freq = W83627HF_BASE_PWM_FREQ >> reg;
return freq;
}
static inline u8 pwm_freq_to_reg_627hf(unsigned long val)
{
u8 i;
/* Only 5 dividers (1 2 4 8 16)
Search for the nearest available frequency */
for (i = 0; i < 4; i++) {
if (val > (((W83627HF_BASE_PWM_FREQ >> i) +
(W83627HF_BASE_PWM_FREQ >> (i+1))) / 2))
break;
}
return i;
}
static inline unsigned long pwm_freq_from_reg(u8 reg)
{
/* Clock bit 8 -> 180 kHz or 24 MHz */
unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL;
reg &= 0x7f;
/* This should not happen but anyway... */
if (reg == 0)
reg++;
return (clock / (reg << 8));
}
static inline u8 pwm_freq_to_reg(unsigned long val)
{
/* Minimum divider value is 0x01 and maximum is 0x7F */
if (val >= 93750) /* The highest we can do */
return 0x01;
if (val >= 720) /* Use 24 MHz clock */
return (24000000UL / (val << 8));
if (val < 6) /* The lowest we can do */
return 0xFF;
else /* Use 180 kHz clock */
return (0x80 | (180000UL / (val << 8)));
}
#define BEEP_MASK_FROM_REG(val) (val)
#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff)
#define BEEP_ENABLE_TO_REG(val) ((val)?1:0)
@ -316,6 +371,7 @@ struct w83627hf_data {
u32 beep_mask; /* Register encoding, combined */
u8 beep_enable; /* Boolean */
u8 pwm[3]; /* Register value */
u8 pwm_freq[3]; /* Register value */
u16 sens[3]; /* 782D/783S only.
1 = pentium diode; 2 = 3904 diode;
3000-5000 = thermistor beta.
@ -851,6 +907,64 @@ sysfs_pwm(1);
sysfs_pwm(2);
sysfs_pwm(3);
static ssize_t
show_pwm_freq_reg(struct device *dev, char *buf, int nr)
{
struct w83627hf_data *data = w83627hf_update_device(dev);
if (data->type == w83627hf)
return sprintf(buf, "%ld\n",
pwm_freq_from_reg_627hf(data->pwm_freq[nr - 1]));
else
return sprintf(buf, "%ld\n",
pwm_freq_from_reg(data->pwm_freq[nr - 1]));
}
static ssize_t
store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr)
{
struct w83627hf_data *data = dev_get_drvdata(dev);
static const u8 mask[]={0xF8, 0x8F};
u32 val;
val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
if (data->type == w83627hf) {
data->pwm_freq[nr - 1] = pwm_freq_to_reg_627hf(val);
w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
(data->pwm_freq[nr - 1] << ((nr - 1)*4)) |
(w83627hf_read_value(data,
W83627HF_REG_PWM_FREQ) & mask[nr - 1]));
} else {
data->pwm_freq[nr - 1] = pwm_freq_to_reg(val);
w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr - 1],
data->pwm_freq[nr - 1]);
}
mutex_unlock(&data->update_lock);
return count;
}
#define sysfs_pwm_freq(offset) \
static ssize_t show_regs_pwm_freq_##offset(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
return show_pwm_freq_reg(dev, buf, offset); \
} \
static ssize_t \
store_regs_pwm_freq_##offset(struct device *dev, \
struct device_attribute *attr, const char *buf, size_t count) \
{ \
return store_pwm_freq_reg(dev, buf, count, offset); \
} \
static DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR, \
show_regs_pwm_freq_##offset, store_regs_pwm_freq_##offset);
sysfs_pwm_freq(1);
sysfs_pwm_freq(2);
sysfs_pwm_freq(3);
static ssize_t
show_sensor_reg(struct device *dev, char *buf, int nr)
{
@ -1077,6 +1191,9 @@ static struct attribute *w83627hf_attributes_opt[] = {
&dev_attr_pwm3.attr,
&dev_attr_pwm1_freq.attr,
&dev_attr_pwm2_freq.attr,
&dev_attr_pwm3_freq.attr,
NULL
};
@ -1139,7 +1256,9 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
|| (err = device_create_file(dev, &dev_attr_in5_max))
|| (err = device_create_file(dev, &dev_attr_in6_input))
|| (err = device_create_file(dev, &dev_attr_in6_min))
|| (err = device_create_file(dev, &dev_attr_in6_max)))
|| (err = device_create_file(dev, &dev_attr_in6_max))
|| (err = device_create_file(dev, &dev_attr_pwm1_freq))
|| (err = device_create_file(dev, &dev_attr_pwm2_freq)))
goto ERROR4;
if (data->type != w83697hf)
@ -1169,6 +1288,12 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
if ((err = device_create_file(dev, &dev_attr_pwm3)))
goto ERROR4;
if (data->type == w83637hf || data->type == w83687thf)
if ((err = device_create_file(dev, &dev_attr_pwm1_freq))
|| (err = device_create_file(dev, &dev_attr_pwm2_freq))
|| (err = device_create_file(dev, &dev_attr_pwm3_freq)))
goto ERROR4;
data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
@ -1181,6 +1306,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
sysfs_remove_group(&dev->kobj, &w83627hf_group);
sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
ERROR3:
platform_set_drvdata(pdev, NULL);
kfree(data);
ERROR1:
release_region(res->start, WINB_REGION_SIZE);
@ -1193,11 +1319,11 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
struct w83627hf_data *data = platform_get_drvdata(pdev);
struct resource *res;
platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
platform_set_drvdata(pdev, NULL);
kfree(data);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@ -1472,6 +1598,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
(data->type == w83627hf || data->type == w83697hf))
break;
}
if (data->type == w83627hf) {
u8 tmp = w83627hf_read_value(data,
W83627HF_REG_PWM_FREQ);
data->pwm_freq[0] = tmp & 0x07;
data->pwm_freq[1] = (tmp >> 4) & 0x07;
} else if (data->type != w83627thf) {
for (i = 1; i <= 3; i++) {
data->pwm_freq[i - 1] =
w83627hf_read_value(data,
W83637HF_REG_PWM_FREQ[i - 1]);
if (i == 2 && (data->type == w83697hf))
break;
}
}
data->temp = w83627hf_read_value(data, W83781D_REG_TEMP(1));
data->temp_max =
@ -1548,15 +1688,12 @@ static int __init w83627hf_device_add(unsigned short address,
goto exit_device_put;
}
pdev->dev.platform_data = kmalloc(sizeof(struct w83627hf_sio_data),
GFP_KERNEL);
if (!pdev->dev.platform_data) {
err = -ENOMEM;
err = platform_device_add_data(pdev, sio_data,
sizeof(struct w83627hf_sio_data));
if (err) {
printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
goto exit_device_put;
}
memcpy(pdev->dev.platform_data, sio_data,
sizeof(struct w83627hf_sio_data));
err = platform_device_add(pdev);
if (err) {

View file

@ -237,9 +237,6 @@ config I2C_IOP3XX
This driver can also be built as a module. If so, the module
will be called i2c-iop3xx.
config I2C_ISA
tristate
config I2C_IXP4XX
tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)"
depends on ARCH_IXP4XX

View file

@ -18,7 +18,6 @@ obj-$(CONFIG_I2C_I801) += i2c-i801.o
obj-$(CONFIG_I2C_I810) += i2c-i810.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_ISA) += i2c-isa.o
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o
obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o

View file

@ -1,192 +0,0 @@
/*
i2c-isa.c - an i2c-core-like thing for ISA hardware monitoring chips
Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
Based on the i2c-isa pseudo-adapter from the lm_sensors project
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* This implements an i2c-core-like thing for ISA hardware monitoring
chips. Such chips are linked to the i2c subsystem for historical
reasons (because the early ISA hardware monitoring chips such as the
LM78 had both an I2C and an ISA interface). They used to be
registered with the main i2c-core, but as a first step in the
direction of a clean separation between I2C and ISA chip drivers,
we now have this separate core for ISA ones. It is significantly
more simple than the real one, of course, because we don't have to
handle multiple busses: there is only one (fake) ISA adapter.
It is worth noting that we still rely on i2c-core for some things
at the moment - but hopefully this won't last. */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/i2c-isa.h>
#include <linux/platform_device.h>
#include <linux/completion.h>
/* Exported by i2c-core for i2c-isa only */
extern void i2c_adapter_dev_release(struct device *dev);
extern struct class i2c_adapter_class;
static u32 isa_func(struct i2c_adapter *adapter);
/* This is the actual algorithm we define */
static const struct i2c_algorithm isa_algorithm = {
.functionality = isa_func,
};
/* There can only be one... */
static struct i2c_adapter isa_adapter = {
.owner = THIS_MODULE,
.id = I2C_HW_ISA,
.class = I2C_CLASS_HWMON,
.algo = &isa_algorithm,
.name = "ISA main adapter",
};
/* We can't do a thing... */
static u32 isa_func(struct i2c_adapter *adapter)
{
return 0;
}
/* We implement an interface which resembles i2c_{add,del}_driver,
but for i2c-isa drivers. We don't have to remember and handle lists
of drivers and adapters so this is much more simple, of course. */
int i2c_isa_add_driver(struct i2c_driver *driver)
{
int res;
/* Add the driver to the list of i2c drivers in the driver core */
driver->driver.bus = &i2c_bus_type;
res = driver_register(&driver->driver);
if (res)
return res;
dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->driver.name);
/* Now look for clients */
res = driver->attach_adapter(&isa_adapter);
if (res) {
dev_dbg(&isa_adapter.dev,
"Driver %s failed to attach adapter, unregistering\n",
driver->driver.name);
driver_unregister(&driver->driver);
}
return res;
}
int i2c_isa_del_driver(struct i2c_driver *driver)
{
struct list_head *item, *_n;
struct i2c_client *client;
int res;
/* Detach all clients belonging to this one driver */
list_for_each_safe(item, _n, &isa_adapter.clients) {
client = list_entry(item, struct i2c_client, list);
if (client->driver != driver)
continue;
dev_dbg(&isa_adapter.dev, "Detaching client %s at 0x%x\n",
client->name, client->addr);
if ((res = driver->detach_client(client))) {
dev_err(&isa_adapter.dev, "Failed, driver "
"%s not unregistered!\n",
driver->driver.name);
return res;
}
}
/* Get the driver off the core list */
driver_unregister(&driver->driver);
dev_dbg(&isa_adapter.dev, "Driver %s unregistered\n", driver->driver.name);
return 0;
}
static int __init i2c_isa_init(void)
{
int err;
mutex_init(&isa_adapter.clist_lock);
INIT_LIST_HEAD(&isa_adapter.clients);
isa_adapter.nr = ANY_I2C_ISA_BUS;
isa_adapter.dev.parent = &platform_bus;
sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
isa_adapter.dev.release = &i2c_adapter_dev_release;
isa_adapter.dev.class = &i2c_adapter_class;
err = device_register(&isa_adapter.dev);
if (err) {
printk(KERN_ERR "i2c-isa: Failed to register device\n");
goto exit;
}
dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
return 0;
exit:
return err;
}
static void __exit i2c_isa_exit(void)
{
#ifdef DEBUG
struct list_head *item, *_n;
struct i2c_client *client = NULL;
#endif
/* There should be no more active client */
#ifdef DEBUG
dev_dbg(&isa_adapter.dev, "Looking for clients\n");
list_for_each_safe(item, _n, &isa_adapter.clients) {
client = list_entry(item, struct i2c_client, list);
dev_err(&isa_adapter.dev, "Driver %s still has an active "
"ISA client at 0x%x\n", client->driver->driver.name,
client->addr);
}
if (client != NULL)
return;
#endif
/* Clean up the sysfs representation */
dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n");
init_completion(&isa_adapter.dev_released);
device_unregister(&isa_adapter.dev);
/* Wait for sysfs to drop all references */
dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n");
wait_for_completion(&isa_adapter.dev_released);
dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name);
}
EXPORT_SYMBOL(i2c_isa_add_driver);
EXPORT_SYMBOL(i2c_isa_del_driver);
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
MODULE_DESCRIPTION("ISA bus access through i2c");
MODULE_LICENSE("GPL");
module_init(i2c_isa_init);
module_exit(i2c_isa_exit);

View file

@ -288,7 +288,6 @@ void i2c_adapter_dev_release(struct device *dev)
struct i2c_adapter *adap = to_i2c_adapter(dev);
complete(&adap->dev_released);
}
EXPORT_SYMBOL_GPL(i2c_adapter_dev_release); /* exported to i2c-isa */
static ssize_t
show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
@ -307,7 +306,6 @@ struct class i2c_adapter_class = {
.name = "i2c-adapter",
.dev_attrs = i2c_adapter_attrs,
};
EXPORT_SYMBOL_GPL(i2c_adapter_class); /* exported to i2c-isa */
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{

View file

@ -1,36 +0,0 @@
/*
* i2c-isa.h - definitions for the i2c-isa pseudo-i2c-adapter interface
*
* Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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.
*/
#ifndef _LINUX_I2C_ISA_H
#define _LINUX_I2C_ISA_H
#include <linux/i2c.h>
extern int i2c_isa_add_driver(struct i2c_driver *driver);
extern int i2c_isa_del_driver(struct i2c_driver *driver);
/* Detect whether we are on the isa bus. This is only useful to hybrid
(i2c+isa) drivers. */
#define i2c_is_isa_adapter(adapptr) \
((adapptr)->id == I2C_HW_ISA)
#define i2c_is_isa_client(clientptr) \
i2c_is_isa_adapter((clientptr)->adapter)
#endif /* _LINUX_I2C_ISA_H */

View file

@ -368,7 +368,6 @@ struct i2c_client_address_data {
/* The numbers to use to set I2C bus address */
#define ANY_I2C_BUS 0xffff
#define ANY_I2C_ISA_BUS 9191
/* ----- functions exported by i2c.o */