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:
Коммит
3c6fae67d0
|
@ -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
|
||||
1.0 degree Celsius to avoid Tout "bouncing", though!
|
||||
|
||||
As for alarms, you can read the alarm status of the DS1621 via the 'alarms'
|
||||
/sys file interface. The result consists mainly of bit 6 and 5 of the
|
||||
configuration register of the chip; bit 6 (0x40 or 64) is the high alarm
|
||||
bit and bit 5 (0x20 or 32) the low one. These bits are set when the high or
|
||||
low limits are met or exceeded and are reset by the module as soon as the
|
||||
respective temperature ranges are left.
|
||||
The alarm bits are set when the high or low limits are met or exceeded and
|
||||
are reset by the module as soon as the respective temperature ranges are
|
||||
left.
|
||||
|
||||
The alarm registers are in no way suitable to find out about the actual
|
||||
status of Tout. They will only tell you about its history, whether or not
|
||||
|
@ -64,45 +61,3 @@ with neither of the alarms set.
|
|||
|
||||
Temperature conversion of the DS1621 takes up to 1000ms; internal access to
|
||||
non-volatile registers may last for 10ms or below.
|
||||
|
||||
High Accuracy Temperature Reading
|
||||
---------------------------------
|
||||
|
||||
As said before, the temperature issued via the 9-bit i2c-bus data is
|
||||
somewhat arbitrary. Internally, the temperature conversion is of a
|
||||
different kind that is explained (not so...) well in the DS1621 data sheet.
|
||||
To cut the long story short: Inside the DS1621 there are two oscillators,
|
||||
both of them biassed by a temperature coefficient.
|
||||
|
||||
Higher resolution of the temperature reading can be achieved using the
|
||||
internal projection, which means taking account of REG_COUNT and REG_SLOPE
|
||||
(the driver manages them):
|
||||
|
||||
Taken from Dallas Semiconductors App Note 068: 'Increasing Temperature
|
||||
Resolution on the DS1620' and App Note 105: 'High Resolution Temperature
|
||||
Measurement with Dallas Direct-to-Digital Temperature Sensors'
|
||||
|
||||
- Read the 9-bit temperature and strip the LSB (Truncate the .5 degs)
|
||||
- The resulting value is TEMP_READ.
|
||||
- Then, read REG_COUNT.
|
||||
- And then, REG_SLOPE.
|
||||
|
||||
TEMP = TEMP_READ - 0.25 + ((REG_SLOPE - REG_COUNT) / REG_SLOPE)
|
||||
|
||||
Note that this is what the DONE bit in the DS1621 configuration register is
|
||||
good for: Internally, one temperature conversion takes up to 1000ms. Before
|
||||
that conversion is complete you will not be able to read valid things out
|
||||
of REG_COUNT and REG_SLOPE. The DONE bit, as you may have guessed by now,
|
||||
tells you whether the conversion is complete ("done", in plain English) and
|
||||
thus, whether the values you read are good or not.
|
||||
|
||||
The DS1621 has two modes of operation: "Continuous" conversion, which can
|
||||
be understood as the default stand-alone mode where the chip gets the
|
||||
temperature and controls external devices via its Tout pin or tells other
|
||||
i2c's about it if they care. The other mode is called "1SHOT", that means
|
||||
that it only figures out about the temperature when it is explicitly told
|
||||
to do so; this can be seen as power saving mode.
|
||||
|
||||
Now if you want to read REG_COUNT and REG_SLOPE, you have to either stop
|
||||
the continuous conversions until the contents of these registers are valid,
|
||||
or, in 1SHOT mode, you have to have one conversion made.
|
||||
|
|
|
@ -365,6 +365,7 @@ energy[1-*]_input Cumulative energy use
|
|||
Unit: microJoule
|
||||
RO
|
||||
|
||||
|
||||
**********
|
||||
* Alarms *
|
||||
**********
|
||||
|
@ -453,6 +454,27 @@ beep_mask Bitmask for beep.
|
|||
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
|
||||
-------------------------------------
|
||||
|
||||
|
|
|
@ -2,30 +2,40 @@ Kernel driver w83627ehf
|
|||
=======================
|
||||
|
||||
Supported chips:
|
||||
* Winbond W83627EHF/EHG/DHG (ISA access ONLY)
|
||||
* Winbond W83627EHF/EHG (ISA access ONLY)
|
||||
Prefix: 'w83627ehf'
|
||||
Addresses scanned: ISA address retrieved from Super I/O registers
|
||||
Datasheet:
|
||||
http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf
|
||||
DHG datasheet confidential.
|
||||
http://www.nuvoton.com.tw/NR/rdonlyres/A6A258F0-F0C9-4F97-81C0-C4D29E7E943E/0/W83627EHF.pdf
|
||||
* 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:
|
||||
Jean Delvare <khali@linux-fr.org>
|
||||
Yuan Mu (Winbond)
|
||||
Rudolf Marek <r.marek@assembler.cz>
|
||||
David Hubbard <david.c.hubbard@gmail.com>
|
||||
Gong Jun <JGong@nuvoton.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the Winbond W83627EHF, W83627EHG, and
|
||||
W83627DHG super I/O chips. We will refer to them collectively as Winbond chips.
|
||||
This driver implements support for the Winbond W83627EHF, W83627EHG,
|
||||
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
|
||||
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
|
||||
warnings (control unimplemented), and some automatic fan regulation
|
||||
strategies (plus manual fan control mode).
|
||||
VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG), alarms
|
||||
with beep warnings (control unimplemented), and some automatic fan
|
||||
regulation strategies (plus manual fan control mode).
|
||||
|
||||
Temperatures are measured in degrees Celsius and measurement resolution is 1
|
||||
degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
|
||||
|
@ -54,7 +64,8 @@ follows:
|
|||
temp1 -> pwm1
|
||||
temp2 -> pwm2
|
||||
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
|
||||
----------
|
||||
|
|
|
@ -68,7 +68,8 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s)
|
|||
* pointing to completely the wrong place for example
|
||||
*/
|
||||
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;
|
||||
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]))
|
||||
data++;
|
||||
if (data - buf < len - 1)
|
||||
decode(dm);
|
||||
decode(dm, private_data);
|
||||
data += 2;
|
||||
i++;
|
||||
}
|
||||
|
@ -99,7 +100,8 @@ static u32 dmi_base;
|
|||
static u16 dmi_len;
|
||||
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;
|
||||
|
||||
|
@ -107,7 +109,7 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *))
|
|||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
dmi_table(buf, dmi_len, dmi_num, decode);
|
||||
dmi_table(buf, dmi_len, dmi_num, decode, NULL);
|
||||
|
||||
dmi_iounmap(buf, dmi_len);
|
||||
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
|
||||
* 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) {
|
||||
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
|
||||
* @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.
|
||||
*/
|
||||
int dmi_walk(void (*decode)(const struct dmi_header *))
|
||||
int dmi_walk(void (*decode)(const struct dmi_header *, void *),
|
||||
void *private_data)
|
||||
{
|
||||
u8 *buf;
|
||||
|
||||
|
@ -612,7 +616,7 @@ int dmi_walk(void (*decode)(const struct dmi_header *))
|
|||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
dmi_table(buf, dmi_len, dmi_num, decode);
|
||||
dmi_table(buf, dmi_len, dmi_num, decode, private_data);
|
||||
|
||||
iounmap(buf);
|
||||
return 0;
|
||||
|
|
|
@ -343,12 +343,13 @@ config SENSORS_FSCPOS
|
|||
will be called fscpos.
|
||||
|
||||
config SENSORS_FSCHMD
|
||||
tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles"
|
||||
tristate "Fujitsu Siemens Computers sensor chips"
|
||||
depends on X86 && I2C
|
||||
help
|
||||
If you say yes here you get support for various Fujitsu Siemens
|
||||
Computers sensor chips, including support for the integrated
|
||||
watchdog.
|
||||
If you say yes here you get support for the following Fujitsu
|
||||
Siemens Computers (FSC) sensor chips: Poseidon, Scylla, Hermes,
|
||||
Heimdall, Heracles, Hades and Syleus including support for the
|
||||
integrated watchdog.
|
||||
|
||||
This is a merged driver for FSC sensor chips replacing the fscpos,
|
||||
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
|
||||
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
|
||||
tristate "Silicon Integrated Systems Corp. SiS5595"
|
||||
depends on PCI
|
||||
|
@ -827,7 +842,7 @@ config SENSORS_W83627HF
|
|||
will be called w83627hf.
|
||||
|
||||
config SENSORS_W83627EHF
|
||||
tristate "Winbond W83627EHF/DHG"
|
||||
tristate "Winbond W83627EHF/EHG/DHG, W83667HG"
|
||||
select HWMON_VID
|
||||
help
|
||||
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
|
||||
the Core 2 Duo.
|
||||
|
||||
This driver also supports the W83667HG chip.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called w83627ehf.
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
|
|||
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
|
||||
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
|
||||
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
|
||||
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
|
||||
obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
|
||||
obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
|
||||
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
|
||||
|
|
|
@ -81,71 +81,84 @@ struct ds1621_data {
|
|||
u8 conf; /* Register encoding, combined */
|
||||
};
|
||||
|
||||
static int ds1621_probe(struct i2c_client *client,
|
||||
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.
|
||||
/* Temperature registers are word-sized.
|
||||
DS1621 uses a high-byte first convention, which is exactly opposite to
|
||||
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)
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
else
|
||||
return swab16(i2c_smbus_read_word_data(client, reg));
|
||||
int ret;
|
||||
|
||||
ret = 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)
|
||||
{
|
||||
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 */
|
||||
reg &= ~ DS1621_REG_CONFIG_1SHOT;
|
||||
new_conf &= ~DS1621_REG_CONFIG_1SHOT;
|
||||
|
||||
/* setup output polarity */
|
||||
if (polarity == 0)
|
||||
reg &= ~DS1621_REG_CONFIG_POLARITY;
|
||||
new_conf &= ~DS1621_REG_CONFIG_POLARITY;
|
||||
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 */
|
||||
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,
|
||||
char *buf)
|
||||
{
|
||||
|
@ -160,13 +173,13 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
|
|||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ds1621_data *data = ds1621_update_client(dev);
|
||||
struct ds1621_data *data = i2c_get_clientdata(client);
|
||||
u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10));
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp[attr->index] = val;
|
||||
ds1621_write_value(client, DS1621_REG_TEMP[attr->index],
|
||||
data->temp[attr->index]);
|
||||
ds1621_write_temp(client, DS1621_REG_TEMP[attr->index],
|
||||
data->temp[attr->index]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
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
|
||||
requested during the latest 10ms, which is highly
|
||||
improbable in our case. */
|
||||
conf = ds1621_read_value(client, DS1621_REG_CONF);
|
||||
if (conf & DS1621_REG_CONFIG_NVB)
|
||||
conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
|
||||
if (conf < 0 || conf & DS1621_REG_CONFIG_NVB)
|
||||
return -ENODEV;
|
||||
/* The 7 lowest bits of a temperature should always be 0. */
|
||||
for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) {
|
||||
temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
|
||||
if (temp & 0x007f)
|
||||
temp = i2c_smbus_read_word_data(client,
|
||||
DS1621_REG_TEMP[i]);
|
||||
if (temp < 0 || (temp & 0x7f00))
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
@ -294,45 +308,25 @@ static int ds1621_remove(struct i2c_client *client)
|
|||
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)
|
||||
{
|
||||
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 = 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;
|
||||
}
|
||||
/* 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,
|
||||
};
|
||||
|
||||
static int __init ds1621_init(void)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* 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
|
||||
* 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,
|
||||
* 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
|
||||
* (candidate) fschmd drivers:
|
||||
|
@ -56,7 +56,7 @@ static int nowayout = WATCHDOG_NOWAYOUT;
|
|||
module_param(nowayout, int, 0);
|
||||
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
|
||||
__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
|
||||
|
@ -75,9 +75,12 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
|
|||
#define FSCHMD_CONTROL_ALERT_LED 0x01
|
||||
|
||||
/* watchdog */
|
||||
#define FSCHMD_REG_WDOG_PRESET 0x28
|
||||
#define FSCHMD_REG_WDOG_STATE 0x23
|
||||
#define FSCHMD_REG_WDOG_CONTROL 0x21
|
||||
static const u8 FSCHMD_REG_WDOG_CONTROL[7] =
|
||||
{ 0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 };
|
||||
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_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
|
||||
|
||||
/* 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
|
||||
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
|
||||
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, 0xb5 }, /* her */
|
||||
{ 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */
|
||||
{ 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */
|
||||
{ 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */
|
||||
{ 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hds */
|
||||
{ 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 }, /* syl */
|
||||
};
|
||||
|
||||
/* 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, 0xbb }, /* her */
|
||||
{ 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */
|
||||
{ 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */
|
||||
{ 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */
|
||||
{ 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hds */
|
||||
{ 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 }, /* syl */
|
||||
};
|
||||
|
||||
/* 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, 0xb2 }, /* her */
|
||||
{ 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */
|
||||
{ 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */
|
||||
{ 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */
|
||||
{ 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hds */
|
||||
{ 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 }, /* syl */
|
||||
};
|
||||
|
||||
/* 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, 0xbf }, /* her */
|
||||
{ 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */
|
||||
{ 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */
|
||||
{ 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 */
|
||||
#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 */
|
||||
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 }, /* her */
|
||||
{ 0x64, 0xD0, 0x32, 0x35 }, /* scy */
|
||||
{ 0x64, 0x32, 0x35 }, /* hrc */
|
||||
{ 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 */
|
||||
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 }, /* her */
|
||||
{ 0x71, 0xd1, 0x81, 0x91 }, /* scy */
|
||||
{ 0x71, 0x81, 0x91 }, /* hrc */
|
||||
{ 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
|
||||
|
@ -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
|
||||
at these addresses, but doesn't want to confirm they are the same as with
|
||||
the fscher?? */
|
||||
static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = {
|
||||
static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = {
|
||||
{ 0, 0, 0 }, /* pos */
|
||||
{ 0x76, 0x86, 0x96 }, /* her */
|
||||
{ 0x76, 0xd6, 0x86, 0x96 }, /* scy */
|
||||
{ 0x76, 0x86, 0x96 }, /* hrc */
|
||||
{ 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
|
||||
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_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 */
|
||||
#define FSCHMD_TEMP_WORKING 0x01
|
||||
#define FSCHMD_TEMP_ALERT 0x02
|
||||
#define FSCHMD_TEMP_DISABLED 0x80
|
||||
/* there only really is an alarm if the sensor is working and alert == 1 */
|
||||
#define FSCHMD_TEMP_ALARM_MASK \
|
||||
(FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT)
|
||||
|
@ -201,6 +236,8 @@ static const struct i2c_device_id fschmd_id[] = {
|
|||
{ "fscscy", fscscy },
|
||||
{ "fschrc", fschrc },
|
||||
{ "fschmd", fschmd },
|
||||
{ "fschds", fschds },
|
||||
{ "fscsyl", fscsyl },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, fschmd_id);
|
||||
|
@ -242,14 +279,14 @@ struct fschmd_data {
|
|||
u8 watchdog_control; /* watchdog control register */
|
||||
u8 watchdog_state; /* watchdog status register */
|
||||
u8 watchdog_preset; /* watchdog counter preset on trigger val */
|
||||
u8 volt[3]; /* 12, 5, battery voltage */
|
||||
u8 temp_act[5]; /* temperature */
|
||||
u8 temp_status[5]; /* status of sensor */
|
||||
u8 temp_max[5]; /* high temp limit, notice: undocumented! */
|
||||
u8 fan_act[6]; /* fans revolutions per second */
|
||||
u8 fan_status[6]; /* fan status */
|
||||
u8 fan_min[6]; /* fan min value for rps */
|
||||
u8 fan_ripple[6]; /* divider for rps */
|
||||
u8 volt[6]; /* voltage */
|
||||
u8 temp_act[11]; /* temperature */
|
||||
u8 temp_status[11]; /* status of sensor */
|
||||
u8 temp_max[11]; /* high temp limit, notice: undocumented! */
|
||||
u8 fan_act[7]; /* fans revolutions per second */
|
||||
u8 fan_status[7]; /* fan status */
|
||||
u8 fan_min[7]; /* fan min value for rps */
|
||||
u8 fan_ripple[7]; /* divider for rps */
|
||||
};
|
||||
|
||||
/* 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
|
||||
which always gets called with the i2c-core lock held and never accessed
|
||||
before the attach function is done with them. */
|
||||
static int dmi_mult[3] = { 490, 200, 100 };
|
||||
static int dmi_offset[3] = { 0, 0, 0 };
|
||||
static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 };
|
||||
static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 };
|
||||
static int dmi_vref = -1;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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% */
|
||||
if (val)
|
||||
/* 0 = allow turning off (except on the syl), 1-255 = 50-100% */
|
||||
if (val || data->kind == fscsyl - 1)
|
||||
val = val / 2 + 128;
|
||||
|
||||
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);
|
||||
unsigned long v = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
/* register: 0 = allow turning off, 1-255 = 50-100% */
|
||||
if (v) {
|
||||
/* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
|
||||
if (v || data->kind == fscsyl - 1) {
|
||||
v = SENSORS_LIMIT(v, 128, 255);
|
||||
v = (v - 128) * 2 + 1;
|
||||
}
|
||||
|
@ -522,11 +560,15 @@ static ssize_t store_alert_led(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led);
|
||||
|
||||
static struct sensor_device_attribute fschmd_attr[] = {
|
||||
SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
|
||||
SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
|
||||
SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
|
||||
SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0),
|
||||
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[] = {
|
||||
|
@ -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_fault, 0444, show_temp_fault, 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[] = {
|
||||
|
@ -589,6 +655,12 @@ static struct sensor_device_attribute fschmd_fan_attr[] = {
|
|||
SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
|
||||
SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
|
||||
store_pwm_auto_point1_pwm, 5),
|
||||
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);
|
||||
|
||||
/* Write new timeout value */
|
||||
i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_PRESET,
|
||||
data->watchdog_preset);
|
||||
i2c_smbus_write_byte_data(data->client,
|
||||
FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset);
|
||||
/* 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);
|
||||
|
||||
ret = data->watchdog_preset * resolution;
|
||||
|
@ -662,8 +735,9 @@ static int watchdog_trigger(struct fschmd_data *data)
|
|||
}
|
||||
|
||||
data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER;
|
||||
i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
|
||||
data->watchdog_control);
|
||||
i2c_smbus_write_byte_data(data->client,
|
||||
FSCHMD_REG_WDOG_CONTROL[data->kind],
|
||||
data->watchdog_control);
|
||||
leave:
|
||||
mutex_unlock(&data->watchdog_lock);
|
||||
return ret;
|
||||
|
@ -682,7 +756,8 @@ static int watchdog_stop(struct fschmd_data *data)
|
|||
data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED;
|
||||
/* Don't store the stop flag in our watchdog control register copy, as
|
||||
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);
|
||||
leave:
|
||||
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,
|
||||
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;
|
||||
|
||||
|
@ -912,6 +987,15 @@ static void fschmd_dmi_decode(const struct dmi_header *header)
|
|||
dmi_mult[i] = mult[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;
|
||||
}
|
||||
}
|
||||
|
@ -920,8 +1004,6 @@ static int fschmd_detect(struct i2c_client *client, int kind,
|
|||
struct i2c_board_info *info)
|
||||
{
|
||||
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))
|
||||
return -ENODEV;
|
||||
|
@ -948,11 +1030,15 @@ static int fschmd_detect(struct i2c_client *client, int kind,
|
|||
kind = fschrc;
|
||||
else if (!strcmp(id, "HMD"))
|
||||
kind = fschmd;
|
||||
else if (!strcmp(id, "HDS"))
|
||||
kind = fschds;
|
||||
else if (!strcmp(id, "SYL"))
|
||||
kind = fscsyl;
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
@ -961,8 +1047,8 @@ static int fschmd_probe(struct i2c_client *client,
|
|||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct fschmd_data *data;
|
||||
const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
|
||||
"Heracles", "Heimdall" };
|
||||
const char * const names[7] = { "Poseidon", "Hermes", "Scylla",
|
||||
"Heracles", "Heimdall", "Hades", "Syleus" };
|
||||
const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
|
||||
int i, err;
|
||||
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 */
|
||||
if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) {
|
||||
dmi_walk(fschmd_dmi_decode);
|
||||
dmi_walk(fschmd_dmi_decode, NULL);
|
||||
if (dmi_vref == -1) {
|
||||
dev_warn(&client->dev,
|
||||
"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 */
|
||||
data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
|
||||
data->global_control = i2c_smbus_read_byte_data(client,
|
||||
FSCHMD_REG_CONTROL);
|
||||
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,
|
||||
FSCHMD_REG_WDOG_STATE);
|
||||
FSCHMD_REG_WDOG_STATE[data->kind]);
|
||||
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 */
|
||||
data->kind = kind - 1;
|
||||
err = device_create_file(&client->dev, &dev_attr_alert_led);
|
||||
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,
|
||||
&fschmd_attr[i].dev_attr);
|
||||
if (err)
|
||||
|
@ -1027,6 +1117,16 @@ static int fschmd_probe(struct i2c_client *client,
|
|||
show_temp_max)
|
||||
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,
|
||||
&fschmd_temp_attr[i].dev_attr);
|
||||
if (err)
|
||||
|
@ -1040,6 +1140,16 @@ static int fschmd_probe(struct i2c_client *client,
|
|||
"pwm3_auto_point1_pwm"))
|
||||
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,
|
||||
&fschmd_fan_attr[i].dev_attr);
|
||||
if (err)
|
||||
|
@ -1126,7 +1236,8 @@ static int fschmd_remove(struct i2c_client *client)
|
|||
if (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);
|
||||
for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
|
||||
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])
|
||||
i2c_smbus_write_byte_data(client,
|
||||
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++) {
|
||||
|
@ -1193,12 +1304,12 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
|
|||
data->fan_act[i])
|
||||
i2c_smbus_write_byte_data(client,
|
||||
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,
|
||||
FSCHMD_REG_VOLT[i]);
|
||||
FSCHMD_REG_VOLT[data->kind][i]);
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
|
@ -1220,8 +1331,8 @@ static void __exit fschmd_exit(void)
|
|||
}
|
||||
|
||||
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
|
||||
MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and "
|
||||
"Heimdall driver");
|
||||
MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades "
|
||||
"and Syleus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(fschmd_init);
|
||||
|
|
|
@ -65,6 +65,10 @@
|
|||
#define HDAPS_INPUT_FUZZ 4 /* input event threshold */
|
||||
#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 input_polled_dev *hdaps_idev;
|
||||
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);
|
||||
__device_complete();
|
||||
|
||||
/* if hdaps_invert is set, negate the two values */
|
||||
if (hdaps_invert) {
|
||||
/* hdaps_invert is a bitvector to negate the axes */
|
||||
if (hdaps_invert & HDAPS_X_AXIS)
|
||||
*x = -*x;
|
||||
if (hdaps_invert & HDAPS_Y_AXIS)
|
||||
*y = -*y;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -436,7 +440,8 @@ static ssize_t hdaps_invert_store(struct device *dev,
|
|||
{
|
||||
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;
|
||||
|
||||
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. */
|
||||
static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
|
||||
{
|
||||
hdaps_invert = 1;
|
||||
printk(KERN_INFO "hdaps: inverting axis readings.\n");
|
||||
hdaps_invert = (unsigned long)id->driver_data;
|
||||
printk(KERN_INFO "hdaps: inverting axis (%u) readings.\n",
|
||||
hdaps_invert);
|
||||
return hdaps_dmi_match(id);
|
||||
}
|
||||
|
||||
#define HDAPS_DMI_MATCH_NORMAL(vendor, model) { \
|
||||
#define HDAPS_DMI_MATCH_INVERT(vendor, model, axes) { \
|
||||
.ident = vendor " " model, \
|
||||
.callback = hdaps_dmi_match, \
|
||||
.callback = hdaps_dmi_match_invert, \
|
||||
.driver_data = (void *)axes, \
|
||||
.matches = { \
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, model) \
|
||||
} \
|
||||
}
|
||||
|
||||
#define HDAPS_DMI_MATCH_INVERT(vendor, model) { \
|
||||
.ident = vendor " " model, \
|
||||
.callback = hdaps_dmi_match_invert, \
|
||||
.matches = { \
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, model) \
|
||||
} \
|
||||
}
|
||||
#define HDAPS_DMI_MATCH_NORMAL(vendor, model) \
|
||||
HDAPS_DMI_MATCH_INVERT(vendor, model, 0)
|
||||
|
||||
/* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
|
||||
"ThinkPad T42p", so the order of the entries matters.
|
||||
If your ThinkPad is not recognized, please update to latest
|
||||
BIOS. This is especially the case for some R52 ThinkPads. */
|
||||
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 R51"),
|
||||
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i"),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61"),
|
||||
HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p"),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i", HDAPS_BOTH_AXES),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61", HDAPS_BOTH_AXES),
|
||||
HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p", HDAPS_BOTH_AXES),
|
||||
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 T43"),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60"),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p"),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61"),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60", HDAPS_BOTH_AXES),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p", HDAPS_BOTH_AXES),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61", HDAPS_BOTH_AXES),
|
||||
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"),
|
||||
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X41"),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60"),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s"),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61"),
|
||||
HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad X41", HDAPS_Y_AXIS),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60", HDAPS_BOTH_AXES),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s", HDAPS_BOTH_AXES),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61", HDAPS_BOTH_AXES),
|
||||
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m"),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p"),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m", HDAPS_BOTH_AXES),
|
||||
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p", HDAPS_BOTH_AXES),
|
||||
{ .ident = NULL }
|
||||
};
|
||||
|
||||
|
@ -627,8 +628,9 @@ static void __exit hdaps_exit(void)
|
|||
module_init(hdaps_init);
|
||||
module_exit(hdaps_exit);
|
||||
|
||||
module_param_named(invert, hdaps_invert, bool, 0);
|
||||
MODULE_PARM_DESC(invert, "invert data along each axis");
|
||||
module_param_named(invert, hdaps_invert, int, 0);
|
||||
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_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net>
|
||||
Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
|
||||
Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
|
||||
the help of Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -41,13 +41,13 @@ MODULE_PARM_DESC(input_mode,
|
|||
" 3 = two differential inputs\n");
|
||||
|
||||
/* The PCF8591 control byte
|
||||
7 6 5 4 3 2 1 0
|
||||
7 6 5 4 3 2 1 0
|
||||
| 0 |AOEF| AIP | 0 |AINC| AICH | */
|
||||
|
||||
/* Analog Output Enable Flag (analog output active if 1) */
|
||||
#define PCF8591_CONTROL_AOEF 0x40
|
||||
|
||||
/* Analog Input Programming
|
||||
|
||||
/* Analog Input Programming
|
||||
0x00 = four single ended inputs
|
||||
0x10 = three differential inputs
|
||||
0x20 = single ended and differential mixed
|
||||
|
@ -58,7 +58,7 @@ MODULE_PARM_DESC(input_mode,
|
|||
#define PCF8591_CONTROL_AINC 0x04
|
||||
|
||||
/* Channel selection
|
||||
0x00 = channel 0
|
||||
0x00 = channel 0
|
||||
0x01 = channel 1
|
||||
0x02 = channel 2
|
||||
0x03 = channel 3 */
|
||||
|
@ -114,7 +114,7 @@ static ssize_t set_out0_output(struct device *dev, struct device_attribute *attr
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO,
|
||||
static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO,
|
||||
show_out0_ouput, set_out0_output);
|
||||
|
||||
static ssize_t show_out0_enable(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
|
@ -139,7 +139,7 @@ static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr
|
|||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO,
|
||||
static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO,
|
||||
show_out0_enable, set_out0_enable);
|
||||
|
||||
static struct attribute *pcf8591_attributes[] = {
|
||||
|
@ -196,7 +196,7 @@ static int pcf8591_probe(struct i2c_client *client,
|
|||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
|
@ -249,8 +249,8 @@ static void pcf8591_init_client(struct i2c_client *client)
|
|||
data->aout = PCF8591_INIT_AOUT;
|
||||
|
||||
i2c_smbus_write_byte_data(client, data->control, data->aout);
|
||||
|
||||
/* The first byte transmitted contains the conversion code of the
|
||||
|
||||
/* The first byte transmitted contains the conversion code of the
|
||||
previous read cycle. FLUSH IT! */
|
||||
i2c_smbus_read_byte(client);
|
||||
}
|
||||
|
@ -267,8 +267,8 @@ static int pcf8591_read_channel(struct device *dev, int channel)
|
|||
data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK)
|
||||
| channel;
|
||||
i2c_smbus_write_byte(client, data->control);
|
||||
|
||||
/* The first byte transmitted contains the conversion code of
|
||||
|
||||
/* The first byte transmitted contains the conversion code of
|
||||
the previous read cycle. FLUSH IT! */
|
||||
i2c_smbus_read_byte(client);
|
||||
}
|
|
@ -36,6 +36,7 @@
|
|||
w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
|
||||
0x8860 0xa1
|
||||
w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
|
||||
w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -52,12 +53,13 @@
|
|||
#include <asm/io.h>
|
||||
#include "lm75.h"
|
||||
|
||||
enum kinds { w83627ehf, w83627dhg };
|
||||
enum kinds { w83627ehf, w83627dhg, w83667hg };
|
||||
|
||||
/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
|
||||
static const char * w83627ehf_device_names[] = {
|
||||
"w83627ehf",
|
||||
"w83627dhg",
|
||||
"w83667hg",
|
||||
};
|
||||
|
||||
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 W83667HG_LD_VID 0x0d
|
||||
|
||||
#define SIO_REG_LDSEL 0x07 /* Logical device select */
|
||||
#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_W83627EHG_ID 0x8860
|
||||
#define SIO_W83627DHG_ID 0xa020
|
||||
#define SIO_W83667HG_ID 0xa510
|
||||
#define SIO_ID_MASK 0xFFF0
|
||||
|
||||
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_enable[4]; /* 1->manual
|
||||
2->thermal cruise (also called SmartFan I) */
|
||||
u8 pwm_num; /* number of pwm */
|
||||
u8 pwm[4];
|
||||
u8 target_temp[4];
|
||||
u8 tolerance[4];
|
||||
|
@ -298,6 +303,9 @@ struct w83627ehf_data {
|
|||
|
||||
u8 vid;
|
||||
u8 vrm;
|
||||
|
||||
u8 temp3_disable;
|
||||
u8 in6_skip;
|
||||
};
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
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(temp2_input, S_IRUGO, show_temp, NULL, 0),
|
||||
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,
|
||||
store_temp1_max, 0),
|
||||
SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
|
||||
store_temp_max, 0),
|
||||
SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
|
||||
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,
|
||||
store_temp1_max_hyst, 0),
|
||||
SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
|
||||
store_temp_max_hyst, 0),
|
||||
SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
|
||||
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(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
|
||||
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(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
|
||||
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++)
|
||||
device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
|
||||
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_alarm[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_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_mode[i].dev_attr);
|
||||
device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
|
||||
device_remove_file(dev, &sda_target_temp[i].dev_attr);
|
||||
device_remove_file(dev, &sda_tolerance[i].dev_attr);
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
|
||||
device_remove_file(dev, &sda_temp[i].dev_attr);
|
||||
for (i = 0; i < 3; i++) {
|
||||
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_cpu0_vid);
|
||||
|
@ -1222,6 +1251,8 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
|
|||
for (i = 0; i < 2; i++) {
|
||||
tmp = w83627ehf_read_value(data,
|
||||
W83627EHF_REG_TEMP_CONFIG[i]);
|
||||
if ((i == 1) && data->temp3_disable)
|
||||
continue;
|
||||
if (tmp & 0x01)
|
||||
w83627ehf_write_value(data,
|
||||
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];
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
/* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */
|
||||
data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10;
|
||||
/* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
|
||||
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 */
|
||||
w83627ehf_init_device(data);
|
||||
|
@ -1281,44 +1321,64 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|||
data->vrm = vid_which_vrm();
|
||||
superio_enter(sio_data->sioreg);
|
||||
/* Read VID value */
|
||||
superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
|
||||
if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
|
||||
/* Set VID input sensibility if needed. In theory the BIOS
|
||||
should have set it, but in practice it's not always the
|
||||
case. We only do it for the W83627EHF/EHG because the
|
||||
W83627DHG is more complex in this respect. */
|
||||
if (sio_data->kind == w83627ehf) {
|
||||
en_vrm10 = superio_inb(sio_data->sioreg,
|
||||
SIO_REG_EN_VRM10);
|
||||
if ((en_vrm10 & 0x08) && data->vrm == 90) {
|
||||
dev_warn(dev, "Setting VID input voltage to "
|
||||
"TTL\n");
|
||||
superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
|
||||
en_vrm10 & ~0x08);
|
||||
} else if (!(en_vrm10 & 0x08) && data->vrm == 100) {
|
||||
dev_warn(dev, "Setting VID input voltage to "
|
||||
"VRM10\n");
|
||||
superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
|
||||
en_vrm10 | 0x08);
|
||||
}
|
||||
}
|
||||
|
||||
data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA);
|
||||
if (sio_data->kind == w83627ehf) /* 6 VID pins only */
|
||||
data->vid &= 0x3f;
|
||||
|
||||
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 {
|
||||
dev_info(dev, "VID pins in output mode, CPU VID not "
|
||||
"available\n");
|
||||
superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
|
||||
if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
|
||||
/* Set VID input sensibility if needed. In theory the
|
||||
BIOS should have set it, but in practice it's not
|
||||
always the case. We only do it for the W83627EHF/EHG
|
||||
because the W83627DHG is more complex in this
|
||||
respect. */
|
||||
if (sio_data->kind == w83627ehf) {
|
||||
en_vrm10 = superio_inb(sio_data->sioreg,
|
||||
SIO_REG_EN_VRM10);
|
||||
if ((en_vrm10 & 0x08) && data->vrm == 90) {
|
||||
dev_warn(dev, "Setting VID input "
|
||||
"voltage to TTL\n");
|
||||
superio_outb(sio_data->sioreg,
|
||||
SIO_REG_EN_VRM10,
|
||||
en_vrm10 & ~0x08);
|
||||
} else if (!(en_vrm10 & 0x08)
|
||||
&& data->vrm == 100) {
|
||||
dev_warn(dev, "Setting VID input "
|
||||
"voltage to VRM10\n");
|
||||
superio_outb(sio_data->sioreg,
|
||||
SIO_REG_EN_VRM10,
|
||||
en_vrm10 | 0x08);
|
||||
}
|
||||
}
|
||||
|
||||
data->vid = superio_inb(sio_data->sioreg,
|
||||
SIO_REG_VID_DATA);
|
||||
if (sio_data->kind == w83627ehf) /* 6 VID pins only */
|
||||
data->vid &= 0x3f;
|
||||
|
||||
err = device_create_file(dev, &dev_attr_cpu0_vid);
|
||||
if (err)
|
||||
goto exit_release;
|
||||
} else {
|
||||
dev_info(dev, "VID pins in output mode, CPU VID not "
|
||||
"available\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* fan4 and fan5 share some pins with the GPIO and serial flash */
|
||||
|
||||
fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2;
|
||||
fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6;
|
||||
if (sio_data->kind == w83667hg) {
|
||||
fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
|
||||
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);
|
||||
|
||||
/* 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 */
|
||||
i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
|
||||
if ((i & (1 << 2)) && (!fan4pin))
|
||||
if ((i & (1 << 2)) && fan4pin)
|
||||
data->has_fan |= (1 << 3);
|
||||
if (!(i & (1 << 1)) && (!fan5pin))
|
||||
if (!(i & (1 << 1)) && fan5pin)
|
||||
data->has_fan |= (1 << 4);
|
||||
|
||||
/* Read fan clock dividers immediately */
|
||||
|
@ -1344,14 +1404,16 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|||
goto exit_remove;
|
||||
|
||||
/* 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++) {
|
||||
if ((err = device_create_file(dev,
|
||||
&sda_sf3_arrays_fan4[i].dev_attr)))
|
||||
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))
|
||||
|| (err = device_create_file(dev,
|
||||
&sda_in_alarm[i].dev_attr))
|
||||
|
@ -1360,6 +1422,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|||
|| (err = device_create_file(dev,
|
||||
&sda_in_max[i].dev_attr)))
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (data->has_fan & (1 << i)) {
|
||||
|
@ -1372,7 +1435,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
|
|||
|| (err = device_create_file(dev,
|
||||
&sda_fan_min[i].dev_attr)))
|
||||
goto exit_remove;
|
||||
if (i < 4 && /* w83627ehf only has 4 pwm */
|
||||
if (i < data->pwm_num &&
|
||||
((err = device_create_file(dev,
|
||||
&sda_pwm[i].dev_attr))
|
||||
|| (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++)
|
||||
if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
|
||||
for (i = 0; i < 3; i++) {
|
||||
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;
|
||||
}
|
||||
|
||||
err = device_create_file(dev, &dev_attr_name);
|
||||
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_W83627EHG[] = "W83627EHG";
|
||||
static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
|
||||
static const char __initdata sio_name_W83667HG[] = "W83667HG";
|
||||
|
||||
u16 val;
|
||||
const char *sio_name;
|
||||
|
@ -1466,6 +1542,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
|
|||
sio_data->kind = w83627dhg;
|
||||
sio_name = sio_name_W83627DHG;
|
||||
break;
|
||||
case SIO_W83667HG_ID:
|
||||
sio_data->kind = w83667hg;
|
||||
sio_name = sio_name_W83667HG;
|
||||
break;
|
||||
default:
|
||||
if (val != 0xffff)
|
||||
pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
/* I801 SMBus address offsets */
|
||||
#define SMBHSTSTS (0 + i801_smba)
|
||||
|
@ -616,10 +617,81 @@ static void __init input_apanel_init(void)
|
|||
static void __init input_apanel_init(void) {}
|
||||
#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)
|
||||
{
|
||||
unsigned char temp;
|
||||
int err;
|
||||
#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
|
||||
const char *vendor;
|
||||
#endif
|
||||
|
||||
I801_dev = dev;
|
||||
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);
|
||||
}
|
||||
#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;
|
||||
|
||||
|
|
|
@ -64,19 +64,6 @@ config SENSORS_PCA9539
|
|||
This driver is deprecated and will be dropped soon. Use
|
||||
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
|
||||
tristate "Maxim MAX6875 Power supply supervisor"
|
||||
depends on EXPERIMENTAL
|
||||
|
|
|
@ -15,7 +15,6 @@ obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
|
|||
obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
|
||||
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
|
||||
obj-$(CONFIG_PCF8575) += pcf8575.o
|
||||
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
|
||||
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
|
||||
|
||||
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
|
||||
|
|
|
@ -103,7 +103,7 @@ static void parse_da_table(const struct dmi_header *dm)
|
|||
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) {
|
||||
case 0xd4: /* Indexed IO */
|
||||
|
@ -356,7 +356,7 @@ static int __init dell_init(void)
|
|||
if (!dmi_check_system(dell_device_table))
|
||||
return -ENODEV;
|
||||
|
||||
dmi_walk(find_tokens);
|
||||
dmi_walk(find_tokens, NULL);
|
||||
|
||||
if (!da_tokens) {
|
||||
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
|
||||
* 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;
|
||||
unsigned long cru_physical_address;
|
||||
|
@ -403,7 +403,7 @@ static int __devinit detect_cru_service(void)
|
|||
{
|
||||
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 */
|
||||
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_serial(const char *str);
|
||||
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);
|
||||
|
||||
#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_serial(const char *s) { return 0; }
|
||||
#define dmi_available 0
|
||||
static inline int dmi_walk(void (*decode)(const struct dmi_header *))
|
||||
{ return -1; }
|
||||
static inline int dmi_walk(void (*decode)(const struct dmi_header *, void *),
|
||||
void *private_data) { return -1; }
|
||||
static inline bool dmi_match(enum dmi_field f, const char *str)
|
||||
{ return false; }
|
||||
static inline const struct dmi_system_id *
|
||||
|
|
Загрузка…
Ссылка в новой задаче