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: (it87) Support for 16-bit fan reading in it8705 >= rev 0x03
  hwmon: (it87) Support for 16-bit fan reading in it8712 >= rev 0x07
  hwmon: (hwmon-vid) Add 6-bit vid codes for AMD NPT 0Fh cpus
  hwmon: (hwmon-vid) Trivial format multi-line comments per CodingStyle
  hwmon: ad7414 driver
  hwmon: (thmc50) Add support for critical temperature limits
  hwmon: (adm9240) Remove EXPERIMENTAL dependency
  hwmon: (w83627hf) Drop reset module parameter
  hwmon: (w83627hf) Add pwm_enable sysfs interface
  hwmon: (w83791d) Use fan divisor bits from vbat register
  hwmon: (f71882fg) Delete needless forward declarations
  hwmon: (dme1737) Add support for the SMSC SCH5027
  hwmon: (dme1737) Skip detection if forced
  hwmon: (dme1737) Cleanups
This commit is contained in:
Linus Torvalds 2008-08-07 18:05:39 -07:00
commit a06dee41a3
14 changed files with 734 additions and 267 deletions

View File

@ -10,6 +10,10 @@ Supported chips:
Prefix: 'sch311x'
Addresses scanned: none, address read from Super-I/O config space
Datasheet: http://www.nuhorizons.com/FeaturedProducts/Volume1/SMSC/311x.pdf
* SMSC SCH5027
Prefix: 'sch5027'
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
Datasheet: Provided by SMSC upon request and under NDA
Authors:
Juerg Haefliger <juergh@gmail.com>
@ -27,33 +31,31 @@ Module Parameters
following boards:
- VIA EPIA SN18000
Note that there is no need to use this parameter if the driver loads without
complaining. The driver will say so if it is necessary.
Description
-----------
This driver implements support for the hardware monitoring capabilities of the
SMSC DME1737 and Asus A8000 (which are the same) and SMSC SCH311x Super-I/O
chips. These chips feature monitoring of 3 temp sensors temp[1-3] (2 remote
diodes and 1 internal), 7 voltages in[0-6] (6 external and 1 internal) and up
to 6 fan speeds fan[1-6]. Additionally, the chips implement up to 5 PWM
outputs pwm[1-3,5-6] for controlling fan speeds both manually and
SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, and SMSC
SCH311x Super-I/O chips. These chips feature monitoring of 3 temp sensors
temp[1-3] (2 remote diodes and 1 internal), 7 voltages in[0-6] (6 external and
1 internal) and up to 6 fan speeds fan[1-6]. Additionally, the chips implement
up to 5 PWM outputs pwm[1-3,5-6] for controlling fan speeds both manually and
automatically.
For the DME1737 and A8000, fan[1-2] and pwm[1-2] are always present. Fan[3-6]
and pwm[3,5-6] are optional features and their availability depends on the
configuration of the chip. The driver will detect which features are present
during initialization and create the sysfs attributes accordingly.
For the DME1737, A8000 and SCH5027, fan[1-2] and pwm[1-2] are always present.
Fan[3-6] and pwm[3,5-6] are optional features and their availability depends on
the configuration of the chip. The driver will detect which features are
present during initialization and create the sysfs attributes accordingly.
For the SCH311x, fan[1-3] and pwm[1-3] are always present and fan[4-6] and
pwm[5-6] don't exist.
The hardware monitoring features of the DME1737 and A8000 are only accessible
via SMBus, while the SCH311x only provides access via the ISA bus. The driver
will therefore register itself as an I2C client driver if it detects a DME1737
or A8000 and as a platform driver if it detects a SCH311x chip.
The hardware monitoring features of the DME1737, A8000, and SCH5027 are only
accessible via SMBus, while the SCH311x only provides access via the ISA bus.
The driver will therefore register itself as an I2C client driver if it detects
a DME1737, A8000, or SCH5027 and as a platform driver if it detects a SCH311x
chip.
Voltage Monitoring
@ -64,6 +66,7 @@ scaling resistors. The values returned by the driver therefore reflect true
millivolts and don't need scaling. The voltage inputs are mapped as follows
(the last column indicates the input ranges):
DME1737, A8000:
in0: +5VTR (+5V standby) 0V - 6.64V
in1: Vccp (processor core) 0V - 3V
in2: VCC (internal +3.3V) 0V - 4.38V
@ -72,6 +75,24 @@ millivolts and don't need scaling. The voltage inputs are mapped as follows
in5: VTR (+3.3V standby) 0V - 4.38V
in6: Vbat (+3.0V) 0V - 4.38V
SCH311x:
in0: +2.5V 0V - 6.64V
in1: Vccp (processor core) 0V - 2V
in2: VCC (internal +3.3V) 0V - 4.38V
in3: +5V 0V - 6.64V
in4: +12V 0V - 16V
in5: VTR (+3.3V standby) 0V - 4.38V
in6: Vbat (+3.0V) 0V - 4.38V
SCH5027:
in0: +5VTR (+5V standby) 0V - 6.64V
in1: Vccp (processor core) 0V - 3V
in2: VCC (internal +3.3V) 0V - 4.38V
in3: V2_IN 0V - 1.5V
in4: V1_IN 0V - 1.5V
in5: VTR (+3.3V standby) 0V - 4.38V
in6: Vbat (+3.0V) 0V - 4.38V
Each voltage input has associated min and max limits which trigger an alarm
when crossed.

View File

@ -6,12 +6,14 @@ Supported chips:
Prefix: 'it87'
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Publicly available at the ITE website
http://www.ite.com.tw/
http://www.ite.com.tw/product_info/file/pc/IT8705F_V.0.4.1.pdf
* IT8712F
Prefix: 'it8712'
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Publicly available at the ITE website
http://www.ite.com.tw/
http://www.ite.com.tw/product_info/file/pc/IT8712F_V0.9.1.pdf
http://www.ite.com.tw/product_info/file/pc/Errata%20V0.1%20for%20IT8712F%20V0.9.1.pdf
http://www.ite.com.tw/product_info/file/pc/IT8712F_V0.9.3.pdf
* IT8716F/IT8726F
Prefix: 'it8716'
Addresses scanned: from Super I/O config space (8 I/O ports)
@ -90,14 +92,13 @@ upper VID bits share their pins with voltage inputs (in5 and in6) so you
can't have both on a given board.
The IT8716F, IT8718F and later IT8712F revisions have support for
2 additional fans. They are supported by the driver for the IT8716F and
IT8718F but not for the IT8712F
2 additional fans. The additional fans are supported by the driver.
The IT8716F and IT8718F, and late IT8712F and IT8705F also have optional
16-bit tachometer counters for fans 1 to 3. This is better (no more fan
clock divider mess) but not compatible with the older chips and
revisions. For now, the driver only uses the 16-bit mode on the
IT8716F and IT8718F.
revisions. The 16-bit tachometer mode is enabled by the driver when one
of the above chips is detected.
The IT8726F is just bit enhanced IT8716F with additional hardware
for AMD power sequencing. Therefore the chip will appear as IT8716F

View File

@ -40,10 +40,6 @@ Module Parameters
(default is 1)
Use 'init=0' to bypass initializing the chip.
Try this if your computer crashes when you load the module.
* reset: int
(default is 0)
The driver used to reset the chip on load, but does no more. Use
'reset=1' to restore the old behavior. Report if you need to do this.
Description
-----------

View File

@ -22,6 +22,7 @@ Credits:
Additional contributors:
Sven Anders <anders@anduras.de>
Marc Hulsman <m.hulsman@tudelft.nl>
Module Parameters
-----------------
@ -67,9 +68,8 @@ on until the temperature falls below the Hysteresis value.
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
triggered if the rotation speed has dropped below a programmable limit. Fan
readings can be divided by a programmable divider (1, 2, 4, 8 for fan 1/2/3
and 1, 2, 4, 8, 16, 32, 64 or 128 for fan 4/5) to give the readings more
range or accuracy.
readings can be divided by a programmable divider (1, 2, 4, 8, 16,
32, 64 or 128 for all fans) to give the readings more range or accuracy.
Voltage sensors (also known as IN sensors) report their values in millivolts.
An alarm is triggered if the voltage has crossed a programmable minimum

View File

@ -57,6 +57,16 @@ config SENSORS_ABITUGURU3
This driver can also be built as a module. If so, the module
will be called abituguru3.
config SENSORS_AD7414
tristate "Analog Devices AD7414"
depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for the Analog Devices
AD7414 temperature monitoring chip.
This driver can also be built as a module. If so, the module
will be called ad7414.
config SENSORS_AD7418
tristate "Analog Devices AD7416, AD7417 and AD7418"
depends on I2C && EXPERIMENTAL
@ -124,7 +134,7 @@ config SENSORS_ADM1031
config SENSORS_ADM9240
tristate "Analog Devices ADM9240 and compatibles"
depends on I2C && EXPERIMENTAL
depends on I2C
select HWMON_VID
help
If you say yes here you get support for Analog Devices ADM9240,
@ -575,8 +585,8 @@ config SENSORS_DME1737
select HWMON_VID
help
If you say yes here you get support for the hardware monitoring
and fan control features of the SMSC DME1737 (and compatibles
like the Asus A8000) and SCH311x Super-I/O chips.
and fan control features of the SMSC DME1737, SCH311x, SCH5027, and
Asus A8000 Super-I/O chips.
This driver can also be built as a module. If so, the module
will be called dme1737.

View File

@ -15,6 +15,7 @@ obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
obj-$(CONFIG_SENSORS_AD7414) += ad7414.o
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o

268
drivers/hwmon/ad7414.c Normal file
View File

@ -0,0 +1,268 @@
/*
* An hwmon driver for the Analog Devices AD7414
*
* Copyright 2006 Stefan Roese <sr at denx.de>, DENX Software Engineering
*
* Copyright (c) 2008 PIKA Technologies
* Sean MacLennan <smaclennan@pikatech.com>
*
* Copyright (c) 2008 Spansion Inc.
* Frank Edelhaeuser <frank.edelhaeuser at spansion.com>
* (converted to "new style" I2C driver model, removed checkpatch.pl warnings)
*
* Based on ad7418.c
* Copyright 2006 Tower Technologies, Alessandro Zummo <a.zummo at towertech.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
/* AD7414 registers */
#define AD7414_REG_TEMP 0x00
#define AD7414_REG_CONF 0x01
#define AD7414_REG_T_HIGH 0x02
#define AD7414_REG_T_LOW 0x03
static u8 AD7414_REG_LIMIT[] = { AD7414_REG_T_HIGH, AD7414_REG_T_LOW };
struct ad7414_data {
struct device *hwmon_dev;
struct mutex lock; /* atomic read data updates */
char valid; /* !=0 if following fields are valid */
unsigned long next_update; /* In jiffies */
s16 temp_input; /* Register values */
s8 temps[ARRAY_SIZE(AD7414_REG_LIMIT)];
};
/* REG: (0.25C/bit, two's complement) << 6 */
static inline int ad7414_temp_from_reg(s16 reg)
{
/* use integer division instead of equivalent right shift to
* guarantee arithmetic shift and preserve the sign
*/
return ((int)reg / 64) * 250;
}
static inline int ad7414_read(struct i2c_client *client, u8 reg)
{
if (reg == AD7414_REG_TEMP) {
int value = i2c_smbus_read_word_data(client, reg);
return (value < 0) ? value : swab16(value);
} else
return i2c_smbus_read_byte_data(client, reg);
}
static inline int ad7414_write(struct i2c_client *client, u8 reg, u8 value)
{
return i2c_smbus_write_byte_data(client, reg, value);
}
struct ad7414_data *ad7414_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ad7414_data *data = i2c_get_clientdata(client);
mutex_lock(&data->lock);
if (time_after(jiffies, data->next_update) || !data->valid) {
int value, i;
dev_dbg(&client->dev, "starting ad7414 update\n");
value = ad7414_read(client, AD7414_REG_TEMP);
if (value < 0)
dev_dbg(&client->dev, "AD7414_REG_TEMP err %d\n",
value);
else
data->temp_input = value;
for (i = 0; i < ARRAY_SIZE(AD7414_REG_LIMIT); ++i) {
value = ad7414_read(client, AD7414_REG_LIMIT[i]);
if (value < 0)
dev_dbg(&client->dev, "AD7414 reg %d err %d\n",
AD7414_REG_LIMIT[i], value);
else
data->temps[i] = value;
}
data->next_update = jiffies + HZ + HZ / 2;
data->valid = 1;
}
mutex_unlock(&data->lock);
return data;
}
static ssize_t show_temp_input(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ad7414_data *data = ad7414_update_device(dev);
return sprintf(buf, "%d\n", ad7414_temp_from_reg(data->temp_input));
}
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
static ssize_t show_max_min(struct device *dev, struct device_attribute *attr,
char *buf)
{
int index = to_sensor_dev_attr(attr)->index;
struct ad7414_data *data = ad7414_update_device(dev);
return sprintf(buf, "%d\n", data->temps[index] * 1000);
}
static ssize_t set_max_min(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct ad7414_data *data = i2c_get_clientdata(client);
int index = to_sensor_dev_attr(attr)->index;
u8 reg = AD7414_REG_LIMIT[index];
long temp = simple_strtol(buf, NULL, 10);
temp = SENSORS_LIMIT(temp, -40000, 85000);
temp = (temp + (temp < 0 ? -500 : 500)) / 1000;
mutex_lock(&data->lock);
data->temps[index] = temp;
ad7414_write(client, reg, temp);
mutex_unlock(&data->lock);
return count;
}
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
show_max_min, set_max_min, 0);
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
show_max_min, set_max_min, 1);
static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
char *buf)
{
int bitnr = to_sensor_dev_attr(attr)->index;
struct ad7414_data *data = ad7414_update_device(dev);
int value = (data->temp_input >> bitnr) & 1;
return sprintf(buf, "%d\n", value);
}
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 3);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 4);
static struct attribute *ad7414_attributes[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
NULL
};
static const struct attribute_group ad7414_group = {
.attrs = ad7414_attributes,
};
static int ad7414_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct ad7414_data *data;
int conf;
int err = 0;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_READ_WORD_DATA))
goto exit;
data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL);
if (!data) {
err = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
mutex_init(&data->lock);
dev_info(&client->dev, "chip found\n");
/* Make sure the chip is powered up. */
conf = i2c_smbus_read_byte_data(client, AD7414_REG_CONF);
if (conf < 0)
dev_warn(&client->dev,
"ad7414_probe unable to read config register.\n");
else {
conf &= ~(1 << 7);
i2c_smbus_write_byte_data(client, AD7414_REG_CONF, conf);
}
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &ad7414_group);
if (err)
goto exit_free;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
return 0;
exit_remove:
sysfs_remove_group(&client->dev.kobj, &ad7414_group);
exit_free:
kfree(data);
exit:
return err;
}
static int __devexit ad7414_remove(struct i2c_client *client)
{
struct ad7414_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ad7414_group);
kfree(data);
return 0;
}
static const struct i2c_device_id ad7414_id[] = {
{ "ad7414", 0 },
{}
};
static struct i2c_driver ad7414_driver = {
.driver = {
.name = "ad7414",
},
.probe = ad7414_probe,
.remove = __devexit_p(ad7414_remove),
.id_table = ad7414_id,
};
static int __init ad7414_init(void)
{
return i2c_add_driver(&ad7414_driver);
}
module_init(ad7414_init);
static void __exit ad7414_exit(void)
{
i2c_del_driver(&ad7414_driver);
}
module_exit(ad7414_exit);
MODULE_AUTHOR("Stefan Roese <sr at denx.de>, "
"Frank Edelhaeuser <frank.edelhaeuser at spansion.com>");
MODULE_DESCRIPTION("AD7414 driver");
MODULE_LICENSE("GPL");

View File

@ -1,11 +1,11 @@
/*
* dme1737.c - Driver for the SMSC DME1737, Asus A8000, and SMSC SCH311x
* Super-I/O chips integrated hardware monitoring features.
* Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com>
* dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x and
* SCH5027 Super-I/O chips integrated hardware monitoring features.
* Copyright (c) 2007, 2008 Juerg Haefliger <juergh@gmail.com>
*
* This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access
* the chip registers if a DME1737 (or A8000) is found and the ISA bus if a
* SCH311x chip is found. Both types of chips have very similar hardware
* the chip registers if a DME1737, A8000, or SCH5027 is found and the ISA bus
* if a SCH311x chip is found. Both types of chips have very similar hardware
* monitoring capabilities but differ in the way they can be accessed.
*
* This program is free software; you can redistribute it and/or modify
@ -57,7 +57,10 @@ MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC "
static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(dme1737);
I2C_CLIENT_INSMOD_2(dme1737, sch5027);
/* ISA chip types */
enum isa_chips { sch311x = sch5027 + 1 };
/* ---------------------------------------------------------------------
* Registers
@ -163,6 +166,7 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
#define DME1737_VERSTEP 0x88
#define DME1737_VERSTEP_MASK 0xf8
#define SCH311X_DEVICE 0x8c
#define SCH5027_VERSTEP 0x69
/* Length of ISA address segment */
#define DME1737_EXTENT 2
@ -182,6 +186,7 @@ struct dme1737_data {
unsigned long last_update; /* in jiffies */
unsigned long last_vbat; /* in jiffies */
enum chips type;
const int *in_nominal; /* pointer to IN_NOMINAL array */
u8 vid;
u8 pwm_rr_en;
@ -220,23 +225,23 @@ static const int IN_NOMINAL_DME1737[] = {5000, 2250, 3300, 5000, 12000, 3300,
3300};
static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
3300};
#define IN_NOMINAL(ix, type) (((type) == dme1737) ? \
IN_NOMINAL_DME1737[(ix)] : \
IN_NOMINAL_SCH311x[(ix)])
static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300,
3300};
#define IN_NOMINAL(type) ((type) == sch311x ? IN_NOMINAL_SCH311x : \
(type) == sch5027 ? IN_NOMINAL_SCH5027 : \
IN_NOMINAL_DME1737)
/* Voltage input
* Voltage inputs have 16 bits resolution, limit values have 8 bits
* resolution. */
static inline int IN_FROM_REG(int reg, int ix, int res, int type)
static inline int IN_FROM_REG(int reg, int nominal, int res)
{
return (reg * IN_NOMINAL(ix, type) + (3 << (res - 3))) /
(3 << (res - 2));
return (reg * nominal + (3 << (res - 3))) / (3 << (res - 2));
}
static inline int IN_TO_REG(int val, int ix, int type)
static inline int IN_TO_REG(int val, int nominal)
{
return SENSORS_LIMIT((val * 192 + IN_NOMINAL(ix, type) / 2) /
IN_NOMINAL(ix, type), 0, 255);
return SENSORS_LIMIT((val * 192 + nominal / 2) / nominal, 0, 255);
}
/* Temperature input
@ -565,7 +570,10 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
/* Sample register contents every 1 sec */
if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
data->vid = dme1737_read(client, DME1737_REG_VID) & 0x3f;
if (data->type != sch5027) {
data->vid = dme1737_read(client, DME1737_REG_VID) &
0x3f;
}
/* In (voltage) registers */
for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
@ -593,8 +601,10 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
DME1737_REG_TEMP_MIN(ix));
data->temp_max[ix] = dme1737_read(client,
DME1737_REG_TEMP_MAX(ix));
data->temp_offset[ix] = dme1737_read(client,
DME1737_REG_TEMP_OFFSET(ix));
if (data->type != sch5027) {
data->temp_offset[ix] = dme1737_read(client,
DME1737_REG_TEMP_OFFSET(ix));
}
}
/* In and temp LSB registers
@ -669,9 +679,11 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
data->zone_abs[ix] = dme1737_read(client,
DME1737_REG_ZONE_ABS(ix));
}
for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
data->zone_hyst[ix] = dme1737_read(client,
if (data->type != sch5027) {
for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
data->zone_hyst[ix] = dme1737_read(client,
DME1737_REG_ZONE_HYST(ix));
}
}
/* Alarm registers */
@ -735,13 +747,13 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
switch (fn) {
case SYS_IN_INPUT:
res = IN_FROM_REG(data->in[ix], ix, 16, data->type);
res = IN_FROM_REG(data->in[ix], data->in_nominal[ix], 16);
break;
case SYS_IN_MIN:
res = IN_FROM_REG(data->in_min[ix], ix, 8, data->type);
res = IN_FROM_REG(data->in_min[ix], data->in_nominal[ix], 8);
break;
case SYS_IN_MAX:
res = IN_FROM_REG(data->in_max[ix], ix, 8, data->type);
res = IN_FROM_REG(data->in_max[ix], data->in_nominal[ix], 8);
break;
case SYS_IN_ALARM:
res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01;
@ -768,12 +780,12 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
switch (fn) {
case SYS_IN_MIN:
data->in_min[ix] = IN_TO_REG(val, ix, data->type);
data->in_min[ix] = IN_TO_REG(val, data->in_nominal[ix]);
dme1737_write(client, DME1737_REG_IN_MIN(ix),
data->in_min[ix]);
break;
case SYS_IN_MAX:
data->in_max[ix] = IN_TO_REG(val, ix, data->type);
data->in_max[ix] = IN_TO_REG(val, data->in_nominal[ix]);
dme1737_write(client, DME1737_REG_IN_MAX(ix),
data->in_max[ix]);
break;
@ -1166,7 +1178,7 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", res);
}
static struct attribute *dme1737_attr_pwm[];
static struct attribute *dme1737_pwm_chmod_attr[];
static void dme1737_chmod_file(struct device*, struct attribute*, mode_t);
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
@ -1230,7 +1242,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
switch (val) {
case 0:
/* Change permissions of pwm[ix] to read-only */
dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
S_IRUGO);
/* Turn fan fully on */
data->pwm_config[ix] = PWM_EN_TO_REG(0,
@ -1245,12 +1257,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
data->pwm_config[ix]);
/* Change permissions of pwm[ix] to read-writeable */
dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
S_IRUGO | S_IWUSR);
break;
case 2:
/* Change permissions of pwm[ix] to read-only */
dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
S_IRUGO);
/* Turn on auto mode using the saved zone channel
* assignment */
@ -1570,38 +1582,29 @@ static struct attribute *dme1737_attr[] ={
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_fault.dev_attr.attr,
&sensor_dev_attr_temp1_offset.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp2_offset.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_fault.dev_attr.attr,
&sensor_dev_attr_temp3_offset.dev_attr.attr,
/* Zones */
&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_zone1_auto_channels_temp.dev_attr.attr,
&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
/* Misc */
&dev_attr_vrm.attr,
&dev_attr_cpu0_vid.attr,
NULL
};
@ -1609,49 +1612,68 @@ static const struct attribute_group dme1737_group = {
.attrs = dme1737_attr,
};
/* The following struct holds misc attributes, which are not available in all
* chips. Their creation depends on the chip type which is determined during
* module load. */
static struct attribute *dme1737_misc_attr[] = {
/* Temperatures */
&sensor_dev_attr_temp1_offset.dev_attr.attr,
&sensor_dev_attr_temp2_offset.dev_attr.attr,
&sensor_dev_attr_temp3_offset.dev_attr.attr,
/* Zones */
&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
/* Misc */
&dev_attr_vrm.attr,
&dev_attr_cpu0_vid.attr,
NULL
};
static const struct attribute_group dme1737_misc_group = {
.attrs = dme1737_misc_attr,
};
/* The following structs hold the PWM attributes, some of which are optional.
* Their creation depends on the chip configuration which is determined during
* module load. */
static struct attribute *dme1737_attr_pwm1[] = {
static struct attribute *dme1737_pwm1_attr[] = {
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm1_freq.dev_attr.attr,
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
NULL
};
static struct attribute *dme1737_attr_pwm2[] = {
static struct attribute *dme1737_pwm2_attr[] = {
&sensor_dev_attr_pwm2.dev_attr.attr,
&sensor_dev_attr_pwm2_freq.dev_attr.attr,
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
NULL
};
static struct attribute *dme1737_attr_pwm3[] = {
static struct attribute *dme1737_pwm3_attr[] = {
&sensor_dev_attr_pwm3.dev_attr.attr,
&sensor_dev_attr_pwm3_freq.dev_attr.attr,
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
NULL
};
static struct attribute *dme1737_attr_pwm5[] = {
static struct attribute *dme1737_pwm5_attr[] = {
&sensor_dev_attr_pwm5.dev_attr.attr,
&sensor_dev_attr_pwm5_freq.dev_attr.attr,
&sensor_dev_attr_pwm5_enable.dev_attr.attr,
NULL
};
static struct attribute *dme1737_attr_pwm6[] = {
static struct attribute *dme1737_pwm6_attr[] = {
&sensor_dev_attr_pwm6.dev_attr.attr,
&sensor_dev_attr_pwm6_freq.dev_attr.attr,
&sensor_dev_attr_pwm6_enable.dev_attr.attr,
@ -1659,53 +1681,62 @@ static struct attribute *dme1737_attr_pwm6[] = {
};
static const struct attribute_group dme1737_pwm_group[] = {
{ .attrs = dme1737_attr_pwm1 },
{ .attrs = dme1737_attr_pwm2 },
{ .attrs = dme1737_attr_pwm3 },
{ .attrs = dme1737_pwm1_attr },
{ .attrs = dme1737_pwm2_attr },
{ .attrs = dme1737_pwm3_attr },
{ .attrs = NULL },
{ .attrs = dme1737_attr_pwm5 },
{ .attrs = dme1737_attr_pwm6 },
{ .attrs = dme1737_pwm5_attr },
{ .attrs = dme1737_pwm6_attr },
};
/* The following struct holds misc PWM attributes, which are not available in
* all chips. Their creation depends on the chip type which is determined
* during module load. */
static struct attribute *dme1737_pwm_misc_attr[] = {
&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
};
/* The following structs hold the fan attributes, some of which are optional.
* Their creation depends on the chip configuration which is determined during
* module load. */
static struct attribute *dme1737_attr_fan1[] = {
static struct attribute *dme1737_fan1_attr[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_type.dev_attr.attr,
NULL
};
static struct attribute *dme1737_attr_fan2[] = {
static struct attribute *dme1737_fan2_attr[] = {
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_alarm.dev_attr.attr,
&sensor_dev_attr_fan2_type.dev_attr.attr,
NULL
};
static struct attribute *dme1737_attr_fan3[] = {
static struct attribute *dme1737_fan3_attr[] = {
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan3_alarm.dev_attr.attr,
&sensor_dev_attr_fan3_type.dev_attr.attr,
NULL
};
static struct attribute *dme1737_attr_fan4[] = {
static struct attribute *dme1737_fan4_attr[] = {
&sensor_dev_attr_fan4_input.dev_attr.attr,
&sensor_dev_attr_fan4_min.dev_attr.attr,
&sensor_dev_attr_fan4_alarm.dev_attr.attr,
&sensor_dev_attr_fan4_type.dev_attr.attr,
NULL
};
static struct attribute *dme1737_attr_fan5[] = {
static struct attribute *dme1737_fan5_attr[] = {
&sensor_dev_attr_fan5_input.dev_attr.attr,
&sensor_dev_attr_fan5_min.dev_attr.attr,
&sensor_dev_attr_fan5_alarm.dev_attr.attr,
&sensor_dev_attr_fan5_max.dev_attr.attr,
NULL
};
static struct attribute *dme1737_attr_fan6[] = {
static struct attribute *dme1737_fan6_attr[] = {
&sensor_dev_attr_fan6_input.dev_attr.attr,
&sensor_dev_attr_fan6_min.dev_attr.attr,
&sensor_dev_attr_fan6_alarm.dev_attr.attr,
@ -1714,94 +1745,83 @@ static struct attribute *dme1737_attr_fan6[] = {
};
static const struct attribute_group dme1737_fan_group[] = {
{ .attrs = dme1737_attr_fan1 },
{ .attrs = dme1737_attr_fan2 },
{ .attrs = dme1737_attr_fan3 },
{ .attrs = dme1737_attr_fan4 },
{ .attrs = dme1737_attr_fan5 },
{ .attrs = dme1737_attr_fan6 },
{ .attrs = dme1737_fan1_attr },
{ .attrs = dme1737_fan2_attr },
{ .attrs = dme1737_fan3_attr },
{ .attrs = dme1737_fan4_attr },
{ .attrs = dme1737_fan5_attr },
{ .attrs = dme1737_fan6_attr },
};
/* The permissions of all of the following attributes are changed to read-
/* The permissions of the following zone attributes are changed to read-
* writeable if the chip is *not* locked. Otherwise they stay read-only. */
static struct attribute *dme1737_attr_lock[] = {
/* Temperatures */
&sensor_dev_attr_temp1_offset.dev_attr.attr,
&sensor_dev_attr_temp2_offset.dev_attr.attr,
&sensor_dev_attr_temp3_offset.dev_attr.attr,
/* Zones */
&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
static struct attribute *dme1737_zone_chmod_attr[] = {
&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
NULL
};
static const struct attribute_group dme1737_lock_group = {
.attrs = dme1737_attr_lock,
static const struct attribute_group dme1737_zone_chmod_group = {
.attrs = dme1737_zone_chmod_attr,
};
/* The permissions of the following PWM attributes are changed to read-
* writeable if the chip is *not* locked and the respective PWM is available.
* Otherwise they stay read-only. */
static struct attribute *dme1737_attr_pwm1_lock[] = {
static struct attribute *dme1737_pwm1_chmod_attr[] = {
&sensor_dev_attr_pwm1_freq.dev_attr.attr,
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
NULL
};
static struct attribute *dme1737_attr_pwm2_lock[] = {
static struct attribute *dme1737_pwm2_chmod_attr[] = {
&sensor_dev_attr_pwm2_freq.dev_attr.attr,
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
NULL
};
static struct attribute *dme1737_attr_pwm3_lock[] = {
static struct attribute *dme1737_pwm3_chmod_attr[] = {
&sensor_dev_attr_pwm3_freq.dev_attr.attr,
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
NULL
};
static struct attribute *dme1737_attr_pwm5_lock[] = {
static struct attribute *dme1737_pwm5_chmod_attr[] = {
&sensor_dev_attr_pwm5.dev_attr.attr,
&sensor_dev_attr_pwm5_freq.dev_attr.attr,
NULL
};
static struct attribute *dme1737_attr_pwm6_lock[] = {
static struct attribute *dme1737_pwm6_chmod_attr[] = {
&sensor_dev_attr_pwm6.dev_attr.attr,
&sensor_dev_attr_pwm6_freq.dev_attr.attr,
NULL
};
static const struct attribute_group dme1737_pwm_lock_group[] = {
{ .attrs = dme1737_attr_pwm1_lock },
{ .attrs = dme1737_attr_pwm2_lock },
{ .attrs = dme1737_attr_pwm3_lock },
static const struct attribute_group dme1737_pwm_chmod_group[] = {
{ .attrs = dme1737_pwm1_chmod_attr },
{ .attrs = dme1737_pwm2_chmod_attr },
{ .attrs = dme1737_pwm3_chmod_attr },
{ .attrs = NULL },
{ .attrs = dme1737_attr_pwm5_lock },
{ .attrs = dme1737_attr_pwm6_lock },
{ .attrs = dme1737_pwm5_chmod_attr },
{ .attrs = dme1737_pwm6_chmod_attr },
};
/* Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the
* chip is not locked. Otherwise they are read-only. */
static struct attribute *dme1737_attr_pwm[] = {
static struct attribute *dme1737_pwm_chmod_attr[] = {
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm2.dev_attr.attr,
&sensor_dev_attr_pwm3.dev_attr.attr,
@ -1875,9 +1895,17 @@ static void dme1737_remove_files(struct device *dev)
if (data->has_pwm & (1 << ix)) {
sysfs_remove_group(&dev->kobj,
&dme1737_pwm_group[ix]);
if (data->type != sch5027 && ix < 3) {
sysfs_remove_file(&dev->kobj,
dme1737_pwm_misc_attr[ix]);
}
}
}
if (data->type != sch5027) {
sysfs_remove_group(&dev->kobj, &dme1737_misc_group);
}
sysfs_remove_group(&dev->kobj, &dme1737_group);
if (!data->client.driver) {
@ -1901,6 +1929,13 @@ static int dme1737_create_files(struct device *dev)
goto exit_remove;
}
/* Create misc sysfs attributes */
if ((data->type != sch5027) &&
(err = sysfs_create_group(&dev->kobj,
&dme1737_misc_group))) {
goto exit_remove;
}
/* Create fan sysfs attributes */
for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
if (data->has_fan & (1 << ix)) {
@ -1918,6 +1953,11 @@ static int dme1737_create_files(struct device *dev)
&dme1737_pwm_group[ix]))) {
goto exit_remove;
}
if (data->type != sch5027 && ix < 3 &&
(err = sysfs_create_file(&dev->kobj,
dme1737_pwm_misc_attr[ix]))) {
goto exit_remove;
}
}
}
@ -1927,16 +1967,27 @@ static int dme1737_create_files(struct device *dev)
dev_info(dev, "Device is locked. Some attributes "
"will be read-only.\n");
} else {
/* Change permissions of standard attributes */
dme1737_chmod_group(dev, &dme1737_lock_group,
/* Change permissions of zone sysfs attributes */
dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
S_IRUGO | S_IWUSR);
/* Change permissions of PWM attributes */
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) {
/* Change permissions of misc sysfs attributes */
if (data->type != sch5027) {
dme1737_chmod_group(dev, &dme1737_misc_group,
S_IRUGO | S_IWUSR);
}
/* Change permissions of PWM sysfs attributes */
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_chmod_group); ix++) {
if (data->has_pwm & (1 << ix)) {
dme1737_chmod_group(dev,
&dme1737_pwm_lock_group[ix],
&dme1737_pwm_chmod_group[ix],
S_IRUGO | S_IWUSR);
if (data->type != sch5027 && ix < 3) {
dme1737_chmod_file(dev,
dme1737_pwm_misc_attr[ix],
S_IRUGO | S_IWUSR);
}
}
}
@ -1945,7 +1996,7 @@ static int dme1737_create_files(struct device *dev)
if ((data->has_pwm & (1 << ix)) &&
(PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
dme1737_chmod_file(dev,
dme1737_attr_pwm[ix],
dme1737_pwm_chmod_attr[ix],
S_IRUGO | S_IWUSR);
}
}
@ -1966,6 +2017,9 @@ static int dme1737_init_device(struct device *dev)
int ix;
u8 reg;
/* Point to the right nominal voltages array */
data->in_nominal = IN_NOMINAL(data->type);
data->config = dme1737_read(client, DME1737_REG_CONFIG);
/* Inform if part is not monitoring/started */
if (!(data->config & 0x01)) {
@ -2076,7 +2130,9 @@ static int dme1737_init_device(struct device *dev)
data->pwm_acz[2] = 4; /* pwm3 -> zone3 */
/* Set VRM */
data->vrm = vid_which_vrm();
if (data->type != sch5027) {
data->vrm = vid_which_vrm();
}
return 0;
}
@ -2095,9 +2151,10 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
dme1737_sio_enter(sio_cip);
/* Check device ID
* The DME1737 can return either 0x78 or 0x77 as its device ID. */
* The DME1737 can return either 0x78 or 0x77 as its device ID.
* The SCH5027 returns 0x89 as its device ID. */
reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
if (!(reg == 0x77 || reg == 0x78)) {
if (!(reg == 0x77 || reg == 0x78 || reg == 0x89)) {
err = -ENODEV;
goto exit;
}
@ -2166,15 +2223,24 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
company = dme1737_read(client, DME1737_REG_COMPANY);
verstep = dme1737_read(client, DME1737_REG_VERSTEP);
if (!((company == DME1737_COMPANY_SMSC) &&
((verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP))) {
if (company == DME1737_COMPANY_SMSC &&
(verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
kind = dme1737;
} else if (company == DME1737_COMPANY_SMSC &&
verstep == SCH5027_VERSTEP) {
kind = sch5027;
} else {
err = -ENODEV;
goto exit_kfree;
}
}
kind = dme1737;
name = "dme1737";
if (kind == sch5027) {
name = "sch5027";
} else {
kind = dme1737;
name = "dme1737";
}
data->type = kind;
/* Fill in the remaining client fields and put it into the global
@ -2187,8 +2253,9 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
goto exit_kfree;
}
dev_info(dev, "Found a DME1737 chip at 0x%02x (rev 0x%02x).\n",
client->addr, verstep);
dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n",
kind == sch5027 ? "SCH5027" : "DME1737", client->addr,
verstep);
/* Initialize the DME1737 chip */
if ((err = dme1737_init_device(dev))) {
@ -2360,15 +2427,18 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
client->addr = res->start;
platform_set_drvdata(pdev, data);
company = dme1737_read(client, DME1737_REG_COMPANY);
device = dme1737_read(client, DME1737_REG_DEVICE);
/* Skip chip detection if module is loaded with force_id parameter */
if (!force_id) {
company = dme1737_read(client, DME1737_REG_COMPANY);
device = dme1737_read(client, DME1737_REG_DEVICE);
if (!((company == DME1737_COMPANY_SMSC) &&
(device == SCH311X_DEVICE))) {
err = -ENODEV;
goto exit_kfree;
if (!((company == DME1737_COMPANY_SMSC) &&
(device == SCH311X_DEVICE))) {
err = -ENODEV;
goto exit_kfree;
}
}
data->type = -1;
data->type = sch311x;
/* Fill in the remaining client fields and initialize the mutex */
strlcpy(client->name, "sch311x", I2C_NAME_SIZE);

View File

@ -87,8 +87,6 @@ static inline void superio_enter(int base);
static inline void superio_select(int base, int ld);
static inline void superio_exit(int base);
static inline u16 fan_from_reg ( u16 reg );
struct f71882fg_data {
unsigned short addr;
struct device *hwmon_dev;
@ -116,10 +114,6 @@ struct f71882fg_data {
u8 temp_diode_open;
};
static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg);
static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg);
static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val);
/* Sysfs in*/
static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
char *buf);

View File

@ -1,76 +1,74 @@
/*
hwmon-vid.c - VID/VRM/VRD voltage conversions
Copyright (c) 2004 Rudolf Marek <r.marek@assembler.cz>
Partly imported from i2c-vid.h of the lm_sensors project
Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
With assistance from Trent Piepho <xyzzy@speakeasy.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
* hwmon-vid.c - VID/VRM/VRD voltage conversions
*
* Copyright (c) 2004 Rudolf Marek <r.marek@assembler.cz>
*
* Partly imported from i2c-vid.h of the lm_sensors project
* Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
* With assistance from Trent Piepho <xyzzy@speakeasy.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/hwmon-vid.h>
/*
Common code for decoding VID pins.
* Common code for decoding VID pins.
*
* References:
*
* For VRM 8.4 to 9.1, "VRM x.y DC-DC Converter Design Guidelines",
* available at http://developer.intel.com/.
*
* For VRD 10.0 and up, "VRD x.y Design Guide",
* available at http://developer.intel.com/.
*
* AMD NPT 0Fh (Athlon64 & Opteron), AMD Publication 32559,
* http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf
* Table 71. VID Code Voltages
* AMD Opteron processors don't follow the Intel specifications.
* I'm going to "make up" 2.4 as the spec number for the Opterons.
* No good reason just a mnemonic for the 24x Opteron processor
* series.
*
* The 17 specification is in fact Intel Mobile Voltage Positioning -
* (IMVP-II). You can find more information in the datasheet of Max1718
* http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2452
*
* The 13 specification corresponds to the Intel Pentium M series. There
* doesn't seem to be any named specification for these. The conversion
* tables are detailed directly in the various Pentium M datasheets:
* http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm
*
* The 14 specification corresponds to Intel Core series. There
* doesn't seem to be any named specification for these. The conversion
* tables are detailed directly in the various Pentium Core datasheets:
* http://www.intel.com/design/mobile/datashts/309221.htm
*
* The 110 (VRM 11) specification corresponds to Intel Conroe based series.
* http://www.intel.com/design/processor/applnots/313214.htm
*/
References:
For VRM 8.4 to 9.1, "VRM x.y DC-DC Converter Design Guidelines",
available at http://developer.intel.com/.
For VRD 10.0 and up, "VRD x.y Design Guide",
available at http://developer.intel.com/.
AMD Opteron processors don't follow the Intel specifications.
I'm going to "make up" 2.4 as the spec number for the Opterons.
No good reason just a mnemonic for the 24x Opteron processor
series.
Opteron VID encoding is:
00000 = 1.550 V
00001 = 1.525 V
. . . .
11110 = 0.800 V
11111 = 0.000 V (off)
The 17 specification is in fact Intel Mobile Voltage Positioning -
(IMVP-II). You can find more information in the datasheet of Max1718
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2452
The 13 specification corresponds to the Intel Pentium M series. There
doesn't seem to be any named specification for these. The conversion
tables are detailed directly in the various Pentium M datasheets:
http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm
The 14 specification corresponds to Intel Core series. There
doesn't seem to be any named specification for these. The conversion
tables are detailed directly in the various Pentium Core datasheets:
http://www.intel.com/design/mobile/datashts/309221.htm
The 110 (VRM 11) specification corresponds to Intel Conroe based series.
http://www.intel.com/design/processor/applnots/313214.htm
*/
/* vrm is the VRM/VRD document version multiplied by 10.
val is the 4-bit or more VID code.
Returned value is in mV to avoid floating point in the kernel.
Some VID have some bits in uV scale, this is rounded to mV */
/*
* vrm is the VRM/VRD document version multiplied by 10.
* val is the 4-bit or more VID code.
* Returned value is in mV to avoid floating point in the kernel.
* Some VID have some bits in uV scale, this is rounded to mV.
*/
int vid_from_reg(int val, u8 vrm)
{
int vid;
@ -96,9 +94,11 @@ int vid_from_reg(int val, u8 vrm)
if (val < 0x02 || val > 0xb2)
return 0;
return((1600000 - (val - 2) * 6250 + 500) / 1000);
case 24: /* Opteron processor */
val &= 0x1f;
return(val == 0x1f ? 0 : 1550 - val * 25);
case 24: /* AMD NPT 0Fh (Athlon64 & Opteron) */
val &= 0x3f;
return (val < 32) ? 1550 - 25 * val
: 775 - (25 * (val - 31)) / 2;
case 91: /* VRM 9.1 */
case 90: /* VRM 9.0 */
@ -141,9 +141,9 @@ int vid_from_reg(int val, u8 vrm)
/*
After this point is the code to automatically determine which
VRM/VRD specification should be used depending on the CPU.
*/
* After this point is the code to automatically determine which
* VRM/VRD specification should be used depending on the CPU.
*/
struct vrm_model {
u8 vendor;

View File

@ -151,9 +151,9 @@ static int fix_pwm_polarity;
/* The IT8718F has the VID value in a different register, in Super-I/O
configuration space. */
#define IT87_REG_VID 0x0a
/* Warning: register 0x0b is used for something completely different in
new chips/revisions. I suspect only 16-bit tachometer mode will work
for these. */
/* The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b
for fan divisors. Later IT8712F revisions must use 16-bit tachometer
mode. */
#define IT87_REG_FAN_DIV 0x0b
#define IT87_REG_FAN_16BIT 0x0c
@ -234,6 +234,7 @@ static const unsigned int pwm_freq[8] = {
struct it87_sio_data {
enum chips type;
/* Values read from Super-I/O config space */
u8 revision;
u8 vid_value;
};
@ -242,6 +243,7 @@ struct it87_sio_data {
struct it87_data {
struct device *hwmon_dev;
enum chips type;
u8 revision;
unsigned short addr;
const char *name;
@ -268,6 +270,16 @@ struct it87_data {
u8 manual_pwm_ctl[3]; /* manual PWM value set by user */
};
static inline int has_16bit_fans(const struct it87_data *data)
{
/* IT8705F Datasheet 0.4.1, 3h == Version G.
IT8712F Datasheet 0.9.1, section 8.3.5 indicates 7h == Version I.
These are the first revisions with 16bit tachometer support. */
return (data->type == it87 && data->revision >= 0x03)
|| (data->type == it8712 && data->revision >= 0x07)
|| data->type == it8716
|| data->type == it8718;
}
static int it87_probe(struct platform_device *pdev);
static int __devexit it87_remove(struct platform_device *pdev);
@ -991,8 +1003,9 @@ static int __init it87_find(unsigned short *address,
}
err = 0;
sio_data->revision = superio_inb(DEVREV) & 0x0f;
pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n",
chip_type, *address, superio_inb(DEVREV) & 0x0f);
chip_type, *address, sio_data->revision);
/* Read GPIO config and VID value from LDN 7 (GPIO) */
if (chip_type != IT8705F_DEVID) {
@ -1045,6 +1058,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
data->addr = res->start;
data->type = sio_data->type;
data->revision = sio_data->revision;
data->name = names[sio_data->type];
/* Now, we do the remaining detection. */
@ -1069,7 +1083,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
goto ERROR2;
/* Do not create fan files for disabled fans */
if (data->type == it8716 || data->type == it8718) {
if (has_16bit_fans(data)) {
/* 16-bit tachometers */
if (data->has_fan & (1 << 0)) {
if ((err = device_create_file(dev,
@ -1350,7 +1364,7 @@ static void __devinit it87_init_device(struct platform_device *pdev)
data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
/* Set tachometers to 16-bit mode if needed */
if (data->type == it8716 || data->type == it8718) {
if (has_16bit_fans(data)) {
tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
if (~tmp & 0x07 & data->has_fan) {
dev_dbg(&pdev->dev,
@ -1358,10 +1372,13 @@ static void __devinit it87_init_device(struct platform_device *pdev)
it87_write_value(data, IT87_REG_FAN_16BIT,
tmp | 0x07);
}
if (tmp & (1 << 4))
data->has_fan |= (1 << 3); /* fan4 enabled */
if (tmp & (1 << 5))
data->has_fan |= (1 << 4); /* fan5 enabled */
/* IT8705F only supports three fans. */
if (data->type != it87) {
if (tmp & (1 << 4))
data->has_fan |= (1 << 3); /* fan4 enabled */
if (tmp & (1 << 5))
data->has_fan |= (1 << 4); /* fan5 enabled */
}
}
/* Set current fan mode registers and the default settings for the
@ -1426,7 +1443,7 @@ static struct it87_data *it87_update_device(struct device *dev)
data->fan[i] = it87_read_value(data,
IT87_REG_FAN[i]);
/* Add high byte if in 16-bit mode */
if (data->type == it8716 || data->type == it8718) {
if (has_16bit_fans(data)) {
data->fan[i] |= it87_read_value(data,
IT87_REG_FANX[i]) << 8;
data->fan_min[i] |= it87_read_value(data,
@ -1443,8 +1460,7 @@ static struct it87_data *it87_update_device(struct device *dev)
}
/* Newer chips don't have clock dividers */
if ((data->has_fan & 0x07) && data->type != it8716
&& data->type != it8718) {
if ((data->has_fan & 0x07) && !has_16bit_fans(data)) {
i = it87_read_value(data, IT87_REG_FAN_DIV);
data->fan_div[0] = i & 0x07;
data->fan_div[1] = (i >> 3) & 0x07;
@ -1460,7 +1476,8 @@ static struct it87_data *it87_update_device(struct device *dev)
data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
/* The 8705 does not have VID capability */
/* The 8705 does not have VID capability.
The 8718 does not use IT87_REG_VID for the same purpose. */
if (data->type == it8712 || data->type == it8716) {
data->vid = it87_read_value(data, IT87_REG_VID);
/* The older IT8712F revisions had only 5 VID pins,

View File

@ -55,8 +55,11 @@ I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs "
static const u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
static const u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
static const u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
static const u8 THMC50_REG_TEMP_CRITICAL[] = { 0x13, 0x14, 0x14 };
static const u8 THMC50_REG_TEMP_DEFAULT[] = { 0x17, 0x18, 0x18 };
#define THMC50_REG_CONF_nFANOFF 0x20
#define THMC50_REG_CONF_PROGRAMMED 0x08
/* Each client has this additional data */
struct thmc50_data {
@ -72,6 +75,7 @@ struct thmc50_data {
s8 temp_input[3];
s8 temp_max[3];
s8 temp_min[3];
s8 temp_critical[3];
u8 analog_out;
u8 alarms;
};
@ -199,6 +203,15 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
return count;
}
static ssize_t show_temp_critical(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int nr = to_sensor_dev_attr(attr)->index;
struct thmc50_data *data = thmc50_update_device(dev);
return sprintf(buf, "%d\n", data->temp_critical[nr] * 1000);
}
static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
char *buf)
{
@ -214,7 +227,9 @@ static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \
static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
show_temp_min, set_temp_min, offset - 1); \
static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
show_temp_max, set_temp_max, offset - 1);
show_temp_max, set_temp_max, offset - 1); \
static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO, \
show_temp_critical, NULL, offset - 1);
temp_reg(1);
temp_reg(2);
@ -234,10 +249,12 @@ static struct attribute *thmc50_attributes[] = {
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp2_crit.dev_attr.attr,
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
@ -254,6 +271,7 @@ static struct attribute *temp3_attributes[] = {
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp3_crit.dev_attr.attr,
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_fault.dev_attr.attr,
NULL
@ -429,6 +447,10 @@ static struct thmc50_data *thmc50_update_device(struct device *dev)
int temps = data->has_temp3 ? 3 : 2;
int i;
int prog = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
prog &= THMC50_REG_CONF_PROGRAMMED;
for (i = 0; i < temps; i++) {
data->temp_input[i] = i2c_smbus_read_byte_data(client,
THMC50_REG_TEMP[i]);
@ -436,6 +458,10 @@ static struct thmc50_data *thmc50_update_device(struct device *dev)
THMC50_REG_TEMP_MAX[i]);
data->temp_min[i] = i2c_smbus_read_byte_data(client,
THMC50_REG_TEMP_MIN[i]);
data->temp_critical[i] =
i2c_smbus_read_byte_data(client,
prog ? THMC50_REG_TEMP_CRITICAL[i]
: THMC50_REG_TEMP_DEFAULT[i]);
}
data->analog_out =
i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);

View File

@ -67,10 +67,6 @@ module_param(force_i2c, byte, 0);
MODULE_PARM_DESC(force_i2c,
"Initialize the i2c address of the sensors");
static int reset;
module_param(reset, bool, 0);
MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
static int init = 1;
module_param(init, bool, 0);
MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
@ -209,6 +205,13 @@ static const u16 w83627hf_reg_temp_over[] = { 0x39, 0x155, 0x255 };
#define W83627HF_REG_PWM1 0x5A
#define W83627HF_REG_PWM2 0x5B
static const u8 W83627THF_REG_PWM_ENABLE[] = {
0x04, /* FAN 1 mode */
0x04, /* FAN 2 mode */
0x12, /* FAN AUX mode */
};
static const u8 W83627THF_PWM_ENABLE_SHIFT[] = { 2, 4, 1 };
#define W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */
#define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */
#define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */
@ -366,6 +369,9 @@ struct w83627hf_data {
u32 alarms; /* Register encoding, combined */
u32 beep_mask; /* Register encoding, combined */
u8 pwm[3]; /* Register value */
u8 pwm_enable[3]; /* 1 = manual
2 = thermal cruise (also called SmartFan I)
3 = fan speed cruise */
u8 pwm_freq[3]; /* Register value */
u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode;
4 = thermistor */
@ -956,6 +962,42 @@ static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0);
static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
static ssize_t
show_pwm_enable(struct device *dev, struct device_attribute *devattr, char *buf)
{
int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = w83627hf_update_device(dev);
return sprintf(buf, "%d\n", data->pwm_enable[nr]);
}
static ssize_t
store_pwm_enable(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
u8 reg;
if (!val || (val > 3)) /* modes 1, 2 and 3 are supported */
return -EINVAL;
mutex_lock(&data->update_lock);
data->pwm_enable[nr] = val;
reg = w83627hf_read_value(data, W83627THF_REG_PWM_ENABLE[nr]);
reg &= ~(0x03 << W83627THF_PWM_ENABLE_SHIFT[nr]);
reg |= (val - 1) << W83627THF_PWM_ENABLE_SHIFT[nr];
w83627hf_write_value(data, W83627THF_REG_PWM_ENABLE[nr], reg);
mutex_unlock(&data->update_lock);
return count;
}
static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
store_pwm_enable, 0);
static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
store_pwm_enable, 1);
static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
store_pwm_enable, 2);
static ssize_t
show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
{
@ -1223,6 +1265,11 @@ static struct attribute *w83627hf_attributes_opt[] = {
&sensor_dev_attr_pwm1_freq.dev_attr.attr,
&sensor_dev_attr_pwm2_freq.dev_attr.attr,
&sensor_dev_attr_pwm3_freq.dev_attr.attr,
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
NULL
};
@ -1366,6 +1413,19 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
&sensor_dev_attr_pwm3_freq.dev_attr)))
goto ERROR4;
if (data->type != w83627hf)
if ((err = device_create_file(dev,
&sensor_dev_attr_pwm1_enable.dev_attr))
|| (err = device_create_file(dev,
&sensor_dev_attr_pwm2_enable.dev_attr)))
goto ERROR4;
if (data->type == w83627thf || data->type == w83637hf
|| data->type == w83687thf)
if ((err = device_create_file(dev,
&sensor_dev_attr_pwm3_enable.dev_attr)))
goto ERROR4;
data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
@ -1536,29 +1596,6 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
enum chips type = data->type;
u8 tmp;
if (reset) {
/* Resetting the chip has been the default for a long time,
but repeatedly caused problems (fans going to full
speed...) so it is now optional. It might even go away if
nobody reports it as being useful, as I see very little
reason why this would be needed at all. */
dev_info(&pdev->dev, "If reset=1 solved a problem you were "
"having, please report!\n");
/* save this register */
i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG);
/* Reset all except Watchdog values and last conversion values
This sets fan-divs to 2, among others */
w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80);
/* Restore the register and disable power-on abnormal beep.
This saves FAN 1/2/3 input/output values set by BIOS. */
w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
/* Disable master beep-enable (reset turns it on).
Individual beeps should be reset to off but for some reason
disabling this bit helps some people not get beeped */
w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0);
}
/* Minimize conflicts with other winbond i2c-only clients... */
/* disable i2c subclients... how to disable main i2c client?? */
/* force i2c address to relatively uncommon address */
@ -1655,6 +1692,7 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
{
struct w83627hf_data *data = dev_get_drvdata(dev);
int i, num_temps = (data->type == w83697hf) ? 2 : 3;
int num_pwms = (data->type == w83697hf) ? 2 : 3;
mutex_lock(&data->update_lock);
@ -1707,6 +1745,15 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
break;
}
}
if (data->type != w83627hf) {
for (i = 0; i < num_pwms; i++) {
u8 tmp = w83627hf_read_value(data,
W83627THF_REG_PWM_ENABLE[i]);
data->pwm_enable[i] =
((tmp >> W83627THF_PWM_ENABLE_SHIFT[i])
& 0x03) + 1;
}
}
for (i = 0; i < num_temps; i++) {
data->temp[i] = w83627hf_read_value(
data, w83627hf_reg_temp[i]);

View File

@ -233,11 +233,9 @@ static u8 fan_to_reg(long rpm, int div)
static u8 div_to_reg(int nr, long val)
{
int i;
int max;
/* first three fan's divisor max out at 8, rest max out at 128 */
max = (nr < 3) ? 8 : 128;
val = SENSORS_LIMIT(val, 1, max) >> 1;
/* fan divisors max out at 128 */
val = SENSORS_LIMIT(val, 1, 128) >> 1;
for (i = 0; i < 7; i++) {
if (val == 0)
break;
@ -530,6 +528,7 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr,
unsigned long min;
u8 tmp_fan_div;
u8 fan_div_reg;
u8 vbat_reg;
int indx = 0;
u8 keep_mask = 0;
u8 new_shift = 0;
@ -581,6 +580,16 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr,
w83791d_write(client, W83791D_REG_FAN_DIV[indx],
fan_div_reg | tmp_fan_div);
/* Bit 2 of fans 0-2 is stored in the vbat register (bits 5-7) */
if (nr < 3) {
keep_mask = ~(1 << (nr + 5));
vbat_reg = w83791d_read(client, W83791D_REG_VBAT)
& keep_mask;
tmp_fan_div = (data->fan_div[nr] << (3 + nr)) & ~keep_mask;
w83791d_write(client, W83791D_REG_VBAT,
vbat_reg | tmp_fan_div);
}
/* Restore fan_min */
data->fan_min[nr] = fan_to_reg(min, DIV_FROM_REG(data->fan_div[nr]));
w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]);
@ -1182,6 +1191,7 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
struct w83791d_data *data = i2c_get_clientdata(client);
int i, j;
u8 reg_array_tmp[3];
u8 vbat_reg;
mutex_lock(&data->update_lock);
@ -1219,6 +1229,12 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
data->fan_div[3] = reg_array_tmp[2] & 0x07;
data->fan_div[4] = (reg_array_tmp[2] >> 4) & 0x07;
/* The fan divisor for fans 0-2 get bit 2 from
bits 5-7 respectively of vbat register */
vbat_reg = w83791d_read(client, W83791D_REG_VBAT);
for (i = 0; i < 3; i++)
data->fan_div[i] |= (vbat_reg >> (3 + i)) & 0x04;
/* Update the first temperature sensor */
for (i = 0; i < 3; i++) {
data->temp1[i] = w83791d_read(client,