Various enhancements

Add support for 6 pwm channels on IT8620E
Fix pwm frequency value for newer chips
Add second pwm frequency control for newer chips

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
Guenter Roeck
2015-03-26 20:09:38 -07:00
parent fd9c7812cd
commit 44c6a98613

260
it87.c
View File

@@ -164,7 +164,9 @@ static inline void superio_exit(void)
/* Logical device 7 registers (IT8712F and later) */ /* Logical device 7 registers (IT8712F and later) */
#define IT87_SIO_GPIO1_REG 0x25 #define IT87_SIO_GPIO1_REG 0x25
#define IT87_SIO_GPIO2_REG 0x26
#define IT87_SIO_GPIO3_REG 0x27 #define IT87_SIO_GPIO3_REG 0x27
#define IT87_SIO_GPIO4_REG 0x28
#define IT87_SIO_GPIO5_REG 0x29 #define IT87_SIO_GPIO5_REG 0x29
#define IT87_SIO_PINX1_REG 0x2a /* Pin selection */ #define IT87_SIO_PINX1_REG 0x2a /* Pin selection */
#define IT87_SIO_PINX2_REG 0x2c /* Pin selection */ #define IT87_SIO_PINX2_REG 0x2c /* Pin selection */
@@ -216,16 +218,16 @@ static bool fix_pwm_polarity;
/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ /* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */
static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82, 0x4c }; static const u8 IT87_REG_FAN[] = {0x0d, 0x0e, 0x0f, 0x80, 0x82, 0x4c};
static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86, 0x4e }; static const u8 IT87_REG_FAN_MIN[] = {0x10, 0x11, 0x12, 0x84, 0x86, 0x4e};
static const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83, 0x4d }; static const u8 IT87_REG_FANX[] = {0x18, 0x19, 0x1a, 0x81, 0x83, 0x4d};
static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87, 0x4f }; static const u8 IT87_REG_FANX_MIN[] = {0x1b, 0x1c, 0x1d, 0x85, 0x87, 0x4f};
static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 }; static const u8 IT87_REG_TEMP_OFFSET[] = {0x56, 0x57, 0x59};
#define IT87_REG_FAN_MAIN_CTRL 0x13 #define IT87_REG_FAN_MAIN_CTRL 0x13
#define IT87_REG_FAN_CTL 0x14 #define IT87_REG_FAN_CTL 0x14
#define IT87_REG_PWM(nr) (0x15 + (nr)) static const u8 IT87_REG_PWM[] = {0x15, 0x16, 0x17, 0x7f, 0xa7, 0xaf};
#define IT87_REG_PWM_DUTY(nr) (0x63 + (nr) * 8) static const u8 IT87_REG_PWM_DUTY[] = {0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab};
#define IT87_REG_VIN(nr) (0x20 + (nr)) #define IT87_REG_VIN(nr) (0x20 + (nr))
#define IT87_REG_TEMP(nr) (0x29 + (nr)) #define IT87_REG_TEMP(nr) (0x29 + (nr))
@@ -268,6 +270,8 @@ struct it87_devices {
#define FEAT_VID (1 << 10) /* Set if chip supports VID */ #define FEAT_VID (1 << 10) /* Set if chip supports VID */
#define FEAT_IN7_INTERNAL (1 << 11) /* Set if in7 is internal */ #define FEAT_IN7_INTERNAL (1 << 11) /* Set if in7 is internal */
#define FEAT_AVCC3 (1 << 12) /* Chip supports in9/AVCC3 */ #define FEAT_AVCC3 (1 << 12) /* Chip supports in9/AVCC3 */
#define FEAT_SIX_PWM (1 << 13) /* Chip supports 6 pwm chn */
#define FEAT_PWM_FREQ2 (1 << 14) /* Separate pwm freq 2 */
static const struct it87_devices it87_devices[] = { static const struct it87_devices it87_devices[] = {
[it87] = { [it87] = {
@@ -284,20 +288,22 @@ static const struct it87_devices it87_devices[] = {
[it8716] = { [it8716] = {
.name = "it8716", .name = "it8716",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS, | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2,
.suffix = "F", .suffix = "F",
}, },
[it8718] = { [it8718] = {
.name = "it8718", .name = "it8718",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS, | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
| FEAT_PWM_FREQ2,
.old_peci_mask = 0x4, .old_peci_mask = 0x4,
.suffix = "F", .suffix = "F",
}, },
[it8720] = { [it8720] = {
.name = "it8720", .name = "it8720",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS, | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
| FEAT_PWM_FREQ2,
.old_peci_mask = 0x4, .old_peci_mask = 0x4,
.suffix = "F", .suffix = "F",
}, },
@@ -305,7 +311,8 @@ static const struct it87_devices it87_devices[] = {
.name = "it8721", .name = "it8721",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL, | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
.peci_mask = 0x05, .peci_mask = 0x05,
.old_peci_mask = 0x02, /* Actually reports PCH */ .old_peci_mask = 0x02, /* Actually reports PCH */
.suffix = "F", .suffix = "F",
@@ -314,14 +321,15 @@ static const struct it87_devices it87_devices[] = {
.name = "it8728", .name = "it8728",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
| FEAT_IN7_INTERNAL, | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2,
.peci_mask = 0x07, .peci_mask = 0x07,
.suffix = "F", .suffix = "F",
}, },
[it8771] = { [it8771] = {
.name = "it8771", .name = "it8771",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL, | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
/* PECI: guesswork */ /* PECI: guesswork */
/* 12mV ADC (OHM) */ /* 12mV ADC (OHM) */
/* 16 bit fans (OHM) */ /* 16 bit fans (OHM) */
@@ -332,7 +340,8 @@ static const struct it87_devices it87_devices[] = {
[it8772] = { [it8772] = {
.name = "it8772", .name = "it8772",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL, | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
/* PECI (coreboot) */ /* PECI (coreboot) */
/* 12mV ADC (HWSensors4, OHM) */ /* 12mV ADC (HWSensors4, OHM) */
/* 16 bit fans (HWSensors4, OHM) */ /* 16 bit fans (HWSensors4, OHM) */
@@ -343,35 +352,37 @@ static const struct it87_devices it87_devices[] = {
[it8781] = { [it8781] = {
.name = "it8781", .name = "it8781",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG, | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4, .old_peci_mask = 0x4,
.suffix = "F", .suffix = "F",
}, },
[it8782] = { [it8782] = {
.name = "it8782", .name = "it8782",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG, | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4, .old_peci_mask = 0x4,
.suffix = "F", .suffix = "F",
}, },
[it8783] = { [it8783] = {
.name = "it8783", .name = "it8783",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG, | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4, .old_peci_mask = 0x4,
.suffix = "E/F", .suffix = "E/F",
}, },
[it8786] = { [it8786] = {
.name = "it8786", .name = "it8786",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL, | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
.peci_mask = 0x07, .peci_mask = 0x07,
.suffix = "E", .suffix = "E",
}, },
[it8790] = { [it8790] = {
.name = "it8790", .name = "it8790",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL, | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
.peci_mask = 0x07, .peci_mask = 0x07,
.suffix = "E", .suffix = "E",
}, },
@@ -379,7 +390,7 @@ static const struct it87_devices it87_devices[] = {
.name = "it8603", .name = "it8603",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_AVCC3, | FEAT_AVCC3 | FEAT_PWM_FREQ2,
.peci_mask = 0x07, .peci_mask = 0x07,
.suffix = "E", .suffix = "E",
}, },
@@ -387,7 +398,8 @@ static const struct it87_devices it87_devices[] = {
.name = "it8620", .name = "it8620",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
| FEAT_IN7_INTERNAL | FEAT_AVCC3, | FEAT_IN7_INTERNAL | FEAT_AVCC3 | FEAT_SIX_PWM
| FEAT_PWM_FREQ2,
.peci_mask = 0x07, .peci_mask = 0x07,
.suffix = "E", .suffix = "E",
}, },
@@ -410,6 +422,8 @@ static const struct it87_devices it87_devices[] = {
#define has_vid(data) ((data)->features & FEAT_VID) #define has_vid(data) ((data)->features & FEAT_VID)
#define has_in7_internal(data) ((data)->features & FEAT_IN7_INTERNAL) #define has_in7_internal(data) ((data)->features & FEAT_IN7_INTERNAL)
#define has_avcc3(data) ((data)->features & FEAT_AVCC3) #define has_avcc3(data) ((data)->features & FEAT_AVCC3)
#define has_six_pwm(data) ((data)->features & FEAT_SIX_PWM)
#define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2)
struct it87_sio_data { struct it87_sio_data {
enum chips type; enum chips type;
@@ -469,9 +483,9 @@ struct it87_data {
* is no longer needed, but it is still done to keep the driver * is no longer needed, but it is still done to keep the driver
* simple. * simple.
*/ */
u8 pwm_ctrl[3]; /* Register value */ u8 pwm_ctrl[6]; /* Register value */
u8 pwm_duty[3]; /* Manual PWM value set by user */ u8 pwm_duty[6]; /* Manual PWM value set by user */
u8 pwm_temp_map[3]; /* PWM to temp. chan. mapping (bits 1-0) */ u8 pwm_temp_map[6]; /* PWM to temp. chan. mapping (bits 1-0) */
/* Automatic fan speed control registers */ /* Automatic fan speed control registers */
u8 auto_pwm[3][4]; /* [nr][3] is hard-coded */ u8 auto_pwm[3][4]; /* [nr][3] is hard-coded */
@@ -549,14 +563,14 @@ static int DIV_TO_REG(int val)
#define DIV_FROM_REG(val) (1 << (val)) #define DIV_FROM_REG(val) (1 << (val))
static const unsigned int pwm_freq[8] = { static const unsigned int pwm_freq[8] = {
48000000 / 128, 48000000,
24000000 / 128, 24000000,
12000000 / 128, 12000000,
8000000 / 128, 8000000,
6000000 / 128, 6000000,
3000000 / 128, 3000000,
1500000 / 128, 1500000,
750000 / 128, 750000,
}; };
static int it87_probe(struct platform_device *pdev); static int it87_probe(struct platform_device *pdev);
@@ -872,10 +886,20 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr, static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
struct it87_data *data = it87_update_device(dev); struct it87_data *data = it87_update_device(dev);
int index = (data->fan_ctl >> 4) & 0x07; int nr = sensor_attr->index;
unsigned int freq;
int index;
return sprintf(buf, "%u\n", pwm_freq[index]); if (has_pwm_freq2(data) && nr == 1)
index = (data->extra >> 4) & 0x07;
else
index = (data->fan_ctl >> 4) & 0x07;
freq = pwm_freq[index] / has_newer_autopwm(data) ? 256 : 128;
return sprintf(buf, "%u\n", freq);
} }
static ssize_t set_fan(struct device *dev, struct device_attribute *attr, static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
@@ -1034,7 +1058,7 @@ static ssize_t set_pwm_enable(struct device *dev,
data->pwm_duty[nr]; data->pwm_duty[nr];
else /* Automatic mode */ else /* Automatic mode */
data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr]; data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]); it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);
if (data->type != it8603) { if (data->type != it8603) {
/* set SmartGuardian mode */ /* set SmartGuardian mode */
@@ -1070,7 +1094,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
return -EBUSY; return -EBUSY;
} }
data->pwm_duty[nr] = pwm_to_reg(data, val); data->pwm_duty[nr] = pwm_to_reg(data, val);
it87_write_value(data, IT87_REG_PWM_DUTY(nr), it87_write_value(data, IT87_REG_PWM_DUTY[nr],
data->pwm_duty[nr]); data->pwm_duty[nr]);
} else { } else {
data->pwm_duty[nr] = pwm_to_reg(data, val); data->pwm_duty[nr] = pwm_to_reg(data, val);
@@ -1080,7 +1104,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
*/ */
if (!(data->pwm_ctrl[nr] & 0x80)) { if (!(data->pwm_ctrl[nr] & 0x80)) {
data->pwm_ctrl[nr] = data->pwm_duty[nr]; data->pwm_ctrl[nr] = data->pwm_duty[nr];
it87_write_value(data, IT87_REG_PWM(nr), it87_write_value(data, IT87_REG_PWM[nr],
data->pwm_ctrl[nr]); data->pwm_ctrl[nr]);
} }
} }
@@ -1090,13 +1114,18 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
static ssize_t set_pwm_freq(struct device *dev, static ssize_t set_pwm_freq(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count) struct device_attribute *attr, const char *buf, size_t count)
{ {
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
struct it87_data *data = dev_get_drvdata(dev); struct it87_data *data = dev_get_drvdata(dev);
int nr = sensor_attr->index;
unsigned long val; unsigned long val;
int i; int i;
if (kstrtoul(buf, 10, &val) < 0) if (kstrtoul(buf, 10, &val) < 0)
return -EINVAL; return -EINVAL;
val = clamp_val(val, 0, 1000000);
val *= has_newer_autopwm(data) ? 256 : 128;
/* Search for the nearest available frequency */ /* Search for the nearest available frequency */
for (i = 0; i < 7; i++) { for (i = 0; i < 7; i++) {
if (val > (pwm_freq[i] + pwm_freq[i+1]) / 2) if (val > (pwm_freq[i] + pwm_freq[i+1]) / 2)
@@ -1104,9 +1133,15 @@ static ssize_t set_pwm_freq(struct device *dev,
} }
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f; if (nr == 0) {
data->fan_ctl |= i << 4; data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
it87_write_value(data, IT87_REG_FAN_CTL, data->fan_ctl); data->fan_ctl |= i << 4;
it87_write_value(data, IT87_REG_FAN_CTL, data->fan_ctl);
} else {
data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x8f;
data->extra |= i << 4;
it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
}
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
return count; return count;
@@ -1170,7 +1205,7 @@ static ssize_t set_pwm_temp_map(struct device *dev,
*/ */
if (data->pwm_ctrl[nr] & 0x80) { if (data->pwm_ctrl[nr] & 0x80) {
data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr]; data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]); it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);
} }
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
return count; return count;
@@ -1276,7 +1311,8 @@ static SENSOR_DEVICE_ATTR_2(fan6_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 0); show_pwm_enable, set_pwm_enable, 0);
static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0); static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
static DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq); static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, show_pwm_freq,
set_pwm_freq, 0);
static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO | S_IWUSR,
show_pwm_temp_map, set_pwm_temp_map, 0); show_pwm_temp_map, set_pwm_temp_map, 0);
static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR,
@@ -1301,7 +1337,7 @@ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 1); show_pwm_enable, set_pwm_enable, 1);
static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1); static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1);
static DEVICE_ATTR(pwm2_freq, S_IRUGO, show_pwm_freq, NULL); static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO, show_pwm_freq, set_pwm_freq, 1);
static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IRUGO | S_IWUSR,
show_pwm_temp_map, set_pwm_temp_map, 1); show_pwm_temp_map, set_pwm_temp_map, 1);
static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR,
@@ -1326,7 +1362,7 @@ static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 2); show_pwm_enable, set_pwm_enable, 2);
static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 2); static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 2);
static DEVICE_ATTR(pwm3_freq, S_IRUGO, show_pwm_freq, NULL); static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO, show_pwm_freq, NULL, 2);
static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IRUGO | S_IWUSR,
show_pwm_temp_map, set_pwm_temp_map, 2); show_pwm_temp_map, set_pwm_temp_map, 2);
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR,
@@ -1348,6 +1384,27 @@ static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR,
show_auto_temp, set_auto_temp, 2, 4); show_auto_temp, set_auto_temp, 2, 4);
static SENSOR_DEVICE_ATTR(pwm4_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 3);
static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 3);
static SENSOR_DEVICE_ATTR(pwm4_freq, S_IRUGO, show_pwm_freq, NULL, 3);
static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IRUGO | S_IWUSR,
show_pwm_temp_map, set_pwm_temp_map, 3);
static SENSOR_DEVICE_ATTR(pwm5_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 4);
static SENSOR_DEVICE_ATTR(pwm5, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 4);
static SENSOR_DEVICE_ATTR(pwm5_freq, S_IRUGO, show_pwm_freq, NULL, 4);
static SENSOR_DEVICE_ATTR(pwm5_auto_channels_temp, S_IRUGO | S_IWUSR,
show_pwm_temp_map, set_pwm_temp_map, 4);
static SENSOR_DEVICE_ATTR(pwm6_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable, 5);
static SENSOR_DEVICE_ATTR(pwm6, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 5);
static SENSOR_DEVICE_ATTR(pwm6_freq, S_IRUGO, show_pwm_freq, NULL, 5);
static SENSOR_DEVICE_ATTR(pwm6_auto_channels_temp, S_IRUGO | S_IWUSR,
show_pwm_temp_map, set_pwm_temp_map, 5);
/* Alarms */ /* Alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
@@ -1705,30 +1762,64 @@ static const struct attribute *it87_attributes_fan_div[] = {
&sensor_dev_attr_fan3_div.dev_attr.attr, &sensor_dev_attr_fan3_div.dev_attr.attr,
}; };
static struct attribute *it87_attributes_pwm[3][4+1] = { { static struct attribute *it87_attributes_pwm[6][4+1] = { {
&sensor_dev_attr_pwm1_enable.dev_attr.attr, &sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr,
&dev_attr_pwm1_freq.attr, &sensor_dev_attr_pwm1_freq.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr, &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
NULL NULL
}, { }, {
&sensor_dev_attr_pwm2_enable.dev_attr.attr, &sensor_dev_attr_pwm2_enable.dev_attr.attr,
&sensor_dev_attr_pwm2.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr,
&dev_attr_pwm2_freq.attr, &sensor_dev_attr_pwm2_freq.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr, &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
NULL NULL
}, { }, {
&sensor_dev_attr_pwm3_enable.dev_attr.attr, &sensor_dev_attr_pwm3_enable.dev_attr.attr,
&sensor_dev_attr_pwm3.dev_attr.attr, &sensor_dev_attr_pwm3.dev_attr.attr,
&dev_attr_pwm3_freq.attr, &sensor_dev_attr_pwm3_freq.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr, &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
NULL NULL
}, {
&sensor_dev_attr_pwm4_enable.dev_attr.attr,
&sensor_dev_attr_pwm4.dev_attr.attr,
&sensor_dev_attr_pwm4_freq.dev_attr.attr,
&sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_pwm5_enable.dev_attr.attr,
&sensor_dev_attr_pwm5.dev_attr.attr,
&sensor_dev_attr_pwm5_freq.dev_attr.attr,
&sensor_dev_attr_pwm5_auto_channels_temp.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_pwm6_enable.dev_attr.attr,
&sensor_dev_attr_pwm6.dev_attr.attr,
&sensor_dev_attr_pwm6_freq.dev_attr.attr,
&sensor_dev_attr_pwm6_auto_channels_temp.dev_attr.attr,
NULL
} }; } };
static const struct attribute_group it87_group_pwm[3] = { static umode_t pwm_attribute_mode(struct kobject *kobj, struct attribute *attr,
int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct it87_data *data = dev_get_drvdata(dev);
if (has_pwm_freq2(data) && index == 2)
return attr->mode | S_IWUSR;
return attr->mode;
}
static const struct attribute_group it87_group_pwm[6] = {
{ .attrs = it87_attributes_pwm[0] }, { .attrs = it87_attributes_pwm[0] },
{ .attrs = it87_attributes_pwm[1] }, { .attrs = it87_attributes_pwm[1],
.is_visible = pwm_attribute_mode, },
{ .attrs = it87_attributes_pwm[2] }, { .attrs = it87_attributes_pwm[2] },
{ .attrs = it87_attributes_pwm[3] },
{ .attrs = it87_attributes_pwm[4] },
{ .attrs = it87_attributes_pwm[5] },
}; };
static struct attribute *it87_attributes_autopwm[3][9+1] = { { static struct attribute *it87_attributes_autopwm[3][9+1] = { {
@@ -1907,6 +1998,9 @@ static int __init it87_find(unsigned short *address,
else else
sio_data->skip_in |= (1 << 9); sio_data->skip_in |= (1 << 9);
if (!(it87_devices[sio_data->type].features & FEAT_SIX_PWM))
sio_data->skip_pwm |= (1 << 3) | (1 << 4) | (1 << 5);
if (!(it87_devices[sio_data->type].features & FEAT_VID)) if (!(it87_devices[sio_data->type].features & FEAT_VID))
sio_data->skip_vid = 1; sio_data->skip_vid = 1;
@@ -2003,6 +2097,48 @@ static int __init it87_find(unsigned short *address,
sio_data->skip_in |= (1 << 5); /* No VIN5 */ sio_data->skip_in |= (1 << 5); /* No VIN5 */
sio_data->skip_in |= (1 << 6); /* No VIN6 */ sio_data->skip_in |= (1 << 6); /* No VIN6 */
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else if (sio_data->type == it8620) {
int reg;
superio_select(GPIO);
/* Check for pwm5 */
reg = superio_inb(IT87_SIO_GPIO1_REG);
if (reg & (1 << 6))
sio_data->skip_pwm |= (1 << 4);
/* Check for fan4, fan5 */
reg = superio_inb(IT87_SIO_GPIO2_REG);
if (!(reg & (1 << 5)))
sio_data->skip_fan |= (1 << 3);
if (!(reg & (1 << 4)))
sio_data->skip_fan |= (1 << 4);
/* Check for pwm3, fan3 */
reg = superio_inb(IT87_SIO_GPIO3_REG);
if (reg & (1 << 6))
sio_data->skip_pwm |= (1 << 2);
if (reg & (1 << 7))
sio_data->skip_fan |= (1 << 2);
/* Check for pwm4 */
reg = superio_inb(IT87_SIO_GPIO4_REG);
if (!(reg & (1 << 4)))
sio_data->skip_pwm |= (1 << 3);
/* Check for pwm2, fan2 */
reg = superio_inb(IT87_SIO_GPIO5_REG);
if (reg & (1 << 1))
sio_data->skip_pwm |= (1 << 1);
if (reg & (1 << 2))
sio_data->skip_fan |= (1 << 1);
/* Check for pwm6, fan6 */
if (!(reg & (1 << 7))) {
sio_data->skip_pwm |= (1 << 5);
sio_data->skip_fan |= (1 << 5);
}
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else { } else {
int reg; int reg;
@@ -2144,8 +2280,8 @@ static void it87_remove_files(struct device *dev)
sysfs_remove_file(&dev->kobj, sysfs_remove_file(&dev->kobj,
it87_attributes_fan_div[i]); it87_attributes_fan_div[i]);
} }
for (i = 0; i < 3; i++) { for (i = 0; i < 6; i++) {
if (sio_data->skip_pwm & (1 << 0)) if (sio_data->skip_pwm & (1 << i))
continue; continue;
sysfs_remove_group(&dev->kobj, &it87_group_pwm[i]); sysfs_remove_group(&dev->kobj, &it87_group_pwm[i]);
if (has_old_autopwm(data)) if (has_old_autopwm(data))
@@ -2327,7 +2463,7 @@ static int it87_probe(struct platform_device *pdev)
} }
if (enable_pwm_interface) { if (enable_pwm_interface) {
for (i = 0; i < 3; i++) { for (i = 0; i < 6; i++) {
if (sio_data->skip_pwm & (1 << i)) if (sio_data->skip_pwm & (1 << i))
continue; continue;
err = sysfs_create_group(&dev->kobj, err = sysfs_create_group(&dev->kobj,
@@ -2430,7 +2566,7 @@ static int it87_check_pwm(struct device *dev)
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
pwm[i] = it87_read_value(data, pwm[i] = it87_read_value(data,
IT87_REG_PWM(i)); IT87_REG_PWM[i]);
/* /*
* If any fan is in automatic pwm mode, the polarity * If any fan is in automatic pwm mode, the polarity
@@ -2445,7 +2581,7 @@ static int it87_check_pwm(struct device *dev)
tmp | 0x87); tmp | 0x87);
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
it87_write_value(data, it87_write_value(data,
IT87_REG_PWM(i), IT87_REG_PWM[i],
0x7f & ~pwm[i]); 0x7f & ~pwm[i]);
return 1; return 1;
} }
@@ -2563,6 +2699,16 @@ static void it87_init_device(struct platform_device *pdev)
/* Fan input pins may be used for alternative functions */ /* Fan input pins may be used for alternative functions */
data->has_fan &= ~sio_data->skip_fan; data->has_fan &= ~sio_data->skip_fan;
/* Check if pwm5, pwm6 are enabled */
if (has_six_pwm(data)) {
/* The following code may be IT8620E specific */
tmp = it87_read_value(data, IT87_REG_FAN_DIV);
if ((tmp & 0xc0) == 0xc0)
sio_data->skip_pwm |= (1 << 4);
if (!(tmp & (1 << 3)))
sio_data->skip_pwm |= (1 << 5);
}
/* Start monitoring */ /* Start monitoring */
it87_write_value(data, IT87_REG_CONFIG, it87_write_value(data, IT87_REG_CONFIG,
(it87_read_value(data, IT87_REG_CONFIG) & 0x3e) (it87_read_value(data, IT87_REG_CONFIG) & 0x3e)
@@ -2571,11 +2717,11 @@ static void 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 (has_newer_autopwm(data)) { 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]);
} else { } else {
if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */ if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;