IT8620E supports up to 6 pwm channels. Add support for it. Also check if fan tachometers 4..6 are enabled before instantiating the respective sysfs attributes. Signed-off-by: Guenter Roeck <linux@xxxxxxxxxxxx> --- v2: Fix formatting of IT87_REG_PWM and IT87_REG_PWM_DUTY Use feature macros on configuration data Fix pwm_temp_map display (pwm4..6 use temp4..6) Call it87_update_pwm_ctrl for all 6 pwm channels drivers/hwmon/it87.c | 114 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 94 insertions(+), 20 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index d26b51f6683b..0602f0d251e4 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -165,6 +165,7 @@ static inline void superio_exit(void) #define IT87_SIO_GPIO1_REG 0x25 #define IT87_SIO_GPIO2_REG 0x26 #define IT87_SIO_GPIO3_REG 0x27 +#define IT87_SIO_GPIO4_REG 0x28 #define IT87_SIO_GPIO5_REG 0x29 #define IT87_SIO_PINX1_REG 0x2a /* Pin selection */ #define IT87_SIO_PINX2_REG 0x2c /* Pin selection */ @@ -224,8 +225,8 @@ static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 }; #define IT87_REG_FAN_MAIN_CTRL 0x13 #define IT87_REG_FAN_CTL 0x14 -#define IT87_REG_PWM(nr) (0x15 + (nr)) -#define IT87_REG_PWM_DUTY(nr) (0x63 + (nr) * 8) +static const u8 IT87_REG_PWM[] = { 0x15, 0x16, 0x17, 0x7f, 0xa7, 0xaf }; +static const u8 IT87_REG_PWM_DUTY[] = { 0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab }; #define IT87_REG_VIN(nr) (0x20 + (nr)) #define IT87_REG_TEMP(nr) (0x29 + (nr)) @@ -268,6 +269,7 @@ struct it87_devices { #define FEAT_IN7_INTERNAL (1 << 10) /* Set if in7 is internal */ #define FEAT_SIX_FANS (1 << 11) /* Supports six fans */ #define FEAT_AVCC3 (1 << 12) /* Chip supports in9/AVCC3 */ +#define FEAT_SIX_PWM (1 << 13) /* Chip supports 6 pwm chn */ static const struct it87_devices it87_devices[] = { [it87] = { @@ -388,7 +390,7 @@ static const struct it87_devices it87_devices[] = { .suffix = "E", .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS - | FEAT_IN7_INTERNAL | FEAT_AVCC3, + | FEAT_IN7_INTERNAL | FEAT_AVCC3 | FEAT_SIX_PWM, .peci_mask = 0x07, }, }; @@ -410,6 +412,7 @@ static const struct it87_devices it87_devices[] = { #define has_in7_internal(data) ((data)->features & FEAT_IN7_INTERNAL) #define has_six_fans(data) ((data)->features & FEAT_SIX_FANS) #define has_avcc3(data) ((data)->features & FEAT_AVCC3) +#define has_six_pwm(data) ((data)->features & FEAT_SIX_PWM) struct it87_sio_data { enum chips type; @@ -469,9 +472,9 @@ struct it87_data { * is no longer needed, but it is still done to keep the driver * simple. */ - u8 pwm_ctrl[3]; /* Register value */ - u8 pwm_duty[3]; /* Manual PWM value set by user */ - u8 pwm_temp_map[3]; /* PWM to temp. chan. mapping (bits 1-0) */ + u8 pwm_ctrl[6]; /* Register value */ + u8 pwm_duty[6]; /* Manual PWM value set by user */ + u8 pwm_temp_map[6]; /* PWM to temp. chan. mapping (bits 1-0) */ /* Automatic fan speed control registers */ u8 auto_pwm[3][4]; /* [nr][3] is hard-coded */ @@ -1047,7 +1050,7 @@ static ssize_t set_pwm_enable(struct device *dev, data->pwm_duty[nr]; else /* Automatic mode */ 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) { /* set SmartGuardian mode */ @@ -1083,7 +1086,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, return -EBUSY; } 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]); } else { data->pwm_duty[nr] = pwm_to_reg(data, val); @@ -1093,7 +1096,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, */ if (!(data->pwm_ctrl[nr] & 0x80)) { 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]); } } @@ -1186,7 +1189,7 @@ static ssize_t set_pwm_temp_map(struct device *dev, */ if (data->pwm_ctrl[nr] & 0x80) { 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); return count; @@ -1364,6 +1367,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, 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 DEVICE_ATTR(pwm4_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq); +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 DEVICE_ATTR(pwm5_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq); +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 DEVICE_ATTR(pwm6_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq); +static SENSOR_DEVICE_ATTR(pwm6_auto_channels_temp, S_IRUGO | S_IWUSR, + show_pwm_temp_map, set_pwm_temp_map, 5); + /* Alarms */ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) @@ -1721,7 +1745,7 @@ static const struct attribute *it87_attributes_fan_div[] = { &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.dev_attr.attr, &dev_attr_pwm1_freq.attr, @@ -1739,12 +1763,33 @@ static struct attribute *it87_attributes_pwm[3][4+1] = { { &dev_attr_pwm3_freq.attr, &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr, NULL +}, { + &sensor_dev_attr_pwm4_enable.dev_attr.attr, + &sensor_dev_attr_pwm4.dev_attr.attr, + &dev_attr_pwm4_freq.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, + &dev_attr_pwm5_freq.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, + &dev_attr_pwm6_freq.attr, + &sensor_dev_attr_pwm6_auto_channels_temp.dev_attr.attr, + NULL } }; -static const struct attribute_group it87_group_pwm[3] = { +static const struct attribute_group it87_group_pwm[6] = { { .attrs = it87_attributes_pwm[0] }, { .attrs = it87_attributes_pwm[1] }, { .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] = { { @@ -1926,6 +1971,9 @@ static int __init it87_find(unsigned short *address, else sio_data->skip_in |= (1 << 9); + if (!has_six_pwm(config)) + sio_data->skip_pwm |= (1 << 3) | (1 << 4) | (1 << 5); + if (!has_vid(config)) sio_data->skip_vid = 1; @@ -2028,6 +2076,11 @@ static int __init it87_find(unsigned short *address, 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))) @@ -2042,12 +2095,22 @@ static int __init it87_find(unsigned short *address, 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; } else { @@ -2190,7 +2253,7 @@ static void it87_remove_files(struct device *dev) sysfs_remove_file(&dev->kobj, it87_attributes_fan_div[i]); } - for (i = 0; i < 3; i++) { + for (i = 0; i < 6; i++) { if (sio_data->skip_pwm & (1 << i)) continue; sysfs_remove_group(&dev->kobj, &it87_group_pwm[i]); @@ -2373,7 +2436,7 @@ static int it87_probe(struct platform_device *pdev) } if (enable_pwm_interface) { - for (i = 0; i < 3; i++) { + for (i = 0; i < 6; i++) { if (sio_data->skip_pwm & (1 << i)) continue; err = sysfs_create_group(&dev->kobj, @@ -2476,7 +2539,7 @@ static int it87_check_pwm(struct device *dev) for (i = 0; i < 3; i++) pwm[i] = it87_read_value(data, - IT87_REG_PWM(i)); + IT87_REG_PWM[i]); /* * If any fan is in automatic pwm mode, the polarity @@ -2491,7 +2554,7 @@ static int it87_check_pwm(struct device *dev) tmp | 0x87); for (i = 0; i < 3; i++) it87_write_value(data, - IT87_REG_PWM(i), + IT87_REG_PWM[i], 0x7f & ~pwm[i]); return 1; } @@ -2606,6 +2669,16 @@ static void it87_init_device(struct platform_device *pdev) /* Fan input pins may be used for alternative functions */ 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 */ it87_write_value(data, IT87_REG_CONFIG, (it87_read_value(data, IT87_REG_CONFIG) & 0x3e) @@ -2614,11 +2687,12 @@ static void it87_init_device(struct platform_device *pdev) 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)) { - data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; + data->pwm_temp_map[nr] = (data->pwm_ctrl[nr] & 0x03) + + nr < 3 ? 0 : 3; data->pwm_duty[nr] = it87_read_value(data, - IT87_REG_PWM_DUTY(nr)); + IT87_REG_PWM_DUTY[nr]); } else { if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */ data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; @@ -2717,7 +2791,7 @@ static struct it87_data *it87_update_device(struct device *dev) data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL); data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL); - for (i = 0; i < 3; i++) + for (i = 0; i < 6; i++) it87_update_pwm_ctrl(data, i); data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE); -- 2.1.0 _______________________________________________ lm-sensors mailing list lm-sensors@xxxxxxxxxxxxxx http://lists.lm-sensors.org/mailman/listinfo/lm-sensors