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:
Linus Torvalds 2009-03-30 17:54:32 -07:00
Родитель c4e1aa67ed de15f093e6
Коммит 3c6fae67d0
18 изменённых файлов: 588 добавлений и 327 удалений

Просмотреть файл

@ -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 *