Commit a06dee41 authored by Linus Torvalds's avatar Linus Torvalds

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
parents b588e2bb 816d8c6a
...@@ -10,6 +10,10 @@ Supported chips: ...@@ -10,6 +10,10 @@ Supported chips:
Prefix: 'sch311x' Prefix: 'sch311x'
Addresses scanned: none, address read from Super-I/O config space Addresses scanned: none, address read from Super-I/O config space
Datasheet: http://www.nuhorizons.com/FeaturedProducts/Volume1/SMSC/311x.pdf 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: Authors:
Juerg Haefliger <juergh@gmail.com> Juerg Haefliger <juergh@gmail.com>
...@@ -27,33 +31,31 @@ Module Parameters ...@@ -27,33 +31,31 @@ Module Parameters
following boards: following boards:
- VIA EPIA SN18000 - 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 Description
----------- -----------
This driver implements support for the hardware monitoring capabilities of the 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 SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, and SMSC
chips. These chips feature monitoring of 3 temp sensors temp[1-3] (2 remote SCH311x Super-I/O chips. These chips feature monitoring of 3 temp sensors
diodes and 1 internal), 7 voltages in[0-6] (6 external and 1 internal) and up temp[1-3] (2 remote diodes and 1 internal), 7 voltages in[0-6] (6 external and
to 6 fan speeds fan[1-6]. Additionally, the chips implement up to 5 PWM 1 internal) and up to 6 fan speeds fan[1-6]. Additionally, the chips implement
outputs pwm[1-3,5-6] for controlling fan speeds both manually and up to 5 PWM outputs pwm[1-3,5-6] for controlling fan speeds both manually and
automatically. automatically.
For the DME1737 and A8000, fan[1-2] and pwm[1-2] are always present. Fan[3-6] For the DME1737, A8000 and SCH5027, fan[1-2] and pwm[1-2] are always present.
and pwm[3,5-6] are optional features and their availability depends on the Fan[3-6] and pwm[3,5-6] are optional features and their availability depends on
configuration of the chip. The driver will detect which features are present the configuration of the chip. The driver will detect which features are
during initialization and create the sysfs attributes accordingly. 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 For the SCH311x, fan[1-3] and pwm[1-3] are always present and fan[4-6] and
pwm[5-6] don't exist. pwm[5-6] don't exist.
The hardware monitoring features of the DME1737 and A8000 are only accessible The hardware monitoring features of the DME1737, A8000, and SCH5027 are only
via SMBus, while the SCH311x only provides access via the ISA bus. The driver accessible via SMBus, while the SCH311x only provides access via the ISA bus.
will therefore register itself as an I2C client driver if it detects a DME1737 The driver will therefore register itself as an I2C client driver if it detects
or A8000 and as a platform driver if it detects a SCH311x chip. a DME1737, A8000, or SCH5027 and as a platform driver if it detects a SCH311x
chip.
Voltage Monitoring Voltage Monitoring
...@@ -64,6 +66,7 @@ scaling resistors. The values returned by the driver therefore reflect true ...@@ -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 millivolts and don't need scaling. The voltage inputs are mapped as follows
(the last column indicates the input ranges): (the last column indicates the input ranges):
DME1737, A8000:
in0: +5VTR (+5V standby) 0V - 6.64V in0: +5VTR (+5V standby) 0V - 6.64V
in1: Vccp (processor core) 0V - 3V in1: Vccp (processor core) 0V - 3V
in2: VCC (internal +3.3V) 0V - 4.38V 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 ...@@ -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 in5: VTR (+3.3V standby) 0V - 4.38V
in6: Vbat (+3.0V) 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 Each voltage input has associated min and max limits which trigger an alarm
when crossed. when crossed.
......
...@@ -6,12 +6,14 @@ Supported chips: ...@@ -6,12 +6,14 @@ Supported chips:
Prefix: 'it87' Prefix: 'it87'
Addresses scanned: from Super I/O config space (8 I/O ports) Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Publicly available at the ITE website 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 * IT8712F
Prefix: 'it8712' Prefix: 'it8712'
Addresses scanned: from Super I/O config space (8 I/O ports) Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Publicly available at the ITE website 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 * IT8716F/IT8726F
Prefix: 'it8716' Prefix: 'it8716'
Addresses scanned: from Super I/O config space (8 I/O ports) 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 ...@@ -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. can't have both on a given board.
The IT8716F, IT8718F and later IT8712F revisions have support for The IT8716F, IT8718F and later IT8712F revisions have support for
2 additional fans. They are supported by the driver for the IT8716F and 2 additional fans. The additional fans are supported by the driver.
IT8718F but not for the IT8712F
The IT8716F and IT8718F, and late IT8712F and IT8705F also have optional 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 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 clock divider mess) but not compatible with the older chips and
revisions. For now, the driver only uses the 16-bit mode on the revisions. The 16-bit tachometer mode is enabled by the driver when one
IT8716F and IT8718F. of the above chips is detected.
The IT8726F is just bit enhanced IT8716F with additional hardware The IT8726F is just bit enhanced IT8716F with additional hardware
for AMD power sequencing. Therefore the chip will appear as IT8716F for AMD power sequencing. Therefore the chip will appear as IT8716F
......
...@@ -40,10 +40,6 @@ Module Parameters ...@@ -40,10 +40,6 @@ Module Parameters
(default is 1) (default is 1)
Use 'init=0' to bypass initializing the chip. Use 'init=0' to bypass initializing the chip.
Try this if your computer crashes when you load the module. 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 Description
----------- -----------
......
...@@ -22,6 +22,7 @@ Credits: ...@@ -22,6 +22,7 @@ Credits:
Additional contributors: Additional contributors:
Sven Anders <anders@anduras.de> Sven Anders <anders@anduras.de>
Marc Hulsman <m.hulsman@tudelft.nl>
Module Parameters Module Parameters
----------------- -----------------
...@@ -67,9 +68,8 @@ on until the temperature falls below the Hysteresis value. ...@@ -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 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 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 readings can be divided by a programmable divider (1, 2, 4, 8, 16,
and 1, 2, 4, 8, 16, 32, 64 or 128 for fan 4/5) to give the readings more 32, 64 or 128 for all fans) to give the readings more range or accuracy.
range or accuracy.
Voltage sensors (also known as IN sensors) report their values in millivolts. Voltage sensors (also known as IN sensors) report their values in millivolts.
An alarm is triggered if the voltage has crossed a programmable minimum An alarm is triggered if the voltage has crossed a programmable minimum
......
...@@ -57,6 +57,16 @@ config SENSORS_ABITUGURU3 ...@@ -57,6 +57,16 @@ config SENSORS_ABITUGURU3
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called abituguru3. 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 config SENSORS_AD7418
tristate "Analog Devices AD7416, AD7417 and AD7418" tristate "Analog Devices AD7416, AD7417 and AD7418"
depends on I2C && EXPERIMENTAL depends on I2C && EXPERIMENTAL
...@@ -124,7 +134,7 @@ config SENSORS_ADM1031 ...@@ -124,7 +134,7 @@ config SENSORS_ADM1031
config SENSORS_ADM9240 config SENSORS_ADM9240
tristate "Analog Devices ADM9240 and compatibles" tristate "Analog Devices ADM9240 and compatibles"
depends on I2C && EXPERIMENTAL depends on I2C
select HWMON_VID select HWMON_VID
help help
If you say yes here you get support for Analog Devices ADM9240, If you say yes here you get support for Analog Devices ADM9240,
...@@ -575,8 +585,8 @@ config SENSORS_DME1737 ...@@ -575,8 +585,8 @@ config SENSORS_DME1737
select HWMON_VID select HWMON_VID
help help
If you say yes here you get support for the hardware monitoring If you say yes here you get support for the hardware monitoring
and fan control features of the SMSC DME1737 (and compatibles and fan control features of the SMSC DME1737, SCH311x, SCH5027, and
like the Asus A8000) and SCH311x Super-I/O chips. Asus A8000 Super-I/O chips.
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called dme1737. will be called dme1737.
......
...@@ -15,6 +15,7 @@ obj-$(CONFIG_SENSORS_W83791D) += w83791d.o ...@@ -15,6 +15,7 @@ obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
obj-$(CONFIG_SENSORS_AD7414) += ad7414.o
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
......
/*
* 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");
/* /*
* dme1737.c - Driver for the SMSC DME1737, Asus A8000, and SMSC SCH311x * dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x and
* Super-I/O chips integrated hardware monitoring features. * SCH5027 Super-I/O chips integrated hardware monitoring features.
* Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com> * 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 * 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 * the chip registers if a DME1737, A8000, or SCH5027 is found and the ISA bus
* SCH311x chip is found. Both types of chips have very similar hardware * 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. * monitoring capabilities but differ in the way they can be accessed.
* *
* This program is free software; you can redistribute it and/or modify * 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 " ...@@ -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}; static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
/* Insmod parameters */ /* Insmod parameters */
I2C_CLIENT_INSMOD_1(dme1737); I2C_CLIENT_INSMOD_2(dme1737, sch5027);
/* ISA chip types */
enum isa_chips { sch311x = sch5027 + 1 };
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
* Registers * Registers
...@@ -163,6 +166,7 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23}; ...@@ -163,6 +166,7 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
#define DME1737_VERSTEP 0x88 #define DME1737_VERSTEP 0x88
#define DME1737_VERSTEP_MASK 0xf8 #define DME1737_VERSTEP_MASK 0xf8
#define SCH311X_DEVICE 0x8c #define SCH311X_DEVICE 0x8c
#define SCH5027_VERSTEP 0x69
/* Length of ISA address segment */ /* Length of ISA address segment */
#define DME1737_EXTENT 2 #define DME1737_EXTENT 2
...@@ -182,6 +186,7 @@ struct dme1737_data { ...@@ -182,6 +186,7 @@ struct dme1737_data {
unsigned long last_update; /* in jiffies */ unsigned long last_update; /* in jiffies */
unsigned long last_vbat; /* in jiffies */ unsigned long last_vbat; /* in jiffies */
enum chips type; enum chips type;
const int *in_nominal; /* pointer to IN_NOMINAL array */
u8 vid; u8 vid;
u8 pwm_rr_en; u8 pwm_rr_en;
...@@ -220,23 +225,23 @@ static const int IN_NOMINAL_DME1737[] = {5000, 2250, 3300, 5000, 12000, 3300, ...@@ -220,23 +225,23 @@ static const int IN_NOMINAL_DME1737[] = {5000, 2250, 3300, 5000, 12000, 3300,
3300}; 3300};
static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300, static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
3300}; 3300};
#define IN_NOMINAL(ix, type) (((type) == dme1737) ? \ static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300,
IN_NOMINAL_DME1737[(ix)] : \ 3300};
IN_NOMINAL_SCH311x[(ix)]) #define IN_NOMINAL(type) ((type) == sch311x ? IN_NOMINAL_SCH311x : \
(type) == sch5027 ? IN_NOMINAL_SCH5027 : \
IN_NOMINAL_DME1737)
/* Voltage input /* Voltage input
* Voltage inputs have 16 bits resolution, limit values have 8 bits * Voltage inputs have 16 bits resolution, limit values have 8 bits
* resolution. */ * 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))) / return (reg * nominal + (3 << (res - 3))) / (3 << (res - 2));
(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) / return SENSORS_LIMIT((val * 192 + nominal / 2) / nominal, 0, 255);
IN_NOMINAL(ix, type), 0, 255);
} }
/* Temperature input /* Temperature input
...@@ -565,7 +570,10 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) ...@@ -565,7 +570,10 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
/* Sample register contents every 1 sec */ /* Sample register contents every 1 sec */
if (time_after(jiffies, data->last_update + HZ) || !data->valid) { 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 */ /* In (voltage) registers */
for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) { for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
...@@ -593,8 +601,10 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) ...@@ -593,8 +601,10 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
DME1737_REG_TEMP_MIN(ix)); DME1737_REG_TEMP_MIN(ix));
data->temp_max[ix] = dme1737_read(client, data->temp_max[ix] = dme1737_read(client,
DME1737_REG_TEMP_MAX(ix)); DME1737_REG_TEMP_MAX(ix));
data->temp_offset[ix] = dme1737_read(client, if (data->type != sch5027) {
DME1737_REG_TEMP_OFFSET(ix)); data->temp_offset[ix] = dme1737_read(client,
DME1737_REG_TEMP_OFFSET(ix));
}
} }
/* In and temp LSB registers /* In and temp LSB registers
...@@ -669,9 +679,11 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) ...@@ -669,9 +679,11 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
data->zone_abs[ix] = dme1737_read(client, data->zone_abs[ix] = dme1737_read(client,
DME1737_REG_ZONE_ABS(ix)); DME1737_REG_ZONE_ABS(ix));
} }
for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) { if (data->type != sch5027) {
data->zone_hyst[ix] = dme1737_read(client, for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
data->zone_hyst[ix] = dme1737_read(client,
DME1737_REG_ZONE_HYST(ix)); DME1737_REG_ZONE_HYST(ix));
}
} }
/* Alarm registers */ /* Alarm registers */
...@@ -735,13 +747,13 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr, ...@@ -735,13 +747,13 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
switch (fn) { switch (fn) {
case SYS_IN_INPUT: 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; break;
case SYS_IN_MIN: 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; break;
case SYS_IN_MAX: 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; break;
case SYS_IN_ALARM: case SYS_IN_ALARM:
res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01; 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, ...@@ -768,12 +780,12 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
switch (fn) { switch (fn) {
case SYS_IN_MIN: 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), dme1737_write(client, DME1737_REG_IN_MIN(ix),
data->in_min[ix]); data->in_min[ix]);
break; break;
case SYS_IN_MAX: 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), dme1737_write(client, DME1737_REG_IN_MAX(ix),
data->in_max[ix]); data->in_max[ix]);
break; break;
...@@ -1166,7 +1178,7 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, ...@@ -1166,7 +1178,7 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", res); 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 void dme1737_chmod_file(struct device*, struct attribute*, mode_t);
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, 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, ...@@ -1230,7 +1242,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
switch (val) { switch (val) {
case 0: case 0:
/* Change permissions of pwm[ix] to read-only */ /* 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); S_IRUGO);
/* Turn fan fully on */ /* Turn fan fully on */
data->pwm_config[ix] = PWM_EN_TO_REG(0, 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, ...@@ -1245,12 +1257,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
dme1737_write(client, DME1737_REG_PWM_CONFIG(ix), dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
data->pwm_config[ix]); data->pwm_config[ix]);
/* Change permissions of pwm[ix] to read-writeable */ /* 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); S_IRUGO | S_IWUSR);
break; break;
case 2: case 2:
/* Change permissions of pwm[ix] to read-only */ /* 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); S_IRUGO);
/* Turn on auto mode using the saved zone channel /* Turn on auto mode using the saved zone channel
* assignment */ * assignment */
...@@ -1570,88 +1582,98 @@ static struct attribute *dme1737_attr[] ={ ...@@ -1570,88 +1582,98 @@ static struct attribute *dme1737_attr[] ={
&sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_alarm.dev_attr.attr, &sensor_dev_attr_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_fault.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_input.dev_attr.attr,
&sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_alarm.dev_attr.attr, &sensor_dev_attr_temp2_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_fault.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_input.dev_attr.attr,
&sensor_dev_attr_temp3_min.dev_attr.attr, &sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_alarm.dev_attr.attr, &sensor_dev_attr_temp3_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_fault.dev_attr.attr, &sensor_dev_attr_temp3_fault.dev_attr.attr,
&sensor_dev_attr_temp3_offset.dev_attr.attr,
/* Zones */ /* 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_point1_temp.dev_attr.attr,
&sensor_dev_attr_zone1_auto_point2_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_point3_temp.dev_attr.attr,
&sensor_dev_attr_zone1_auto_channels_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_point1_temp.dev_attr.attr,
&sensor_dev_attr_zone2_auto_point2_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_point3_temp.dev_attr.attr,
&sensor_dev_attr_zone2_auto_channels_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_point1_temp.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point2_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_point3_temp.dev_attr.attr,
&sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr, &sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
NULL
};
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 */ /* Misc */
&dev_attr_vrm.attr, &dev_attr_vrm.attr,
&dev_attr_cpu0_vid.attr, &dev_attr_cpu0_vid.attr,
NULL NULL
}; };
static const struct attribute_group dme1737_group = { static const struct attribute_group dme1737_misc_group = {
.attrs = dme1737_attr, .attrs = dme1737_misc_attr,
}; };
/* The following structs hold the PWM attributes, some of which are optional. /* The following structs hold the PWM attributes, some of which are optional.
* Their creation depends on the chip configuration which is determined during * Their creation depends on the chip configuration which is determined during
* module load. */ * 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.dev_attr.attr,
&sensor_dev_attr_pwm1_freq.dev_attr.attr, &sensor_dev_attr_pwm1_freq.dev_attr.attr,
&sensor_dev_attr_pwm1_enable.dev_attr.attr, &sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm1_ramp_rate.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_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_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
NULL NULL
}; };
static struct attribute *dme1737_attr_pwm2[] = { static struct attribute *dme1737_pwm2_attr[] = {
&sensor_dev_attr_pwm2.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr,
&sensor_dev_attr_pwm2_freq.dev_attr.attr, &sensor_dev_attr_pwm2_freq.dev_attr.attr,
&sensor_dev_attr_pwm2_enable.dev_attr.attr, &sensor_dev_attr_pwm2_enable.dev_attr.attr,
&sensor_dev_attr_pwm2_ramp_rate.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_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_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
NULL NULL
}; };
static struct attribute *dme1737_attr_pwm3[] = { static struct attribute *dme1737_pwm3_attr[] = {
&sensor_dev_attr_pwm3.dev_attr.attr, &sensor_dev_attr_pwm3.dev_attr.attr,
&sensor_dev_attr_pwm3_freq.dev_attr.attr, &sensor_dev_attr_pwm3_freq.dev_attr.attr,
&sensor_dev_attr_pwm3_enable.dev_attr.attr, &sensor_dev_attr_pwm3_enable.dev_attr.attr,
&sensor_dev_attr_pwm3_ramp_rate.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_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_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
NULL NULL
}; };
static struct attribute *dme1737_attr_pwm5[] = { static struct attribute *dme1737_pwm5_attr[] = {
&sensor_dev_attr_pwm5.dev_attr.attr, &sensor_dev_attr_pwm5.dev_attr.attr,
&sensor_dev_attr_pwm5_freq.dev_attr.attr, &sensor_dev_attr_pwm5_freq.dev_attr.attr,
&sensor_dev_attr_pwm5_enable.dev_attr.attr, &sensor_dev_attr_pwm5_enable.dev_attr.attr,
NULL NULL
}; };
static struct attribute *dme1737_attr_pwm6[] = { static struct attribute *dme1737_pwm6_attr[] = {
&sensor_dev_attr_pwm6.dev_attr.attr, &sensor_dev_attr_pwm6.dev_attr.attr,
&sensor_dev_attr_pwm6_freq.dev_attr.attr, &sensor_dev_attr_pwm6_freq.dev_attr.attr,
&sensor_dev_attr_pwm6_enable.dev_attr.attr, &sensor_dev_attr_pwm6_enable.dev_attr.attr,
...@@ -1659,53 +1681,62 @@ static struct attribute *dme1737_attr_pwm6[] = { ...@@ -1659,53 +1681,62 @@ static struct attribute *dme1737_attr_pwm6[] = {
}; };
static const struct attribute_group dme1737_pwm_group[] = { static const struct attribute_group dme1737_pwm_group[] = {
{ .attrs = dme1737_attr_pwm1 }, { .attrs = dme1737_pwm1_attr },
{ .attrs = dme1737_attr_pwm2 }, { .attrs = dme1737_pwm2_attr },
{ .attrs = dme1737_attr_pwm3 }, { .attrs = dme1737_pwm3_attr },
{ .attrs = NULL }, { .attrs = NULL },
{ .attrs = dme1737_attr_pwm5 }, { .attrs = dme1737_pwm5_attr },
{ .attrs = dme1737_attr_pwm6 }, { .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. /* The following structs hold the fan attributes, some of which are optional.
* Their creation depends on the chip configuration which is determined during * Their creation depends on the chip configuration which is determined during
* module load. */ * 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_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_alarm.dev_attr.attr, &sensor_dev_attr_fan1_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_type.dev_attr.attr, &sensor_dev_attr_fan1_type.dev_attr.attr,
NULL 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_input.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr, &sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_alarm.dev_attr.attr, &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&sensor_dev_attr_fan2_type.dev_attr.attr, &sensor_dev_attr_fan2_type.dev_attr.attr,
NULL 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_input.dev_attr.attr,
&sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan3_alarm.dev_attr.attr, &sensor_dev_attr_fan3_alarm.dev_attr.attr,
&sensor_dev_attr_fan3_type.dev_attr.attr, &sensor_dev_attr_fan3_type.dev_attr.attr,
NULL 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_input.dev_attr.attr,
&sensor_dev_attr_fan4_min.dev_attr.attr, &sensor_dev_attr_fan4_min.dev_attr.attr,
&sensor_dev_attr_fan4_alarm.dev_attr.attr, &sensor_dev_attr_fan4_alarm.dev_attr.attr,
&sensor_dev_attr_fan4_type.dev_attr.attr, &sensor_dev_attr_fan4_type.dev_attr.attr,
NULL 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_input.dev_attr.attr,
&sensor_dev_attr_fan5_min.dev_attr.attr, &sensor_dev_attr_fan5_min.dev_attr.attr,
&sensor_dev_attr_fan5_alarm.dev_attr.attr, &sensor_dev_attr_fan5_alarm.dev_attr.attr,
&sensor_dev_attr_fan5_max.dev_attr.attr, &sensor_dev_attr_fan5_max.dev_attr.attr,
NULL 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_input.dev_attr.attr,
&sensor_dev_attr_fan6_min.dev_attr.attr, &sensor_dev_attr_fan6_min.dev_attr.attr,
&sensor_dev_attr_fan6_alarm.dev_attr.attr, &sensor_dev_attr_fan6_alarm.dev_attr.attr,
...@@ -1714,94 +1745,83 @@ static struct attribute *dme1737_attr_fan6[] = { ...@@ -1714,94 +1745,83 @@ static struct attribute *dme1737_attr_fan6[] = {
}; };
static const struct attribute_group dme1737_fan_group[] = { static const struct attribute_group dme1737_fan_group[] = {
{ .attrs = dme1737_attr_fan1 }, { .attrs = dme1737_fan1_attr },
{ .attrs = dme1737_attr_fan2 }, { .attrs = dme1737_fan2_attr },
{ .attrs = dme1737_attr_fan3 }, { .attrs = dme1737_fan3_attr },
{ .attrs = dme1737_attr_fan4 }, { .attrs = dme1737_fan4_attr },
{ .attrs = dme1737_attr_fan5 }, { .attrs = dme1737_fan5_attr },
{ .attrs = dme1737_attr_fan6 }, { .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. */ * writeable if the chip is *not* locked. Otherwise they stay read-only. */
static struct attribute *dme1737_attr_lock[] = { static struct attribute *dme1737_zone_chmod_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_zone1_auto_point1_temp.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_point2_temp.dev_attr.attr,
&sensor_dev_attr_zone1_auto_point3_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_point1_temp.dev_attr.attr,
&sensor_dev_attr_zone2_auto_point2_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_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_point1_temp.dev_attr.attr,
&sensor_dev_attr_zone3_auto_point2_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_point3_temp.dev_attr.attr,
NULL NULL
}; };
static const struct attribute_group dme1737_lock_group = { static const struct attribute_group dme1737_zone_chmod_group = {
.attrs = dme1737_attr_lock, .attrs = dme1737_zone_chmod_attr,
}; };
/* The permissions of the following PWM attributes are changed to read- /* The permissions of the following PWM attributes are changed to read-
* writeable if the chip is *not* locked and the respective PWM is available. * writeable if the chip is *not* locked and the respective PWM is available.
* Otherwise they stay read-only. */ * 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_freq.dev_attr.attr,
&sensor_dev_attr_pwm1_enable.dev_attr.attr, &sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm1_ramp_rate.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_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_point1_pwm.dev_attr.attr,
NULL 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_freq.dev_attr.attr,
&sensor_dev_attr_pwm2_enable.dev_attr.attr, &sensor_dev_attr_pwm2_enable.dev_attr.attr,
&sensor_dev_attr_pwm2_ramp_rate.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_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_point1_pwm.dev_attr.attr,
NULL 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_freq.dev_attr.attr,
&sensor_dev_attr_pwm3_enable.dev_attr.attr, &sensor_dev_attr_pwm3_enable.dev_attr.attr,
&sensor_dev_attr_pwm3_ramp_rate.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_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_point1_pwm.dev_attr.attr,
NULL 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.dev_attr.attr,
&sensor_dev_attr_pwm5_freq.dev_attr.attr, &sensor_dev_attr_pwm5_freq.dev_attr.attr,
NULL 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.dev_attr.attr,
&sensor_dev_attr_pwm6_freq.dev_attr.attr, &sensor_dev_attr_pwm6_freq.dev_attr.attr,
NULL NULL
}; };
static const struct attribute_group dme1737_pwm_lock_group[] = { static const struct attribute_group dme1737_pwm_chmod_group[] = {
{ .attrs = dme1737_attr_pwm1_lock }, { .attrs = dme1737_pwm1_chmod_attr },
{ .attrs = dme1737_attr_pwm2_lock }, { .attrs = dme1737_pwm2_chmod_attr },
{ .attrs = dme1737_attr_pwm3_lock }, { .attrs = dme1737_pwm3_chmod_attr },
{ .attrs = NULL }, { .attrs = NULL },
{ .attrs = dme1737_attr_pwm5_lock }, { .attrs = dme1737_pwm5_chmod_attr },
{ .attrs = dme1737_attr_pwm6_lock }, { .attrs = dme1737_pwm6_chmod_attr },
}; };
/* Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the /* 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. */ * 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_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm2.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr,
&sensor_dev_attr_pwm3.dev_attr.attr, &sensor_dev_attr_pwm3.dev_attr.attr,
...@@ -1875,9 +1895,17 @@ static void dme1737_remove_files(struct device *dev) ...@@ -1875,9 +1895,17 @@ static void dme1737_remove_files(struct device *dev)
if (data->has_pwm & (1 << ix)) { if (data->has_pwm & (1 << ix)) {
sysfs_remove_group(&dev->kobj, sysfs_remove_group(&dev->kobj,
&dme1737_pwm_group[ix]); &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); sysfs_remove_group(&dev->kobj, &dme1737_group);
if (!data->client.driver) { if (!data->client.driver) {
...@@ -1901,6 +1929,13 @@ static int dme1737_create_files(struct device *dev) ...@@ -1901,6 +1929,13 @@ static int dme1737_create_files(struct device *dev)
goto exit_remove; 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 */ /* Create fan sysfs attributes */
for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
if (data->has_fan & (1 << ix)) { if (data->has_fan & (1 << ix)) {
...@@ -1918,6 +1953,11 @@ static int dme1737_create_files(struct device *dev) ...@@ -1918,6 +1953,11 @@ static int dme1737_create_files(struct device *dev)
&dme1737_pwm_group[ix]))) { &dme1737_pwm_group[ix]))) {
goto exit_remove; 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) ...@@ -1927,16 +1967,27 @@ static int dme1737_create_files(struct device *dev)
dev_info(dev, "Device is locked. Some attributes " dev_info(dev, "Device is locked. Some attributes "
"will be read-only.\n"); "will be read-only.\n");
} else { } else {
/* Change permissions of standard attributes */ /* Change permissions of zone sysfs attributes */
dme1737_chmod_group(dev, &dme1737_lock_group, dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
S_IRUGO | S_IWUSR); S_IRUGO | S_IWUSR);
/* Change permissions of PWM attributes */ /* Change permissions of misc sysfs attributes */
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) { 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)) { if (data->has_pwm & (1 << ix)) {
dme1737_chmod_group(dev, 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); S_IRUGO | S_IWUSR);
}
} }
} }
...@@ -1945,7 +1996,7 @@ static int dme1737_create_files(struct device *dev) ...@@ -1945,7 +1996,7 @@ static int dme1737_create_files(struct device *dev)
if ((data->has_pwm & (1 << ix)) && if ((data->has_pwm & (1 << ix)) &&
(PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) { (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
dme1737_chmod_file(dev, dme1737_chmod_file(dev,
dme1737_attr_pwm[ix], dme1737_pwm_chmod_attr[ix],
S_IRUGO | S_IWUSR); S_IRUGO | S_IWUSR);
} }
} }
...@@ -1966,6 +2017,9 @@ static int dme1737_init_device(struct device *dev) ...@@ -1966,6 +2017,9 @@ static int dme1737_init_device(struct device *dev)
int ix; int ix;
u8 reg; u8 reg;
/* Point to the right nominal voltages array */
data->in_nominal = IN_NOMINAL(data->type);
data->config = dme1737_read(client, DME1737_REG_CONFIG); data->config = dme1737_read(client, DME1737_REG_CONFIG);
/* Inform if part is not monitoring/started */ /* Inform if part is not monitoring/started */
if (!(data->config & 0x01)) { if (!(data->config & 0x01)) {
...@@ -2076,7 +2130,9 @@ static int dme1737_init_device(struct device *dev) ...@@ -2076,7 +2130,9 @@ static int dme1737_init_device(struct device *dev)
data->pwm_acz[2] = 4; /* pwm3 -> zone3 */ data->pwm_acz[2] = 4; /* pwm3 -> zone3 */
/* Set VRM */ /* Set VRM */
data->vrm = vid_which_vrm(); if (data->type != sch5027) {
data->vrm = vid_which_vrm();
}
return 0; return 0;
} }
...@@ -2095,9 +2151,10 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data) ...@@ -2095,9 +2151,10 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
dme1737_sio_enter(sio_cip); dme1737_sio_enter(sio_cip);
/* Check device ID /* 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); 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; err = -ENODEV;
goto exit; goto exit;
} }
...@@ -2166,15 +2223,24 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address, ...@@ -2166,15 +2223,24 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
company = dme1737_read(client, DME1737_REG_COMPANY); company = dme1737_read(client, DME1737_REG_COMPANY);
verstep = dme1737_read(client, DME1737_REG_VERSTEP); verstep = dme1737_read(client, DME1737_REG_VERSTEP);
if (!((company == DME1737_COMPANY_SMSC) && if (company == DME1737_COMPANY_SMSC &&
((verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP))) { (verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
kind = dme1737;
} else if (company == DME1737_COMPANY_SMSC &&
verstep == SCH5027_VERSTEP) {
kind = sch5027;
} else {
err = -ENODEV; err = -ENODEV;
goto exit_kfree; goto exit_kfree;
} }
} }
kind = dme1737; if (kind == sch5027) {
name = "dme1737"; name = "sch5027";
} else {
kind = dme1737;
name = "dme1737";
}
data->type = kind; data->type = kind;
/* Fill in the remaining client fields and put it into the global /* 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, ...@@ -2187,8 +2253,9 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
goto exit_kfree; goto exit_kfree;
} }
dev_info(dev, "Found a DME1737 chip at 0x%02x (rev 0x%02x).\n", dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n",
client->addr, verstep); kind == sch5027 ? "SCH5027" : "DME1737", client->addr,
verstep);
/* Initialize the DME1737 chip */ /* Initialize the DME1737 chip */
if ((err = dme1737_init_device(dev))) { if ((err = dme1737_init_device(dev))) {
...@@ -2360,15 +2427,18 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev) ...@@ -2360,15 +2427,18 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
client->addr = res->start; client->addr = res->start;
platform_set_drvdata(pdev, data); platform_set_drvdata(pdev, data);
company = dme1737_read(client, DME1737_REG_COMPANY); /* Skip chip detection if module is loaded with force_id parameter */
device = dme1737_read(client, DME1737_REG_DEVICE); if (!force_id) {
company = dme1737_read(client, DME1737_REG_COMPANY);
device = dme1737_read(client, DME1737_REG_DEVICE);
if (!((company == DME1737_COMPANY_SMSC) && if (!((company == DME1737_COMPANY_SMSC) &&
(device == SCH311X_DEVICE))) { (device == SCH311X_DEVICE))) {
err = -ENODEV; err = -ENODEV;
goto exit_kfree; goto exit_kfree;
}
} }
data->type = -1; data->type = sch311x;
/* Fill in the remaining client fields and initialize the mutex */ /* Fill in the remaining client fields and initialize the mutex */
strlcpy(client->name, "sch311x", I2C_NAME_SIZE); strlcpy(client->name, "sch311x", I2C_NAME_SIZE);
......
...@@ -87,8 +87,6 @@ static inline void superio_enter(int base); ...@@ -87,8 +87,6 @@ static inline void superio_enter(int base);
static inline void superio_select(int base, int ld); static inline void superio_select(int base, int ld);
static inline void superio_exit(int base); static inline void superio_exit(int base);
static inline u16 fan_from_reg ( u16 reg );
struct f71882fg_data { struct f71882fg_data {
unsigned short addr; unsigned short addr;
struct device *hwmon_dev; struct device *hwmon_dev;
...@@ -116,10 +114,6 @@ struct f71882fg_data { ...@@ -116,10 +114,6 @@ struct f71882fg_data {
u8 temp_diode_open; 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*/ /* Sysfs in*/
static ssize_t show_in(struct device *dev, struct device_attribute *devattr, static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
char *buf); char *buf);
......
/* /*
hwmon-vid.c - VID/VRM/VRD voltage conversions * hwmon-vid.c - VID/VRM/VRD voltage conversions
*
Copyright (c) 2004 Rudolf Marek <r.marek@assembler.cz> * Copyright (c) 2004 Rudolf Marek <r.marek@assembler.cz>
*
Partly imported from i2c-vid.h of the lm_sensors project * Partly imported from i2c-vid.h of the lm_sensors project
Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> * Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
With assistance from Trent Piepho <xyzzy@speakeasy.org> * With assistance from Trent Piepho <xyzzy@speakeasy.org>
*
This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. * (at your option) any later version.
*
This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. * GNU General Public License for more details.
*
You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/hwmon-vid.h> #include <linux/hwmon-vid.h>
/* /*
Common code for decoding VID pins. * Common code for decoding VID pins.
*
References: * References:
*
For VRM 8.4 to 9.1, "VRM x.y DC-DC Converter Design Guidelines", * For VRM 8.4 to 9.1, "VRM x.y DC-DC Converter Design Guidelines",
available at http://developer.intel.com/. * available at http://developer.intel.com/.
*
For VRD 10.0 and up, "VRD x.y Design Guide", * For VRD 10.0 and up, "VRD x.y Design Guide",
available at http://developer.intel.com/. * available at http://developer.intel.com/.
*
AMD Opteron processors don't follow the Intel specifications. * AMD NPT 0Fh (Athlon64 & Opteron), AMD Publication 32559,
I'm going to "make up" 2.4 as the spec number for the Opterons. * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf
No good reason just a mnemonic for the 24x Opteron processor * Table 71. VID Code Voltages
series. * AMD Opteron processors don't follow the Intel specifications.
* I'm going to "make up" 2.4 as the spec number for the Opterons.
Opteron VID encoding is: * No good reason just a mnemonic for the 24x Opteron processor
00000 = 1.550 V * series.
00001 = 1.525 V *
. . . . * The 17 specification is in fact Intel Mobile Voltage Positioning -
11110 = 0.800 V * (IMVP-II). You can find more information in the datasheet of Max1718
11111 = 0.000 V (off) * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2452
*
The 17 specification is in fact Intel Mobile Voltage Positioning - * The 13 specification corresponds to the Intel Pentium M series. There
(IMVP-II). You can find more information in the datasheet of Max1718 * doesn't seem to be any named specification for these. The conversion
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2452 * tables are detailed directly in the various Pentium M datasheets:
* http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm
The 13 specification corresponds to the Intel Pentium M series. There *
doesn't seem to be any named specification for these. The conversion * The 14 specification corresponds to Intel Core series. There
tables are detailed directly in the various Pentium M datasheets: * doesn't seem to be any named specification for these. The conversion
http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm * tables are detailed directly in the various Pentium Core datasheets:
* http://www.intel.com/design/mobile/datashts/309221.htm
The 14 specification corresponds to Intel Core series. There *
doesn't seem to be any named specification for these. The conversion * The 110 (VRM 11) specification corresponds to Intel Conroe based series.
tables are detailed directly in the various Pentium Core datasheets: * http://www.intel.com/design/processor/applnots/313214.htm
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.
/* vrm is the VRM/VRD document version multiplied by 10. * Some VID have some bits in uV scale, this is rounded to mV.
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_from_reg(int val, u8 vrm)
{ {
int vid; int vid;
...@@ -96,9 +94,11 @@ int vid_from_reg(int val, u8 vrm) ...@@ -96,9 +94,11 @@ int vid_from_reg(int val, u8 vrm)
if (val < 0x02 || val > 0xb2) if (val < 0x02 || val > 0xb2)
return 0; return 0;
return((1600000 - (val - 2) * 6250 + 500) / 1000); return((1600000 - (val - 2) * 6250 + 500) / 1000);
case 24: /* Opteron processor */
val &= 0x1f; case 24: /* AMD NPT 0Fh (Athlon64 & Opteron) */
return(val == 0x1f ? 0 : 1550 - val * 25); val &= 0x3f;
return (val < 32) ? 1550 - 25 * val
: 775 - (25 * (val - 31)) / 2;
case 91: /* VRM 9.1 */ case 91: /* VRM 9.1 */
case 90: /* VRM 9.0 */ case 90: /* VRM 9.0 */
...@@ -141,9 +141,9 @@ int vid_from_reg(int val, u8 vrm) ...@@ -141,9 +141,9 @@ int vid_from_reg(int val, u8 vrm)
/* /*
After this point is the code to automatically determine which * After this point is the code to automatically determine which
VRM/VRD specification should be used depending on the CPU. * VRM/VRD specification should be used depending on the CPU.
*/ */
struct vrm_model { struct vrm_model {
u8 vendor; u8 vendor;
......
...@@ -151,9 +151,9 @@ static int fix_pwm_polarity; ...@@ -151,9 +151,9 @@ static int fix_pwm_polarity;
/* The IT8718F has the VID value in a different register, in Super-I/O /* The IT8718F has the VID value in a different register, in Super-I/O
configuration space. */ configuration space. */
#define IT87_REG_VID 0x0a #define IT87_REG_VID 0x0a
/* Warning: register 0x0b is used for something completely different in /* The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b
new chips/revisions. I suspect only 16-bit tachometer mode will work for fan divisors. Later IT8712F revisions must use 16-bit tachometer
for these. */ mode. */
#define IT87_REG_FAN_DIV 0x0b #define IT87_REG_FAN_DIV 0x0b
#define IT87_REG_FAN_16BIT 0x0c #define IT87_REG_FAN_16BIT 0x0c
...@@ -234,6 +234,7 @@ static const unsigned int pwm_freq[8] = { ...@@ -234,6 +234,7 @@ static const unsigned int pwm_freq[8] = {
struct it87_sio_data { struct it87_sio_data {
enum chips type; enum chips type;
/* Values read from Super-I/O config space */ /* Values read from Super-I/O config space */
u8 revision;
u8 vid_value; u8 vid_value;
}; };
...@@ -242,6 +243,7 @@ struct it87_sio_data { ...@@ -242,6 +243,7 @@ struct it87_sio_data {
struct it87_data { struct it87_data {
struct device *hwmon_dev; struct device *hwmon_dev;
enum chips type; enum chips type;
u8 revision;
unsigned short addr; unsigned short addr;
const char *name; const char *name;
...@@ -268,6 +270,16 @@ struct it87_data { ...@@ -268,6 +270,16 @@ struct it87_data {
u8 manual_pwm_ctl[3]; /* manual PWM value set by user */ 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 it87_probe(struct platform_device *pdev);
static int __devexit it87_remove(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, ...@@ -991,8 +1003,9 @@ static int __init it87_find(unsigned short *address,
} }
err = 0; err = 0;
sio_data->revision = superio_inb(DEVREV) & 0x0f;
pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n", 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) */ /* Read GPIO config and VID value from LDN 7 (GPIO) */
if (chip_type != IT8705F_DEVID) { if (chip_type != IT8705F_DEVID) {
...@@ -1045,6 +1058,7 @@ static int __devinit it87_probe(struct platform_device *pdev) ...@@ -1045,6 +1058,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
data->addr = res->start; data->addr = res->start;
data->type = sio_data->type; data->type = sio_data->type;
data->revision = sio_data->revision;
data->name = names[sio_data->type]; data->name = names[sio_data->type];
/* Now, we do the remaining detection. */ /* Now, we do the remaining detection. */
...@@ -1069,7 +1083,7 @@ static int __devinit it87_probe(struct platform_device *pdev) ...@@ -1069,7 +1083,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
goto ERROR2; goto ERROR2;
/* Do not create fan files for disabled fans */ /* Do not create fan files for disabled fans */
if (data->type == it8716 || data->type == it8718) { if (has_16bit_fans(data)) {
/* 16-bit tachometers */ /* 16-bit tachometers */
if (data->has_fan & (1 << 0)) { if (data->has_fan & (1 << 0)) {
if ((err = device_create_file(dev, if ((err = device_create_file(dev,
...@@ -1350,7 +1364,7 @@ static void __devinit it87_init_device(struct platform_device *pdev) ...@@ -1350,7 +1364,7 @@ static void __devinit it87_init_device(struct platform_device *pdev)
data->has_fan = (data->fan_main_ctrl >> 4) & 0x07; data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
/* Set tachometers to 16-bit mode if needed */ /* 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); tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
if (~tmp & 0x07 & data->has_fan) { if (~tmp & 0x07 & data->has_fan) {
dev_dbg(&pdev->dev, dev_dbg(&pdev->dev,
...@@ -1358,10 +1372,13 @@ static void __devinit it87_init_device(struct platform_device *pdev) ...@@ -1358,10 +1372,13 @@ static void __devinit it87_init_device(struct platform_device *pdev)
it87_write_value(data, IT87_REG_FAN_16BIT, it87_write_value(data, IT87_REG_FAN_16BIT,
tmp | 0x07); tmp | 0x07);
} }
if (tmp & (1 << 4)) /* IT8705F only supports three fans. */
data->has_fan |= (1 << 3); /* fan4 enabled */ if (data->type != it87) {
if (tmp & (1 << 5)) if (tmp & (1 << 4))
data->has_fan |= (1 << 4); /* fan5 enabled */ 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 /* 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) ...@@ -1426,7 +1443,7 @@ static struct it87_data *it87_update_device(struct device *dev)
data->fan[i] = it87_read_value(data, data->fan[i] = it87_read_value(data,
IT87_REG_FAN[i]); IT87_REG_FAN[i]);
/* Add high byte if in 16-bit mode */ /* 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, data->fan[i] |= it87_read_value(data,
IT87_REG_FANX[i]) << 8; IT87_REG_FANX[i]) << 8;
data->fan_min[i] |= it87_read_value(data, data->fan_min[i] |= it87_read_value(data,
...@@ -1443,8 +1460,7 @@ static struct it87_data *it87_update_device(struct device *dev) ...@@ -1443,8 +1460,7 @@ static struct it87_data *it87_update_device(struct device *dev)
} }
/* Newer chips don't have clock dividers */ /* Newer chips don't have clock dividers */
if ((data->has_fan & 0x07) && data->type != it8716 if ((data->has_fan & 0x07) && !has_16bit_fans(data)) {
&& data->type != it8718) {
i = it87_read_value(data, IT87_REG_FAN_DIV); i = it87_read_value(data, IT87_REG_FAN_DIV);
data->fan_div[0] = i & 0x07; data->fan_div[0] = i & 0x07;
data->fan_div[1] = (i >> 3) & 0x07; data->fan_div[1] = (i >> 3) & 0x07;
...@@ -1460,7 +1476,8 @@ static struct it87_data *it87_update_device(struct device *dev) ...@@ -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->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE); 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) { if (data->type == it8712 || data->type == it8716) {
data->vid = it87_read_value(data, IT87_REG_VID); data->vid = it87_read_value(data, IT87_REG_VID);
/* The older IT8712F revisions had only 5 VID pins, /* The older IT8712F revisions had only 5 VID pins,
......
...@@ -55,8 +55,11 @@ I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs " ...@@ -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[] = { 0x27, 0x26, 0x20 };
static const u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C }; 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_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_nFANOFF 0x20
#define THMC50_REG_CONF_PROGRAMMED 0x08
/* Each client has this additional data */ /* Each client has this additional data */
struct thmc50_data { struct thmc50_data {
...@@ -72,6 +75,7 @@ struct thmc50_data { ...@@ -72,6 +75,7 @@ struct thmc50_data {
s8 temp_input[3]; s8 temp_input[3];
s8 temp_max[3]; s8 temp_max[3];
s8 temp_min[3]; s8 temp_min[3];
s8 temp_critical[3];
u8 analog_out; u8 analog_out;
u8 alarms; u8 alarms;
}; };
...@@ -199,6 +203,15 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, ...@@ -199,6 +203,15 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
return count; 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, static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
...@@ -214,7 +227,9 @@ static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \ ...@@ -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, \ static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
show_temp_min, set_temp_min, offset - 1); \ show_temp_min, set_temp_min, offset - 1); \
static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ 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(1);
temp_reg(2); temp_reg(2);
...@@ -234,10 +249,12 @@ static struct attribute *thmc50_attributes[] = { ...@@ -234,10 +249,12 @@ static struct attribute *thmc50_attributes[] = {
&sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr, &sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_input.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_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_input.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_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr, &sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr,
...@@ -254,6 +271,7 @@ static struct attribute *temp3_attributes[] = { ...@@ -254,6 +271,7 @@ static struct attribute *temp3_attributes[] = {
&sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_min.dev_attr.attr, &sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_input.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_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_fault.dev_attr.attr, &sensor_dev_attr_temp3_fault.dev_attr.attr,
NULL NULL
...@@ -429,6 +447,10 @@ static struct thmc50_data *thmc50_update_device(struct device *dev) ...@@ -429,6 +447,10 @@ static struct thmc50_data *thmc50_update_device(struct device *dev)
int temps = data->has_temp3 ? 3 : 2; int temps = data->has_temp3 ? 3 : 2;
int i; int i;
int prog = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
prog &= THMC50_REG_CONF_PROGRAMMED;
for (i = 0; i < temps; i++) { for (i = 0; i < temps; i++) {
data->temp_input[i] = i2c_smbus_read_byte_data(client, data->temp_input[i] = i2c_smbus_read_byte_data(client,
THMC50_REG_TEMP[i]); THMC50_REG_TEMP[i]);
...@@ -436,6 +458,10 @@ static struct thmc50_data *thmc50_update_device(struct device *dev) ...@@ -436,6 +458,10 @@ static struct thmc50_data *thmc50_update_device(struct device *dev)
THMC50_REG_TEMP_MAX[i]); THMC50_REG_TEMP_MAX[i]);
data->temp_min[i] = i2c_smbus_read_byte_data(client, data->temp_min[i] = i2c_smbus_read_byte_data(client,
THMC50_REG_TEMP_MIN[i]); 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 = data->analog_out =
i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT); i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
......
...@@ -67,10 +67,6 @@ module_param(force_i2c, byte, 0); ...@@ -67,10 +67,6 @@ module_param(force_i2c, byte, 0);
MODULE_PARM_DESC(force_i2c, MODULE_PARM_DESC(force_i2c,
"Initialize the i2c address of the sensors"); "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; static int init = 1;
module_param(init, bool, 0); module_param(init, bool, 0);
MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); 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 }; ...@@ -209,6 +205,13 @@ static const u16 w83627hf_reg_temp_over[] = { 0x39, 0x155, 0x255 };
#define W83627HF_REG_PWM1 0x5A #define W83627HF_REG_PWM1 0x5A
#define W83627HF_REG_PWM2 0x5B #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_PWM1 0x01 /* 697HF/637HF/687THF too */
#define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */ #define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */
#define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */ #define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */
...@@ -366,6 +369,9 @@ struct w83627hf_data { ...@@ -366,6 +369,9 @@ struct w83627hf_data {
u32 alarms; /* Register encoding, combined */ u32 alarms; /* Register encoding, combined */
u32 beep_mask; /* Register encoding, combined */ u32 beep_mask; /* Register encoding, combined */
u8 pwm[3]; /* Register value */ 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 */ u8 pwm_freq[3]; /* Register value */
u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode; u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode;
4 = thermistor */ 4 = thermistor */
...@@ -956,6 +962,42 @@ static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0); ...@@ -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(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 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 static ssize_t
show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf) show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
{ {
...@@ -1223,6 +1265,11 @@ static struct attribute *w83627hf_attributes_opt[] = { ...@@ -1223,6 +1265,11 @@ static struct attribute *w83627hf_attributes_opt[] = {
&sensor_dev_attr_pwm1_freq.dev_attr.attr, &sensor_dev_attr_pwm1_freq.dev_attr.attr,
&sensor_dev_attr_pwm2_freq.dev_attr.attr, &sensor_dev_attr_pwm2_freq.dev_attr.attr,
&sensor_dev_attr_pwm3_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 NULL
}; };
...@@ -1366,6 +1413,19 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) ...@@ -1366,6 +1413,19 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
&sensor_dev_attr_pwm3_freq.dev_attr))) &sensor_dev_attr_pwm3_freq.dev_attr)))
goto ERROR4; 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); data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev)) { if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev); err = PTR_ERR(data->hwmon_dev);
...@@ -1536,29 +1596,6 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev) ...@@ -1536,29 +1596,6 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
enum chips type = data->type; enum chips type = data->type;
u8 tmp; 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... */ /* Minimize conflicts with other winbond i2c-only clients... */
/* disable i2c subclients... how to disable main i2c client?? */ /* disable i2c subclients... how to disable main i2c client?? */
/* force i2c address to relatively uncommon address */ /* force i2c address to relatively uncommon address */
...@@ -1655,6 +1692,7 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev) ...@@ -1655,6 +1692,7 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
{ {
struct w83627hf_data *data = dev_get_drvdata(dev); struct w83627hf_data *data = dev_get_drvdata(dev);
int i, num_temps = (data->type == w83697hf) ? 2 : 3; int i, num_temps = (data->type == w83697hf) ? 2 : 3;
int num_pwms = (data->type == w83697hf) ? 2 : 3;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
...@@ -1707,6 +1745,15 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev) ...@@ -1707,6 +1745,15 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
break; 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++) { for (i = 0; i < num_temps; i++) {
data->temp[i] = w83627hf_read_value( data->temp[i] = w83627hf_read_value(
data, w83627hf_reg_temp[i]); data, w83627hf_reg_temp[i]);
......
...@@ -233,11 +233,9 @@ static u8 fan_to_reg(long rpm, int div) ...@@ -233,11 +233,9 @@ static u8 fan_to_reg(long rpm, int div)
static u8 div_to_reg(int nr, long val) static u8 div_to_reg(int nr, long val)
{ {
int i; int i;
int max;
/* first three fan's divisor max out at 8, rest max out at 128 */ /* fan divisors max out at 128 */
max = (nr < 3) ? 8 : 128; val = SENSORS_LIMIT(val, 1, 128) >> 1;
val = SENSORS_LIMIT(val, 1, max) >> 1;
for (i = 0; i < 7; i++) { for (i = 0; i < 7; i++) {
if (val == 0) if (val == 0)
break; break;
...@@ -530,6 +528,7 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, ...@@ -530,6 +528,7 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr,
unsigned long min; unsigned long min;
u8 tmp_fan_div; u8 tmp_fan_div;
u8 fan_div_reg; u8 fan_div_reg;
u8 vbat_reg;
int indx = 0; int indx = 0;
u8 keep_mask = 0; u8 keep_mask = 0;
u8 new_shift = 0; u8 new_shift = 0;
...@@ -581,6 +580,16 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, ...@@ -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], w83791d_write(client, W83791D_REG_FAN_DIV[indx],
fan_div_reg | tmp_fan_div); 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 */ /* Restore fan_min */
data->fan_min[nr] = fan_to_reg(min, DIV_FROM_REG(data->fan_div[nr])); 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]); 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) ...@@ -1182,6 +1191,7 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
struct w83791d_data *data = i2c_get_clientdata(client); struct w83791d_data *data = i2c_get_clientdata(client);
int i, j; int i, j;
u8 reg_array_tmp[3]; u8 reg_array_tmp[3];
u8 vbat_reg;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
...@@ -1219,6 +1229,12 @@ static struct w83791d_data *w83791d_update_device(struct device *dev) ...@@ -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[3] = reg_array_tmp[2] & 0x07;
data->fan_div[4] = (reg_array_tmp[2] >> 4) & 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 */ /* Update the first temperature sensor */
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
data->temp1[i] = w83791d_read(client, data->temp1[i] = w83791d_read(client,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment