mirror of
https://github.com/fail0verflow/switch-linux.git
synced 2025-05-04 02:34:21 -04:00
Merge branch 'hwmon-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6
* 'hwmon-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6: hwmon: (fschmd) Add support for the FSC Hades IC hwmon: (fschmd) Add support for the FSC Syleus IC i2c-i801: Instantiate FSC hardware montioring chips dmi: Let dmi_walk() users pass private data hwmon: Define a standard interface for chassis intrusion detection Move the pcf8591 driver to hwmon hwmon: (w83627ehf) Only expose in6 or temp3 on the W83667HG hwmon: (w83627ehf) Add support for W83667HG hwmon: (w83627ehf) Invert fan pin variables logic hwmon: (hdaps) Fix Thinkpad X41 axis inversion hwmon: (hdaps) Allow inversion of separate axis hwmon: (ds1621) Clean up documentation hwmon: (ds1621) Avoid unneeded register access hwmon: (ds1621) Clean up register access hwmon: (ds1621) Reorder code statements
This commit is contained in:
commit
3c6fae67d0
18 changed files with 588 additions and 327 deletions
|
@ -49,12 +49,9 @@ of up to +/- 0.5 degrees even when compared against precise temperature
|
||||||
readings. Be sure to have a high vs. low temperature limit gap of al least
|
readings. Be sure to have a high vs. low temperature limit gap of al least
|
||||||
1.0 degree Celsius to avoid Tout "bouncing", though!
|
1.0 degree Celsius to avoid Tout "bouncing", though!
|
||||||
|
|
||||||
As for alarms, you can read the alarm status of the DS1621 via the 'alarms'
|
The alarm bits are set when the high or low limits are met or exceeded and
|
||||||
/sys file interface. The result consists mainly of bit 6 and 5 of the
|
are reset by the module as soon as the respective temperature ranges are
|
||||||
configuration register of the chip; bit 6 (0x40 or 64) is the high alarm
|
left.
|
||||||
bit and bit 5 (0x20 or 32) the low one. These bits are set when the high or
|
|
||||||
low limits are met or exceeded and are reset by the module as soon as the
|
|
||||||
respective temperature ranges are left.
|
|
||||||
|
|
||||||
The alarm registers are in no way suitable to find out about the actual
|
The alarm registers are in no way suitable to find out about the actual
|
||||||
status of Tout. They will only tell you about its history, whether or not
|
status of Tout. They will only tell you about its history, whether or not
|
||||||
|
@ -64,45 +61,3 @@ with neither of the alarms set.
|
||||||
|
|
||||||
Temperature conversion of the DS1621 takes up to 1000ms; internal access to
|
Temperature conversion of the DS1621 takes up to 1000ms; internal access to
|
||||||
non-volatile registers may last for 10ms or below.
|
non-volatile registers may last for 10ms or below.
|
||||||
|
|
||||||
High Accuracy Temperature Reading
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
As said before, the temperature issued via the 9-bit i2c-bus data is
|
|
||||||
somewhat arbitrary. Internally, the temperature conversion is of a
|
|
||||||
different kind that is explained (not so...) well in the DS1621 data sheet.
|
|
||||||
To cut the long story short: Inside the DS1621 there are two oscillators,
|
|
||||||
both of them biassed by a temperature coefficient.
|
|
||||||
|
|
||||||
Higher resolution of the temperature reading can be achieved using the
|
|
||||||
internal projection, which means taking account of REG_COUNT and REG_SLOPE
|
|
||||||
(the driver manages them):
|
|
||||||
|
|
||||||
Taken from Dallas Semiconductors App Note 068: 'Increasing Temperature
|
|
||||||
Resolution on the DS1620' and App Note 105: 'High Resolution Temperature
|
|
||||||
Measurement with Dallas Direct-to-Digital Temperature Sensors'
|
|
||||||
|
|
||||||
- Read the 9-bit temperature and strip the LSB (Truncate the .5 degs)
|
|
||||||
- The resulting value is TEMP_READ.
|
|
||||||
- Then, read REG_COUNT.
|
|
||||||
- And then, REG_SLOPE.
|
|
||||||
|
|
||||||
TEMP = TEMP_READ - 0.25 + ((REG_SLOPE - REG_COUNT) / REG_SLOPE)
|
|
||||||
|
|
||||||
Note that this is what the DONE bit in the DS1621 configuration register is
|
|
||||||
good for: Internally, one temperature conversion takes up to 1000ms. Before
|
|
||||||
that conversion is complete you will not be able to read valid things out
|
|
||||||
of REG_COUNT and REG_SLOPE. The DONE bit, as you may have guessed by now,
|
|
||||||
tells you whether the conversion is complete ("done", in plain English) and
|
|
||||||
thus, whether the values you read are good or not.
|
|
||||||
|
|
||||||
The DS1621 has two modes of operation: "Continuous" conversion, which can
|
|
||||||
be understood as the default stand-alone mode where the chip gets the
|
|
||||||
temperature and controls external devices via its Tout pin or tells other
|
|
||||||
i2c's about it if they care. The other mode is called "1SHOT", that means
|
|
||||||
that it only figures out about the temperature when it is explicitly told
|
|
||||||
to do so; this can be seen as power saving mode.
|
|
||||||
|
|
||||||
Now if you want to read REG_COUNT and REG_SLOPE, you have to either stop
|
|
||||||
the continuous conversions until the contents of these registers are valid,
|
|
||||||
or, in 1SHOT mode, you have to have one conversion made.
|
|
||||||
|
|
|
@ -365,6 +365,7 @@ energy[1-*]_input Cumulative energy use
|
||||||
Unit: microJoule
|
Unit: microJoule
|
||||||
RO
|
RO
|
||||||
|
|
||||||
|
|
||||||
**********
|
**********
|
||||||
* Alarms *
|
* Alarms *
|
||||||
**********
|
**********
|
||||||
|
@ -453,6 +454,27 @@ beep_mask Bitmask for beep.
|
||||||
RW
|
RW
|
||||||
|
|
||||||
|
|
||||||
|
***********************
|
||||||
|
* Intrusion detection *
|
||||||
|
***********************
|
||||||
|
|
||||||
|
intrusion[0-*]_alarm
|
||||||
|
Chassis intrusion detection
|
||||||
|
0: OK
|
||||||
|
1: intrusion detected
|
||||||
|
RW
|
||||||
|
Contrary to regular alarm flags which clear themselves
|
||||||
|
automatically when read, this one sticks until cleared by
|
||||||
|
the user. This is done by writing 0 to the file. Writing
|
||||||
|
other values is unsupported.
|
||||||
|
|
||||||
|
intrusion[0-*]_beep
|
||||||
|
Chassis intrusion beep
|
||||||
|
0: disable
|
||||||
|
1: enable
|
||||||
|
RW
|
||||||
|
|
||||||
|
|
||||||
sysfs attribute writes interpretation
|
sysfs attribute writes interpretation
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -2,30 +2,40 @@ Kernel driver w83627ehf
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
Supported chips:
|
Supported chips:
|
||||||
* Winbond W83627EHF/EHG/DHG (ISA access ONLY)
|
* Winbond W83627EHF/EHG (ISA access ONLY)
|
||||||
Prefix: 'w83627ehf'
|
Prefix: 'w83627ehf'
|
||||||
Addresses scanned: ISA address retrieved from Super I/O registers
|
Addresses scanned: ISA address retrieved from Super I/O registers
|
||||||
Datasheet:
|
Datasheet:
|
||||||
http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf
|
http://www.nuvoton.com.tw/NR/rdonlyres/A6A258F0-F0C9-4F97-81C0-C4D29E7E943E/0/W83627EHF.pdf
|
||||||
DHG datasheet confidential.
|
* Winbond W83627DHG
|
||||||
|
Prefix: 'w83627dhg'
|
||||||
|
Addresses scanned: ISA address retrieved from Super I/O registers
|
||||||
|
Datasheet:
|
||||||
|
http://www.nuvoton.com.tw/NR/rdonlyres/7885623D-A487-4CF9-A47F-30C5F73D6FE6/0/W83627DHG.pdf
|
||||||
|
* Winbond W83667HG
|
||||||
|
Prefix: 'w83667hg'
|
||||||
|
Addresses scanned: ISA address retrieved from Super I/O registers
|
||||||
|
Datasheet: not available
|
||||||
|
|
||||||
Authors:
|
Authors:
|
||||||
Jean Delvare <khali@linux-fr.org>
|
Jean Delvare <khali@linux-fr.org>
|
||||||
Yuan Mu (Winbond)
|
Yuan Mu (Winbond)
|
||||||
Rudolf Marek <r.marek@assembler.cz>
|
Rudolf Marek <r.marek@assembler.cz>
|
||||||
David Hubbard <david.c.hubbard@gmail.com>
|
David Hubbard <david.c.hubbard@gmail.com>
|
||||||
|
Gong Jun <JGong@nuvoton.com>
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
This driver implements support for the Winbond W83627EHF, W83627EHG, and
|
This driver implements support for the Winbond W83627EHF, W83627EHG,
|
||||||
W83627DHG super I/O chips. We will refer to them collectively as Winbond chips.
|
W83627DHG and W83667HG super I/O chips. We will refer to them collectively
|
||||||
|
as Winbond chips.
|
||||||
|
|
||||||
The chips implement three temperature sensors, five fan rotation
|
The chips implement three temperature sensors, five fan rotation
|
||||||
speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
|
speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
|
||||||
VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG), alarms with beep
|
VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG), alarms
|
||||||
warnings (control unimplemented), and some automatic fan regulation
|
with beep warnings (control unimplemented), and some automatic fan
|
||||||
strategies (plus manual fan control mode).
|
regulation strategies (plus manual fan control mode).
|
||||||
|
|
||||||
Temperatures are measured in degrees Celsius and measurement resolution is 1
|
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
|
degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
|
||||||
|
@ -54,7 +64,8 @@ follows:
|
||||||
temp1 -> pwm1
|
temp1 -> pwm1
|
||||||
temp2 -> pwm2
|
temp2 -> pwm2
|
||||||
temp3 -> pwm3
|
temp3 -> pwm3
|
||||||
prog -> pwm4 (the programmable setting is not supported by the driver)
|
prog -> pwm4 (not on 667HG; the programmable setting is not supported by
|
||||||
|
the driver)
|
||||||
|
|
||||||
/sys files
|
/sys files
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -68,7 +68,8 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s)
|
||||||
* pointing to completely the wrong place for example
|
* pointing to completely the wrong place for example
|
||||||
*/
|
*/
|
||||||
static void dmi_table(u8 *buf, int len, int num,
|
static void dmi_table(u8 *buf, int len, int num,
|
||||||
void (*decode)(const struct dmi_header *))
|
void (*decode)(const struct dmi_header *, void *),
|
||||||
|
void *private_data)
|
||||||
{
|
{
|
||||||
u8 *data = buf;
|
u8 *data = buf;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -89,7 +90,7 @@ static void dmi_table(u8 *buf, int len, int num,
|
||||||
while ((data - buf < len - 1) && (data[0] || data[1]))
|
while ((data - buf < len - 1) && (data[0] || data[1]))
|
||||||
data++;
|
data++;
|
||||||
if (data - buf < len - 1)
|
if (data - buf < len - 1)
|
||||||
decode(dm);
|
decode(dm, private_data);
|
||||||
data += 2;
|
data += 2;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -99,7 +100,8 @@ static u32 dmi_base;
|
||||||
static u16 dmi_len;
|
static u16 dmi_len;
|
||||||
static u16 dmi_num;
|
static u16 dmi_num;
|
||||||
|
|
||||||
static int __init dmi_walk_early(void (*decode)(const struct dmi_header *))
|
static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
|
||||||
|
void *))
|
||||||
{
|
{
|
||||||
u8 *buf;
|
u8 *buf;
|
||||||
|
|
||||||
|
@ -107,7 +109,7 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *))
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
dmi_table(buf, dmi_len, dmi_num, decode);
|
dmi_table(buf, dmi_len, dmi_num, decode, NULL);
|
||||||
|
|
||||||
dmi_iounmap(buf, dmi_len);
|
dmi_iounmap(buf, dmi_len);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -295,7 +297,7 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm)
|
||||||
* and machine entries. For 2.5 we should pull the smbus controller info
|
* and machine entries. For 2.5 we should pull the smbus controller info
|
||||||
* out of here.
|
* out of here.
|
||||||
*/
|
*/
|
||||||
static void __init dmi_decode(const struct dmi_header *dm)
|
static void __init dmi_decode(const struct dmi_header *dm, void *dummy)
|
||||||
{
|
{
|
||||||
switch(dm->type) {
|
switch(dm->type) {
|
||||||
case 0: /* BIOS Information */
|
case 0: /* BIOS Information */
|
||||||
|
@ -598,10 +600,12 @@ int dmi_get_year(int field)
|
||||||
/**
|
/**
|
||||||
* dmi_walk - Walk the DMI table and get called back for every record
|
* dmi_walk - Walk the DMI table and get called back for every record
|
||||||
* @decode: Callback function
|
* @decode: Callback function
|
||||||
|
* @private_data: Private data to be passed to the callback function
|
||||||
*
|
*
|
||||||
* Returns -1 when the DMI table can't be reached, 0 on success.
|
* Returns -1 when the DMI table can't be reached, 0 on success.
|
||||||
*/
|
*/
|
||||||
int dmi_walk(void (*decode)(const struct dmi_header *))
|
int dmi_walk(void (*decode)(const struct dmi_header *, void *),
|
||||||
|
void *private_data)
|
||||||
{
|
{
|
||||||
u8 *buf;
|
u8 *buf;
|
||||||
|
|
||||||
|
@ -612,7 +616,7 @@ int dmi_walk(void (*decode)(const struct dmi_header *))
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
dmi_table(buf, dmi_len, dmi_num, decode);
|
dmi_table(buf, dmi_len, dmi_num, decode, private_data);
|
||||||
|
|
||||||
iounmap(buf);
|
iounmap(buf);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -343,12 +343,13 @@ config SENSORS_FSCPOS
|
||||||
will be called fscpos.
|
will be called fscpos.
|
||||||
|
|
||||||
config SENSORS_FSCHMD
|
config SENSORS_FSCHMD
|
||||||
tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles"
|
tristate "Fujitsu Siemens Computers sensor chips"
|
||||||
depends on X86 && I2C
|
depends on X86 && I2C
|
||||||
help
|
help
|
||||||
If you say yes here you get support for various Fujitsu Siemens
|
If you say yes here you get support for the following Fujitsu
|
||||||
Computers sensor chips, including support for the integrated
|
Siemens Computers (FSC) sensor chips: Poseidon, Scylla, Hermes,
|
||||||
watchdog.
|
Heimdall, Heracles, Hades and Syleus including support for the
|
||||||
|
integrated watchdog.
|
||||||
|
|
||||||
This is a merged driver for FSC sensor chips replacing the fscpos,
|
This is a merged driver for FSC sensor chips replacing the fscpos,
|
||||||
fscscy and fscher drivers and adding support for several other FSC
|
fscscy and fscher drivers and adding support for several other FSC
|
||||||
|
@ -635,6 +636,20 @@ config SENSORS_PC87427
|
||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called pc87427.
|
will be called pc87427.
|
||||||
|
|
||||||
|
config SENSORS_PCF8591
|
||||||
|
tristate "Philips PCF8591 ADC/DAC"
|
||||||
|
depends on I2C
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
If you say yes here you get support for Philips PCF8591 4-channel
|
||||||
|
ADC, 1-channel DAC chips.
|
||||||
|
|
||||||
|
This driver can also be built as a module. If so, the module
|
||||||
|
will be called pcf8591.
|
||||||
|
|
||||||
|
These devices are hard to detect and rarely found on mainstream
|
||||||
|
hardware. If unsure, say N.
|
||||||
|
|
||||||
config SENSORS_SIS5595
|
config SENSORS_SIS5595
|
||||||
tristate "Silicon Integrated Systems Corp. SiS5595"
|
tristate "Silicon Integrated Systems Corp. SiS5595"
|
||||||
depends on PCI
|
depends on PCI
|
||||||
|
@ -827,7 +842,7 @@ config SENSORS_W83627HF
|
||||||
will be called w83627hf.
|
will be called w83627hf.
|
||||||
|
|
||||||
config SENSORS_W83627EHF
|
config SENSORS_W83627EHF
|
||||||
tristate "Winbond W83627EHF/DHG"
|
tristate "Winbond W83627EHF/EHG/DHG, W83667HG"
|
||||||
select HWMON_VID
|
select HWMON_VID
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the hardware
|
If you say yes here you get support for the hardware
|
||||||
|
@ -838,6 +853,8 @@ config SENSORS_W83627EHF
|
||||||
chip suited for specific Intel processors that use PECI such as
|
chip suited for specific Intel processors that use PECI such as
|
||||||
the Core 2 Duo.
|
the Core 2 Duo.
|
||||||
|
|
||||||
|
This driver also supports the W83667HG chip.
|
||||||
|
|
||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called w83627ehf.
|
will be called w83627ehf.
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,7 @@ obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
|
||||||
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
|
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
|
||||||
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
|
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
|
||||||
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
|
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
|
||||||
|
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
|
||||||
obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
|
obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
|
||||||
obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
|
obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
|
||||||
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
|
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
|
||||||
|
|
|
@ -81,71 +81,84 @@ struct ds1621_data {
|
||||||
u8 conf; /* Register encoding, combined */
|
u8 conf; /* Register encoding, combined */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ds1621_probe(struct i2c_client *client,
|
/* Temperature registers are word-sized.
|
||||||
const struct i2c_device_id *id);
|
|
||||||
static int ds1621_detect(struct i2c_client *client, int kind,
|
|
||||||
struct i2c_board_info *info);
|
|
||||||
static void ds1621_init_client(struct i2c_client *client);
|
|
||||||
static int ds1621_remove(struct i2c_client *client);
|
|
||||||
static struct ds1621_data *ds1621_update_client(struct device *dev);
|
|
||||||
|
|
||||||
static const struct i2c_device_id ds1621_id[] = {
|
|
||||||
{ "ds1621", ds1621 },
|
|
||||||
{ "ds1625", ds1621 },
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(i2c, ds1621_id);
|
|
||||||
|
|
||||||
/* This is the driver that will be inserted */
|
|
||||||
static struct i2c_driver ds1621_driver = {
|
|
||||||
.class = I2C_CLASS_HWMON,
|
|
||||||
.driver = {
|
|
||||||
.name = "ds1621",
|
|
||||||
},
|
|
||||||
.probe = ds1621_probe,
|
|
||||||
.remove = ds1621_remove,
|
|
||||||
.id_table = ds1621_id,
|
|
||||||
.detect = ds1621_detect,
|
|
||||||
.address_data = &addr_data,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* All registers are word-sized, except for the configuration register.
|
|
||||||
DS1621 uses a high-byte first convention, which is exactly opposite to
|
DS1621 uses a high-byte first convention, which is exactly opposite to
|
||||||
the SMBus standard. */
|
the SMBus standard. */
|
||||||
static int ds1621_read_value(struct i2c_client *client, u8 reg)
|
static int ds1621_read_temp(struct i2c_client *client, u8 reg)
|
||||||
{
|
{
|
||||||
if (reg == DS1621_REG_CONF)
|
int ret;
|
||||||
return i2c_smbus_read_byte_data(client, reg);
|
|
||||||
else
|
ret = i2c_smbus_read_word_data(client, reg);
|
||||||
return swab16(i2c_smbus_read_word_data(client, reg));
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
return swab16(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
|
static int ds1621_write_temp(struct i2c_client *client, u8 reg, u16 value)
|
||||||
{
|
{
|
||||||
if (reg == DS1621_REG_CONF)
|
|
||||||
return i2c_smbus_write_byte_data(client, reg, value);
|
|
||||||
else
|
|
||||||
return i2c_smbus_write_word_data(client, reg, swab16(value));
|
return i2c_smbus_write_word_data(client, reg, swab16(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ds1621_init_client(struct i2c_client *client)
|
static void ds1621_init_client(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
int reg = ds1621_read_value(client, DS1621_REG_CONF);
|
u8 conf, new_conf;
|
||||||
|
|
||||||
|
new_conf = conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
|
||||||
/* switch to continuous conversion mode */
|
/* switch to continuous conversion mode */
|
||||||
reg &= ~ DS1621_REG_CONFIG_1SHOT;
|
new_conf &= ~DS1621_REG_CONFIG_1SHOT;
|
||||||
|
|
||||||
/* setup output polarity */
|
/* setup output polarity */
|
||||||
if (polarity == 0)
|
if (polarity == 0)
|
||||||
reg &= ~DS1621_REG_CONFIG_POLARITY;
|
new_conf &= ~DS1621_REG_CONFIG_POLARITY;
|
||||||
else if (polarity == 1)
|
else if (polarity == 1)
|
||||||
reg |= DS1621_REG_CONFIG_POLARITY;
|
new_conf |= DS1621_REG_CONFIG_POLARITY;
|
||||||
|
|
||||||
ds1621_write_value(client, DS1621_REG_CONF, reg);
|
if (conf != new_conf)
|
||||||
|
i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf);
|
||||||
|
|
||||||
/* start conversion */
|
/* start conversion */
|
||||||
i2c_smbus_write_byte(client, DS1621_COM_START);
|
i2c_smbus_write_byte(client, DS1621_COM_START);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct ds1621_data *ds1621_update_client(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct ds1621_data *data = i2c_get_clientdata(client);
|
||||||
|
u8 new_conf;
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
|
||||||
|
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||||
|
|| !data->valid) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dev_dbg(&client->dev, "Starting ds1621 update\n");
|
||||||
|
|
||||||
|
data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(data->temp); i++)
|
||||||
|
data->temp[i] = ds1621_read_temp(client,
|
||||||
|
DS1621_REG_TEMP[i]);
|
||||||
|
|
||||||
|
/* reset alarms if necessary */
|
||||||
|
new_conf = data->conf;
|
||||||
|
if (data->temp[0] > data->temp[1]) /* input > min */
|
||||||
|
new_conf &= ~DS1621_ALARM_TEMP_LOW;
|
||||||
|
if (data->temp[0] < data->temp[2]) /* input < max */
|
||||||
|
new_conf &= ~DS1621_ALARM_TEMP_HIGH;
|
||||||
|
if (data->conf != new_conf)
|
||||||
|
i2c_smbus_write_byte_data(client, DS1621_REG_CONF,
|
||||||
|
new_conf);
|
||||||
|
|
||||||
|
data->last_updated = jiffies;
|
||||||
|
data->valid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t show_temp(struct device *dev, struct device_attribute *da,
|
static ssize_t show_temp(struct device *dev, struct device_attribute *da,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
|
@ -160,12 +173,12 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
|
||||||
{
|
{
|
||||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct ds1621_data *data = ds1621_update_client(dev);
|
struct ds1621_data *data = i2c_get_clientdata(client);
|
||||||
u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10));
|
u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10));
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
data->temp[attr->index] = val;
|
data->temp[attr->index] = val;
|
||||||
ds1621_write_value(client, DS1621_REG_TEMP[attr->index],
|
ds1621_write_temp(client, DS1621_REG_TEMP[attr->index],
|
||||||
data->temp[attr->index]);
|
data->temp[attr->index]);
|
||||||
mutex_unlock(&data->update_lock);
|
mutex_unlock(&data->update_lock);
|
||||||
return count;
|
return count;
|
||||||
|
@ -228,13 +241,14 @@ static int ds1621_detect(struct i2c_client *client, int kind,
|
||||||
/* The NVB bit should be low if no EEPROM write has been
|
/* The NVB bit should be low if no EEPROM write has been
|
||||||
requested during the latest 10ms, which is highly
|
requested during the latest 10ms, which is highly
|
||||||
improbable in our case. */
|
improbable in our case. */
|
||||||
conf = ds1621_read_value(client, DS1621_REG_CONF);
|
conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
|
||||||
if (conf & DS1621_REG_CONFIG_NVB)
|
if (conf < 0 || conf & DS1621_REG_CONFIG_NVB)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
/* The 7 lowest bits of a temperature should always be 0. */
|
/* The 7 lowest bits of a temperature should always be 0. */
|
||||||
for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) {
|
for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) {
|
||||||
temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
|
temp = i2c_smbus_read_word_data(client,
|
||||||
if (temp & 0x007f)
|
DS1621_REG_TEMP[i]);
|
||||||
|
if (temp < 0 || (temp & 0x7f00))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,45 +308,25 @@ static int ds1621_remove(struct i2c_client *client)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id ds1621_id[] = {
|
||||||
|
{ "ds1621", ds1621 },
|
||||||
|
{ "ds1625", ds1621 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, ds1621_id);
|
||||||
|
|
||||||
static struct ds1621_data *ds1621_update_client(struct device *dev)
|
/* This is the driver that will be inserted */
|
||||||
{
|
static struct i2c_driver ds1621_driver = {
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
.class = I2C_CLASS_HWMON,
|
||||||
struct ds1621_data *data = i2c_get_clientdata(client);
|
.driver = {
|
||||||
u8 new_conf;
|
.name = "ds1621",
|
||||||
|
},
|
||||||
mutex_lock(&data->update_lock);
|
.probe = ds1621_probe,
|
||||||
|
.remove = ds1621_remove,
|
||||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
.id_table = ds1621_id,
|
||||||
|| !data->valid) {
|
.detect = ds1621_detect,
|
||||||
int i;
|
.address_data = &addr_data,
|
||||||
|
};
|
||||||
dev_dbg(&client->dev, "Starting ds1621 update\n");
|
|
||||||
|
|
||||||
data->conf = ds1621_read_value(client, DS1621_REG_CONF);
|
|
||||||
|
|
||||||
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[0] > data->temp[1]) /* input > min */
|
|
||||||
new_conf &= ~DS1621_ALARM_TEMP_LOW;
|
|
||||||
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,
|
|
||||||
new_conf);
|
|
||||||
|
|
||||||
data->last_updated = jiffies;
|
|
||||||
data->valid = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&data->update_lock);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init ds1621_init(void)
|
static int __init ds1621_init(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* fschmd.c
|
/* fschmd.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com>
|
* Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes,
|
* Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes,
|
||||||
* Scylla, Heracles and Heimdall chips
|
* Scylla, Heracles, Heimdall, Hades and Syleus chips
|
||||||
*
|
*
|
||||||
* Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6
|
* Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6
|
||||||
* (candidate) fschmd drivers:
|
* (candidate) fschmd drivers:
|
||||||
|
@ -56,7 +56,7 @@ static int nowayout = WATCHDOG_NOWAYOUT;
|
||||||
module_param(nowayout, int, 0);
|
module_param(nowayout, int, 0);
|
||||||
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
|
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
|
||||||
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
|
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
|
||||||
I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
|
I2C_CLIENT_INSMOD_7(fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The FSCHMD registers and other defines
|
* The FSCHMD registers and other defines
|
||||||
|
@ -75,9 +75,12 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
|
||||||
#define FSCHMD_CONTROL_ALERT_LED 0x01
|
#define FSCHMD_CONTROL_ALERT_LED 0x01
|
||||||
|
|
||||||
/* watchdog */
|
/* watchdog */
|
||||||
#define FSCHMD_REG_WDOG_PRESET 0x28
|
static const u8 FSCHMD_REG_WDOG_CONTROL[7] =
|
||||||
#define FSCHMD_REG_WDOG_STATE 0x23
|
{ 0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 };
|
||||||
#define FSCHMD_REG_WDOG_CONTROL 0x21
|
static const u8 FSCHMD_REG_WDOG_STATE[7] =
|
||||||
|
{ 0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 };
|
||||||
|
static const u8 FSCHMD_REG_WDOG_PRESET[7] =
|
||||||
|
{ 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a };
|
||||||
|
|
||||||
#define FSCHMD_WDOG_CONTROL_TRIGGER 0x10
|
#define FSCHMD_WDOG_CONTROL_TRIGGER 0x10
|
||||||
#define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */
|
#define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */
|
||||||
|
@ -87,70 +90,95 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
|
||||||
#define FSCHMD_WDOG_STATE_CARDRESET 0x02
|
#define FSCHMD_WDOG_STATE_CARDRESET 0x02
|
||||||
|
|
||||||
/* voltages, weird order is to keep the same order as the old drivers */
|
/* voltages, weird order is to keep the same order as the old drivers */
|
||||||
static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 };
|
static const u8 FSCHMD_REG_VOLT[7][6] = {
|
||||||
|
{ 0x45, 0x42, 0x48 }, /* pos */
|
||||||
|
{ 0x45, 0x42, 0x48 }, /* her */
|
||||||
|
{ 0x45, 0x42, 0x48 }, /* scy */
|
||||||
|
{ 0x45, 0x42, 0x48 }, /* hrc */
|
||||||
|
{ 0x45, 0x42, 0x48 }, /* hmd */
|
||||||
|
{ 0x21, 0x20, 0x22 }, /* hds */
|
||||||
|
{ 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 }, /* syl */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 };
|
||||||
|
|
||||||
/* minimum pwm at which the fan is driven (pwm can by increased depending on
|
/* minimum pwm at which the fan is driven (pwm can by increased depending on
|
||||||
the temp. Notice that for the scy some fans share there minimum speed.
|
the temp. Notice that for the scy some fans share there minimum speed.
|
||||||
Also notice that with the scy the sensor order is different than with the
|
Also notice that with the scy the sensor order is different than with the
|
||||||
other chips, this order was in the 2.4 driver and kept for consistency. */
|
other chips, this order was in the 2.4 driver and kept for consistency. */
|
||||||
static const u8 FSCHMD_REG_FAN_MIN[5][6] = {
|
static const u8 FSCHMD_REG_FAN_MIN[7][7] = {
|
||||||
{ 0x55, 0x65 }, /* pos */
|
{ 0x55, 0x65 }, /* pos */
|
||||||
{ 0x55, 0x65, 0xb5 }, /* her */
|
{ 0x55, 0x65, 0xb5 }, /* her */
|
||||||
{ 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */
|
{ 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */
|
||||||
{ 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */
|
{ 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */
|
||||||
{ 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */
|
{ 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */
|
||||||
|
{ 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hds */
|
||||||
|
{ 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 }, /* syl */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* actual fan speed */
|
/* actual fan speed */
|
||||||
static const u8 FSCHMD_REG_FAN_ACT[5][6] = {
|
static const u8 FSCHMD_REG_FAN_ACT[7][7] = {
|
||||||
{ 0x0e, 0x6b, 0xab }, /* pos */
|
{ 0x0e, 0x6b, 0xab }, /* pos */
|
||||||
{ 0x0e, 0x6b, 0xbb }, /* her */
|
{ 0x0e, 0x6b, 0xbb }, /* her */
|
||||||
{ 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */
|
{ 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */
|
||||||
{ 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */
|
{ 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */
|
||||||
{ 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */
|
{ 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */
|
||||||
|
{ 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hds */
|
||||||
|
{ 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 }, /* syl */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* fan status registers */
|
/* fan status registers */
|
||||||
static const u8 FSCHMD_REG_FAN_STATE[5][6] = {
|
static const u8 FSCHMD_REG_FAN_STATE[7][7] = {
|
||||||
{ 0x0d, 0x62, 0xa2 }, /* pos */
|
{ 0x0d, 0x62, 0xa2 }, /* pos */
|
||||||
{ 0x0d, 0x62, 0xb2 }, /* her */
|
{ 0x0d, 0x62, 0xb2 }, /* her */
|
||||||
{ 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */
|
{ 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */
|
||||||
{ 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */
|
{ 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */
|
||||||
{ 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */
|
{ 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */
|
||||||
|
{ 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hds */
|
||||||
|
{ 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 }, /* syl */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* fan ripple / divider registers */
|
/* fan ripple / divider registers */
|
||||||
static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = {
|
static const u8 FSCHMD_REG_FAN_RIPPLE[7][7] = {
|
||||||
{ 0x0f, 0x6f, 0xaf }, /* pos */
|
{ 0x0f, 0x6f, 0xaf }, /* pos */
|
||||||
{ 0x0f, 0x6f, 0xbf }, /* her */
|
{ 0x0f, 0x6f, 0xbf }, /* her */
|
||||||
{ 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */
|
{ 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */
|
||||||
{ 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */
|
{ 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */
|
||||||
{ 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */
|
{ 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */
|
||||||
|
{ 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hds */
|
||||||
|
{ 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 }, /* syl */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 };
|
static const int FSCHMD_NO_FAN_SENSORS[7] = { 3, 3, 6, 4, 5, 5, 7 };
|
||||||
|
|
||||||
/* Fan status register bitmasks */
|
/* Fan status register bitmasks */
|
||||||
#define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */
|
#define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */
|
||||||
#define FSCHMD_FAN_NOT_PRESENT 0x08 /* not documented */
|
#define FSCHMD_FAN_NOT_PRESENT 0x08
|
||||||
|
#define FSCHMD_FAN_DISABLED 0x80
|
||||||
|
|
||||||
|
|
||||||
/* actual temperature registers */
|
/* actual temperature registers */
|
||||||
static const u8 FSCHMD_REG_TEMP_ACT[5][5] = {
|
static const u8 FSCHMD_REG_TEMP_ACT[7][11] = {
|
||||||
{ 0x64, 0x32, 0x35 }, /* pos */
|
{ 0x64, 0x32, 0x35 }, /* pos */
|
||||||
{ 0x64, 0x32, 0x35 }, /* her */
|
{ 0x64, 0x32, 0x35 }, /* her */
|
||||||
{ 0x64, 0xD0, 0x32, 0x35 }, /* scy */
|
{ 0x64, 0xD0, 0x32, 0x35 }, /* scy */
|
||||||
{ 0x64, 0x32, 0x35 }, /* hrc */
|
{ 0x64, 0x32, 0x35 }, /* hrc */
|
||||||
{ 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */
|
{ 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */
|
||||||
|
{ 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hds */
|
||||||
|
{ 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, /* syl */
|
||||||
|
0xb8, 0xc8, 0xd8, 0xe8, 0xf8 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* temperature state registers */
|
/* temperature state registers */
|
||||||
static const u8 FSCHMD_REG_TEMP_STATE[5][5] = {
|
static const u8 FSCHMD_REG_TEMP_STATE[7][11] = {
|
||||||
{ 0x71, 0x81, 0x91 }, /* pos */
|
{ 0x71, 0x81, 0x91 }, /* pos */
|
||||||
{ 0x71, 0x81, 0x91 }, /* her */
|
{ 0x71, 0x81, 0x91 }, /* her */
|
||||||
{ 0x71, 0xd1, 0x81, 0x91 }, /* scy */
|
{ 0x71, 0xd1, 0x81, 0x91 }, /* scy */
|
||||||
{ 0x71, 0x81, 0x91 }, /* hrc */
|
{ 0x71, 0x81, 0x91 }, /* hrc */
|
||||||
{ 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */
|
{ 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */
|
||||||
|
{ 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hds */
|
||||||
|
{ 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, /* syl */
|
||||||
|
0xb9, 0xc9, 0xd9, 0xe9, 0xf9 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* temperature high limit registers, FSC does not document these. Proven to be
|
/* temperature high limit registers, FSC does not document these. Proven to be
|
||||||
|
@ -158,24 +186,31 @@ static const u8 FSCHMD_REG_TEMP_STATE[5][5] = {
|
||||||
in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
|
in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
|
||||||
at these addresses, but doesn't want to confirm they are the same as with
|
at these addresses, but doesn't want to confirm they are the same as with
|
||||||
the fscher?? */
|
the fscher?? */
|
||||||
static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = {
|
static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = {
|
||||||
{ 0, 0, 0 }, /* pos */
|
{ 0, 0, 0 }, /* pos */
|
||||||
{ 0x76, 0x86, 0x96 }, /* her */
|
{ 0x76, 0x86, 0x96 }, /* her */
|
||||||
{ 0x76, 0xd6, 0x86, 0x96 }, /* scy */
|
{ 0x76, 0xd6, 0x86, 0x96 }, /* scy */
|
||||||
{ 0x76, 0x86, 0x96 }, /* hrc */
|
{ 0x76, 0x86, 0x96 }, /* hrc */
|
||||||
{ 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */
|
{ 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */
|
||||||
|
{ 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hds */
|
||||||
|
{ 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, /* syl */
|
||||||
|
0xba, 0xca, 0xda, 0xea, 0xfa },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* These were found through experimenting with an fscher, currently they are
|
/* These were found through experimenting with an fscher, currently they are
|
||||||
not used, but we keep them around for future reference.
|
not used, but we keep them around for future reference.
|
||||||
|
On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc),
|
||||||
|
AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence
|
||||||
|
the fan speed.
|
||||||
static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 };
|
static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 };
|
||||||
static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */
|
static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */
|
||||||
|
|
||||||
static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 };
|
static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 };
|
||||||
|
|
||||||
/* temp status register bitmasks */
|
/* temp status register bitmasks */
|
||||||
#define FSCHMD_TEMP_WORKING 0x01
|
#define FSCHMD_TEMP_WORKING 0x01
|
||||||
#define FSCHMD_TEMP_ALERT 0x02
|
#define FSCHMD_TEMP_ALERT 0x02
|
||||||
|
#define FSCHMD_TEMP_DISABLED 0x80
|
||||||
/* there only really is an alarm if the sensor is working and alert == 1 */
|
/* there only really is an alarm if the sensor is working and alert == 1 */
|
||||||
#define FSCHMD_TEMP_ALARM_MASK \
|
#define FSCHMD_TEMP_ALARM_MASK \
|
||||||
(FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT)
|
(FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT)
|
||||||
|
@ -201,6 +236,8 @@ static const struct i2c_device_id fschmd_id[] = {
|
||||||
{ "fscscy", fscscy },
|
{ "fscscy", fscscy },
|
||||||
{ "fschrc", fschrc },
|
{ "fschrc", fschrc },
|
||||||
{ "fschmd", fschmd },
|
{ "fschmd", fschmd },
|
||||||
|
{ "fschds", fschds },
|
||||||
|
{ "fscsyl", fscsyl },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(i2c, fschmd_id);
|
MODULE_DEVICE_TABLE(i2c, fschmd_id);
|
||||||
|
@ -242,14 +279,14 @@ struct fschmd_data {
|
||||||
u8 watchdog_control; /* watchdog control register */
|
u8 watchdog_control; /* watchdog control register */
|
||||||
u8 watchdog_state; /* watchdog status register */
|
u8 watchdog_state; /* watchdog status register */
|
||||||
u8 watchdog_preset; /* watchdog counter preset on trigger val */
|
u8 watchdog_preset; /* watchdog counter preset on trigger val */
|
||||||
u8 volt[3]; /* 12, 5, battery voltage */
|
u8 volt[6]; /* voltage */
|
||||||
u8 temp_act[5]; /* temperature */
|
u8 temp_act[11]; /* temperature */
|
||||||
u8 temp_status[5]; /* status of sensor */
|
u8 temp_status[11]; /* status of sensor */
|
||||||
u8 temp_max[5]; /* high temp limit, notice: undocumented! */
|
u8 temp_max[11]; /* high temp limit, notice: undocumented! */
|
||||||
u8 fan_act[6]; /* fans revolutions per second */
|
u8 fan_act[7]; /* fans revolutions per second */
|
||||||
u8 fan_status[6]; /* fan status */
|
u8 fan_status[7]; /* fan status */
|
||||||
u8 fan_min[6]; /* fan min value for rps */
|
u8 fan_min[7]; /* fan min value for rps */
|
||||||
u8 fan_ripple[6]; /* divider for rps */
|
u8 fan_ripple[7]; /* divider for rps */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Global variables to hold information read from special DMI tables, which are
|
/* Global variables to hold information read from special DMI tables, which are
|
||||||
|
@ -257,8 +294,8 @@ struct fschmd_data {
|
||||||
protect these with a lock as they are only modified from our attach function
|
protect these with a lock as they are only modified from our attach function
|
||||||
which always gets called with the i2c-core lock held and never accessed
|
which always gets called with the i2c-core lock held and never accessed
|
||||||
before the attach function is done with them. */
|
before the attach function is done with them. */
|
||||||
static int dmi_mult[3] = { 490, 200, 100 };
|
static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 };
|
||||||
static int dmi_offset[3] = { 0, 0, 0 };
|
static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 };
|
||||||
static int dmi_vref = -1;
|
static int dmi_vref = -1;
|
||||||
|
|
||||||
/* Somewhat ugly :( global data pointer list with all fschmd devices, so that
|
/* Somewhat ugly :( global data pointer list with all fschmd devices, so that
|
||||||
|
@ -450,10 +487,11 @@ static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
|
||||||
struct device_attribute *devattr, char *buf)
|
struct device_attribute *devattr, char *buf)
|
||||||
{
|
{
|
||||||
int index = to_sensor_dev_attr(devattr)->index;
|
int index = to_sensor_dev_attr(devattr)->index;
|
||||||
int val = fschmd_update_device(dev)->fan_min[index];
|
struct fschmd_data *data = fschmd_update_device(dev);
|
||||||
|
int val = data->fan_min[index];
|
||||||
|
|
||||||
/* 0 = allow turning off, 1-255 = 50-100% */
|
/* 0 = allow turning off (except on the syl), 1-255 = 50-100% */
|
||||||
if (val)
|
if (val || data->kind == fscsyl - 1)
|
||||||
val = val / 2 + 128;
|
val = val / 2 + 128;
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", val);
|
return sprintf(buf, "%d\n", val);
|
||||||
|
@ -466,8 +504,8 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
|
||||||
struct fschmd_data *data = dev_get_drvdata(dev);
|
struct fschmd_data *data = dev_get_drvdata(dev);
|
||||||
unsigned long v = simple_strtoul(buf, NULL, 10);
|
unsigned long v = simple_strtoul(buf, NULL, 10);
|
||||||
|
|
||||||
/* register: 0 = allow turning off, 1-255 = 50-100% */
|
/* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
|
||||||
if (v) {
|
if (v || data->kind == fscsyl - 1) {
|
||||||
v = SENSORS_LIMIT(v, 128, 255);
|
v = SENSORS_LIMIT(v, 128, 255);
|
||||||
v = (v - 128) * 2 + 1;
|
v = (v - 128) * 2 + 1;
|
||||||
}
|
}
|
||||||
|
@ -522,11 +560,15 @@ static ssize_t store_alert_led(struct device *dev,
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led);
|
||||||
|
|
||||||
static struct sensor_device_attribute fschmd_attr[] = {
|
static struct sensor_device_attribute fschmd_attr[] = {
|
||||||
SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
|
SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
|
||||||
SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
|
SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
|
||||||
SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
|
SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
|
||||||
SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0),
|
SENSOR_ATTR(in3_input, 0444, show_in_value, NULL, 3),
|
||||||
|
SENSOR_ATTR(in4_input, 0444, show_in_value, NULL, 4),
|
||||||
|
SENSOR_ATTR(in5_input, 0444, show_in_value, NULL, 5),
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct sensor_device_attribute fschmd_temp_attr[] = {
|
static struct sensor_device_attribute fschmd_temp_attr[] = {
|
||||||
|
@ -550,6 +592,30 @@ static struct sensor_device_attribute fschmd_temp_attr[] = {
|
||||||
SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4),
|
SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4),
|
||||||
SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
|
SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
|
||||||
SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
|
SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
|
||||||
|
SENSOR_ATTR(temp6_input, 0444, show_temp_value, NULL, 5),
|
||||||
|
SENSOR_ATTR(temp6_max, 0644, show_temp_max, store_temp_max, 5),
|
||||||
|
SENSOR_ATTR(temp6_fault, 0444, show_temp_fault, NULL, 5),
|
||||||
|
SENSOR_ATTR(temp6_alarm, 0444, show_temp_alarm, NULL, 5),
|
||||||
|
SENSOR_ATTR(temp7_input, 0444, show_temp_value, NULL, 6),
|
||||||
|
SENSOR_ATTR(temp7_max, 0644, show_temp_max, store_temp_max, 6),
|
||||||
|
SENSOR_ATTR(temp7_fault, 0444, show_temp_fault, NULL, 6),
|
||||||
|
SENSOR_ATTR(temp7_alarm, 0444, show_temp_alarm, NULL, 6),
|
||||||
|
SENSOR_ATTR(temp8_input, 0444, show_temp_value, NULL, 7),
|
||||||
|
SENSOR_ATTR(temp8_max, 0644, show_temp_max, store_temp_max, 7),
|
||||||
|
SENSOR_ATTR(temp8_fault, 0444, show_temp_fault, NULL, 7),
|
||||||
|
SENSOR_ATTR(temp8_alarm, 0444, show_temp_alarm, NULL, 7),
|
||||||
|
SENSOR_ATTR(temp9_input, 0444, show_temp_value, NULL, 8),
|
||||||
|
SENSOR_ATTR(temp9_max, 0644, show_temp_max, store_temp_max, 8),
|
||||||
|
SENSOR_ATTR(temp9_fault, 0444, show_temp_fault, NULL, 8),
|
||||||
|
SENSOR_ATTR(temp9_alarm, 0444, show_temp_alarm, NULL, 8),
|
||||||
|
SENSOR_ATTR(temp10_input, 0444, show_temp_value, NULL, 9),
|
||||||
|
SENSOR_ATTR(temp10_max, 0644, show_temp_max, store_temp_max, 9),
|
||||||
|
SENSOR_ATTR(temp10_fault, 0444, show_temp_fault, NULL, 9),
|
||||||
|
SENSOR_ATTR(temp10_alarm, 0444, show_temp_alarm, NULL, 9),
|
||||||
|
SENSOR_ATTR(temp11_input, 0444, show_temp_value, NULL, 10),
|
||||||
|
SENSOR_ATTR(temp11_max, 0644, show_temp_max, store_temp_max, 10),
|
||||||
|
SENSOR_ATTR(temp11_fault, 0444, show_temp_fault, NULL, 10),
|
||||||
|
SENSOR_ATTR(temp11_alarm, 0444, show_temp_alarm, NULL, 10),
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct sensor_device_attribute fschmd_fan_attr[] = {
|
static struct sensor_device_attribute fschmd_fan_attr[] = {
|
||||||
|
@ -589,6 +655,12 @@ static struct sensor_device_attribute fschmd_fan_attr[] = {
|
||||||
SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
|
SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
|
||||||
SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
|
SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
|
||||||
store_pwm_auto_point1_pwm, 5),
|
store_pwm_auto_point1_pwm, 5),
|
||||||
|
SENSOR_ATTR(fan7_input, 0444, show_fan_value, NULL, 6),
|
||||||
|
SENSOR_ATTR(fan7_div, 0644, show_fan_div, store_fan_div, 6),
|
||||||
|
SENSOR_ATTR(fan7_alarm, 0444, show_fan_alarm, NULL, 6),
|
||||||
|
SENSOR_ATTR(fan7_fault, 0444, show_fan_fault, NULL, 6),
|
||||||
|
SENSOR_ATTR(pwm7_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
|
||||||
|
store_pwm_auto_point1_pwm, 6),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -624,10 +696,11 @@ static int watchdog_set_timeout(struct fschmd_data *data, int timeout)
|
||||||
data->watchdog_preset = DIV_ROUND_UP(timeout, resolution);
|
data->watchdog_preset = DIV_ROUND_UP(timeout, resolution);
|
||||||
|
|
||||||
/* Write new timeout value */
|
/* Write new timeout value */
|
||||||
i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_PRESET,
|
i2c_smbus_write_byte_data(data->client,
|
||||||
data->watchdog_preset);
|
FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset);
|
||||||
/* Write new control register, do not trigger! */
|
/* Write new control register, do not trigger! */
|
||||||
i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
|
i2c_smbus_write_byte_data(data->client,
|
||||||
|
FSCHMD_REG_WDOG_CONTROL[data->kind],
|
||||||
data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER);
|
data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER);
|
||||||
|
|
||||||
ret = data->watchdog_preset * resolution;
|
ret = data->watchdog_preset * resolution;
|
||||||
|
@ -662,7 +735,8 @@ static int watchdog_trigger(struct fschmd_data *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER;
|
data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER;
|
||||||
i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
|
i2c_smbus_write_byte_data(data->client,
|
||||||
|
FSCHMD_REG_WDOG_CONTROL[data->kind],
|
||||||
data->watchdog_control);
|
data->watchdog_control);
|
||||||
leave:
|
leave:
|
||||||
mutex_unlock(&data->watchdog_lock);
|
mutex_unlock(&data->watchdog_lock);
|
||||||
|
@ -682,7 +756,8 @@ static int watchdog_stop(struct fschmd_data *data)
|
||||||
data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED;
|
data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED;
|
||||||
/* Don't store the stop flag in our watchdog control register copy, as
|
/* Don't store the stop flag in our watchdog control register copy, as
|
||||||
its a write only bit (read always returns 0) */
|
its a write only bit (read always returns 0) */
|
||||||
i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
|
i2c_smbus_write_byte_data(data->client,
|
||||||
|
FSCHMD_REG_WDOG_CONTROL[data->kind],
|
||||||
data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP);
|
data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP);
|
||||||
leave:
|
leave:
|
||||||
mutex_unlock(&data->watchdog_lock);
|
mutex_unlock(&data->watchdog_lock);
|
||||||
|
@ -856,7 +931,7 @@ static struct file_operations watchdog_fops = {
|
||||||
|
|
||||||
/* DMI decode routine to read voltage scaling factors from special DMI tables,
|
/* DMI decode routine to read voltage scaling factors from special DMI tables,
|
||||||
which are available on FSC machines with an fscher or later chip. */
|
which are available on FSC machines with an fscher or later chip. */
|
||||||
static void fschmd_dmi_decode(const struct dmi_header *header)
|
static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy)
|
||||||
{
|
{
|
||||||
int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0;
|
int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0;
|
||||||
|
|
||||||
|
@ -912,6 +987,15 @@ static void fschmd_dmi_decode(const struct dmi_header *header)
|
||||||
dmi_mult[i] = mult[i] * 10;
|
dmi_mult[i] = mult[i] * 10;
|
||||||
dmi_offset[i] = offset[i] * 10;
|
dmi_offset[i] = offset[i] * 10;
|
||||||
}
|
}
|
||||||
|
/* According to the docs there should be separate dmi entries
|
||||||
|
for the mult's and offsets of in3-5 of the syl, but on
|
||||||
|
my test machine these are not present */
|
||||||
|
dmi_mult[3] = dmi_mult[2];
|
||||||
|
dmi_mult[4] = dmi_mult[1];
|
||||||
|
dmi_mult[5] = dmi_mult[2];
|
||||||
|
dmi_offset[3] = dmi_offset[2];
|
||||||
|
dmi_offset[4] = dmi_offset[1];
|
||||||
|
dmi_offset[5] = dmi_offset[2];
|
||||||
dmi_vref = vref;
|
dmi_vref = vref;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -920,8 +1004,6 @@ static int fschmd_detect(struct i2c_client *client, int kind,
|
||||||
struct i2c_board_info *info)
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adapter = client->adapter;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
const char * const client_names[5] = { "fscpos", "fscher", "fscscy",
|
|
||||||
"fschrc", "fschmd" };
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -948,11 +1030,15 @@ static int fschmd_detect(struct i2c_client *client, int kind,
|
||||||
kind = fschrc;
|
kind = fschrc;
|
||||||
else if (!strcmp(id, "HMD"))
|
else if (!strcmp(id, "HMD"))
|
||||||
kind = fschmd;
|
kind = fschmd;
|
||||||
|
else if (!strcmp(id, "HDS"))
|
||||||
|
kind = fschds;
|
||||||
|
else if (!strcmp(id, "SYL"))
|
||||||
|
kind = fscsyl;
|
||||||
else
|
else
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
strlcpy(info->type, client_names[kind - 1], I2C_NAME_SIZE);
|
strlcpy(info->type, fschmd_id[kind - 1].name, I2C_NAME_SIZE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -961,8 +1047,8 @@ static int fschmd_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
struct fschmd_data *data;
|
struct fschmd_data *data;
|
||||||
const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
|
const char * const names[7] = { "Poseidon", "Hermes", "Scylla",
|
||||||
"Heracles", "Heimdall" };
|
"Heracles", "Heimdall", "Hades", "Syleus" };
|
||||||
const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
|
const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
|
||||||
int i, err;
|
int i, err;
|
||||||
enum chips kind = id->driver_data;
|
enum chips kind = id->driver_data;
|
||||||
|
@ -991,7 +1077,7 @@ static int fschmd_probe(struct i2c_client *client,
|
||||||
|
|
||||||
/* Read the special DMI table for fscher and newer chips */
|
/* Read the special DMI table for fscher and newer chips */
|
||||||
if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) {
|
if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) {
|
||||||
dmi_walk(fschmd_dmi_decode);
|
dmi_walk(fschmd_dmi_decode, NULL);
|
||||||
if (dmi_vref == -1) {
|
if (dmi_vref == -1) {
|
||||||
dev_warn(&client->dev,
|
dev_warn(&client->dev,
|
||||||
"Couldn't get voltage scaling factors from "
|
"Couldn't get voltage scaling factors from "
|
||||||
|
@ -1000,21 +1086,25 @@ static int fschmd_probe(struct i2c_client *client,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* i2c kind goes from 1-6, we want from 0-5 to address arrays */
|
||||||
|
data->kind = kind - 1;
|
||||||
|
|
||||||
/* Read in some never changing registers */
|
/* Read in some never changing registers */
|
||||||
data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
|
data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
|
||||||
data->global_control = i2c_smbus_read_byte_data(client,
|
data->global_control = i2c_smbus_read_byte_data(client,
|
||||||
FSCHMD_REG_CONTROL);
|
FSCHMD_REG_CONTROL);
|
||||||
data->watchdog_control = i2c_smbus_read_byte_data(client,
|
data->watchdog_control = i2c_smbus_read_byte_data(client,
|
||||||
FSCHMD_REG_WDOG_CONTROL);
|
FSCHMD_REG_WDOG_CONTROL[data->kind]);
|
||||||
data->watchdog_state = i2c_smbus_read_byte_data(client,
|
data->watchdog_state = i2c_smbus_read_byte_data(client,
|
||||||
FSCHMD_REG_WDOG_STATE);
|
FSCHMD_REG_WDOG_STATE[data->kind]);
|
||||||
data->watchdog_preset = i2c_smbus_read_byte_data(client,
|
data->watchdog_preset = i2c_smbus_read_byte_data(client,
|
||||||
FSCHMD_REG_WDOG_PRESET);
|
FSCHMD_REG_WDOG_PRESET[data->kind]);
|
||||||
|
|
||||||
/* i2c kind goes from 1-5, we want from 0-4 to address arrays */
|
err = device_create_file(&client->dev, &dev_attr_alert_led);
|
||||||
data->kind = kind - 1;
|
if (err)
|
||||||
|
goto exit_detach;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) {
|
for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) {
|
||||||
err = device_create_file(&client->dev,
|
err = device_create_file(&client->dev,
|
||||||
&fschmd_attr[i].dev_attr);
|
&fschmd_attr[i].dev_attr);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -1027,6 +1117,16 @@ static int fschmd_probe(struct i2c_client *client,
|
||||||
show_temp_max)
|
show_temp_max)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (kind == fscsyl) {
|
||||||
|
if (i % 4 == 0)
|
||||||
|
data->temp_status[i / 4] =
|
||||||
|
i2c_smbus_read_byte_data(client,
|
||||||
|
FSCHMD_REG_TEMP_STATE
|
||||||
|
[data->kind][i / 4]);
|
||||||
|
if (data->temp_status[i / 4] & FSCHMD_TEMP_DISABLED)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
err = device_create_file(&client->dev,
|
err = device_create_file(&client->dev,
|
||||||
&fschmd_temp_attr[i].dev_attr);
|
&fschmd_temp_attr[i].dev_attr);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -1040,6 +1140,16 @@ static int fschmd_probe(struct i2c_client *client,
|
||||||
"pwm3_auto_point1_pwm"))
|
"pwm3_auto_point1_pwm"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (kind == fscsyl) {
|
||||||
|
if (i % 5 == 0)
|
||||||
|
data->fan_status[i / 5] =
|
||||||
|
i2c_smbus_read_byte_data(client,
|
||||||
|
FSCHMD_REG_FAN_STATE
|
||||||
|
[data->kind][i / 5]);
|
||||||
|
if (data->fan_status[i / 5] & FSCHMD_FAN_DISABLED)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
err = device_create_file(&client->dev,
|
err = device_create_file(&client->dev,
|
||||||
&fschmd_fan_attr[i].dev_attr);
|
&fschmd_fan_attr[i].dev_attr);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -1126,7 +1236,8 @@ static int fschmd_remove(struct i2c_client *client)
|
||||||
if (data->hwmon_dev)
|
if (data->hwmon_dev)
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++)
|
device_remove_file(&client->dev, &dev_attr_alert_led);
|
||||||
|
for (i = 0; i < (FSCHMD_NO_VOLT_SENSORS[data->kind]); i++)
|
||||||
device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);
|
device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);
|
||||||
for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
|
for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
|
||||||
device_remove_file(&client->dev,
|
device_remove_file(&client->dev,
|
||||||
|
@ -1171,7 +1282,7 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
|
||||||
data->temp_act[i] < data->temp_max[i])
|
data->temp_act[i] < data->temp_max[i])
|
||||||
i2c_smbus_write_byte_data(client,
|
i2c_smbus_write_byte_data(client,
|
||||||
FSCHMD_REG_TEMP_STATE[data->kind][i],
|
FSCHMD_REG_TEMP_STATE[data->kind][i],
|
||||||
FSCHMD_TEMP_ALERT);
|
data->temp_status[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
|
for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
|
||||||
|
@ -1193,12 +1304,12 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
|
||||||
data->fan_act[i])
|
data->fan_act[i])
|
||||||
i2c_smbus_write_byte_data(client,
|
i2c_smbus_write_byte_data(client,
|
||||||
FSCHMD_REG_FAN_STATE[data->kind][i],
|
FSCHMD_REG_FAN_STATE[data->kind][i],
|
||||||
FSCHMD_FAN_ALARM);
|
data->fan_status[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++)
|
||||||
data->volt[i] = i2c_smbus_read_byte_data(client,
|
data->volt[i] = i2c_smbus_read_byte_data(client,
|
||||||
FSCHMD_REG_VOLT[i]);
|
FSCHMD_REG_VOLT[data->kind][i]);
|
||||||
|
|
||||||
data->last_updated = jiffies;
|
data->last_updated = jiffies;
|
||||||
data->valid = 1;
|
data->valid = 1;
|
||||||
|
@ -1220,8 +1331,8 @@ static void __exit fschmd_exit(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
|
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
|
||||||
MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and "
|
MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades "
|
||||||
"Heimdall driver");
|
"and Syleus driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
module_init(fschmd_init);
|
module_init(fschmd_init);
|
||||||
|
|
|
@ -65,6 +65,10 @@
|
||||||
#define HDAPS_INPUT_FUZZ 4 /* input event threshold */
|
#define HDAPS_INPUT_FUZZ 4 /* input event threshold */
|
||||||
#define HDAPS_INPUT_FLAT 4
|
#define HDAPS_INPUT_FLAT 4
|
||||||
|
|
||||||
|
#define HDAPS_X_AXIS (1 << 0)
|
||||||
|
#define HDAPS_Y_AXIS (1 << 1)
|
||||||
|
#define HDAPS_BOTH_AXES (HDAPS_X_AXIS | HDAPS_Y_AXIS)
|
||||||
|
|
||||||
static struct platform_device *pdev;
|
static struct platform_device *pdev;
|
||||||
static struct input_polled_dev *hdaps_idev;
|
static struct input_polled_dev *hdaps_idev;
|
||||||
static unsigned int hdaps_invert;
|
static unsigned int hdaps_invert;
|
||||||
|
@ -182,11 +186,11 @@ static int __hdaps_read_pair(unsigned int port1, unsigned int port2,
|
||||||
km_activity = inb(HDAPS_PORT_KMACT);
|
km_activity = inb(HDAPS_PORT_KMACT);
|
||||||
__device_complete();
|
__device_complete();
|
||||||
|
|
||||||
/* if hdaps_invert is set, negate the two values */
|
/* hdaps_invert is a bitvector to negate the axes */
|
||||||
if (hdaps_invert) {
|
if (hdaps_invert & HDAPS_X_AXIS)
|
||||||
*x = -*x;
|
*x = -*x;
|
||||||
|
if (hdaps_invert & HDAPS_Y_AXIS)
|
||||||
*y = -*y;
|
*y = -*y;
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -436,7 +440,8 @@ static ssize_t hdaps_invert_store(struct device *dev,
|
||||||
{
|
{
|
||||||
int invert;
|
int invert;
|
||||||
|
|
||||||
if (sscanf(buf, "%d", &invert) != 1 || (invert != 1 && invert != 0))
|
if (sscanf(buf, "%d", &invert) != 1 ||
|
||||||
|
invert < 0 || invert > HDAPS_BOTH_AXES)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
hdaps_invert = invert;
|
hdaps_invert = invert;
|
||||||
|
@ -483,56 +488,52 @@ static int __init hdaps_dmi_match(const struct dmi_system_id *id)
|
||||||
/* hdaps_dmi_match_invert - found an inverted match. */
|
/* hdaps_dmi_match_invert - found an inverted match. */
|
||||||
static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
|
static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
|
||||||
{
|
{
|
||||||
hdaps_invert = 1;
|
hdaps_invert = (unsigned long)id->driver_data;
|
||||||
printk(KERN_INFO "hdaps: inverting axis readings.\n");
|
printk(KERN_INFO "hdaps: inverting axis (%u) readings.\n",
|
||||||
|
hdaps_invert);
|
||||||
return hdaps_dmi_match(id);
|
return hdaps_dmi_match(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HDAPS_DMI_MATCH_NORMAL(vendor, model) { \
|
#define HDAPS_DMI_MATCH_INVERT(vendor, model, axes) { \
|
||||||
.ident = vendor " " model, \
|
.ident = vendor " " model, \
|
||||||
.callback = hdaps_dmi_match, \
|
.callback = hdaps_dmi_match_invert, \
|
||||||
|
.driver_data = (void *)axes, \
|
||||||
.matches = { \
|
.matches = { \
|
||||||
DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
|
DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
|
||||||
DMI_MATCH(DMI_PRODUCT_VERSION, model) \
|
DMI_MATCH(DMI_PRODUCT_VERSION, model) \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HDAPS_DMI_MATCH_INVERT(vendor, model) { \
|
#define HDAPS_DMI_MATCH_NORMAL(vendor, model) \
|
||||||
.ident = vendor " " model, \
|
HDAPS_DMI_MATCH_INVERT(vendor, model, 0)
|
||||||
.callback = hdaps_dmi_match_invert, \
|
|
||||||
.matches = { \
|
|
||||||
DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
|
|
||||||
DMI_MATCH(DMI_PRODUCT_VERSION, model) \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
|
/* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
|
||||||
"ThinkPad T42p", so the order of the entries matters.
|
"ThinkPad T42p", so the order of the entries matters.
|
||||||
If your ThinkPad is not recognized, please update to latest
|
If your ThinkPad is not recognized, please update to latest
|
||||||
BIOS. This is especially the case for some R52 ThinkPads. */
|
BIOS. This is especially the case for some R52 ThinkPads. */
|
||||||
static struct dmi_system_id __initdata hdaps_whitelist[] = {
|
static struct dmi_system_id __initdata hdaps_whitelist[] = {
|
||||||
HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p"),
|
HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p", HDAPS_BOTH_AXES),
|
||||||
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"),
|
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"),
|
||||||
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"),
|
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"),
|
||||||
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"),
|
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"),
|
||||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i"),
|
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i", HDAPS_BOTH_AXES),
|
||||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61"),
|
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61", HDAPS_BOTH_AXES),
|
||||||
HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p"),
|
HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p", HDAPS_BOTH_AXES),
|
||||||
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"),
|
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"),
|
||||||
HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p"),
|
HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p", HDAPS_BOTH_AXES),
|
||||||
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"),
|
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"),
|
||||||
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"),
|
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"),
|
||||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60"),
|
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60", HDAPS_BOTH_AXES),
|
||||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p"),
|
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p", HDAPS_BOTH_AXES),
|
||||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61"),
|
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61", HDAPS_BOTH_AXES),
|
||||||
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"),
|
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"),
|
||||||
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X41"),
|
HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad X41", HDAPS_Y_AXIS),
|
||||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60"),
|
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60", HDAPS_BOTH_AXES),
|
||||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s"),
|
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s", HDAPS_BOTH_AXES),
|
||||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61"),
|
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61", HDAPS_BOTH_AXES),
|
||||||
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"),
|
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"),
|
||||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m"),
|
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m", HDAPS_BOTH_AXES),
|
||||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p"),
|
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p", HDAPS_BOTH_AXES),
|
||||||
{ .ident = NULL }
|
{ .ident = NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -627,8 +628,9 @@ static void __exit hdaps_exit(void)
|
||||||
module_init(hdaps_init);
|
module_init(hdaps_init);
|
||||||
module_exit(hdaps_exit);
|
module_exit(hdaps_exit);
|
||||||
|
|
||||||
module_param_named(invert, hdaps_invert, bool, 0);
|
module_param_named(invert, hdaps_invert, int, 0);
|
||||||
MODULE_PARM_DESC(invert, "invert data along each axis");
|
MODULE_PARM_DESC(invert, "invert data along each axis. 1 invert x-axis, "
|
||||||
|
"2 invert y-axis, 3 invert both axes.");
|
||||||
|
|
||||||
MODULE_AUTHOR("Robert Love");
|
MODULE_AUTHOR("Robert Love");
|
||||||
MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");
|
MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
|
w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
|
||||||
0x8860 0xa1
|
0x8860 0xa1
|
||||||
w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
|
w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
|
||||||
|
w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
@ -52,12 +53,13 @@
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include "lm75.h"
|
#include "lm75.h"
|
||||||
|
|
||||||
enum kinds { w83627ehf, w83627dhg };
|
enum kinds { w83627ehf, w83627dhg, w83667hg };
|
||||||
|
|
||||||
/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
|
/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
|
||||||
static const char * w83627ehf_device_names[] = {
|
static const char * w83627ehf_device_names[] = {
|
||||||
"w83627ehf",
|
"w83627ehf",
|
||||||
"w83627dhg",
|
"w83627dhg",
|
||||||
|
"w83667hg",
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned short force_id;
|
static unsigned short force_id;
|
||||||
|
@ -71,6 +73,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define W83627EHF_LD_HWM 0x0b
|
#define W83627EHF_LD_HWM 0x0b
|
||||||
|
#define W83667HG_LD_VID 0x0d
|
||||||
|
|
||||||
#define SIO_REG_LDSEL 0x07 /* Logical device select */
|
#define SIO_REG_LDSEL 0x07 /* Logical device select */
|
||||||
#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
|
#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
|
||||||
|
@ -83,6 +86,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
|
||||||
#define SIO_W83627EHF_ID 0x8850
|
#define SIO_W83627EHF_ID 0x8850
|
||||||
#define SIO_W83627EHG_ID 0x8860
|
#define SIO_W83627EHG_ID 0x8860
|
||||||
#define SIO_W83627DHG_ID 0xa020
|
#define SIO_W83627DHG_ID 0xa020
|
||||||
|
#define SIO_W83667HG_ID 0xa510
|
||||||
#define SIO_ID_MASK 0xFFF0
|
#define SIO_ID_MASK 0xFFF0
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -289,6 +293,7 @@ struct w83627ehf_data {
|
||||||
u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
|
u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
|
||||||
u8 pwm_enable[4]; /* 1->manual
|
u8 pwm_enable[4]; /* 1->manual
|
||||||
2->thermal cruise (also called SmartFan I) */
|
2->thermal cruise (also called SmartFan I) */
|
||||||
|
u8 pwm_num; /* number of pwm */
|
||||||
u8 pwm[4];
|
u8 pwm[4];
|
||||||
u8 target_temp[4];
|
u8 target_temp[4];
|
||||||
u8 tolerance[4];
|
u8 tolerance[4];
|
||||||
|
@ -298,6 +303,9 @@ struct w83627ehf_data {
|
||||||
|
|
||||||
u8 vid;
|
u8 vid;
|
||||||
u8 vrm;
|
u8 vrm;
|
||||||
|
|
||||||
|
u8 temp3_disable;
|
||||||
|
u8 in6_skip;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct w83627ehf_sio_data {
|
struct w83627ehf_sio_data {
|
||||||
|
@ -866,25 +874,37 @@ show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
|
return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sensor_device_attribute sda_temp[] = {
|
static struct sensor_device_attribute sda_temp_input[] = {
|
||||||
SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
|
SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
|
||||||
SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
|
SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
|
||||||
SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
|
SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sensor_device_attribute sda_temp_max[] = {
|
||||||
SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
|
SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
|
||||||
store_temp1_max, 0),
|
store_temp1_max, 0),
|
||||||
SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
|
SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
|
||||||
store_temp_max, 0),
|
store_temp_max, 0),
|
||||||
SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
|
SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
|
||||||
store_temp_max, 1),
|
store_temp_max, 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sensor_device_attribute sda_temp_max_hyst[] = {
|
||||||
SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
|
SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
|
||||||
store_temp1_max_hyst, 0),
|
store_temp1_max_hyst, 0),
|
||||||
SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
|
SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
|
||||||
store_temp_max_hyst, 0),
|
store_temp_max_hyst, 0),
|
||||||
SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
|
SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
|
||||||
store_temp_max_hyst, 1),
|
store_temp_max_hyst, 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sensor_device_attribute sda_temp_alarm[] = {
|
||||||
SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
|
SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
|
||||||
SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
|
SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
|
||||||
SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
|
SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sensor_device_attribute sda_temp_type[] = {
|
||||||
SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
|
SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
|
||||||
SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
|
SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
|
||||||
SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
|
SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
|
||||||
|
@ -1181,6 +1201,8 @@ static void w83627ehf_device_remove_files(struct device *dev)
|
||||||
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
|
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
|
||||||
device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
|
device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
|
||||||
for (i = 0; i < data->in_num; i++) {
|
for (i = 0; i < data->in_num; i++) {
|
||||||
|
if ((i == 6) && data->in6_skip)
|
||||||
|
continue;
|
||||||
device_remove_file(dev, &sda_in_input[i].dev_attr);
|
device_remove_file(dev, &sda_in_input[i].dev_attr);
|
||||||
device_remove_file(dev, &sda_in_alarm[i].dev_attr);
|
device_remove_file(dev, &sda_in_alarm[i].dev_attr);
|
||||||
device_remove_file(dev, &sda_in_min[i].dev_attr);
|
device_remove_file(dev, &sda_in_min[i].dev_attr);
|
||||||
|
@ -1192,15 +1214,22 @@ static void w83627ehf_device_remove_files(struct device *dev)
|
||||||
device_remove_file(dev, &sda_fan_div[i].dev_attr);
|
device_remove_file(dev, &sda_fan_div[i].dev_attr);
|
||||||
device_remove_file(dev, &sda_fan_min[i].dev_attr);
|
device_remove_file(dev, &sda_fan_min[i].dev_attr);
|
||||||
}
|
}
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < data->pwm_num; i++) {
|
||||||
device_remove_file(dev, &sda_pwm[i].dev_attr);
|
device_remove_file(dev, &sda_pwm[i].dev_attr);
|
||||||
device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
|
device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
|
||||||
device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
|
device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
|
||||||
device_remove_file(dev, &sda_target_temp[i].dev_attr);
|
device_remove_file(dev, &sda_target_temp[i].dev_attr);
|
||||||
device_remove_file(dev, &sda_tolerance[i].dev_attr);
|
device_remove_file(dev, &sda_tolerance[i].dev_attr);
|
||||||
}
|
}
|
||||||
for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
|
for (i = 0; i < 3; i++) {
|
||||||
device_remove_file(dev, &sda_temp[i].dev_attr);
|
if ((i == 2) && data->temp3_disable)
|
||||||
|
continue;
|
||||||
|
device_remove_file(dev, &sda_temp_input[i].dev_attr);
|
||||||
|
device_remove_file(dev, &sda_temp_max[i].dev_attr);
|
||||||
|
device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
|
||||||
|
device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
|
||||||
|
device_remove_file(dev, &sda_temp_type[i].dev_attr);
|
||||||
|
}
|
||||||
|
|
||||||
device_remove_file(dev, &dev_attr_name);
|
device_remove_file(dev, &dev_attr_name);
|
||||||
device_remove_file(dev, &dev_attr_cpu0_vid);
|
device_remove_file(dev, &dev_attr_cpu0_vid);
|
||||||
|
@ -1222,6 +1251,8 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
tmp = w83627ehf_read_value(data,
|
tmp = w83627ehf_read_value(data,
|
||||||
W83627EHF_REG_TEMP_CONFIG[i]);
|
W83627EHF_REG_TEMP_CONFIG[i]);
|
||||||
|
if ((i == 1) && data->temp3_disable)
|
||||||
|
continue;
|
||||||
if (tmp & 0x01)
|
if (tmp & 0x01)
|
||||||
w83627ehf_write_value(data,
|
w83627ehf_write_value(data,
|
||||||
W83627EHF_REG_TEMP_CONFIG[i],
|
W83627EHF_REG_TEMP_CONFIG[i],
|
||||||
|
@ -1272,8 +1303,17 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
||||||
data->name = w83627ehf_device_names[sio_data->kind];
|
data->name = w83627ehf_device_names[sio_data->kind];
|
||||||
platform_set_drvdata(pdev, data);
|
platform_set_drvdata(pdev, data);
|
||||||
|
|
||||||
/* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */
|
/* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
|
||||||
data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10;
|
data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
|
||||||
|
/* 667HG has 3 pwms */
|
||||||
|
data->pwm_num = (sio_data->kind == w83667hg) ? 3 : 4;
|
||||||
|
|
||||||
|
/* Check temp3 configuration bit for 667HG */
|
||||||
|
if (sio_data->kind == w83667hg) {
|
||||||
|
data->temp3_disable = w83627ehf_read_value(data,
|
||||||
|
W83627EHF_REG_TEMP_CONFIG[1]) & 0x01;
|
||||||
|
data->in6_skip = !data->temp3_disable;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize the chip */
|
/* Initialize the chip */
|
||||||
w83627ehf_init_device(data);
|
w83627ehf_init_device(data);
|
||||||
|
@ -1281,29 +1321,44 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
||||||
data->vrm = vid_which_vrm();
|
data->vrm = vid_which_vrm();
|
||||||
superio_enter(sio_data->sioreg);
|
superio_enter(sio_data->sioreg);
|
||||||
/* Read VID value */
|
/* Read VID value */
|
||||||
|
if (sio_data->kind == w83667hg) {
|
||||||
|
/* W83667HG has different pins for VID input and output, so
|
||||||
|
we can get the VID input values directly at logical device D
|
||||||
|
0xe3. */
|
||||||
|
superio_select(sio_data->sioreg, W83667HG_LD_VID);
|
||||||
|
data->vid = superio_inb(sio_data->sioreg, 0xe3);
|
||||||
|
err = device_create_file(dev, &dev_attr_cpu0_vid);
|
||||||
|
if (err)
|
||||||
|
goto exit_release;
|
||||||
|
} else {
|
||||||
superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
|
superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
|
||||||
if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
|
if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
|
||||||
/* Set VID input sensibility if needed. In theory the BIOS
|
/* Set VID input sensibility if needed. In theory the
|
||||||
should have set it, but in practice it's not always the
|
BIOS should have set it, but in practice it's not
|
||||||
case. We only do it for the W83627EHF/EHG because the
|
always the case. We only do it for the W83627EHF/EHG
|
||||||
W83627DHG is more complex in this respect. */
|
because the W83627DHG is more complex in this
|
||||||
|
respect. */
|
||||||
if (sio_data->kind == w83627ehf) {
|
if (sio_data->kind == w83627ehf) {
|
||||||
en_vrm10 = superio_inb(sio_data->sioreg,
|
en_vrm10 = superio_inb(sio_data->sioreg,
|
||||||
SIO_REG_EN_VRM10);
|
SIO_REG_EN_VRM10);
|
||||||
if ((en_vrm10 & 0x08) && data->vrm == 90) {
|
if ((en_vrm10 & 0x08) && data->vrm == 90) {
|
||||||
dev_warn(dev, "Setting VID input voltage to "
|
dev_warn(dev, "Setting VID input "
|
||||||
"TTL\n");
|
"voltage to TTL\n");
|
||||||
superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
|
superio_outb(sio_data->sioreg,
|
||||||
|
SIO_REG_EN_VRM10,
|
||||||
en_vrm10 & ~0x08);
|
en_vrm10 & ~0x08);
|
||||||
} else if (!(en_vrm10 & 0x08) && data->vrm == 100) {
|
} else if (!(en_vrm10 & 0x08)
|
||||||
dev_warn(dev, "Setting VID input voltage to "
|
&& data->vrm == 100) {
|
||||||
"VRM10\n");
|
dev_warn(dev, "Setting VID input "
|
||||||
superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
|
"voltage to VRM10\n");
|
||||||
|
superio_outb(sio_data->sioreg,
|
||||||
|
SIO_REG_EN_VRM10,
|
||||||
en_vrm10 | 0x08);
|
en_vrm10 | 0x08);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA);
|
data->vid = superio_inb(sio_data->sioreg,
|
||||||
|
SIO_REG_VID_DATA);
|
||||||
if (sio_data->kind == w83627ehf) /* 6 VID pins only */
|
if (sio_data->kind == w83627ehf) /* 6 VID pins only */
|
||||||
data->vid &= 0x3f;
|
data->vid &= 0x3f;
|
||||||
|
|
||||||
|
@ -1314,11 +1369,16 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
||||||
dev_info(dev, "VID pins in output mode, CPU VID not "
|
dev_info(dev, "VID pins in output mode, CPU VID not "
|
||||||
"available\n");
|
"available\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* fan4 and fan5 share some pins with the GPIO and serial flash */
|
/* fan4 and fan5 share some pins with the GPIO and serial flash */
|
||||||
|
if (sio_data->kind == w83667hg) {
|
||||||
fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2;
|
fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
|
||||||
fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6;
|
fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
|
||||||
|
} else {
|
||||||
|
fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
|
||||||
|
fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
|
||||||
|
}
|
||||||
superio_exit(sio_data->sioreg);
|
superio_exit(sio_data->sioreg);
|
||||||
|
|
||||||
/* It looks like fan4 and fan5 pins can be alternatively used
|
/* It looks like fan4 and fan5 pins can be alternatively used
|
||||||
|
@ -1329,9 +1389,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
data->has_fan = 0x07; /* fan1, fan2 and fan3 */
|
data->has_fan = 0x07; /* fan1, fan2 and fan3 */
|
||||||
i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
|
i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
|
||||||
if ((i & (1 << 2)) && (!fan4pin))
|
if ((i & (1 << 2)) && fan4pin)
|
||||||
data->has_fan |= (1 << 3);
|
data->has_fan |= (1 << 3);
|
||||||
if (!(i & (1 << 1)) && (!fan5pin))
|
if (!(i & (1 << 1)) && fan5pin)
|
||||||
data->has_fan |= (1 << 4);
|
data->has_fan |= (1 << 4);
|
||||||
|
|
||||||
/* Read fan clock dividers immediately */
|
/* Read fan clock dividers immediately */
|
||||||
|
@ -1344,14 +1404,16 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
||||||
goto exit_remove;
|
goto exit_remove;
|
||||||
|
|
||||||
/* if fan4 is enabled create the sf3 files for it */
|
/* if fan4 is enabled create the sf3 files for it */
|
||||||
if (data->has_fan & (1 << 3))
|
if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
|
||||||
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
|
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
|
||||||
if ((err = device_create_file(dev,
|
if ((err = device_create_file(dev,
|
||||||
&sda_sf3_arrays_fan4[i].dev_attr)))
|
&sda_sf3_arrays_fan4[i].dev_attr)))
|
||||||
goto exit_remove;
|
goto exit_remove;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < data->in_num; i++)
|
for (i = 0; i < data->in_num; i++) {
|
||||||
|
if ((i == 6) && data->in6_skip)
|
||||||
|
continue;
|
||||||
if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
|
if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
|
||||||
|| (err = device_create_file(dev,
|
|| (err = device_create_file(dev,
|
||||||
&sda_in_alarm[i].dev_attr))
|
&sda_in_alarm[i].dev_attr))
|
||||||
|
@ -1360,6 +1422,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
||||||
|| (err = device_create_file(dev,
|
|| (err = device_create_file(dev,
|
||||||
&sda_in_max[i].dev_attr)))
|
&sda_in_max[i].dev_attr)))
|
||||||
goto exit_remove;
|
goto exit_remove;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
if (data->has_fan & (1 << i)) {
|
if (data->has_fan & (1 << i)) {
|
||||||
|
@ -1372,7 +1435,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
||||||
|| (err = device_create_file(dev,
|
|| (err = device_create_file(dev,
|
||||||
&sda_fan_min[i].dev_attr)))
|
&sda_fan_min[i].dev_attr)))
|
||||||
goto exit_remove;
|
goto exit_remove;
|
||||||
if (i < 4 && /* w83627ehf only has 4 pwm */
|
if (i < data->pwm_num &&
|
||||||
((err = device_create_file(dev,
|
((err = device_create_file(dev,
|
||||||
&sda_pwm[i].dev_attr))
|
&sda_pwm[i].dev_attr))
|
||||||
|| (err = device_create_file(dev,
|
|| (err = device_create_file(dev,
|
||||||
|
@ -1387,9 +1450,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
|
for (i = 0; i < 3; i++) {
|
||||||
if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
|
if ((i == 2) && data->temp3_disable)
|
||||||
|
continue;
|
||||||
|
if ((err = device_create_file(dev,
|
||||||
|
&sda_temp_input[i].dev_attr))
|
||||||
|
|| (err = device_create_file(dev,
|
||||||
|
&sda_temp_max[i].dev_attr))
|
||||||
|
|| (err = device_create_file(dev,
|
||||||
|
&sda_temp_max_hyst[i].dev_attr))
|
||||||
|
|| (err = device_create_file(dev,
|
||||||
|
&sda_temp_alarm[i].dev_attr))
|
||||||
|
|| (err = device_create_file(dev,
|
||||||
|
&sda_temp_type[i].dev_attr)))
|
||||||
goto exit_remove;
|
goto exit_remove;
|
||||||
|
}
|
||||||
|
|
||||||
err = device_create_file(dev, &dev_attr_name);
|
err = device_create_file(dev, &dev_attr_name);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -1442,6 +1517,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
|
||||||
static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
|
static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
|
||||||
static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
|
static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
|
||||||
static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
|
static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
|
||||||
|
static const char __initdata sio_name_W83667HG[] = "W83667HG";
|
||||||
|
|
||||||
u16 val;
|
u16 val;
|
||||||
const char *sio_name;
|
const char *sio_name;
|
||||||
|
@ -1466,6 +1542,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
|
||||||
sio_data->kind = w83627dhg;
|
sio_data->kind = w83627dhg;
|
||||||
sio_name = sio_name_W83627DHG;
|
sio_name = sio_name_W83627DHG;
|
||||||
break;
|
break;
|
||||||
|
case SIO_W83667HG_ID:
|
||||||
|
sio_data->kind = w83667hg;
|
||||||
|
sio_name = sio_name_W83667HG;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (val != 0xffff)
|
if (val != 0xffff)
|
||||||
pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
|
pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/dmi.h>
|
||||||
|
|
||||||
/* I801 SMBus address offsets */
|
/* I801 SMBus address offsets */
|
||||||
#define SMBHSTSTS (0 + i801_smba)
|
#define SMBHSTSTS (0 + i801_smba)
|
||||||
|
@ -616,10 +617,81 @@ static void __init input_apanel_init(void)
|
||||||
static void __init input_apanel_init(void) {}
|
static void __init input_apanel_init(void) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
|
||||||
|
struct dmi_onboard_device_info {
|
||||||
|
const char *name;
|
||||||
|
u8 type;
|
||||||
|
unsigned short i2c_addr;
|
||||||
|
const char *i2c_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dmi_onboard_device_info __devinitdata dmi_devices[] = {
|
||||||
|
{ "Syleus", DMI_DEV_TYPE_OTHER, 0x73, "fscsyl" },
|
||||||
|
{ "Hermes", DMI_DEV_TYPE_OTHER, 0x73, "fscher" },
|
||||||
|
{ "Hades", DMI_DEV_TYPE_OTHER, 0x73, "fschds" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void __devinit dmi_check_onboard_device(u8 type, const char *name,
|
||||||
|
struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct i2c_board_info info;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(dmi_devices); i++) {
|
||||||
|
/* & ~0x80, ignore enabled/disabled bit */
|
||||||
|
if ((type & ~0x80) != dmi_devices[i].type)
|
||||||
|
continue;
|
||||||
|
if (strcmp(name, dmi_devices[i].name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||||
|
info.addr = dmi_devices[i].i2c_addr;
|
||||||
|
strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE);
|
||||||
|
i2c_new_device(adap, &info);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We use our own function to check for onboard devices instead of
|
||||||
|
dmi_find_device() as some buggy BIOS's have the devices we are interested
|
||||||
|
in marked as disabled */
|
||||||
|
static void __devinit dmi_check_onboard_devices(const struct dmi_header *dm,
|
||||||
|
void *adap)
|
||||||
|
{
|
||||||
|
int i, count;
|
||||||
|
|
||||||
|
if (dm->type != 10)
|
||||||
|
return;
|
||||||
|
|
||||||
|
count = (dm->length - sizeof(struct dmi_header)) / 2;
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
const u8 *d = (char *)(dm + 1) + (i * 2);
|
||||||
|
const char *name = ((char *) dm) + dm->length;
|
||||||
|
u8 type = d[0];
|
||||||
|
u8 s = d[1];
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
continue;
|
||||||
|
s--;
|
||||||
|
while (s > 0 && name[0]) {
|
||||||
|
name += strlen(name) + 1;
|
||||||
|
s--;
|
||||||
|
}
|
||||||
|
if (name[0] == 0) /* Bogus string reference */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
dmi_check_onboard_device(type, name, adap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||||
{
|
{
|
||||||
unsigned char temp;
|
unsigned char temp;
|
||||||
int err;
|
int err;
|
||||||
|
#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
|
||||||
|
const char *vendor;
|
||||||
|
#endif
|
||||||
|
|
||||||
I801_dev = dev;
|
I801_dev = dev;
|
||||||
i801_features = 0;
|
i801_features = 0;
|
||||||
|
@ -712,6 +784,11 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
|
||||||
i2c_new_device(&i801_adapter, &info);
|
i2c_new_device(&i801_adapter, &info);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
|
||||||
|
vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
|
||||||
|
if (vendor && !strcmp(vendor, "FUJITSU SIEMENS"))
|
||||||
|
dmi_walk(dmi_check_onboard_devices, &i801_adapter);
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -64,19 +64,6 @@ config SENSORS_PCA9539
|
||||||
This driver is deprecated and will be dropped soon. Use
|
This driver is deprecated and will be dropped soon. Use
|
||||||
drivers/gpio/pca953x.c instead.
|
drivers/gpio/pca953x.c instead.
|
||||||
|
|
||||||
config SENSORS_PCF8591
|
|
||||||
tristate "Philips PCF8591"
|
|
||||||
depends on EXPERIMENTAL
|
|
||||||
default n
|
|
||||||
help
|
|
||||||
If you say yes here you get support for Philips PCF8591 chips.
|
|
||||||
|
|
||||||
This driver can also be built as a module. If so, the module
|
|
||||||
will be called pcf8591.
|
|
||||||
|
|
||||||
These devices are hard to detect and rarely found on mainstream
|
|
||||||
hardware. If unsure, say N.
|
|
||||||
|
|
||||||
config SENSORS_MAX6875
|
config SENSORS_MAX6875
|
||||||
tristate "Maxim MAX6875 Power supply supervisor"
|
tristate "Maxim MAX6875 Power supply supervisor"
|
||||||
depends on EXPERIMENTAL
|
depends on EXPERIMENTAL
|
||||||
|
|
|
@ -15,7 +15,6 @@ obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
|
||||||
obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
|
obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
|
||||||
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
|
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
|
||||||
obj-$(CONFIG_PCF8575) += pcf8575.o
|
obj-$(CONFIG_PCF8575) += pcf8575.o
|
||||||
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
|
|
||||||
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
|
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
|
||||||
|
|
||||||
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
|
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
|
||||||
|
|
|
@ -103,7 +103,7 @@ static void parse_da_table(const struct dmi_header *dm)
|
||||||
da_num_tokens += tokens;
|
da_num_tokens += tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void find_tokens(const struct dmi_header *dm)
|
static void find_tokens(const struct dmi_header *dm, void *dummy)
|
||||||
{
|
{
|
||||||
switch (dm->type) {
|
switch (dm->type) {
|
||||||
case 0xd4: /* Indexed IO */
|
case 0xd4: /* Indexed IO */
|
||||||
|
@ -356,7 +356,7 @@ static int __init dell_init(void)
|
||||||
if (!dmi_check_system(dell_device_table))
|
if (!dmi_check_system(dell_device_table))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
dmi_walk(find_tokens);
|
dmi_walk(find_tokens, NULL);
|
||||||
|
|
||||||
if (!da_tokens) {
|
if (!da_tokens) {
|
||||||
printk(KERN_INFO "dell-laptop: Unable to find dmi tokens\n");
|
printk(KERN_INFO "dell-laptop: Unable to find dmi tokens\n");
|
||||||
|
|
|
@ -380,7 +380,7 @@ asm(".text \n\t"
|
||||||
* This function checks whether or not a SMBIOS/DMI record is
|
* This function checks whether or not a SMBIOS/DMI record is
|
||||||
* the 64bit CRU info or not
|
* the 64bit CRU info or not
|
||||||
*/
|
*/
|
||||||
static void __devinit dmi_find_cru(const struct dmi_header *dm)
|
static void __devinit dmi_find_cru(const struct dmi_header *dm, void *dummy)
|
||||||
{
|
{
|
||||||
struct smbios_cru64_info *smbios_cru64_ptr;
|
struct smbios_cru64_info *smbios_cru64_ptr;
|
||||||
unsigned long cru_physical_address;
|
unsigned long cru_physical_address;
|
||||||
|
@ -403,7 +403,7 @@ static int __devinit detect_cru_service(void)
|
||||||
{
|
{
|
||||||
cru_rom_addr = NULL;
|
cru_rom_addr = NULL;
|
||||||
|
|
||||||
dmi_walk(dmi_find_cru);
|
dmi_walk(dmi_find_cru, NULL);
|
||||||
|
|
||||||
/* if cru_rom_addr has been set then we found a CRU service */
|
/* if cru_rom_addr has been set then we found a CRU service */
|
||||||
return ((cru_rom_addr != NULL) ? 0 : -ENODEV);
|
return ((cru_rom_addr != NULL) ? 0 : -ENODEV);
|
||||||
|
|
|
@ -47,7 +47,8 @@ extern int dmi_get_year(int field);
|
||||||
extern int dmi_name_in_vendors(const char *str);
|
extern int dmi_name_in_vendors(const char *str);
|
||||||
extern int dmi_name_in_serial(const char *str);
|
extern int dmi_name_in_serial(const char *str);
|
||||||
extern int dmi_available;
|
extern int dmi_available;
|
||||||
extern int dmi_walk(void (*decode)(const struct dmi_header *));
|
extern int dmi_walk(void (*decode)(const struct dmi_header *, void *),
|
||||||
|
void *private_data);
|
||||||
extern bool dmi_match(enum dmi_field f, const char *str);
|
extern bool dmi_match(enum dmi_field f, const char *str);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -61,8 +62,8 @@ static inline int dmi_get_year(int year) { return 0; }
|
||||||
static inline int dmi_name_in_vendors(const char *s) { return 0; }
|
static inline int dmi_name_in_vendors(const char *s) { return 0; }
|
||||||
static inline int dmi_name_in_serial(const char *s) { return 0; }
|
static inline int dmi_name_in_serial(const char *s) { return 0; }
|
||||||
#define dmi_available 0
|
#define dmi_available 0
|
||||||
static inline int dmi_walk(void (*decode)(const struct dmi_header *))
|
static inline int dmi_walk(void (*decode)(const struct dmi_header *, void *),
|
||||||
{ return -1; }
|
void *private_data) { return -1; }
|
||||||
static inline bool dmi_match(enum dmi_field f, const char *str)
|
static inline bool dmi_match(enum dmi_field f, const char *str)
|
||||||
{ return false; }
|
{ return false; }
|
||||||
static inline const struct dmi_system_id *
|
static inline const struct dmi_system_id *
|
||||||
|
|
Loading…
Add table
Reference in a new issue