Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging
* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging: hwmon: (sysfs-interface) Update tempX_type attribute to be more generic hwmon: (adm1031) Fix coding style issues hwmon: (it87) Add IT8728F support hwmon: (coretemp) Add missing section annotations hwmon: (lm90) Add range check to set_update_interval hwmon: (lm63) Support extended lookup table of LM96163 hwmon: (lm63) Expose automatic fan speed control lookup table hwmon: (lm63) Fix incorrect comment about I2C address hwmon: (lm63) LM64 has a dedicated pin for tachometer hwmon: (lm63) Add sensor type attribute for external sensor on LM96163 hwmon: (lm63) Add support for update_interval sysfs attribute hwmon: (lm63) Add support for writing the external critical temperature hwmon: (lm63) Add support for unsigned upper temperature limits hwmon: (lm63) Add support for LM96163 hwmon: (lm63) Add support for external temperature offset register hwmon: (lm63) Fix checkpatch errors hwmon: (max1111) Change sysfs interface to in[0-3]_input in millivolts
This commit is contained in:
@@ -26,6 +26,10 @@ Supported chips:
|
|||||||
Prefix: 'it8721'
|
Prefix: 'it8721'
|
||||||
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: Not publicly available
|
Datasheet: Not publicly available
|
||||||
|
* IT8728F
|
||||||
|
Prefix: 'it8728'
|
||||||
|
Addresses scanned: from Super I/O config space (8 I/O ports)
|
||||||
|
Datasheet: Not publicly available
|
||||||
* SiS950 [clone of IT8705F]
|
* SiS950 [clone of IT8705F]
|
||||||
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)
|
||||||
@@ -71,7 +75,7 @@ Description
|
|||||||
-----------
|
-----------
|
||||||
|
|
||||||
This driver implements support for the IT8705F, IT8712F, IT8716F,
|
This driver implements support for the IT8705F, IT8712F, IT8716F,
|
||||||
IT8718F, IT8720F, IT8721F, IT8726F, IT8758E and SiS950 chips.
|
IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E and SiS950 chips.
|
||||||
|
|
||||||
These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
|
These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
|
||||||
joysticks and other miscellaneous stuff. For hardware monitoring, they
|
joysticks and other miscellaneous stuff. For hardware monitoring, they
|
||||||
@@ -105,6 +109,9 @@ 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
|
||||||
to userspace applications.
|
to userspace applications.
|
||||||
|
|
||||||
|
The IT8728F is considered compatible with the IT8721F, until a datasheet
|
||||||
|
becomes available (hopefully.)
|
||||||
|
|
||||||
Temperatures are measured in degrees Celsius. An alarm is triggered once
|
Temperatures are measured in degrees Celsius. An alarm is triggered once
|
||||||
when the Overtemperature Shutdown limit is crossed.
|
when the Overtemperature Shutdown limit is crossed.
|
||||||
|
|
||||||
@@ -121,8 +128,8 @@ alarm is triggered if the voltage has crossed a programmable minimum or
|
|||||||
maximum limit. Note that minimum in this case always means 'closest to
|
maximum limit. Note that minimum in this case always means 'closest to
|
||||||
zero'; this is important for negative voltage measurements. All voltage
|
zero'; this is important for negative voltage measurements. All voltage
|
||||||
inputs can measure voltages between 0 and 4.08 volts, with a resolution of
|
inputs can measure voltages between 0 and 4.08 volts, with a resolution of
|
||||||
0.016 volt (except IT8721F/IT8758E: 0.012 volt.) The battery voltage in8 does
|
0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery
|
||||||
not have limit registers.
|
voltage in8 does not have limit registers.
|
||||||
|
|
||||||
On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside
|
On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside
|
||||||
the chip (in7, in8 and optionally in3). The driver handles this transparently
|
the chip (in7, in8 and optionally in3). The driver handles this transparently
|
||||||
|
@@ -12,6 +12,11 @@ Supported chips:
|
|||||||
Addresses scanned: I2C 0x18 and 0x4e
|
Addresses scanned: I2C 0x18 and 0x4e
|
||||||
Datasheet: Publicly available at the National Semiconductor website
|
Datasheet: Publicly available at the National Semiconductor website
|
||||||
http://www.national.com/pf/LM/LM64.html
|
http://www.national.com/pf/LM/LM64.html
|
||||||
|
* National Semiconductor LM96163
|
||||||
|
Prefix: 'lm96163'
|
||||||
|
Addresses scanned: I2C 0x4c
|
||||||
|
Datasheet: Publicly available at the National Semiconductor website
|
||||||
|
http://www.national.com/pf/LM/LM96163.html
|
||||||
|
|
||||||
Author: Jean Delvare <khali@linux-fr.org>
|
Author: Jean Delvare <khali@linux-fr.org>
|
||||||
|
|
||||||
@@ -49,16 +54,24 @@ value for measuring the speed of the fan. It can measure fan speeds down to
|
|||||||
Note that the pin used for fan monitoring is shared with an alert out
|
Note that the pin used for fan monitoring is shared with an alert out
|
||||||
function. Depending on how the board designer wanted to use the chip, fan
|
function. Depending on how the board designer wanted to use the chip, fan
|
||||||
speed monitoring will or will not be possible. The proper chip configuration
|
speed monitoring will or will not be possible. The proper chip configuration
|
||||||
is left to the BIOS, and the driver will blindly trust it.
|
is left to the BIOS, and the driver will blindly trust it. Only the original
|
||||||
|
LM63 suffers from this limitation, the LM64 and LM96163 have separate pins
|
||||||
|
for fan monitoring and alert out. On the LM64, monitoring is always enabled;
|
||||||
|
on the LM96163 it can be disabled.
|
||||||
|
|
||||||
A PWM output can be used to control the speed of the fan. The LM63 has two
|
A PWM output can be used to control the speed of the fan. The LM63 has two
|
||||||
PWM modes: manual and automatic. Automatic mode is not fully implemented yet
|
PWM modes: manual and automatic. Automatic mode is not fully implemented yet
|
||||||
(you cannot define your custom PWM/temperature curve), and mode change isn't
|
(you cannot define your custom PWM/temperature curve), and mode change isn't
|
||||||
supported either.
|
supported either.
|
||||||
|
|
||||||
The lm63 driver will not update its values more frequently than every
|
The lm63 driver will not update its values more frequently than configured with
|
||||||
second; reading them more often will do no harm, but will return 'old'
|
the update_interval sysfs attribute; reading them more often will do no harm,
|
||||||
values.
|
but will return 'old' values. Values in the automatic fan control lookup table
|
||||||
|
(attributes pwm1_auto_*) have their own independent lifetime of 5 seconds.
|
||||||
|
|
||||||
The LM64 is effectively an LM63 with GPIO lines. The driver does not
|
The LM64 is effectively an LM63 with GPIO lines. The driver does not
|
||||||
support these GPIO lines at present.
|
support these GPIO lines at present.
|
||||||
|
|
||||||
|
The LM96163 is an enhanced version of LM63 with improved temperature accuracy
|
||||||
|
and better PWM resolution. For LM96163, the external temperature sensor type is
|
||||||
|
configurable as CPU embedded diode(1) or 3904 transistor(2).
|
||||||
|
@@ -304,7 +304,7 @@ value (fastest fan speed) wins.
|
|||||||
temp[1-*]_type Sensor type selection.
|
temp[1-*]_type Sensor type selection.
|
||||||
Integers 1 to 6
|
Integers 1 to 6
|
||||||
RW
|
RW
|
||||||
1: PII/Celeron Diode
|
1: CPU embedded diode
|
||||||
2: 3904 transistor
|
2: 3904 transistor
|
||||||
3: thermal diode
|
3: thermal diode
|
||||||
4: thermistor
|
4: thermistor
|
||||||
|
@@ -474,8 +474,8 @@ config SENSORS_IT87
|
|||||||
select HWMON_VID
|
select HWMON_VID
|
||||||
help
|
help
|
||||||
If you say yes here you get support for ITE IT8705F, IT8712F,
|
If you say yes here you get support for ITE IT8705F, IT8712F,
|
||||||
IT8716F, IT8718F, IT8720F, IT8721F, IT8726F and IT8758E sensor
|
IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F and IT8758E
|
||||||
chips, and the SiS960 clone.
|
sensor chips, and the SiS960 clone.
|
||||||
|
|
||||||
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 it87.
|
will be called it87.
|
||||||
@@ -515,11 +515,11 @@ config SENSORS_LINEAGE
|
|||||||
will be called lineage-pem.
|
will be called lineage-pem.
|
||||||
|
|
||||||
config SENSORS_LM63
|
config SENSORS_LM63
|
||||||
tristate "National Semiconductor LM63 and LM64"
|
tristate "National Semiconductor LM63 and compatibles"
|
||||||
depends on I2C
|
depends on I2C
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the National
|
If you say yes here you get support for the National
|
||||||
Semiconductor LM63 and LM64 remote diode digital temperature
|
Semiconductor LM63, LM64, and LM96163 remote diode digital temperature
|
||||||
sensors with integrated fan control. Such chips are found
|
sensors with integrated fan control. Such chips are found
|
||||||
on the Tyan S4882 (Thunder K8QS Pro) motherboard, among
|
on the Tyan S4882 (Thunder K8QS Pro) motherboard, among
|
||||||
others.
|
others.
|
||||||
|
@@ -155,7 +155,8 @@ adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value)
|
|||||||
#define TEMP_OFFSET_FROM_REG(val) TEMP_FROM_REG((val) < 0 ? \
|
#define TEMP_OFFSET_FROM_REG(val) TEMP_FROM_REG((val) < 0 ? \
|
||||||
(val) | 0x70 : (val))
|
(val) | 0x70 : (val))
|
||||||
|
|
||||||
#define FAN_FROM_REG(reg, div) ((reg) ? (11250 * 60) / ((reg) * (div)) : 0)
|
#define FAN_FROM_REG(reg, div) ((reg) ? \
|
||||||
|
(11250 * 60) / ((reg) * (div)) : 0)
|
||||||
|
|
||||||
static int FAN_TO_REG(int reg, int div)
|
static int FAN_TO_REG(int reg, int div)
|
||||||
{
|
{
|
||||||
@@ -174,8 +175,8 @@ static int FAN_TO_REG(int reg, int div)
|
|||||||
(((reg) & 0x1F) | (((val) << 5) & 0xe0))
|
(((reg) & 0x1F) | (((val) << 5) & 0xe0))
|
||||||
|
|
||||||
#define AUTO_TEMP_MIN_TO_REG(val, reg) \
|
#define AUTO_TEMP_MIN_TO_REG(val, reg) \
|
||||||
((((val)/500) & 0xf8)|((reg) & 0x7))
|
((((val) / 500) & 0xf8) | ((reg) & 0x7))
|
||||||
#define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1<< ((reg)&0x7)))
|
#define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1 << ((reg) & 0x7)))
|
||||||
#define AUTO_TEMP_MIN_FROM_REG(reg) (1000 * ((((reg) >> 3) & 0x1f) << 2))
|
#define AUTO_TEMP_MIN_FROM_REG(reg) (1000 * ((((reg) >> 3) & 0x1f) << 2))
|
||||||
|
|
||||||
#define AUTO_TEMP_MIN_FROM_REG_DEG(reg) ((((reg) >> 3) & 0x1f) << 2)
|
#define AUTO_TEMP_MIN_FROM_REG_DEG(reg) ((((reg) >> 3) & 0x1f) << 2)
|
||||||
@@ -202,7 +203,7 @@ static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm)
|
|||||||
|
|
||||||
/* FAN auto control */
|
/* FAN auto control */
|
||||||
#define GET_FAN_AUTO_BITFIELD(data, idx) \
|
#define GET_FAN_AUTO_BITFIELD(data, idx) \
|
||||||
(*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx%2]
|
(*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx % 2]
|
||||||
|
|
||||||
/* The tables below contains the possible values for the auto fan
|
/* The tables below contains the possible values for the auto fan
|
||||||
* control bitfields. the index in the table is the register value.
|
* control bitfields. the index in the table is the register value.
|
||||||
@@ -230,7 +231,7 @@ static const auto_chan_table_t auto_channel_select_table_adm1030 = {
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
get_fan_auto_nearest(struct adm1031_data *data,
|
get_fan_auto_nearest(struct adm1031_data *data,
|
||||||
int chan, u8 val, u8 reg, u8 * new_reg)
|
int chan, u8 val, u8 reg, u8 *new_reg)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int first_match = -1, exact_match = -1;
|
int first_match = -1, exact_match = -1;
|
||||||
@@ -258,13 +259,13 @@ get_fan_auto_nearest(struct adm1031_data *data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exact_match >= 0) {
|
if (exact_match >= 0)
|
||||||
*new_reg = exact_match;
|
*new_reg = exact_match;
|
||||||
} else if (first_match >= 0) {
|
else if (first_match >= 0)
|
||||||
*new_reg = first_match;
|
*new_reg = first_match;
|
||||||
} else {
|
else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,23 +284,28 @@ set_fan_auto_channel(struct device *dev, struct device_attribute *attr,
|
|||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||||
int nr = to_sensor_dev_attr(attr)->index;
|
int nr = to_sensor_dev_attr(attr)->index;
|
||||||
int val = simple_strtol(buf, NULL, 10);
|
long val;
|
||||||
u8 reg;
|
u8 reg;
|
||||||
int ret;
|
int ret;
|
||||||
u8 old_fan_mode;
|
u8 old_fan_mode;
|
||||||
|
|
||||||
|
ret = kstrtol(buf, 10, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
old_fan_mode = data->conf1;
|
old_fan_mode = data->conf1;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
|
|
||||||
if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®))) {
|
ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®);
|
||||||
|
if (ret) {
|
||||||
mutex_unlock(&data->update_lock);
|
mutex_unlock(&data->update_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
|
data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
|
||||||
if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^
|
if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^
|
||||||
(old_fan_mode & ADM1031_CONF1_AUTO_MODE)) {
|
(old_fan_mode & ADM1031_CONF1_AUTO_MODE)) {
|
||||||
if (data->conf1 & ADM1031_CONF1_AUTO_MODE){
|
if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
|
||||||
/* Switch to Auto Fan Mode
|
/* Switch to Auto Fan Mode
|
||||||
* Save PWM registers
|
* Save PWM registers
|
||||||
* Set PWM registers to 33% Both */
|
* Set PWM registers to 33% Both */
|
||||||
@@ -350,7 +356,12 @@ set_auto_temp_min(struct device *dev, struct device_attribute *attr,
|
|||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||||
int nr = to_sensor_dev_attr(attr)->index;
|
int nr = to_sensor_dev_attr(attr)->index;
|
||||||
int val = simple_strtol(buf, NULL, 10);
|
long val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtol(buf, 10, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]);
|
data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]);
|
||||||
@@ -374,10 +385,16 @@ set_auto_temp_max(struct device *dev, struct device_attribute *attr,
|
|||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||||
int nr = to_sensor_dev_attr(attr)->index;
|
int nr = to_sensor_dev_attr(attr)->index;
|
||||||
int val = simple_strtol(buf, NULL, 10);
|
long val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtol(buf, 10, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], data->pwm[nr]);
|
data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr],
|
||||||
|
data->pwm[nr]);
|
||||||
adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
|
adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
|
||||||
data->temp_max[nr]);
|
data->temp_max[nr]);
|
||||||
mutex_unlock(&data->update_lock);
|
mutex_unlock(&data->update_lock);
|
||||||
@@ -410,8 +427,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
|||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||||
int nr = to_sensor_dev_attr(attr)->index;
|
int nr = to_sensor_dev_attr(attr)->index;
|
||||||
int val = simple_strtol(buf, NULL, 10);
|
long val;
|
||||||
int reg;
|
int ret, reg;
|
||||||
|
|
||||||
|
ret = kstrtol(buf, 10, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) &&
|
if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) &&
|
||||||
@@ -449,9 +470,13 @@ static int trust_fan_readings(struct adm1031_data *data, int chan)
|
|||||||
|
|
||||||
if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
|
if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
|
||||||
switch (data->conf1 & 0x60) {
|
switch (data->conf1 & 0x60) {
|
||||||
case 0x00: /* remote temp1 controls fan1 remote temp2 controls fan2 */
|
case 0x00:
|
||||||
|
/*
|
||||||
|
* remote temp1 controls fan1,
|
||||||
|
* remote temp2 controls fan2
|
||||||
|
*/
|
||||||
res = data->temp[chan+1] >=
|
res = data->temp[chan+1] >=
|
||||||
AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]);
|
AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]);
|
||||||
break;
|
break;
|
||||||
case 0x20: /* remote temp1 controls both fans */
|
case 0x20: /* remote temp1 controls both fans */
|
||||||
res =
|
res =
|
||||||
@@ -515,7 +540,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
|||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||||
int nr = to_sensor_dev_attr(attr)->index;
|
int nr = to_sensor_dev_attr(attr)->index;
|
||||||
int val = simple_strtol(buf, NULL, 10);
|
long val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtol(buf, 10, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
if (val) {
|
if (val) {
|
||||||
@@ -534,10 +564,15 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
|||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||||
int nr = to_sensor_dev_attr(attr)->index;
|
int nr = to_sensor_dev_attr(attr)->index;
|
||||||
int val = simple_strtol(buf, NULL, 10);
|
long val;
|
||||||
u8 tmp;
|
u8 tmp;
|
||||||
int old_div;
|
int old_div;
|
||||||
int new_min;
|
int new_min;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtol(buf, 10, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
tmp = val == 8 ? 0xc0 :
|
tmp = val == 8 ? 0xc0 :
|
||||||
val == 4 ? 0x80 :
|
val == 4 ? 0x80 :
|
||||||
@@ -631,9 +666,13 @@ static ssize_t set_temp_offset(struct device *dev,
|
|||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||||
int nr = to_sensor_dev_attr(attr)->index;
|
int nr = to_sensor_dev_attr(attr)->index;
|
||||||
int val;
|
long val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtol(buf, 10, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
val = simple_strtol(buf, NULL, 10);
|
|
||||||
val = SENSORS_LIMIT(val, -15000, 15000);
|
val = SENSORS_LIMIT(val, -15000, 15000);
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val);
|
data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val);
|
||||||
@@ -648,9 +687,13 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
|
|||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||||
int nr = to_sensor_dev_attr(attr)->index;
|
int nr = to_sensor_dev_attr(attr)->index;
|
||||||
int val;
|
long val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtol(buf, 10, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
val = simple_strtol(buf, NULL, 10);
|
|
||||||
val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
|
val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
data->temp_min[nr] = TEMP_TO_REG(val);
|
data->temp_min[nr] = TEMP_TO_REG(val);
|
||||||
@@ -665,9 +708,13 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
|||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||||
int nr = to_sensor_dev_attr(attr)->index;
|
int nr = to_sensor_dev_attr(attr)->index;
|
||||||
int val;
|
long val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtol(buf, 10, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
val = simple_strtol(buf, NULL, 10);
|
|
||||||
val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
|
val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
data->temp_max[nr] = TEMP_TO_REG(val);
|
data->temp_max[nr] = TEMP_TO_REG(val);
|
||||||
@@ -682,9 +729,13 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr,
|
|||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||||
int nr = to_sensor_dev_attr(attr)->index;
|
int nr = to_sensor_dev_attr(attr)->index;
|
||||||
int val;
|
long val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtol(buf, 10, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
val = simple_strtol(buf, NULL, 10);
|
|
||||||
val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
|
val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875);
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
data->temp_crit[nr] = TEMP_TO_REG(val);
|
data->temp_crit[nr] = TEMP_TO_REG(val);
|
||||||
@@ -711,7 +762,8 @@ temp_reg(2);
|
|||||||
temp_reg(3);
|
temp_reg(3);
|
||||||
|
|
||||||
/* Alarms */
|
/* Alarms */
|
||||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
{
|
{
|
||||||
struct adm1031_data *data = adm1031_update_device(dev);
|
struct adm1031_data *data = adm1031_update_device(dev);
|
||||||
return sprintf(buf, "%d\n", data->alarm);
|
return sprintf(buf, "%d\n", data->alarm);
|
||||||
@@ -919,12 +971,13 @@ static int adm1031_probe(struct i2c_client *client,
|
|||||||
adm1031_init_client(client);
|
adm1031_init_client(client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &adm1031_group)))
|
err = sysfs_create_group(&client->dev.kobj, &adm1031_group);
|
||||||
|
if (err)
|
||||||
goto exit_free;
|
goto exit_free;
|
||||||
|
|
||||||
if (data->chip_type == adm1031) {
|
if (data->chip_type == adm1031) {
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj,
|
err = sysfs_create_group(&client->dev.kobj, &adm1031_group_opt);
|
||||||
&adm1031_group_opt)))
|
if (err)
|
||||||
goto exit_remove;
|
goto exit_remove;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -970,14 +1023,13 @@ static void adm1031_init_client(struct i2c_client *client)
|
|||||||
}
|
}
|
||||||
/* Initialize the ADM1031 chip (enables fan speed reading ) */
|
/* Initialize the ADM1031 chip (enables fan speed reading ) */
|
||||||
read_val = adm1031_read_value(client, ADM1031_REG_CONF2);
|
read_val = adm1031_read_value(client, ADM1031_REG_CONF2);
|
||||||
if ((read_val | mask) != read_val) {
|
if ((read_val | mask) != read_val)
|
||||||
adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask);
|
adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask);
|
||||||
}
|
|
||||||
|
|
||||||
read_val = adm1031_read_value(client, ADM1031_REG_CONF1);
|
read_val = adm1031_read_value(client, ADM1031_REG_CONF1);
|
||||||
if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) {
|
if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) {
|
||||||
adm1031_write_value(client, ADM1031_REG_CONF1, read_val |
|
adm1031_write_value(client, ADM1031_REG_CONF1,
|
||||||
ADM1031_CONF1_MONITOR_ENABLE);
|
read_val | ADM1031_CONF1_MONITOR_ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the chip's update rate */
|
/* Read the chip's update rate */
|
||||||
@@ -1024,8 +1076,7 @@ static struct adm1031_data *adm1031_update_device(struct device *dev)
|
|||||||
/* oldh is actually newer */
|
/* oldh is actually newer */
|
||||||
if (newh != oldh)
|
if (newh != oldh)
|
||||||
dev_warn(&client->dev,
|
dev_warn(&client->dev,
|
||||||
"Remote temperature may be "
|
"Remote temperature may be wrong.\n");
|
||||||
"wrong.\n");
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
data->temp[chan] = newh;
|
data->temp[chan] = newh;
|
||||||
@@ -1052,22 +1103,24 @@ static struct adm1031_data *adm1031_update_device(struct device *dev)
|
|||||||
data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2);
|
data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2);
|
||||||
|
|
||||||
data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0))
|
data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0))
|
||||||
| (adm1031_read_value(client, ADM1031_REG_STATUS(1))
|
| (adm1031_read_value(client, ADM1031_REG_STATUS(1)) << 8);
|
||||||
<< 8);
|
if (data->chip_type == adm1030)
|
||||||
if (data->chip_type == adm1030) {
|
|
||||||
data->alarm &= 0xc0ff;
|
data->alarm &= 0xc0ff;
|
||||||
}
|
|
||||||
|
|
||||||
for (chan=0; chan<(data->chip_type == adm1030 ? 1 : 2); chan++) {
|
for (chan = 0; chan < (data->chip_type == adm1030 ? 1 : 2);
|
||||||
|
chan++) {
|
||||||
data->fan_div[chan] =
|
data->fan_div[chan] =
|
||||||
adm1031_read_value(client, ADM1031_REG_FAN_DIV(chan));
|
adm1031_read_value(client,
|
||||||
|
ADM1031_REG_FAN_DIV(chan));
|
||||||
data->fan_min[chan] =
|
data->fan_min[chan] =
|
||||||
adm1031_read_value(client, ADM1031_REG_FAN_MIN(chan));
|
adm1031_read_value(client,
|
||||||
|
ADM1031_REG_FAN_MIN(chan));
|
||||||
data->fan[chan] =
|
data->fan[chan] =
|
||||||
adm1031_read_value(client, ADM1031_REG_FAN_SPEED(chan));
|
adm1031_read_value(client,
|
||||||
|
ADM1031_REG_FAN_SPEED(chan));
|
||||||
data->pwm[chan] =
|
data->pwm[chan] =
|
||||||
0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >>
|
(adm1031_read_value(client,
|
||||||
(4*chan));
|
ADM1031_REG_PWM) >> (4 * chan)) & 0x0f;
|
||||||
}
|
}
|
||||||
data->last_updated = jiffies;
|
data->last_updated = jiffies;
|
||||||
data->valid = 1;
|
data->valid = 1;
|
||||||
|
@@ -190,7 +190,8 @@ static ssize_t show_temp(struct device *dev,
|
|||||||
return tdata->valid ? sprintf(buf, "%d\n", tdata->temp) : -EAGAIN;
|
return tdata->valid ? sprintf(buf, "%d\n", tdata->temp) : -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
|
static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
|
||||||
|
struct device *dev)
|
||||||
{
|
{
|
||||||
/* The 100C is default for both mobile and non mobile CPUs */
|
/* The 100C is default for both mobile and non mobile CPUs */
|
||||||
|
|
||||||
@@ -284,7 +285,8 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
|
|||||||
return tjmax;
|
return tjmax;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
|
static int __cpuinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
|
||||||
|
struct device *dev)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
u32 eax, edx;
|
u32 eax, edx;
|
||||||
@@ -323,7 +325,8 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
|
|||||||
return adjust_tjmax(c, id, dev);
|
return adjust_tjmax(c, id, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int create_name_attr(struct platform_data *pdata, struct device *dev)
|
static int __devinit create_name_attr(struct platform_data *pdata,
|
||||||
|
struct device *dev)
|
||||||
{
|
{
|
||||||
sysfs_attr_init(&pdata->name_attr.attr);
|
sysfs_attr_init(&pdata->name_attr.attr);
|
||||||
pdata->name_attr.attr.name = "name";
|
pdata->name_attr.attr.name = "name";
|
||||||
@@ -332,8 +335,8 @@ static int create_name_attr(struct platform_data *pdata, struct device *dev)
|
|||||||
return device_create_file(dev, &pdata->name_attr);
|
return device_create_file(dev, &pdata->name_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int create_core_attrs(struct temp_data *tdata, struct device *dev,
|
static int __cpuinit create_core_attrs(struct temp_data *tdata,
|
||||||
int attr_no)
|
struct device *dev, int attr_no)
|
||||||
{
|
{
|
||||||
int err, i;
|
int err, i;
|
||||||
static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
|
static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
|
||||||
@@ -383,7 +386,7 @@ static int __cpuinit chk_ucode_version(unsigned int cpu)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_device *coretemp_get_pdev(unsigned int cpu)
|
static struct platform_device __cpuinit *coretemp_get_pdev(unsigned int cpu)
|
||||||
{
|
{
|
||||||
u16 phys_proc_id = TO_PHYS_ID(cpu);
|
u16 phys_proc_id = TO_PHYS_ID(cpu);
|
||||||
struct pdev_entry *p;
|
struct pdev_entry *p;
|
||||||
@@ -400,7 +403,8 @@ static struct platform_device *coretemp_get_pdev(unsigned int cpu)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
|
static struct temp_data __cpuinit *init_temp_data(unsigned int cpu,
|
||||||
|
int pkg_flag)
|
||||||
{
|
{
|
||||||
struct temp_data *tdata;
|
struct temp_data *tdata;
|
||||||
|
|
||||||
@@ -418,7 +422,7 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
|
|||||||
return tdata;
|
return tdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int create_core_data(struct platform_device *pdev,
|
static int __cpuinit create_core_data(struct platform_device *pdev,
|
||||||
unsigned int cpu, int pkg_flag)
|
unsigned int cpu, int pkg_flag)
|
||||||
{
|
{
|
||||||
struct temp_data *tdata;
|
struct temp_data *tdata;
|
||||||
@@ -489,7 +493,7 @@ exit_free:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coretemp_add_core(unsigned int cpu, int pkg_flag)
|
static void __cpuinit coretemp_add_core(unsigned int cpu, int pkg_flag)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = coretemp_get_pdev(cpu);
|
struct platform_device *pdev = coretemp_get_pdev(cpu);
|
||||||
int err;
|
int err;
|
||||||
@@ -618,7 +622,7 @@ exit:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coretemp_device_remove(unsigned int cpu)
|
static void __cpuinit coretemp_device_remove(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct pdev_entry *p, *n;
|
struct pdev_entry *p, *n;
|
||||||
u16 phys_proc_id = TO_PHYS_ID(cpu);
|
u16 phys_proc_id = TO_PHYS_ID(cpu);
|
||||||
@@ -634,7 +638,7 @@ static void coretemp_device_remove(unsigned int cpu)
|
|||||||
mutex_unlock(&pdev_list_mutex);
|
mutex_unlock(&pdev_list_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_any_core_online(struct platform_data *pdata)
|
static bool __cpuinit is_any_core_online(struct platform_data *pdata)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
* IT8720F Super I/O chip w/LPC interface
|
* IT8720F Super I/O chip w/LPC interface
|
||||||
* IT8721F Super I/O chip w/LPC interface
|
* IT8721F Super I/O chip w/LPC interface
|
||||||
* IT8726F Super I/O chip w/LPC interface
|
* IT8726F Super I/O chip w/LPC interface
|
||||||
|
* IT8728F Super I/O chip w/LPC interface
|
||||||
* IT8758E Super I/O chip w/LPC interface
|
* IT8758E Super I/O chip w/LPC interface
|
||||||
* Sis950 A clone of the IT8705F
|
* Sis950 A clone of the IT8705F
|
||||||
*
|
*
|
||||||
@@ -58,7 +59,7 @@
|
|||||||
|
|
||||||
#define DRVNAME "it87"
|
#define DRVNAME "it87"
|
||||||
|
|
||||||
enum chips { it87, it8712, it8716, it8718, it8720, it8721 };
|
enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728 };
|
||||||
|
|
||||||
static unsigned short force_id;
|
static unsigned short force_id;
|
||||||
module_param(force_id, ushort, 0);
|
module_param(force_id, ushort, 0);
|
||||||
@@ -135,6 +136,7 @@ static inline void superio_exit(void)
|
|||||||
#define IT8720F_DEVID 0x8720
|
#define IT8720F_DEVID 0x8720
|
||||||
#define IT8721F_DEVID 0x8721
|
#define IT8721F_DEVID 0x8721
|
||||||
#define IT8726F_DEVID 0x8726
|
#define IT8726F_DEVID 0x8726
|
||||||
|
#define IT8728F_DEVID 0x8728
|
||||||
#define IT87_ACT_REG 0x30
|
#define IT87_ACT_REG 0x30
|
||||||
#define IT87_BASE_REG 0x60
|
#define IT87_BASE_REG 0x60
|
||||||
|
|
||||||
@@ -274,11 +276,31 @@ struct it87_data {
|
|||||||
s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */
|
s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline int has_12mv_adc(const struct it87_data *data)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* IT8721F and later have a 12 mV ADC, also with internal scaling
|
||||||
|
* on selected inputs.
|
||||||
|
*/
|
||||||
|
return data->type == it8721
|
||||||
|
|| data->type == it8728;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int has_newer_autopwm(const struct it87_data *data)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* IT8721F and later have separate registers for the temperature
|
||||||
|
* mapping and the manual duty cycle.
|
||||||
|
*/
|
||||||
|
return data->type == it8721
|
||||||
|
|| data->type == it8728;
|
||||||
|
}
|
||||||
|
|
||||||
static u8 in_to_reg(const struct it87_data *data, int nr, long val)
|
static u8 in_to_reg(const struct it87_data *data, int nr, long val)
|
||||||
{
|
{
|
||||||
long lsb;
|
long lsb;
|
||||||
|
|
||||||
if (data->type == it8721) {
|
if (has_12mv_adc(data)) {
|
||||||
if (data->in_scaled & (1 << nr))
|
if (data->in_scaled & (1 << nr))
|
||||||
lsb = 24;
|
lsb = 24;
|
||||||
else
|
else
|
||||||
@@ -292,7 +314,7 @@ static u8 in_to_reg(const struct it87_data *data, int nr, long val)
|
|||||||
|
|
||||||
static int in_from_reg(const struct it87_data *data, int nr, int val)
|
static int in_from_reg(const struct it87_data *data, int nr, int val)
|
||||||
{
|
{
|
||||||
if (data->type == it8721) {
|
if (has_12mv_adc(data)) {
|
||||||
if (data->in_scaled & (1 << nr))
|
if (data->in_scaled & (1 << nr))
|
||||||
return val * 24;
|
return val * 24;
|
||||||
else
|
else
|
||||||
@@ -329,7 +351,7 @@ static inline u16 FAN16_TO_REG(long rpm)
|
|||||||
|
|
||||||
static u8 pwm_to_reg(const struct it87_data *data, long val)
|
static u8 pwm_to_reg(const struct it87_data *data, long val)
|
||||||
{
|
{
|
||||||
if (data->type == it8721)
|
if (has_newer_autopwm(data))
|
||||||
return val;
|
return val;
|
||||||
else
|
else
|
||||||
return val >> 1;
|
return val >> 1;
|
||||||
@@ -337,7 +359,7 @@ static u8 pwm_to_reg(const struct it87_data *data, long val)
|
|||||||
|
|
||||||
static int pwm_from_reg(const struct it87_data *data, u8 reg)
|
static int pwm_from_reg(const struct it87_data *data, u8 reg)
|
||||||
{
|
{
|
||||||
if (data->type == it8721)
|
if (has_newer_autopwm(data))
|
||||||
return reg;
|
return reg;
|
||||||
else
|
else
|
||||||
return (reg & 0x7f) << 1;
|
return (reg & 0x7f) << 1;
|
||||||
@@ -374,7 +396,8 @@ static inline int has_16bit_fans(const struct it87_data *data)
|
|||||||
|| data->type == it8716
|
|| data->type == it8716
|
||||||
|| data->type == it8718
|
|| data->type == it8718
|
||||||
|| data->type == it8720
|
|| data->type == it8720
|
||||||
|| data->type == it8721;
|
|| data->type == it8721
|
||||||
|
|| data->type == it8728;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int has_old_autopwm(const struct it87_data *data)
|
static inline int has_old_autopwm(const struct it87_data *data)
|
||||||
@@ -842,7 +865,7 @@ static ssize_t set_pwm_enable(struct device *dev,
|
|||||||
data->fan_main_ctrl);
|
data->fan_main_ctrl);
|
||||||
} else {
|
} else {
|
||||||
if (val == 1) /* Manual mode */
|
if (val == 1) /* Manual mode */
|
||||||
data->pwm_ctrl[nr] = data->type == it8721 ?
|
data->pwm_ctrl[nr] = has_newer_autopwm(data) ?
|
||||||
data->pwm_temp_map[nr] :
|
data->pwm_temp_map[nr] :
|
||||||
data->pwm_duty[nr];
|
data->pwm_duty[nr];
|
||||||
else /* Automatic mode */
|
else /* Automatic mode */
|
||||||
@@ -870,7 +893,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
if (data->type == it8721) {
|
if (has_newer_autopwm(data)) {
|
||||||
/* If we are in automatic mode, the PWM duty cycle register
|
/* If we are in automatic mode, the PWM duty cycle register
|
||||||
* is read-only so we can't write the value */
|
* is read-only so we can't write the value */
|
||||||
if (data->pwm_ctrl[nr] & 0x80) {
|
if (data->pwm_ctrl[nr] & 0x80) {
|
||||||
@@ -1311,8 +1334,8 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr,
|
|||||||
struct it87_data *data = dev_get_drvdata(dev);
|
struct it87_data *data = dev_get_drvdata(dev);
|
||||||
int nr = to_sensor_dev_attr(attr)->index;
|
int nr = to_sensor_dev_attr(attr)->index;
|
||||||
|
|
||||||
return sprintf(buf, "%s\n", data->type == it8721 ? labels_it8721[nr]
|
return sprintf(buf, "%s\n", has_12mv_adc(data) ? labels_it8721[nr]
|
||||||
: labels[nr]);
|
: labels[nr]);
|
||||||
}
|
}
|
||||||
static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0);
|
static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0);
|
||||||
static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1);
|
static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1);
|
||||||
@@ -1605,6 +1628,9 @@ static int __init it87_find(unsigned short *address,
|
|||||||
case IT8721F_DEVID:
|
case IT8721F_DEVID:
|
||||||
sio_data->type = it8721;
|
sio_data->type = it8721;
|
||||||
break;
|
break;
|
||||||
|
case IT8728F_DEVID:
|
||||||
|
sio_data->type = it8728;
|
||||||
|
break;
|
||||||
case 0xffff: /* No device at all */
|
case 0xffff: /* No device at all */
|
||||||
goto exit;
|
goto exit;
|
||||||
default:
|
default:
|
||||||
@@ -1646,8 +1672,11 @@ static int __init it87_find(unsigned short *address,
|
|||||||
superio_select(GPIO);
|
superio_select(GPIO);
|
||||||
|
|
||||||
reg = superio_inb(IT87_SIO_GPIO3_REG);
|
reg = superio_inb(IT87_SIO_GPIO3_REG);
|
||||||
if (sio_data->type == it8721) {
|
if (sio_data->type == it8721 || sio_data->type == it8728) {
|
||||||
/* The IT8721F/IT8758E doesn't have VID pins at all */
|
/*
|
||||||
|
* The IT8721F/IT8758E doesn't have VID pins at all,
|
||||||
|
* not sure about the IT8728F.
|
||||||
|
*/
|
||||||
sio_data->skip_vid = 1;
|
sio_data->skip_vid = 1;
|
||||||
} else {
|
} else {
|
||||||
/* We need at least 4 VID pins */
|
/* We need at least 4 VID pins */
|
||||||
@@ -1692,7 +1721,8 @@ static int __init it87_find(unsigned short *address,
|
|||||||
}
|
}
|
||||||
if (reg & (1 << 0))
|
if (reg & (1 << 0))
|
||||||
sio_data->internal |= (1 << 0);
|
sio_data->internal |= (1 << 0);
|
||||||
if ((reg & (1 << 1)) || sio_data->type == it8721)
|
if ((reg & (1 << 1)) || sio_data->type == it8721 ||
|
||||||
|
sio_data->type == it8728)
|
||||||
sio_data->internal |= (1 << 1);
|
sio_data->internal |= (1 << 1);
|
||||||
|
|
||||||
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
|
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
|
||||||
@@ -1770,6 +1800,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
|
|||||||
"it8718",
|
"it8718",
|
||||||
"it8720",
|
"it8720",
|
||||||
"it8721",
|
"it8721",
|
||||||
|
"it8728",
|
||||||
};
|
};
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||||
@@ -1807,7 +1838,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
|
|||||||
enable_pwm_interface = it87_check_pwm(dev);
|
enable_pwm_interface = it87_check_pwm(dev);
|
||||||
|
|
||||||
/* Starting with IT8721F, we handle scaling of internal voltages */
|
/* Starting with IT8721F, we handle scaling of internal voltages */
|
||||||
if (data->type == it8721) {
|
if (has_12mv_adc(data)) {
|
||||||
if (sio_data->internal & (1 << 0))
|
if (sio_data->internal & (1 << 0))
|
||||||
data->in_scaled |= (1 << 3); /* in3 is AVCC */
|
data->in_scaled |= (1 << 3); /* in3 is AVCC */
|
||||||
if (sio_data->internal & (1 << 1))
|
if (sio_data->internal & (1 << 1))
|
||||||
@@ -2093,7 +2124,7 @@ static void __devinit it87_init_device(struct platform_device *pdev)
|
|||||||
static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
|
static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
|
||||||
{
|
{
|
||||||
data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr));
|
data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr));
|
||||||
if (data->type == it8721) {
|
if (has_newer_autopwm(data)) {
|
||||||
data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
|
data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
|
||||||
data->pwm_duty[nr] = it87_read_value(data,
|
data->pwm_duty[nr] = it87_read_value(data,
|
||||||
IT87_REG_PWM_DUTY(nr));
|
IT87_REG_PWM_DUTY(nr));
|
||||||
|
@@ -47,10 +47,14 @@
|
|||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/sysfs.h>
|
#include <linux/sysfs.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Addresses to scan
|
* Addresses to scan
|
||||||
* Address is fully defined internally and cannot be changed.
|
* Address is fully defined internally and cannot be changed except for
|
||||||
|
* LM64 which has one pin dedicated to address selection.
|
||||||
|
* LM63 and LM96163 have address 0x4c.
|
||||||
|
* LM64 can have address 0x18 or 0x4e.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
|
static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
|
||||||
@@ -60,6 +64,7 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define LM63_REG_CONFIG1 0x03
|
#define LM63_REG_CONFIG1 0x03
|
||||||
|
#define LM63_REG_CONVRATE 0x04
|
||||||
#define LM63_REG_CONFIG2 0xBF
|
#define LM63_REG_CONFIG2 0xBF
|
||||||
#define LM63_REG_CONFIG_FAN 0x4A
|
#define LM63_REG_CONFIG_FAN 0x4A
|
||||||
|
|
||||||
@@ -70,6 +75,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
|
|||||||
|
|
||||||
#define LM63_REG_PWM_VALUE 0x4C
|
#define LM63_REG_PWM_VALUE 0x4C
|
||||||
#define LM63_REG_PWM_FREQ 0x4D
|
#define LM63_REG_PWM_FREQ 0x4D
|
||||||
|
#define LM63_REG_LUT_TEMP_HYST 0x4F
|
||||||
|
#define LM63_REG_LUT_TEMP(nr) (0x50 + 2 * (nr))
|
||||||
|
#define LM63_REG_LUT_PWM(nr) (0x51 + 2 * (nr))
|
||||||
|
|
||||||
#define LM63_REG_LOCAL_TEMP 0x00
|
#define LM63_REG_LOCAL_TEMP 0x00
|
||||||
#define LM63_REG_LOCAL_HIGH 0x05
|
#define LM63_REG_LOCAL_HIGH 0x05
|
||||||
@@ -91,6 +99,16 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
|
|||||||
#define LM63_REG_MAN_ID 0xFE
|
#define LM63_REG_MAN_ID 0xFE
|
||||||
#define LM63_REG_CHIP_ID 0xFF
|
#define LM63_REG_CHIP_ID 0xFF
|
||||||
|
|
||||||
|
#define LM96163_REG_TRUTHERM 0x30
|
||||||
|
#define LM96163_REG_REMOTE_TEMP_U_MSB 0x31
|
||||||
|
#define LM96163_REG_REMOTE_TEMP_U_LSB 0x32
|
||||||
|
#define LM96163_REG_CONFIG_ENHANCED 0x45
|
||||||
|
|
||||||
|
#define LM63_MAX_CONVRATE 9
|
||||||
|
|
||||||
|
#define LM63_MAX_CONVRATE_HZ 32
|
||||||
|
#define LM96163_MAX_CONVRATE_HZ 26
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Conversions and various macros
|
* Conversions and various macros
|
||||||
* For tachometer counts, the LM63 uses 16-bit values.
|
* For tachometer counts, the LM63 uses 16-bit values.
|
||||||
@@ -112,15 +130,24 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
|
|||||||
(val) >= 127000 ? 127 : \
|
(val) >= 127000 ? 127 : \
|
||||||
(val) < 0 ? ((val) - 500) / 1000 : \
|
(val) < 0 ? ((val) - 500) / 1000 : \
|
||||||
((val) + 500) / 1000)
|
((val) + 500) / 1000)
|
||||||
|
#define TEMP8U_TO_REG(val) ((val) <= 0 ? 0 : \
|
||||||
|
(val) >= 255000 ? 255 : \
|
||||||
|
((val) + 500) / 1000)
|
||||||
#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125)
|
#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125)
|
||||||
#define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \
|
#define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \
|
||||||
(val) >= 127875 ? 0x7FE0 : \
|
(val) >= 127875 ? 0x7FE0 : \
|
||||||
(val) < 0 ? ((val) - 62) / 125 * 32 : \
|
(val) < 0 ? ((val) - 62) / 125 * 32 : \
|
||||||
((val) + 62) / 125 * 32)
|
((val) + 62) / 125 * 32)
|
||||||
|
#define TEMP11U_TO_REG(val) ((val) <= 0 ? 0 : \
|
||||||
|
(val) >= 255875 ? 0xFFE0 : \
|
||||||
|
((val) + 62) / 125 * 32)
|
||||||
#define HYST_TO_REG(val) ((val) <= 0 ? 0 : \
|
#define HYST_TO_REG(val) ((val) <= 0 ? 0 : \
|
||||||
(val) >= 127000 ? 127 : \
|
(val) >= 127000 ? 127 : \
|
||||||
((val) + 500) / 1000)
|
((val) + 500) / 1000)
|
||||||
|
|
||||||
|
#define UPDATE_INTERVAL(max, rate) \
|
||||||
|
((1000 << (LM63_MAX_CONVRATE - (rate))) / (max))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functions declaration
|
* Functions declaration
|
||||||
*/
|
*/
|
||||||
@@ -134,7 +161,7 @@ static struct lm63_data *lm63_update_device(struct device *dev);
|
|||||||
static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info);
|
static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info);
|
||||||
static void lm63_init_client(struct i2c_client *client);
|
static void lm63_init_client(struct i2c_client *client);
|
||||||
|
|
||||||
enum chips { lm63, lm64 };
|
enum chips { lm63, lm64, lm96163 };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
@@ -143,6 +170,7 @@ enum chips { lm63, lm64 };
|
|||||||
static const struct i2c_device_id lm63_id[] = {
|
static const struct i2c_device_id lm63_id[] = {
|
||||||
{ "lm63", lm63 },
|
{ "lm63", lm63 },
|
||||||
{ "lm64", lm64 },
|
{ "lm64", lm64 },
|
||||||
|
{ "lm96163", lm96163 },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(i2c, lm63_id);
|
MODULE_DEVICE_TABLE(i2c, lm63_id);
|
||||||
@@ -167,26 +195,53 @@ struct lm63_data {
|
|||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* zero until following fields are valid */
|
char valid; /* zero until following fields are valid */
|
||||||
|
char lut_valid; /* zero until lut fields are valid */
|
||||||
unsigned long last_updated; /* in jiffies */
|
unsigned long last_updated; /* in jiffies */
|
||||||
int kind;
|
unsigned long lut_last_updated; /* in jiffies */
|
||||||
|
enum chips kind;
|
||||||
int temp2_offset;
|
int temp2_offset;
|
||||||
|
|
||||||
|
int update_interval; /* in milliseconds */
|
||||||
|
int max_convrate_hz;
|
||||||
|
int lut_size; /* 8 or 12 */
|
||||||
|
|
||||||
/* registers values */
|
/* registers values */
|
||||||
u8 config, config_fan;
|
u8 config, config_fan;
|
||||||
u16 fan[2]; /* 0: input
|
u16 fan[2]; /* 0: input
|
||||||
1: low limit */
|
1: low limit */
|
||||||
u8 pwm1_freq;
|
u8 pwm1_freq;
|
||||||
u8 pwm1_value;
|
u8 pwm1[13]; /* 0: current output
|
||||||
s8 temp8[3]; /* 0: local input
|
1-12: lookup table */
|
||||||
|
s8 temp8[15]; /* 0: local input
|
||||||
1: local high limit
|
1: local high limit
|
||||||
2: remote critical limit */
|
2: remote critical limit
|
||||||
s16 temp11[3]; /* 0: remote input
|
3-14: lookup table */
|
||||||
|
s16 temp11[4]; /* 0: remote input
|
||||||
1: remote low limit
|
1: remote low limit
|
||||||
2: remote high limit */
|
2: remote high limit
|
||||||
|
3: remote offset */
|
||||||
|
u16 temp11u; /* remote input (unsigned) */
|
||||||
u8 temp2_crit_hyst;
|
u8 temp2_crit_hyst;
|
||||||
|
u8 lut_temp_hyst;
|
||||||
u8 alarms;
|
u8 alarms;
|
||||||
|
bool pwm_highres;
|
||||||
|
bool lut_temp_highres;
|
||||||
|
bool remote_unsigned; /* true if unsigned remote upper limits */
|
||||||
|
bool trutherm;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline int temp8_from_reg(struct lm63_data *data, int nr)
|
||||||
|
{
|
||||||
|
if (data->remote_unsigned)
|
||||||
|
return TEMP8_FROM_REG((u8)data->temp8[nr]);
|
||||||
|
return TEMP8_FROM_REG(data->temp8[nr]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int lut_temp_from_reg(struct lm63_data *data, int nr)
|
||||||
|
{
|
||||||
|
return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sysfs callback functions and files
|
* Sysfs callback functions and files
|
||||||
*/
|
*/
|
||||||
@@ -204,7 +259,12 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
|
|||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct lm63_data *data = i2c_get_clientdata(client);
|
struct lm63_data *data = i2c_get_clientdata(client);
|
||||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
unsigned long val;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = kstrtoul(buf, 10, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
data->fan[1] = FAN_TO_REG(val);
|
data->fan[1] = FAN_TO_REG(val);
|
||||||
@@ -216,13 +276,22 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy,
|
static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||||
struct lm63_data *data = lm63_update_device(dev);
|
struct lm63_data *data = lm63_update_device(dev);
|
||||||
return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ?
|
int nr = attr->index;
|
||||||
255 : (data->pwm1_value * 255 + data->pwm1_freq) /
|
int pwm;
|
||||||
(2 * data->pwm1_freq));
|
|
||||||
|
if (data->pwm_highres)
|
||||||
|
pwm = data->pwm1[nr];
|
||||||
|
else
|
||||||
|
pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ?
|
||||||
|
255 : (data->pwm1[nr] * 255 + data->pwm1_freq) /
|
||||||
|
(2 * data->pwm1_freq);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", pwm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
|
static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
|
||||||
@@ -231,22 +300,26 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
|
|||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct lm63_data *data = i2c_get_clientdata(client);
|
struct lm63_data *data = i2c_get_clientdata(client);
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (!(data->config_fan & 0x20)) /* register is read-only */
|
if (!(data->config_fan & 0x20)) /* register is read-only */
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
val = simple_strtoul(buf, NULL, 10);
|
err = kstrtoul(buf, 10, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
val = SENSORS_LIMIT(val, 0, 255);
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
data->pwm1_value = val <= 0 ? 0 :
|
data->pwm1[0] = data->pwm_highres ? val :
|
||||||
val >= 255 ? 2 * data->pwm1_freq :
|
(val * data->pwm1_freq * 2 + 127) / 255;
|
||||||
(val * data->pwm1_freq * 2 + 127) / 255;
|
i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]);
|
||||||
i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value);
|
|
||||||
mutex_unlock(&data->update_lock);
|
mutex_unlock(&data->update_lock);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy,
|
static ssize_t show_pwm1_enable(struct device *dev,
|
||||||
char *buf)
|
struct device_attribute *dummy, char *buf)
|
||||||
{
|
{
|
||||||
struct lm63_data *data = lm63_update_device(dev);
|
struct lm63_data *data = lm63_update_device(dev);
|
||||||
return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
|
return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
|
||||||
@@ -273,21 +346,47 @@ static ssize_t show_remote_temp8(struct device *dev,
|
|||||||
{
|
{
|
||||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||||
struct lm63_data *data = lm63_update_device(dev);
|
struct lm63_data *data = lm63_update_device(dev);
|
||||||
return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index])
|
return sprintf(buf, "%d\n", temp8_from_reg(data, attr->index)
|
||||||
+ data->temp2_offset);
|
+ data->temp2_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t set_local_temp8(struct device *dev,
|
static ssize_t show_lut_temp(struct device *dev,
|
||||||
struct device_attribute *dummy,
|
struct device_attribute *devattr,
|
||||||
const char *buf, size_t count)
|
char *buf)
|
||||||
{
|
{
|
||||||
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||||
|
struct lm63_data *data = lm63_update_device(dev);
|
||||||
|
return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index)
|
||||||
|
+ data->temp2_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct lm63_data *data = i2c_get_clientdata(client);
|
struct lm63_data *data = i2c_get_clientdata(client);
|
||||||
long val = simple_strtol(buf, NULL, 10);
|
int nr = attr->index;
|
||||||
|
int reg = nr == 2 ? LM63_REG_REMOTE_TCRIT : LM63_REG_LOCAL_HIGH;
|
||||||
|
long val;
|
||||||
|
int err;
|
||||||
|
int temp;
|
||||||
|
|
||||||
|
err = kstrtol(buf, 10, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
data->temp8[1] = TEMP8_TO_REG(val);
|
if (nr == 2) {
|
||||||
i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]);
|
if (data->remote_unsigned)
|
||||||
|
temp = TEMP8U_TO_REG(val - data->temp2_offset);
|
||||||
|
else
|
||||||
|
temp = TEMP8_TO_REG(val - data->temp2_offset);
|
||||||
|
} else {
|
||||||
|
temp = TEMP8_TO_REG(val);
|
||||||
|
}
|
||||||
|
data->temp8[nr] = temp;
|
||||||
|
i2c_smbus_write_byte_data(client, reg, temp);
|
||||||
mutex_unlock(&data->update_lock);
|
mutex_unlock(&data->update_lock);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@@ -297,28 +396,56 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
|
|||||||
{
|
{
|
||||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||||
struct lm63_data *data = lm63_update_device(dev);
|
struct lm63_data *data = lm63_update_device(dev);
|
||||||
return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index])
|
int nr = attr->index;
|
||||||
+ data->temp2_offset);
|
int temp;
|
||||||
|
|
||||||
|
if (!nr) {
|
||||||
|
/*
|
||||||
|
* Use unsigned temperature unless its value is zero.
|
||||||
|
* If it is zero, use signed temperature.
|
||||||
|
*/
|
||||||
|
if (data->temp11u)
|
||||||
|
temp = TEMP11_FROM_REG(data->temp11u);
|
||||||
|
else
|
||||||
|
temp = TEMP11_FROM_REG(data->temp11[nr]);
|
||||||
|
} else {
|
||||||
|
if (data->remote_unsigned && nr == 2)
|
||||||
|
temp = TEMP11_FROM_REG((u16)data->temp11[nr]);
|
||||||
|
else
|
||||||
|
temp = TEMP11_FROM_REG(data->temp11[nr]);
|
||||||
|
}
|
||||||
|
return sprintf(buf, "%d\n", temp + data->temp2_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
|
static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
static const u8 reg[4] = {
|
static const u8 reg[6] = {
|
||||||
LM63_REG_REMOTE_LOW_MSB,
|
LM63_REG_REMOTE_LOW_MSB,
|
||||||
LM63_REG_REMOTE_LOW_LSB,
|
LM63_REG_REMOTE_LOW_LSB,
|
||||||
LM63_REG_REMOTE_HIGH_MSB,
|
LM63_REG_REMOTE_HIGH_MSB,
|
||||||
LM63_REG_REMOTE_HIGH_LSB,
|
LM63_REG_REMOTE_HIGH_LSB,
|
||||||
|
LM63_REG_REMOTE_OFFSET_MSB,
|
||||||
|
LM63_REG_REMOTE_OFFSET_LSB,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct lm63_data *data = i2c_get_clientdata(client);
|
struct lm63_data *data = i2c_get_clientdata(client);
|
||||||
long val = simple_strtol(buf, NULL, 10);
|
long val;
|
||||||
|
int err;
|
||||||
int nr = attr->index;
|
int nr = attr->index;
|
||||||
|
|
||||||
|
err = kstrtol(buf, 10, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset);
|
if (data->remote_unsigned && nr == 2)
|
||||||
|
data->temp11[nr] = TEMP11U_TO_REG(val - data->temp2_offset);
|
||||||
|
else
|
||||||
|
data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset);
|
||||||
|
|
||||||
i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
|
i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
|
||||||
data->temp11[nr] >> 8);
|
data->temp11[nr] >> 8);
|
||||||
i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
|
i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
|
||||||
@@ -327,35 +454,143 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hysteresis register holds a relative value, while we want to present
|
/*
|
||||||
an absolute to user-space */
|
* Hysteresis register holds a relative value, while we want to present
|
||||||
static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
|
* an absolute to user-space
|
||||||
char *buf)
|
*/
|
||||||
|
static ssize_t show_temp2_crit_hyst(struct device *dev,
|
||||||
|
struct device_attribute *dummy, char *buf)
|
||||||
{
|
{
|
||||||
struct lm63_data *data = lm63_update_device(dev);
|
struct lm63_data *data = lm63_update_device(dev);
|
||||||
return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2])
|
return sprintf(buf, "%d\n", temp8_from_reg(data, 2)
|
||||||
+ data->temp2_offset
|
+ data->temp2_offset
|
||||||
- TEMP8_FROM_REG(data->temp2_crit_hyst));
|
- TEMP8_FROM_REG(data->temp2_crit_hyst));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* And now the other way around, user-space provides an absolute
|
static ssize_t show_lut_temp_hyst(struct device *dev,
|
||||||
hysteresis value and we have to store a relative one */
|
struct device_attribute *devattr, char *buf)
|
||||||
static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
|
{
|
||||||
|
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||||
|
struct lm63_data *data = lm63_update_device(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index)
|
||||||
|
+ data->temp2_offset
|
||||||
|
- TEMP8_FROM_REG(data->lut_temp_hyst));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* And now the other way around, user-space provides an absolute
|
||||||
|
* hysteresis value and we have to store a relative one
|
||||||
|
*/
|
||||||
|
static ssize_t set_temp2_crit_hyst(struct device *dev,
|
||||||
|
struct device_attribute *dummy,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct lm63_data *data = i2c_get_clientdata(client);
|
struct lm63_data *data = i2c_get_clientdata(client);
|
||||||
long val = simple_strtol(buf, NULL, 10);
|
long val;
|
||||||
|
int err;
|
||||||
long hyst;
|
long hyst;
|
||||||
|
|
||||||
|
err = kstrtol(buf, 10, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
hyst = TEMP8_FROM_REG(data->temp8[2]) + data->temp2_offset - val;
|
hyst = temp8_from_reg(data, 2) + data->temp2_offset - val;
|
||||||
i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
|
i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
|
||||||
HYST_TO_REG(hyst));
|
HYST_TO_REG(hyst));
|
||||||
mutex_unlock(&data->update_lock);
|
mutex_unlock(&data->update_lock);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set conversion rate.
|
||||||
|
* client->update_lock must be held when calling this function.
|
||||||
|
*/
|
||||||
|
static void lm63_set_convrate(struct i2c_client *client, struct lm63_data *data,
|
||||||
|
unsigned int interval)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned int update_interval;
|
||||||
|
|
||||||
|
/* Shift calculations to avoid rounding errors */
|
||||||
|
interval <<= 6;
|
||||||
|
|
||||||
|
/* find the nearest update rate */
|
||||||
|
update_interval = (1 << (LM63_MAX_CONVRATE + 6)) * 1000
|
||||||
|
/ data->max_convrate_hz;
|
||||||
|
for (i = 0; i < LM63_MAX_CONVRATE; i++, update_interval >>= 1)
|
||||||
|
if (interval >= update_interval * 3 / 4)
|
||||||
|
break;
|
||||||
|
|
||||||
|
i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE, i);
|
||||||
|
data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_update_interval(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct lm63_data *data = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%u\n", data->update_interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t set_update_interval(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct lm63_data *data = i2c_get_clientdata(client);
|
||||||
|
unsigned long val;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = kstrtoul(buf, 10, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
lm63_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000));
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_type(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct lm63_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
return sprintf(buf, data->trutherm ? "1\n" : "2\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t set_type(struct device *dev, struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct lm63_data *data = i2c_get_clientdata(client);
|
||||||
|
unsigned long val;
|
||||||
|
int ret;
|
||||||
|
u8 reg;
|
||||||
|
|
||||||
|
ret = kstrtoul(buf, 10, &val);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
if (val != 1 && val != 2)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
data->trutherm = val == 1;
|
||||||
|
reg = i2c_smbus_read_byte_data(client, LM96163_REG_TRUTHERM) & ~0x02;
|
||||||
|
i2c_smbus_write_byte_data(client, LM96163_REG_TRUTHERM,
|
||||||
|
reg | (data->trutherm ? 0x02 : 0x00));
|
||||||
|
data->valid = 0;
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
|
static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
@@ -377,27 +612,87 @@ static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
|
|||||||
static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
|
static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
|
||||||
set_fan, 1);
|
set_fan, 1);
|
||||||
|
|
||||||
static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1);
|
static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0);
|
||||||
static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
|
static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, show_pwm1, NULL, 1);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IRUGO,
|
||||||
|
show_lut_temp, NULL, 3);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO,
|
||||||
|
show_lut_temp_hyst, NULL, 3);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO, show_pwm1, NULL, 2);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO,
|
||||||
|
show_lut_temp, NULL, 4);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO,
|
||||||
|
show_lut_temp_hyst, NULL, 4);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, show_pwm1, NULL, 3);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IRUGO,
|
||||||
|
show_lut_temp, NULL, 5);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO,
|
||||||
|
show_lut_temp_hyst, NULL, 5);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO, show_pwm1, NULL, 4);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IRUGO,
|
||||||
|
show_lut_temp, NULL, 6);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO,
|
||||||
|
show_lut_temp_hyst, NULL, 6);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm1, NULL, 5);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IRUGO,
|
||||||
|
show_lut_temp, NULL, 7);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO,
|
||||||
|
show_lut_temp_hyst, NULL, 7);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IRUGO, show_pwm1, NULL, 6);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IRUGO,
|
||||||
|
show_lut_temp, NULL, 8);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO,
|
||||||
|
show_lut_temp_hyst, NULL, 8);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IRUGO, show_pwm1, NULL, 7);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IRUGO,
|
||||||
|
show_lut_temp, NULL, 9);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO,
|
||||||
|
show_lut_temp_hyst, NULL, 9);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IRUGO, show_pwm1, NULL, 8);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IRUGO,
|
||||||
|
show_lut_temp, NULL, 10);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO,
|
||||||
|
show_lut_temp_hyst, NULL, 10);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IRUGO, show_pwm1, NULL, 9);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IRUGO,
|
||||||
|
show_lut_temp, NULL, 11);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp_hyst, S_IRUGO,
|
||||||
|
show_lut_temp_hyst, NULL, 11);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IRUGO, show_pwm1, NULL, 10);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IRUGO,
|
||||||
|
show_lut_temp, NULL, 12);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp_hyst, S_IRUGO,
|
||||||
|
show_lut_temp_hyst, NULL, 12);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IRUGO, show_pwm1, NULL, 11);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IRUGO,
|
||||||
|
show_lut_temp, NULL, 13);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp_hyst, S_IRUGO,
|
||||||
|
show_lut_temp_hyst, NULL, 13);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IRUGO, show_pwm1, NULL, 12);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IRUGO,
|
||||||
|
show_lut_temp, NULL, 14);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp_hyst, S_IRUGO,
|
||||||
|
show_lut_temp_hyst, NULL, 14);
|
||||||
|
|
||||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0);
|
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0);
|
||||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8,
|
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8,
|
||||||
set_local_temp8, 1);
|
set_temp8, 1);
|
||||||
|
|
||||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
|
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
|
||||||
static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
|
static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
|
||||||
set_temp11, 1);
|
set_temp11, 1);
|
||||||
static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
|
static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
|
||||||
set_temp11, 2);
|
set_temp11, 2);
|
||||||
/*
|
static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
|
||||||
* On LM63, temp2_crit can be set only once, which should be job
|
set_temp11, 3);
|
||||||
* of the bootloader.
|
|
||||||
*/
|
|
||||||
static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8,
|
static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8,
|
||||||
NULL, 2);
|
set_temp8, 2);
|
||||||
static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
|
static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
|
||||||
set_temp2_crit_hyst);
|
set_temp2_crit_hyst);
|
||||||
|
|
||||||
|
static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type);
|
||||||
|
|
||||||
/* Individual alarm files */
|
/* Individual alarm files */
|
||||||
static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
|
static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
|
||||||
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
|
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
|
||||||
@@ -408,14 +703,43 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
|
|||||||
/* Raw alarm file for compatibility */
|
/* Raw alarm file for compatibility */
|
||||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||||
|
|
||||||
|
static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
|
||||||
|
set_update_interval);
|
||||||
|
|
||||||
static struct attribute *lm63_attributes[] = {
|
static struct attribute *lm63_attributes[] = {
|
||||||
&dev_attr_pwm1.attr,
|
&sensor_dev_attr_pwm1.dev_attr.attr,
|
||||||
&dev_attr_pwm1_enable.attr,
|
&dev_attr_pwm1_enable.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point2_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point3_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point4_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point5_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point6_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point7_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point8_temp_hyst.dev_attr.attr,
|
||||||
|
|
||||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
&sensor_dev_attr_temp1_input.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_temp1_max.dev_attr.attr,
|
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp2_offset.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_crit.dev_attr.attr,
|
&sensor_dev_attr_temp2_crit.dev_attr.attr,
|
||||||
&dev_attr_temp2_crit_hyst.attr,
|
&dev_attr_temp2_crit_hyst.attr,
|
||||||
|
|
||||||
@@ -425,10 +749,54 @@ static struct attribute *lm63_attributes[] = {
|
|||||||
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
|
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||||
&dev_attr_alarms.attr,
|
&dev_attr_alarms.attr,
|
||||||
|
&dev_attr_update_interval.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct attribute *lm63_attributes_extra_lut[] = {
|
||||||
|
&sensor_dev_attr_pwm1_auto_point9_pwm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point9_temp.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point9_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point10_pwm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point10_temp.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point10_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point11_pwm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point11_temp.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point11_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point12_pwm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point12_temp.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm1_auto_point12_temp_hyst.dev_attr.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group lm63_group_extra_lut = {
|
||||||
|
.attrs = lm63_attributes_extra_lut,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On LM63, temp2_crit can be set only once, which should be job
|
||||||
|
* of the bootloader.
|
||||||
|
* On LM64, temp2_crit can always be set.
|
||||||
|
* On LM96163, temp2_crit can be set if bit 1 of the configuration
|
||||||
|
* register is true.
|
||||||
|
*/
|
||||||
|
static umode_t lm63_attribute_mode(struct kobject *kobj,
|
||||||
|
struct attribute *attr, int index)
|
||||||
|
{
|
||||||
|
struct device *dev = container_of(kobj, struct device, kobj);
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct lm63_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr
|
||||||
|
&& (data->kind == lm64 ||
|
||||||
|
(data->kind == lm96163 && (data->config & 0x02))))
|
||||||
|
return attr->mode | S_IWUSR;
|
||||||
|
|
||||||
|
return attr->mode;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct attribute_group lm63_group = {
|
static const struct attribute_group lm63_group = {
|
||||||
|
.is_visible = lm63_attribute_mode,
|
||||||
.attrs = lm63_attributes,
|
.attrs = lm63_attributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -487,6 +855,8 @@ static int lm63_detect(struct i2c_client *new_client,
|
|||||||
strlcpy(info->type, "lm63", I2C_NAME_SIZE);
|
strlcpy(info->type, "lm63", I2C_NAME_SIZE);
|
||||||
else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e))
|
else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e))
|
||||||
strlcpy(info->type, "lm64", I2C_NAME_SIZE);
|
strlcpy(info->type, "lm64", I2C_NAME_SIZE);
|
||||||
|
else if (chip_id == 0x49 && address == 0x4c)
|
||||||
|
strlcpy(info->type, "lm96163", I2C_NAME_SIZE);
|
||||||
else
|
else
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
@@ -518,12 +888,24 @@ static int lm63_probe(struct i2c_client *new_client,
|
|||||||
lm63_init_client(new_client);
|
lm63_init_client(new_client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj,
|
err = sysfs_create_group(&new_client->dev.kobj, &lm63_group);
|
||||||
&lm63_group)))
|
if (err)
|
||||||
goto exit_free;
|
goto exit_free;
|
||||||
if (data->config & 0x04) { /* tachometer enabled */
|
if (data->config & 0x04) { /* tachometer enabled */
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj,
|
err = sysfs_create_group(&new_client->dev.kobj,
|
||||||
&lm63_group_fan1)))
|
&lm63_group_fan1);
|
||||||
|
if (err)
|
||||||
|
goto exit_remove_files;
|
||||||
|
}
|
||||||
|
if (data->kind == lm96163) {
|
||||||
|
err = device_create_file(&new_client->dev,
|
||||||
|
&dev_attr_temp2_type);
|
||||||
|
if (err)
|
||||||
|
goto exit_remove_files;
|
||||||
|
|
||||||
|
err = sysfs_create_group(&new_client->dev.kobj,
|
||||||
|
&lm63_group_extra_lut);
|
||||||
|
if (err)
|
||||||
goto exit_remove_files;
|
goto exit_remove_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,17 +920,25 @@ static int lm63_probe(struct i2c_client *new_client,
|
|||||||
exit_remove_files:
|
exit_remove_files:
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
|
sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
|
sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
|
||||||
|
if (data->kind == lm96163) {
|
||||||
|
device_remove_file(&new_client->dev, &dev_attr_temp2_type);
|
||||||
|
sysfs_remove_group(&new_client->dev.kobj,
|
||||||
|
&lm63_group_extra_lut);
|
||||||
|
}
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Idealy we shouldn't have to initialize anything, since the BIOS
|
/*
|
||||||
should have taken care of everything */
|
* Ideally we shouldn't have to initialize anything, since the BIOS
|
||||||
|
* should have taken care of everything
|
||||||
|
*/
|
||||||
static void lm63_init_client(struct i2c_client *client)
|
static void lm63_init_client(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct lm63_data *data = i2c_get_clientdata(client);
|
struct lm63_data *data = i2c_get_clientdata(client);
|
||||||
|
u8 convrate;
|
||||||
|
|
||||||
data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
|
data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
|
||||||
data->config_fan = i2c_smbus_read_byte_data(client,
|
data->config_fan = i2c_smbus_read_byte_data(client,
|
||||||
@@ -561,16 +951,57 @@ static void lm63_init_client(struct i2c_client *client)
|
|||||||
i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
|
i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
|
||||||
data->config);
|
data->config);
|
||||||
}
|
}
|
||||||
|
/* Tachometer is always enabled on LM64 */
|
||||||
|
if (data->kind == lm64)
|
||||||
|
data->config |= 0x04;
|
||||||
|
|
||||||
/* We may need pwm1_freq before ever updating the client data */
|
/* We may need pwm1_freq before ever updating the client data */
|
||||||
data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ);
|
data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ);
|
||||||
if (data->pwm1_freq == 0)
|
if (data->pwm1_freq == 0)
|
||||||
data->pwm1_freq = 1;
|
data->pwm1_freq = 1;
|
||||||
|
|
||||||
|
switch (data->kind) {
|
||||||
|
case lm63:
|
||||||
|
case lm64:
|
||||||
|
data->max_convrate_hz = LM63_MAX_CONVRATE_HZ;
|
||||||
|
data->lut_size = 8;
|
||||||
|
break;
|
||||||
|
case lm96163:
|
||||||
|
data->max_convrate_hz = LM96163_MAX_CONVRATE_HZ;
|
||||||
|
data->lut_size = 12;
|
||||||
|
data->trutherm
|
||||||
|
= i2c_smbus_read_byte_data(client,
|
||||||
|
LM96163_REG_TRUTHERM) & 0x02;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
convrate = i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE);
|
||||||
|
if (unlikely(convrate > LM63_MAX_CONVRATE))
|
||||||
|
convrate = LM63_MAX_CONVRATE;
|
||||||
|
data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz,
|
||||||
|
convrate);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For LM96163, check if high resolution PWM
|
||||||
|
* and unsigned temperature format is enabled.
|
||||||
|
*/
|
||||||
|
if (data->kind == lm96163) {
|
||||||
|
u8 config_enhanced
|
||||||
|
= i2c_smbus_read_byte_data(client,
|
||||||
|
LM96163_REG_CONFIG_ENHANCED);
|
||||||
|
if (config_enhanced & 0x20)
|
||||||
|
data->lut_temp_highres = true;
|
||||||
|
if ((config_enhanced & 0x10)
|
||||||
|
&& !(data->config_fan & 0x08) && data->pwm1_freq == 8)
|
||||||
|
data->pwm_highres = true;
|
||||||
|
if (config_enhanced & 0x08)
|
||||||
|
data->remote_unsigned = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Show some debug info about the LM63 configuration */
|
/* Show some debug info about the LM63 configuration */
|
||||||
dev_dbg(&client->dev, "Alert/tach pin configured for %s\n",
|
if (data->kind == lm63)
|
||||||
(data->config & 0x04) ? "tachometer input" :
|
dev_dbg(&client->dev, "Alert/tach pin configured for %s\n",
|
||||||
"alert output");
|
(data->config & 0x04) ? "tachometer input" :
|
||||||
|
"alert output");
|
||||||
dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz\n",
|
dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz\n",
|
||||||
(data->config_fan & 0x08) ? "1.4" : "360",
|
(data->config_fan & 0x08) ? "1.4" : "360",
|
||||||
((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq);
|
((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq);
|
||||||
@@ -586,6 +1017,10 @@ static int lm63_remove(struct i2c_client *client)
|
|||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm63_group);
|
sysfs_remove_group(&client->dev.kobj, &lm63_group);
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
|
sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
|
||||||
|
if (data->kind == lm96163) {
|
||||||
|
device_remove_file(&client->dev, &dev_attr_temp2_type);
|
||||||
|
sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut);
|
||||||
|
}
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -595,10 +1030,15 @@ static struct lm63_data *lm63_update_device(struct device *dev)
|
|||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct lm63_data *data = i2c_get_clientdata(client);
|
struct lm63_data *data = i2c_get_clientdata(client);
|
||||||
|
unsigned long next_update;
|
||||||
|
int i;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
|
|
||||||
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
|
next_update = data->last_updated
|
||||||
|
+ msecs_to_jiffies(data->update_interval) + 1;
|
||||||
|
|
||||||
|
if (time_after(jiffies, next_update) || !data->valid) {
|
||||||
if (data->config & 0x04) { /* tachometer enabled */
|
if (data->config & 0x04) { /* tachometer enabled */
|
||||||
/* order matters for fan1_input */
|
/* order matters for fan1_input */
|
||||||
data->fan[0] = i2c_smbus_read_byte_data(client,
|
data->fan[0] = i2c_smbus_read_byte_data(client,
|
||||||
@@ -615,8 +1055,8 @@ static struct lm63_data *lm63_update_device(struct device *dev)
|
|||||||
LM63_REG_PWM_FREQ);
|
LM63_REG_PWM_FREQ);
|
||||||
if (data->pwm1_freq == 0)
|
if (data->pwm1_freq == 0)
|
||||||
data->pwm1_freq = 1;
|
data->pwm1_freq = 1;
|
||||||
data->pwm1_value = i2c_smbus_read_byte_data(client,
|
data->pwm1[0] = i2c_smbus_read_byte_data(client,
|
||||||
LM63_REG_PWM_VALUE);
|
LM63_REG_PWM_VALUE);
|
||||||
|
|
||||||
data->temp8[0] = i2c_smbus_read_byte_data(client,
|
data->temp8[0] = i2c_smbus_read_byte_data(client,
|
||||||
LM63_REG_LOCAL_TEMP);
|
LM63_REG_LOCAL_TEMP);
|
||||||
@@ -636,6 +1076,17 @@ static struct lm63_data *lm63_update_device(struct device *dev)
|
|||||||
LM63_REG_REMOTE_HIGH_MSB) << 8)
|
LM63_REG_REMOTE_HIGH_MSB) << 8)
|
||||||
| i2c_smbus_read_byte_data(client,
|
| i2c_smbus_read_byte_data(client,
|
||||||
LM63_REG_REMOTE_HIGH_LSB);
|
LM63_REG_REMOTE_HIGH_LSB);
|
||||||
|
data->temp11[3] = (i2c_smbus_read_byte_data(client,
|
||||||
|
LM63_REG_REMOTE_OFFSET_MSB) << 8)
|
||||||
|
| i2c_smbus_read_byte_data(client,
|
||||||
|
LM63_REG_REMOTE_OFFSET_LSB);
|
||||||
|
|
||||||
|
if (data->kind == lm96163)
|
||||||
|
data->temp11u = (i2c_smbus_read_byte_data(client,
|
||||||
|
LM96163_REG_REMOTE_TEMP_U_MSB) << 8)
|
||||||
|
| i2c_smbus_read_byte_data(client,
|
||||||
|
LM96163_REG_REMOTE_TEMP_U_LSB);
|
||||||
|
|
||||||
data->temp8[2] = i2c_smbus_read_byte_data(client,
|
data->temp8[2] = i2c_smbus_read_byte_data(client,
|
||||||
LM63_REG_REMOTE_TCRIT);
|
LM63_REG_REMOTE_TCRIT);
|
||||||
data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
|
data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
|
||||||
@@ -648,6 +1099,21 @@ static struct lm63_data *lm63_update_device(struct device *dev)
|
|||||||
data->valid = 1;
|
data->valid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
|
||||||
|
!data->lut_valid) {
|
||||||
|
for (i = 0; i < data->lut_size; i++) {
|
||||||
|
data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
|
||||||
|
LM63_REG_LUT_PWM(i));
|
||||||
|
data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
|
||||||
|
LM63_REG_LUT_TEMP(i));
|
||||||
|
}
|
||||||
|
data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
|
||||||
|
LM63_REG_LUT_TEMP_HYST);
|
||||||
|
|
||||||
|
data->lut_last_updated = jiffies;
|
||||||
|
data->lut_valid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_unlock(&data->update_lock);
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
@@ -917,7 +917,7 @@ static ssize_t set_update_interval(struct device *dev,
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
lm90_set_convrate(client, data, val);
|
lm90_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000));
|
||||||
mutex_unlock(&data->update_lock);
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
@@ -106,11 +106,14 @@ static ssize_t show_adc(struct device *dev,
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", ret);
|
/* assume the reference voltage to be 2.048V, with an 8-bit sample,
|
||||||
|
* the LSB weight is 8mV
|
||||||
|
*/
|
||||||
|
return sprintf(buf, "%d\n", ret * 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX1111_ADC_ATTR(_id) \
|
#define MAX1111_ADC_ATTR(_id) \
|
||||||
SENSOR_DEVICE_ATTR(adc##_id##_in, S_IRUGO, show_adc, NULL, _id)
|
SENSOR_DEVICE_ATTR(in##_id##_input, S_IRUGO, show_adc, NULL, _id)
|
||||||
|
|
||||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||||
static MAX1111_ADC_ATTR(0);
|
static MAX1111_ADC_ATTR(0);
|
||||||
@@ -120,10 +123,10 @@ static MAX1111_ADC_ATTR(3);
|
|||||||
|
|
||||||
static struct attribute *max1111_attributes[] = {
|
static struct attribute *max1111_attributes[] = {
|
||||||
&dev_attr_name.attr,
|
&dev_attr_name.attr,
|
||||||
&sensor_dev_attr_adc0_in.dev_attr.attr,
|
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_adc1_in.dev_attr.attr,
|
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_adc2_in.dev_attr.attr,
|
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_adc3_in.dev_attr.attr,
|
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user