X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=it87.c;h=6f62ff6201bf451ed7f648e1829d3063e14b5d86;hb=65ec08b8a3c118e99a8a5da4052d7719caa69cd1;hp=fb5fdcddd5adaee2a2a7ee8efa9308bbcd847a5f;hpb=c8a5344f8d9da38369f6457cfd59f00dc9cf90d7;p=groeck-it87 diff --git a/it87.c b/it87.c index fb5fdcd..6f62ff6 100644 --- a/it87.c +++ b/it87.c @@ -11,9 +11,14 @@ * similar parts. The other devices are supported by different drivers. * * Supports: IT8603E Super I/O chip w/LPC interface + * IT8607E Super I/O chip w/LPC interface * IT8620E Super I/O chip w/LPC interface + * IT8622E Super I/O chip w/LPC interface * IT8623E Super I/O chip w/LPC interface * IT8628E Super I/O chip w/LPC interface + * IT8655E Super I/O chip w/LPC interface + * IT8665E Super I/O chip w/LPC interface + * IT8686E Super I/O chip w/LPC interface * IT8705F Super I/O chip w/LPC interface * IT8712F Super I/O chip w/LPC interface * IT8716F Super I/O chip w/LPC interface @@ -31,6 +36,7 @@ * IT8783E/F Super I/O chip w/LPC interface * IT8786E Super I/O chip w/LPC interface * IT8790E Super I/O chip w/LPC interface + * IT8792E Super I/O chip w/LPC interface * Sis950 A clone of the IT8705F * * Copyright (C) 2001 Chris Gauthron @@ -70,8 +76,9 @@ #define DRVNAME "it87" enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732, - it8771, it8772, it8781, it8782, it8783, it8786, it8790, it8603, - it8620, it8628 }; + it8771, it8772, it8781, it8782, it8783, it8786, it8790, + it8792, it8603, it8607, it8620, it8622, it8628, it8655, it8665, + it8686 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -152,6 +159,7 @@ static inline void superio_exit(int ioreg) #define IT8726F_DEVID 0x8726 #define IT8728F_DEVID 0x8728 #define IT8732F_DEVID 0x8732 +#define IT8792E_DEVID 0x8733 #define IT8771E_DEVID 0x8771 #define IT8772E_DEVID 0x8772 #define IT8781F_DEVID 0x8781 @@ -160,9 +168,14 @@ static inline void superio_exit(int ioreg) #define IT8786E_DEVID 0x8786 #define IT8790E_DEVID 0x8790 #define IT8603E_DEVID 0x8603 +#define IT8607E_DEVID 0x8607 #define IT8620E_DEVID 0x8620 +#define IT8622E_DEVID 0x8622 #define IT8623E_DEVID 0x8623 #define IT8628E_DEVID 0x8628 +#define IT8655E_DEVID 0x8655 +#define IT8665E_DEVID 0x8665 +#define IT8686E_DEVID 0x8686 #define IT87_ACT_REG 0x30 #define IT87_BASE_REG 0x60 @@ -172,8 +185,10 @@ static inline void superio_exit(int ioreg) #define IT87_SIO_GPIO3_REG 0x27 #define IT87_SIO_GPIO4_REG 0x28 #define IT87_SIO_GPIO5_REG 0x29 +#define IT87_SIO_GPIO9_REG 0xd3 #define IT87_SIO_PINX1_REG 0x2a /* Pin selection */ #define IT87_SIO_PINX2_REG 0x2c /* Pin selection */ +#define IT87_SIO_PINX4_REG 0x2d /* Pin selection */ #define IT87_SIO_SPI_REG 0xef /* SPI function pin select */ #define IT87_SIO_VID_REG 0xfc /* VID value */ #define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */ @@ -207,6 +222,8 @@ static bool fix_pwm_polarity; #define IT87_REG_ALARM2 0x02 #define IT87_REG_ALARM3 0x03 +#define IT87_REG_BANK 0x06 + /* * The IT8718F and IT8720F have the VID value in a different register, in * Super-I/O configuration space. @@ -227,16 +244,27 @@ static bool fix_pwm_polarity; * - up to 6 fan (1 to 6) */ -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_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_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_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_FAN_8665[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82, 0x93 }; +static const u8 IT87_REG_FAN_MIN_8665[] = + { 0x10, 0x11, 0x12, 0x84, 0x86, 0xb2 }; +static const u8 IT87_REG_FANX_8665[] = { 0x18, 0x19, 0x1a, 0x81, 0x83, 0x94 }; +static const u8 IT87_REG_FANX_MIN_8665[] = + { 0x1b, 0x1c, 0x1d, 0x85, 0x87, 0xb3 }; + static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 }; #define IT87_REG_FAN_MAIN_CTRL 0x13 #define IT87_REG_FAN_CTL 0x14 -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 }; + +static const u8 IT87_REG_PWM[] = { 0x15, 0x16, 0x17, 0x7f, 0xa7, 0xaf }; +static const u8 IT87_REG_PWM_8665[] = { 0x15, 0x16, 0x17, 0x1e, 0x1f, 0x92 }; + +static const u8 IT87_REG_PWM_DUTY[] = { 0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab }; static const u8 IT87_REG_VIN[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x2f, 0x2c, 0x2d, 0x2e }; @@ -294,34 +322,43 @@ struct it87_devices { #define FEAT_SIX_FANS BIT(11) /* Supports six fans */ #define FEAT_10_9MV_ADC BIT(12) #define FEAT_AVCC3 BIT(13) /* Chip supports in9/AVCC3 */ -#define FEAT_SIX_PWM BIT(14) /* Chip supports 6 pwm chn */ -#define FEAT_PWM_FREQ2 BIT(15) /* Separate pwm freq 2 */ -#define FEAT_SIX_TEMP BIT(16) /* Up to 6 temp sensors */ +#define FEAT_FIVE_PWM BIT(14) /* Chip supports 5 pwm chn */ +#define FEAT_SIX_PWM BIT(15) /* Chip supports 6 pwm chn */ +#define FEAT_PWM_FREQ2 BIT(16) /* Separate pwm freq 2 */ +#define FEAT_SIX_TEMP BIT(17) /* Up to 6 temp sensors */ +#define FEAT_VIN3_5V BIT(18) /* VIN3 connected to +5V */ +#define FEAT_FOUR_FANS BIT(19) /* Supports four fans */ +#define FEAT_FOUR_PWM BIT(20) /* Supports four fan controls */ +#define FEAT_BANK_SEL BIT(21) /* Chip has multi-bank support */ +#define FEAT_SCALING BIT(22) /* Internal voltage scaling */ +#define FEAT_FANCTL_ONOFF BIT(23) /* chip has FAN_CTL ON/OFF */ static const struct it87_devices it87_devices[] = { [it87] = { .name = "it87", .suffix = "F", - .features = FEAT_OLD_AUTOPWM, /* may need to overwrite */ + .features = FEAT_OLD_AUTOPWM | FEAT_FANCTL_ONOFF, + /* may need to overwrite */ }, [it8712] = { .name = "it8712", .suffix = "F", - .features = FEAT_OLD_AUTOPWM | FEAT_VID, + .features = FEAT_OLD_AUTOPWM | FEAT_VID | FEAT_FANCTL_ONOFF, /* may need to overwrite */ }, [it8716] = { .name = "it8716", .suffix = "F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID - | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2, + | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2 + | FEAT_FANCTL_ONOFF, }, [it8718] = { .name = "it8718", .suffix = "F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS - | FEAT_PWM_FREQ2, + | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF, .old_peci_mask = 0x4, }, [it8720] = { @@ -329,7 +366,7 @@ static const struct it87_devices it87_devices[] = { .suffix = "F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS - | FEAT_PWM_FREQ2, + | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF, .old_peci_mask = 0x4, }, [it8721] = { @@ -338,7 +375,7 @@ static const struct it87_devices it87_devices[] = { .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL - | FEAT_PWM_FREQ2, + | FEAT_PWM_FREQ2 | FEAT_SCALING | FEAT_FANCTL_ONOFF, .peci_mask = 0x05, .old_peci_mask = 0x02, /* Actually reports PCH */ }, @@ -347,7 +384,8 @@ static const struct it87_devices it87_devices[] = { .suffix = "F", .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS - | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2, + | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 | FEAT_SCALING + | FEAT_FANCTL_ONOFF, .peci_mask = 0x07, }, [it8732] = { @@ -355,7 +393,8 @@ static const struct it87_devices it87_devices[] = { .suffix = "F", .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI - | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL, + | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FOUR_FANS + | FEAT_FOUR_PWM | FEAT_FANCTL_ONOFF, .peci_mask = 0x07, .old_peci_mask = 0x02, /* Actually reports PCH */ }, @@ -364,7 +403,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_IN7_INTERNAL - | FEAT_PWM_FREQ2, + | FEAT_PWM_FREQ2 | FEAT_SCALING | FEAT_FANCTL_ONOFF, /* PECI: guesswork */ /* 12mV ADC (OHM) */ /* 16 bit fans (OHM) */ @@ -376,7 +415,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_IN7_INTERNAL - | FEAT_PWM_FREQ2, + | FEAT_PWM_FREQ2 | FEAT_SCALING | FEAT_FANCTL_ONOFF, /* PECI (coreboot) */ /* 12mV ADC (HWSensors4, OHM) */ /* 16 bit fans (HWSensors4, OHM) */ @@ -387,21 +426,24 @@ static const struct it87_devices it87_devices[] = { .name = "it8781", .suffix = "F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET - | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2, + | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2 + | FEAT_FANCTL_ONOFF, .old_peci_mask = 0x4, }, [it8782] = { .name = "it8782", .suffix = "F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET - | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2, + | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2 + | FEAT_FANCTL_ONOFF, .old_peci_mask = 0x4, }, [it8783] = { .name = "it8783", .suffix = "E/F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET - | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2, + | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2 + | FEAT_FANCTL_ONOFF, .old_peci_mask = 0x4, }, [it8786] = { @@ -409,15 +451,23 @@ 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_IN7_INTERNAL - | FEAT_PWM_FREQ2, + | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF, .peci_mask = 0x07, }, [it8790] = { .name = "it8790", .suffix = "E", - .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS - | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL - | FEAT_PWM_FREQ2, + .features = FEAT_NEWER_AUTOPWM | FEAT_10_9MV_ADC | FEAT_SCALING + | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI + | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF, + .peci_mask = 0x07, + }, + [it8792] = { + .name = "it8792", + .suffix = "E", + .features = FEAT_NEWER_AUTOPWM | FEAT_10_9MV_ADC | FEAT_SCALING + | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI + | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF, .peci_mask = 0x07, }, [it8603] = { @@ -425,7 +475,16 @@ 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_IN7_INTERNAL - | FEAT_AVCC3 | FEAT_PWM_FREQ2, + | FEAT_AVCC3 | FEAT_PWM_FREQ2 | FEAT_SCALING, + .peci_mask = 0x07, + }, + [it8607] = { + .name = "it8607", + .suffix = "E", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL + | FEAT_AVCC3 | FEAT_PWM_FREQ2 | FEAT_SCALING + | FEAT_FANCTL_ONOFF, .peci_mask = 0x07, }, [it8620] = { @@ -434,7 +493,17 @@ static const struct it87_devices it87_devices[] = { .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2 - | FEAT_SIX_TEMP, + | FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_SCALING + | FEAT_FANCTL_ONOFF, + .peci_mask = 0x07, + }, + [it8622] = { + .name = "it8622", + .suffix = "E", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS + | FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 + | FEAT_AVCC3 | FEAT_VIN3_5V | FEAT_SCALING, .peci_mask = 0x07, }, [it8628] = { @@ -443,7 +512,34 @@ static const struct it87_devices it87_devices[] = { .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2 - | FEAT_SIX_TEMP, + | FEAT_SIX_TEMP | FEAT_SCALING | FEAT_AVCC3 + | FEAT_FANCTL_ONOFF, + .peci_mask = 0x07, + }, + [it8655] = { + .name = "it8655", + .suffix = "E", + .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_AVCC3 + | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_BANK_SEL, + .peci_mask = 0x07, + }, + [it8665] = { + .name = "it8665", + .suffix = "E", + .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_AVCC3 + | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_SIX_FANS + | FEAT_SIX_PWM | FEAT_BANK_SEL, + .peci_mask = 0x07, + }, + [it8686] = { + .name = "it8686", + .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_SIX_PWM | FEAT_PWM_FREQ2 + | FEAT_SIX_TEMP | FEAT_BANK_SEL | FEAT_SCALING | FEAT_AVCC3, .peci_mask = 0x07, }, }; @@ -466,9 +562,21 @@ 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_five_pwm(data) ((data)->features & (FEAT_FIVE_PWM \ + | FEAT_SIX_PWM)) #define has_six_pwm(data) ((data)->features & FEAT_SIX_PWM) #define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2) #define has_six_temp(data) ((data)->features & FEAT_SIX_TEMP) +#define has_vin3_5v(data) ((data)->features & FEAT_VIN3_5V) +#define has_four_fans(data) ((data)->features & (FEAT_FOUR_FANS | \ + FEAT_FIVE_FANS | \ + FEAT_SIX_FANS)) +#define has_four_pwm(data) ((data)->features & (FEAT_FOUR_PWM | \ + FEAT_FIVE_PWM \ + | FEAT_SIX_PWM)) +#define has_bank_sel(data) ((data)->features & FEAT_BANK_SEL) +#define has_scaling(data) ((data)->features & FEAT_SCALING) +#define has_fanctl_onoff(data) ((data)->features & FEAT_FANCTL_ONOFF) struct it87_sio_data { enum chips type; @@ -492,10 +600,18 @@ struct it87_sio_data { struct it87_data { const struct attribute_group *groups[7]; enum chips type; - u16 features; + u32 features; + u8 bank; u8 peci_mask; u8 old_peci_mask; + const u8 *REG_FAN; + const u8 *REG_FANX; + const u8 *REG_FAN_MIN; + const u8 *REG_FANX_MIN; + + const u8 *REG_PWM; + unsigned short addr; const char *name; struct mutex update_lock; @@ -641,15 +757,39 @@ static const unsigned int pwm_freq[8] = { 750000, }; +static int _it87_read_value(struct it87_data *data, u8 reg) +{ + outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET); + return inb_p(data->addr + IT87_DATA_REG_OFFSET); +} + +static void _it87_write_value(struct it87_data *data, u8 reg, u8 value) +{ + outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET); + outb_p(value, data->addr + IT87_DATA_REG_OFFSET); +} + +static void it87_set_bank(struct it87_data *data, u8 bank) +{ + if (has_bank_sel(data) && bank != data->bank) { + u8 breg = _it87_read_value(data, IT87_REG_BANK); + + breg &= 0x1f; + breg |= (bank << 5); + data->bank = bank; + _it87_write_value(data, IT87_REG_BANK, breg); + } +} + /* * Must be called with data->update_lock held, except during initialization. * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, * would slow down the IT87 access and should not be necessary. */ -static int it87_read_value(struct it87_data *data, u8 reg) +static int it87_read_value(struct it87_data *data, u16 reg) { - outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET); - return inb_p(data->addr + IT87_DATA_REG_OFFSET); + it87_set_bank(data, reg >> 8); + return _it87_read_value(data, reg & 0xff); } /* @@ -657,15 +797,15 @@ static int it87_read_value(struct it87_data *data, u8 reg) * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, * would slow down the IT87 access and should not be necessary. */ -static void it87_write_value(struct it87_data *data, u8 reg, u8 value) +static void it87_write_value(struct it87_data *data, u16 reg, u8 value) { - outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET); - outb_p(value, data->addr + IT87_DATA_REG_OFFSET); + it87_set_bank(data, reg >> 8); + _it87_write_value(data, reg & 0xff, value); } 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, data->REG_PWM[nr]); if (has_newer_autopwm(data)) { data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; data->pwm_duty[nr] = it87_read_value(data, @@ -753,15 +893,15 @@ static struct it87_data *it87_update_device(struct device *dev) continue; data->fan[i][1] = - it87_read_value(data, IT87_REG_FAN_MIN[i]); + it87_read_value(data, data->REG_FAN_MIN[i]); data->fan[i][0] = it87_read_value(data, - IT87_REG_FAN[i]); + data->REG_FAN[i]); /* Add high byte if in 16-bit mode */ if (has_16bit_fans(data)) { data->fan[i][0] |= it87_read_value(data, - IT87_REG_FANX[i]) << 8; + data->REG_FANX[i]) << 8; data->fan[i][1] |= it87_read_value(data, - IT87_REG_FANX_MIN[i]) << 8; + data->REG_FANX_MIN[i]) << 8; } } for (i = 0; i < NUM_TEMP; i++) { @@ -1074,16 +1214,16 @@ static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type, static int pwm_mode(const struct it87_data *data, int nr) { - if (data->type != it8603 && nr < 3 && !(data->fan_main_ctrl & BIT(nr))) + if (has_fanctl_onoff(data) && nr < 3 && + !(data->fan_main_ctrl & BIT(nr))) return 0; /* Full speed */ - if (data->pwm_ctrl[nr] & 0x80) { + if (data->pwm_ctrl[nr] & 0x80) return 2; /* Automatic mode */ - } else { - if ((data->type == it8603 || nr >= 3) && - data->pwm_duty[nr] == pwm_to_reg(data, 0xff)) - return 0; /* Full speed */ - return 1; /* Manual mode */ - } + if ((!has_fanctl_onoff(data) || nr >= 3) && + data->pwm_duty[nr] == pwm_to_reg(data, 0xff)) + return 0; /* Full speed */ + + return 1; /* Manual mode */ } static ssize_t show_fan(struct device *dev, struct device_attribute *attr, @@ -1170,9 +1310,9 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr, if (has_16bit_fans(data)) { data->fan[nr][index] = FAN16_TO_REG(val); - it87_write_value(data, IT87_REG_FAN_MIN[nr], + it87_write_value(data, data->REG_FAN_MIN[nr], data->fan[nr][index] & 0xff); - it87_write_value(data, IT87_REG_FANX_MIN[nr], + it87_write_value(data, data->REG_FANX_MIN[nr], data->fan[nr][index] >> 8); } else { reg = it87_read_value(data, IT87_REG_FAN_DIV); @@ -1189,7 +1329,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr, } data->fan[nr][index] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - it87_write_value(data, IT87_REG_FAN_MIN[nr], + it87_write_value(data, data->REG_FAN_MIN[nr], data->fan[nr][index]); } @@ -1236,7 +1376,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, /* Restore fan min limit */ data->fan[nr][1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]); + it87_write_value(data, data->REG_FAN_MIN[nr], data->fan[nr][1]); mutex_unlock(&data->update_lock); return count; @@ -1292,7 +1432,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); if (val == 0) { - if (nr < 3 && data->type != it8603) { + if (nr < 3 && has_fanctl_onoff(data)) { int tmp; /* make sure the fan is on when in on/off mode */ tmp = it87_read_value(data, IT87_REG_FAN_CTL); @@ -1302,27 +1442,37 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); } else { + u8 ctrl; + /* No on/off mode, set maximum pwm value */ data->pwm_duty[nr] = pwm_to_reg(data, 0xff); it87_write_value(data, IT87_REG_PWM_DUTY[nr], data->pwm_duty[nr]); /* and set manual mode */ - data->pwm_ctrl[nr] = has_newer_autopwm(data) ? - data->pwm_temp_map[nr] : - data->pwm_duty[nr]; - it87_write_value(data, IT87_REG_PWM[nr], - data->pwm_ctrl[nr]); + if (has_newer_autopwm(data)) { + ctrl = (data->pwm_ctrl[nr] & 0x7c) | + data->pwm_temp_map[nr]; + } else { + ctrl = data->pwm_duty[nr]; + } + data->pwm_ctrl[nr] = ctrl; + it87_write_value(data, data->REG_PWM[nr], ctrl); } } else { - if (val == 1) /* Manual mode */ - data->pwm_ctrl[nr] = has_newer_autopwm(data) ? - data->pwm_temp_map[nr] : - 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]); - - if (data->type != it8603 && nr < 3) { + u8 ctrl; + + if (has_newer_autopwm(data)) { + ctrl = (data->pwm_ctrl[nr] & 0x7c) | + data->pwm_temp_map[nr]; + if (val != 1) + ctrl |= 0x80; + } else { + ctrl = (val == 1 ? data->pwm_duty[nr] : 0x80); + } + data->pwm_ctrl[nr] = ctrl; + it87_write_value(data, data->REG_PWM[nr], ctrl); + + if (has_fanctl_onoff(data) && nr < 3) { /* set SmartGuardian mode */ data->fan_main_ctrl |= BIT(nr); it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, @@ -1346,6 +1496,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); + it87_update_pwm_ctrl(data, nr); if (has_newer_autopwm(data)) { /* * If we are in automatic mode, the PWM duty cycle register @@ -1366,7 +1517,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, data->REG_PWM[nr], data->pwm_ctrl[nr]); } } @@ -1458,14 +1609,16 @@ static ssize_t set_pwm_temp_map(struct device *dev, } mutex_lock(&data->update_lock); + it87_update_pwm_ctrl(data, nr); data->pwm_temp_map[nr] = reg; /* * If we are in automatic mode, write the temp mapping immediately; * otherwise, just store it for later use. */ 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]); + data->pwm_ctrl[nr] = (data->pwm_ctrl[nr] & 0xfc) | + data->pwm_temp_map[nr]; + it87_write_value(data, data->REG_PWM[nr], data->pwm_ctrl[nr]); } mutex_unlock(&data->update_lock); return count; @@ -1918,17 +2071,21 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr, "+5V", "5VSB", "Vbat", + "AVCC", }; static const char * const labels_it8721[] = { "+3.3V", "3VSB", "Vbat", + "+3.3V", }; struct it87_data *data = dev_get_drvdata(dev); int nr = to_sensor_dev_attr(attr)->index; const char *label; - if (has_12mv_adc(data) || has_10_9mv_adc(data)) + if (has_vin3_5v(data) && nr == 0) + label = labels[0]; + else if (has_12mv_adc(data) || has_10_9mv_adc(data)) label = labels_it8721[nr]; else label = labels[nr]; @@ -1939,7 +2096,7 @@ 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(in8_label, S_IRUGO, show_label, NULL, 2); /* AVCC3 */ -static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 0); +static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 3); static umode_t it87_in_is_visible(struct kobject *kobj, struct attribute *attr, int index) @@ -2014,9 +2171,10 @@ static struct attribute *it87_attributes_in[] = { &sensor_dev_attr_in8_input.dev_attr.attr, /* 40 */ &sensor_dev_attr_in9_input.dev_attr.attr, /* 41 */ - &sensor_dev_attr_in10_input.dev_attr.attr, /* 41 */ - &sensor_dev_attr_in11_input.dev_attr.attr, /* 41 */ - &sensor_dev_attr_in12_input.dev_attr.attr, /* 41 */ + &sensor_dev_attr_in10_input.dev_attr.attr, /* 42 */ + &sensor_dev_attr_in11_input.dev_attr.attr, /* 43 */ + &sensor_dev_attr_in12_input.dev_attr.attr, /* 44 */ + NULL }; static const struct attribute_group it87_group_in = { @@ -2272,7 +2430,7 @@ static umode_t it87_auto_pwm_is_visible(struct kobject *kobj, return 0; } if (has_old_autopwm(data)) { - if (a >= 9) /* no pwm_auto_start, pwm_auto_slope */ + if (a >= 9) /* no pwm_auto_start, pwm_auto_slope */ return 0; } @@ -2359,7 +2517,12 @@ static int __init it87_find(int sioaddr, unsigned short *address, return err; err = -ENODEV; - chip_type = force_id ? force_id : superio_inw(sioaddr, DEVID); + chip_type = superio_inw(sioaddr, DEVID); + if (chip_type == 0xffff) + goto exit; + + if (force_id) + chip_type = force_id; switch (chip_type) { case IT8705F_DEVID: @@ -2387,6 +2550,9 @@ static int __init it87_find(int sioaddr, unsigned short *address, case IT8732F_DEVID: sio_data->type = it8732; break; + case IT8792E_DEVID: + sio_data->type = it8792; + break; case IT8771E_DEVID: sio_data->type = it8771; break; @@ -2412,12 +2578,27 @@ static int __init it87_find(int sioaddr, unsigned short *address, case IT8623E_DEVID: sio_data->type = it8603; break; + case IT8607E_DEVID: + sio_data->type = it8607; + break; case IT8620E_DEVID: sio_data->type = it8620; break; + case IT8622E_DEVID: + sio_data->type = it8622; + break; case IT8628E_DEVID: sio_data->type = it8628; break; + case IT8655E_DEVID: + sio_data->type = it8655; + break; + case IT8665E_DEVID: + sio_data->type = it8665; + break; + case IT8686E_DEVID: + sio_data->type = it8686; + break; case 0xffff: /* No device at all */ goto exit; default: @@ -2458,8 +2639,12 @@ static int __init it87_find(int sioaddr, unsigned short *address, else sio_data->skip_in |= BIT(9); - if (!has_six_pwm(config)) + if (!has_four_pwm(config)) sio_data->skip_pwm |= BIT(3) | BIT(4) | BIT(5); + else if (!has_five_pwm(config)) + sio_data->skip_pwm |= BIT(4) | BIT(5); + else if (!has_six_pwm(config)) + sio_data->skip_pwm |= BIT(5); if (!has_vid(config)) sio_data->skip_vid = 1; @@ -2537,7 +2722,7 @@ static int __init it87_find(int sioaddr, unsigned short *address, sio_data->beep_pin = superio_inb(sioaddr, IT87_SIO_BEEP_PIN_REG) & 0x3f; - } else if (sio_data->type == it8603) { + } else if (sio_data->type == it8603 || sio_data->type == it8607) { int reg27, reg29; superio_select(sioaddr, GPIO); @@ -2557,12 +2742,15 @@ static int __init it87_find(int sioaddr, unsigned short *address, if (reg29 & BIT(2)) sio_data->skip_fan |= BIT(1); - sio_data->skip_in |= BIT(5); /* No VIN5 */ - sio_data->skip_in |= BIT(6); /* No VIN6 */ + if (sio_data->type == it8603) { + sio_data->skip_in |= BIT(5); /* No VIN5 */ + sio_data->skip_in |= BIT(6); /* No VIN6 */ + } sio_data->beep_pin = superio_inb(sioaddr, IT87_SIO_BEEP_PIN_REG) & 0x3f; - } else if (sio_data->type == it8620 || sio_data->type == it8628) { + } else if (sio_data->type == it8620 || sio_data->type == it8628 || + sio_data->type == it8686) { int reg; superio_select(sioaddr, GPIO); @@ -2588,7 +2776,7 @@ static int __init it87_find(int sioaddr, unsigned short *address, /* Check for pwm4 */ reg = superio_inb(sioaddr, IT87_SIO_GPIO4_REG); - if (!(reg & BIT(2))) + if (reg & BIT(2)) sio_data->skip_pwm |= BIT(3); /* Check for pwm2, fan2 */ @@ -2603,6 +2791,148 @@ static int __init it87_find(int sioaddr, unsigned short *address, sio_data->skip_fan |= BIT(5); } + /* Check if AVCC is on VIN3 */ + reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG); + if (reg & BIT(0)) { + /* For it8686, the bit just enables AVCC3 */ + if (sio_data->type != it8686) + sio_data->internal |= BIT(0); + } else { + sio_data->internal &= ~BIT(3); + sio_data->skip_in |= BIT(9); + } + + sio_data->beep_pin = superio_inb(sioaddr, + IT87_SIO_BEEP_PIN_REG) & 0x3f; + } else if (sio_data->type == it8622) { + int reg; + + superio_select(sioaddr, GPIO); + + /* Check for pwm4, fan4 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO1_REG); + if (reg & BIT(6)) + sio_data->skip_fan |= BIT(3); + if (reg & BIT(5)) + sio_data->skip_pwm |= BIT(3); + + /* Check for pwm3, fan3, pwm5, fan5 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG); + if (reg & BIT(6)) + sio_data->skip_pwm |= BIT(2); + if (reg & BIT(7)) + sio_data->skip_fan |= BIT(2); + if (reg & BIT(3)) + sio_data->skip_pwm |= BIT(4); + if (reg & BIT(1)) + sio_data->skip_fan |= BIT(4); + + /* Check for pwm2, fan2 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG); + if (reg & BIT(1)) + sio_data->skip_pwm |= BIT(1); + if (reg & BIT(2)) + sio_data->skip_fan |= BIT(1); + + /* Check for AVCC */ + reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG); + if (!(reg & BIT(0))) + sio_data->skip_in |= BIT(9); + + sio_data->beep_pin = superio_inb(sioaddr, + IT87_SIO_BEEP_PIN_REG) & 0x3f; + } else if (sio_data->type == it8732) { + int reg; + + superio_select(sioaddr, GPIO); + + /* Check for pwm2, fan2 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG); + if (reg & BIT(1)) + sio_data->skip_pwm |= BIT(1); + if (reg & BIT(2)) + sio_data->skip_fan |= BIT(1); + + /* Check for pwm3, fan3, fan4 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG); + if (reg & BIT(6)) + sio_data->skip_pwm |= BIT(2); + if (reg & BIT(7)) + sio_data->skip_fan |= BIT(2); + if (reg & BIT(5)) + sio_data->skip_fan |= BIT(3); + + /* Check if AVCC is on VIN3 */ + reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG); + if (reg & BIT(0)) + sio_data->internal |= BIT(0); + + sio_data->beep_pin = superio_inb(sioaddr, + IT87_SIO_BEEP_PIN_REG) & 0x3f; + } else if (sio_data->type == it8655) { + int reg; + + superio_select(sioaddr, GPIO); + + /* Check for pwm2 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG); + if (reg & BIT(1)) + sio_data->skip_pwm |= BIT(1); + + /* Check for fan2 */ + reg = superio_inb(sioaddr, IT87_SIO_PINX4_REG); + if (reg & BIT(4)) + sio_data->skip_fan |= BIT(1); + + /* Check for pwm3, fan3 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG); + if (reg & BIT(6)) + sio_data->skip_pwm |= BIT(2); + if (reg & BIT(7)) + sio_data->skip_fan |= BIT(2); + + sio_data->beep_pin = superio_inb(sioaddr, + IT87_SIO_BEEP_PIN_REG) & 0x3f; + } else if (sio_data->type == it8665) { + int reg; + + superio_select(sioaddr, GPIO); + + /* Check for pwm2 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG); + if (reg & BIT(1)) + sio_data->skip_pwm |= BIT(1); + + /* Check for fan2 */ + reg = superio_inb(sioaddr, IT87_SIO_PINX4_REG); + if (reg & BIT(4)) + sio_data->skip_fan |= BIT(1); + + /* Check for pwm3, fan3 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG); + if (reg & BIT(6)) + sio_data->skip_pwm |= BIT(2); + if (reg & BIT(7)) + sio_data->skip_fan |= BIT(2); + + /* Check for pwm5, fan5 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO2_REG); + if (reg & BIT(5)) + sio_data->skip_pwm |= BIT(4); + if (!(reg & BIT(4))) + sio_data->skip_fan |= BIT(4); + + /* Check for pwm4, fan4, pwm6, fan6 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO9_REG); + if (reg & BIT(2)) + sio_data->skip_pwm |= BIT(3); + if (reg & BIT(3)) + sio_data->skip_fan |= BIT(3); + if (reg & BIT(0)) + sio_data->skip_pwm |= BIT(5); + if (reg & BIT(1)) + sio_data->skip_fan |= BIT(5); + sio_data->beep_pin = superio_inb(sioaddr, IT87_SIO_BEEP_PIN_REG) & 0x3f; } else { @@ -2741,6 +3071,32 @@ static void it87_init_device(struct platform_device *pdev) int tmp, i; u8 mask; + /* Initialize chip specific register pointers */ + switch (data->type) { + case it8655: + case it8665: + data->REG_FAN = IT87_REG_FAN_8665; + data->REG_FANX = IT87_REG_FANX_8665; + data->REG_FAN_MIN = IT87_REG_FAN_MIN_8665; + data->REG_FANX_MIN = IT87_REG_FANX_MIN_8665; + data->REG_PWM = IT87_REG_PWM_8665; + break; + case it8622: + data->REG_FAN = IT87_REG_FAN; + data->REG_FANX = IT87_REG_FANX; + data->REG_FAN_MIN = IT87_REG_FAN_MIN; + data->REG_FANX_MIN = IT87_REG_FANX_MIN; + data->REG_PWM = IT87_REG_PWM_8665; + break; + default: + data->REG_FAN = IT87_REG_FAN; + data->REG_FANX = IT87_REG_FANX; + data->REG_FAN_MIN = IT87_REG_FAN_MIN; + data->REG_FANX_MIN = IT87_REG_FANX_MIN; + data->REG_PWM = IT87_REG_PWM; + break; + } + /* * For each PWM channel: * - If it is in automatic mode, setting to manual mode should set @@ -2816,26 +3172,43 @@ static void it87_init_device(struct platform_device *pdev) } /* Check for additional fans */ - if (has_five_fans(data)) { - if (tmp & BIT(4)) - data->has_fan |= BIT(3); /* fan4 enabled */ - if (tmp & BIT(5)) - data->has_fan |= BIT(4); /* fan5 enabled */ - if (has_six_fans(data) && (tmp & BIT(2))) - data->has_fan |= BIT(5); /* fan6 enabled */ + if (has_four_fans(data) && (tmp & BIT(4))) + data->has_fan |= BIT(3); /* fan4 enabled */ + if (has_five_fans(data) && (tmp & BIT(5))) + data->has_fan |= BIT(4); /* fan5 enabled */ + if (has_six_fans(data)) { + switch (data->type) { + case it8620: + case it8628: + case it8686: + if (tmp & BIT(2)) + data->has_fan |= BIT(5); /* fan6 enabled */ + break; + case it8665: + tmp = it87_read_value(data, IT87_REG_FAN_DIV); + if (tmp & BIT(3)) + data->has_fan |= BIT(5); /* fan6 enabled */ + break; + default: + break; + } } /* Fan input pins may be used for alternative functions */ data->has_fan &= ~sio_data->skip_fan; - /* Check if pwm5, pwm6 are enabled */ + /* Check if pwm6 is 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 |= BIT(4); - if (!(tmp & BIT(3))) - sio_data->skip_pwm |= BIT(5); + switch (data->type) { + case it8620: + case it8686: + tmp = it87_read_value(data, IT87_REG_FAN_DIV); + if (!(tmp & BIT(3))) + sio_data->skip_pwm |= BIT(5); + break; + default: + break; + } } /* Start monitoring */ @@ -2867,7 +3240,7 @@ static int it87_check_pwm(struct device *dev) for (i = 0; i < ARRAY_SIZE(pwm); i++) pwm[i] = it87_read_value(data, - IT87_REG_PWM[i]); + data->REG_PWM[i]); /* * If any fan is in automatic pwm mode, the polarity @@ -2882,7 +3255,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], + data->REG_PWM[i], 0x7f & ~pwm[i]); return 1; } @@ -2929,6 +3302,8 @@ static int it87_probe(struct platform_device *pdev) data->features = it87_devices[sio_data->type].features; data->peci_mask = it87_devices[sio_data->type].peci_mask; data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask; + data->bank = 0xff; + /* * IT8705F Datasheet 0.4.1, 3h == Version G. * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J. @@ -2965,7 +3340,7 @@ static int it87_probe(struct platform_device *pdev) enable_pwm_interface = it87_check_pwm(dev); /* Starting with IT8721F, we handle scaling of internal voltages */ - if (has_12mv_adc(data)) { + if (has_scaling(data)) { if (sio_data->internal & BIT(0)) data->in_scaled |= BIT(3); /* in3 is AVCC */ if (sio_data->internal & BIT(1))