diff --git a/doc/chips/it87 b/doc/chips/it87 index 44eec175..893b0eba 100644 --- a/doc/chips/it87 +++ b/doc/chips/it87 @@ -62,7 +62,18 @@ Module Parameters thermistor diode thermistor 0x2a ** default thermistor thermistor diode 0x1c thermistor thermistor thermistor 0x38 - +* reset_it87: integer 1 if the registers of the chip should be reset at + module load time, 0 to not reset the registers. Default is 0. +* init: integer 1 if the registers should be initialized with the module's + default values, 0 skip the initialization. Default is 1. + On some boards (e.g. the Shuttle FN41 from the Shuttle XPC Barebone) + the BIOS configures it87's smart temperature monitoring fan power + adjust feature. A reset/init would unset this and set the power of the + fan to maximum speed (which is very noisy). Set 'reset_it87=0' to + keep the registers at the preconfigured values. + Note: If the registers weren't preconfigured for monitoring by the BIOS + the monitoring will not work if you do not reset and initialize the chip's + registers at module load time. Description ----------- @@ -112,6 +123,61 @@ miss once-only alarms. The IT87xx only updates its values each 1.5 seconds; reading it more often will do no harm, but will return 'old' values. +The fan speed control features can be enabled by setting the bits 0-2 of +the fan_ctl register to 1. (Note: bits 6-4 of this register must be set to +1 to enable the fan monitoring). +0x40 : enable fan speed monitoring for fan3 +0x20 : enable fan speed monitoring for fan2 +0x10 : enable fan speed monitoring for fan1 +0x04 : enable fan smart guardian mode for fan3 +0x02 : enable fan smart guardian mode for fan2 +0x01 : enable fan smart guardian mode for fan1 +If a fans smart guardian bit is not set this fan is in on-off mode +it can be switched on or off by setting/clearing the corresponding bit 0-2 +of the second fan control register fan_on_off. This register has no effect if +a fan is in smart guardian mode. +0x04 : fan3 is on +0x02 : fan2 is on +0x01 : fan1 is on +Bit 7 of the pwm[1-3] registers enables/disables the chips automatic +temperature control mode for the specified fan. If Bit 7 is set the bits +1 and 0 encode the number of the temperature sensor used for this feature. +Possible register values are: +0x00-0x7f direct power control for the fan speed +0x80 automatic smart guardian mode use temperatur sensor 1, +0x81 automatic smart guardian mode use temperatur sensor 2, +0x82 automatic smart guardian mode use temperatur sensor 3 +In automatic smart guardian mode pwm values for low, medium and high speed +can be set in sg_pwm[1-3]. The temperature limits for fan off, low, medium, +hi speed and over temperature are set in sg_tl[1-3]. While the sensors +temperature is between the low and medium speed value the fan will run in +low speed. When the sensors temperature is between the medium and high speed +value the fan spins in medium speed. When the sensors temperature is between +the high speed and over temperature value the fan spins in high speed. +If the sensors temperature is higher than the over temperature limit the +fan will spin with the highest possible speed. +Example: +The preconfigured (BIOS set) values of the Shuttle XPC SN41G2 Barebone. +The MB uses temp2 to monitor the CPU temperature and fan3 as the fan for their +special ICE heatpipe cooling system. +--- +$ cat fan_ctl +116 +$ cat tan_on_off +215 +$ cat pwm3 +129 +$ cat sg_tl3 +16.0 16.0 48.0 54.0 58.0 +$ cat sg_pwm3 +3 4 9 +--- +Explanation: +fan_ctl -> 116 = 0x74 = 01110100 : fan monitoring on for all fans, and fan3 is in smart guardian mode. +fan_on_off -> 215 = 0xd7 =11010111 : all fans are on this setting is ignored for fan3 which is in smart guardian mode +pwm3 -> 129 = 0x81 = 10000001 : fan3 is in automatic mode and uses temp2 for speed control +sg_tl3 -> 16.0 16.0 48.0 54.0 58.0 : off, low, med, high, and over temperature limits of fan3 +sg_pwm3 -> 3 4 9 : pwm values for low, medium and high fan speed of fan3. Chip features ------------- diff --git a/kernel/chips/it87.c b/kernel/chips/it87.c index 8be86e67..5b618043 100644 --- a/kernel/chips/it87.c +++ b/kernel/chips/it87.c @@ -31,6 +31,13 @@ type at module load time. */ +/* + michael.hufer@gmx.de Michael Hufer 09/07/03 + Modified configure (enable/disable) chip reset at module load time. + Added ability to read and set fan pwm registers and the smart + guardian (sg) features of the chip. +*/ + #include #include #include @@ -65,6 +72,12 @@ static int update_vbat = 0; /* Enable Temp3 as thermal resistor */ static int temp_type = 0x2a; +/* Reset the registers on init */ +static int reset_it87 = 0; + +/* Initialize the registers to default values on init */ +static int init = 1; + /* Many IT87 constants specified below */ /* Length of ISA address segment */ @@ -85,12 +98,25 @@ static int temp_type = 0x2a; #define IT87_REG_VID 0x0a #define IT87_REG_FAN_DIV 0x0b -/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ - #define IT87_REG_FAN(nr) (0x0c + (nr)) #define IT87_REG_FAN_MIN(nr) (0x0f + (nr)) #define IT87_REG_FAN_CTRL 0x13 +/* pwm and smart guardian registers */ + +#define IT87_REG_FAN_ONOFF 0x14 +#define IT87_REG_PWM(nr) (0x14 + (nr)) +#define IT87_REG_SG_TL_OFF(nr) (0x58 + (nr)*8) +#define IT87_REG_SG_TL_LOW(nr) (0x59 + (nr)*8) +#define IT87_REG_SG_TL_MED(nr) (0x5a + (nr)*8) +#define IT87_REG_SG_TL_HI(nr) (0x5b + (nr)*8) +#define IT87_REG_SG_TL_OVR(nr) (0x5c + (nr)*8) +#define IT87_REG_SG_PWM_LOW(nr) (0x5d + (nr)*8) +#define IT87_REG_SG_PWM_MED(nr) (0x5e + (nr)*8) +#define IT87_REG_SG_PWM_HI(nr) (0x5f + (nr)*8) + +/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ + #define IT87_REG_VIN(nr) (0x20 + (nr)) #define IT87_REG_TEMP(nr) (0x28 + (nr)) @@ -133,7 +159,17 @@ static inline u8 FAN_TO_REG(long rpm, int div) 205-(val)*5) #define ALARMS_FROM_REG(val) (val) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) +extern inline u8 DIV_TO_REG(long val) +{ + u8 i; + for( i = 0; i <= 7; i++ ) + { + if( val>>i == 1 ) + return i; + } + return 1; +} +/*#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)*/ #define DIV_FROM_REG(val) (1 << (val)) /* Initial limits. Use the config file to set better limits. */ @@ -186,12 +222,23 @@ static inline u8 FAN_TO_REG(long rpm, int div) #define IT87_INIT_FAN_MIN_3 3000 #define IT87_INIT_TEMP_HIGH_1 600 -#define IT87_INIT_TEMP_LOW_1 200 +#define IT87_INIT_TEMP_LOW_1 540 #define IT87_INIT_TEMP_HIGH_2 600 #define IT87_INIT_TEMP_LOW_2 200 -#define IT87_INIT_TEMP_HIGH_3 600 +#define IT87_INIT_TEMP_HIGH_3 600 #define IT87_INIT_TEMP_LOW_3 200 +#define IT87_INIT_PWR_TL_OFF 160 +#define IT87_INIT_PWR_TL_LOW 160 +#define IT87_INIT_PWR_TL_MED 480 +#define IT87_INIT_PWR_TL_HI 540 +#define IT87_INIT_PWR_TL_OVR 580 + +#define IT87_INIT_PWR_LOW 3 +#define IT87_INIT_PWR_MED 4 +#define IT87_INIT_PWR_HI 9 + + /* For each registered IT87, we need to keep some data in memory. That data is pointed to by it87_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new it87 client is @@ -216,6 +263,10 @@ struct it87_data { u8 fan_div[3]; /* Register encoding, shifted right */ u8 vid; /* Register encoding, combined */ u32 alarms; /* Register encoding, combined */ + u8 pwm[3]; /* Register value */ + u8 fan_ctl[2]; /* Register encoding */ + u8 sg_tl[3][5]; /* Register value */ + u8 sg_pwm[3][3]; /* Register value */ }; @@ -243,6 +294,14 @@ static void it87_alarms(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); static void it87_fan_div(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); +static void it87_fan_ctl(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void it87_pwm(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void it87_sgpwm(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void it87_sgtl(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); static struct i2c_driver it87_driver = { .owner = THIS_MODULE, @@ -277,6 +336,13 @@ static int it87_id = 0; #define IT87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ #define IT87_SYSCTL_ALARMS 2004 /* bitvector */ +#define IT87_SYSCTL_PWM1 1401 +#define IT87_SYSCTL_PWM2 1402 +#define IT87_SYSCTL_PWM3 1403 +#define IT87_SYSCTL_FAN_CTL 1501 +#define IT87_SYSCTL_FAN_ON_OFF 1502 + + #define IT87_ALARM_IN0 0x000100 #define IT87_ALARM_IN1 0x000200 #define IT87_ALARM_IN2 0x000400 @@ -336,6 +402,28 @@ static ctl_table it87_dir_table_template[] = { &i2c_sysctl_real, NULL, &it87_fan_div}, {IT87_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &it87_alarms}, + {IT87_SYSCTL_FAN_CTL, "fan_ctl", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &it87_fan_ctl}, + {IT87_SYSCTL_FAN_ON_OFF, "fan_on_off", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &it87_fan_ctl}, + {IT87_SYSCTL_PWM1, "pwm1", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &it87_pwm}, + {IT87_SYSCTL_PWM2, "pwm2", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &it87_pwm}, + {IT87_SYSCTL_PWM3, "pwm3", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &it87_pwm}, + {IT87_SYSCTL_PWM1, "sg_pwm1", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &it87_sgpwm}, + {IT87_SYSCTL_PWM2, "sg_pwm2", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &it87_sgpwm}, + {IT87_SYSCTL_PWM3, "sg_pwm3", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &it87_sgpwm}, + {IT87_SYSCTL_PWM1, "sg_tl1", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &it87_sgtl}, + {IT87_SYSCTL_PWM2, "sg_tl2", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &it87_sgtl}, + {IT87_SYSCTL_PWM3, "sg_tl3", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &it87_sgtl}, {0} }; @@ -563,74 +651,81 @@ static int it87_write_value(struct i2c_client *client, u8 reg, u8 value) /* Called when we have found a new IT87. It should set limits, etc. */ static void it87_init_client(struct i2c_client *client) { + if( init ) + { /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ - it87_write_value(client, IT87_REG_CONFIG, 0x80); - it87_write_value(client, IT87_REG_VIN_MIN(0), - IN_TO_REG(IT87_INIT_IN_MIN_0)); - it87_write_value(client, IT87_REG_VIN_MAX(0), - IN_TO_REG(IT87_INIT_IN_MAX_0)); - it87_write_value(client, IT87_REG_VIN_MIN(1), - IN_TO_REG(IT87_INIT_IN_MIN_1)); - it87_write_value(client, IT87_REG_VIN_MAX(1), - IN_TO_REG(IT87_INIT_IN_MAX_1)); - it87_write_value(client, IT87_REG_VIN_MIN(2), - IN_TO_REG(IT87_INIT_IN_MIN_2)); - it87_write_value(client, IT87_REG_VIN_MAX(2), - IN_TO_REG(IT87_INIT_IN_MAX_2)); - it87_write_value(client, IT87_REG_VIN_MIN(3), - IN_TO_REG(IT87_INIT_IN_MIN_3)); - it87_write_value(client, IT87_REG_VIN_MAX(3), - IN_TO_REG(IT87_INIT_IN_MAX_3)); - it87_write_value(client, IT87_REG_VIN_MIN(4), - IN_TO_REG(IT87_INIT_IN_MIN_4)); - it87_write_value(client, IT87_REG_VIN_MAX(4), - IN_TO_REG(IT87_INIT_IN_MAX_4)); - it87_write_value(client, IT87_REG_VIN_MIN(5), - IN_TO_REG(IT87_INIT_IN_MIN_5)); - it87_write_value(client, IT87_REG_VIN_MAX(5), - IN_TO_REG(IT87_INIT_IN_MAX_5)); - it87_write_value(client, IT87_REG_VIN_MIN(6), - IN_TO_REG(IT87_INIT_IN_MIN_6)); - it87_write_value(client, IT87_REG_VIN_MAX(6), - IN_TO_REG(IT87_INIT_IN_MAX_6)); - it87_write_value(client, IT87_REG_VIN_MIN(7), - IN_TO_REG(IT87_INIT_IN_MIN_7)); - it87_write_value(client, IT87_REG_VIN_MAX(7), - IN_TO_REG(IT87_INIT_IN_MAX_7)); - /* Note: Battery voltage does not have limit registers */ - it87_write_value(client, IT87_REG_FAN_MIN(1), - FAN_TO_REG(IT87_INIT_FAN_MIN_1, 2)); - it87_write_value(client, IT87_REG_FAN_MIN(2), - FAN_TO_REG(IT87_INIT_FAN_MIN_2, 2)); - it87_write_value(client, IT87_REG_FAN_MIN(3), - FAN_TO_REG(IT87_INIT_FAN_MIN_3, 2)); - it87_write_value(client, IT87_REG_TEMP_HIGH(1), - TEMP_TO_REG(IT87_INIT_TEMP_HIGH_1)); - it87_write_value(client, IT87_REG_TEMP_LOW(1), - TEMP_TO_REG(IT87_INIT_TEMP_LOW_1)); - it87_write_value(client, IT87_REG_TEMP_HIGH(2), - TEMP_TO_REG(IT87_INIT_TEMP_HIGH_2)); - it87_write_value(client, IT87_REG_TEMP_LOW(2), - TEMP_TO_REG(IT87_INIT_TEMP_LOW_2)); - it87_write_value(client, IT87_REG_TEMP_HIGH(3), - TEMP_TO_REG(IT87_INIT_TEMP_HIGH_3)); - it87_write_value(client, IT87_REG_TEMP_LOW(3), - TEMP_TO_REG(IT87_INIT_TEMP_LOW_3)); + This sets fan-divs to 2, among others. + It will also reset the automatic temperature controlled fan + speed (noise) control the BIOS configured on POST and the + fan will be set to propably noisy full speed operation */ + if( reset_it87 ) { + it87_write_value(client, IT87_REG_CONFIG, 0x80); + } + it87_write_value(client, IT87_REG_VIN_MIN(0), + IN_TO_REG(IT87_INIT_IN_MIN_0)); + it87_write_value(client, IT87_REG_VIN_MAX(0), + IN_TO_REG(IT87_INIT_IN_MAX_0)); + it87_write_value(client, IT87_REG_VIN_MIN(1), + IN_TO_REG(IT87_INIT_IN_MIN_1)); + it87_write_value(client, IT87_REG_VIN_MAX(1), + IN_TO_REG(IT87_INIT_IN_MAX_1)); + it87_write_value(client, IT87_REG_VIN_MIN(2), + IN_TO_REG(IT87_INIT_IN_MIN_2)); + it87_write_value(client, IT87_REG_VIN_MAX(2), + IN_TO_REG(IT87_INIT_IN_MAX_2)); + it87_write_value(client, IT87_REG_VIN_MIN(3), + IN_TO_REG(IT87_INIT_IN_MIN_3)); + it87_write_value(client, IT87_REG_VIN_MAX(3), + IN_TO_REG(IT87_INIT_IN_MAX_3)); + it87_write_value(client, IT87_REG_VIN_MIN(4), + IN_TO_REG(IT87_INIT_IN_MIN_4)); + it87_write_value(client, IT87_REG_VIN_MAX(4), + IN_TO_REG(IT87_INIT_IN_MAX_4)); + it87_write_value(client, IT87_REG_VIN_MIN(5), + IN_TO_REG(IT87_INIT_IN_MIN_5)); + it87_write_value(client, IT87_REG_VIN_MAX(5), + IN_TO_REG(IT87_INIT_IN_MAX_5)); + it87_write_value(client, IT87_REG_VIN_MIN(6), + IN_TO_REG(IT87_INIT_IN_MIN_6)); + it87_write_value(client, IT87_REG_VIN_MAX(6), + IN_TO_REG(IT87_INIT_IN_MAX_6)); + it87_write_value(client, IT87_REG_VIN_MIN(7), + IN_TO_REG(IT87_INIT_IN_MIN_7)); + it87_write_value(client, IT87_REG_VIN_MAX(7), + IN_TO_REG(IT87_INIT_IN_MAX_7)); + /* Note: Battery voltage does not have limit registers */ + it87_write_value(client, IT87_REG_FAN_MIN(1), + FAN_TO_REG(IT87_INIT_FAN_MIN_1, 2)); + it87_write_value(client, IT87_REG_FAN_MIN(2), + FAN_TO_REG(IT87_INIT_FAN_MIN_2, 2)); + it87_write_value(client, IT87_REG_FAN_MIN(3), + FAN_TO_REG(IT87_INIT_FAN_MIN_3, 2)); + it87_write_value(client, IT87_REG_TEMP_HIGH(1), + TEMP_TO_REG(IT87_INIT_TEMP_HIGH_1)); + it87_write_value(client, IT87_REG_TEMP_LOW(1), + TEMP_TO_REG(IT87_INIT_TEMP_LOW_1)); + it87_write_value(client, IT87_REG_TEMP_HIGH(2), + TEMP_TO_REG(IT87_INIT_TEMP_HIGH_2)); + it87_write_value(client, IT87_REG_TEMP_LOW(2), + TEMP_TO_REG(IT87_INIT_TEMP_LOW_2)); + it87_write_value(client, IT87_REG_TEMP_HIGH(3), + TEMP_TO_REG(IT87_INIT_TEMP_HIGH_3)); + it87_write_value(client, IT87_REG_TEMP_LOW(3), + TEMP_TO_REG(IT87_INIT_TEMP_LOW_3)); - /* Enable voltage monitors */ - it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff); + /* Enable voltage monitors */ + it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff); - /* Enable Temp1-Temp3 */ - it87_write_value(client, IT87_REG_TEMP_ENABLE, - (it87_read_value(client, IT87_REG_TEMP_ENABLE) & 0xc0) - | (temp_type & 0x3f)); - - /* Enable fans */ - it87_write_value(client, IT87_REG_FAN_CTRL, - (it87_read_value(client, IT87_REG_FAN_CTRL) & 0x8f) - | 0x70); + /* Enable Temp1-Temp3 */ + it87_write_value(client, IT87_REG_TEMP_ENABLE, + (it87_read_value(client, IT87_REG_TEMP_ENABLE) & 0xc0) + | (temp_type & 0x3f)); + /* Enable fans */ + it87_write_value(client, IT87_REG_FAN_CTRL, + (it87_read_value(client, IT87_REG_FAN_CTRL) & 0x8f) + | 0x70); + } /* Start monitoring */ it87_write_value(client, IT87_REG_CONFIG, (it87_read_value(client, IT87_REG_CONFIG) & 0xb7) @@ -648,8 +743,8 @@ static void it87_update_client(struct i2c_client *client) (jiffies < data->last_updated) || !data->valid) { if (update_vbat) { - /* Cleared after each update, so reenable. Value - returned by this read will be previous value */ + /* Cleared after each update, so reenable. Value + returned by this read will be previous value */ it87_write_value(client, IT87_REG_CONFIG, it87_read_value(client, IT87_REG_CONFIG) | 0x40); } @@ -663,7 +758,7 @@ static void it87_update_client(struct i2c_client *client) } data->in[8] = it87_read_value(client, IT87_REG_VIN(8)); - /* Temperature sensor doesn't have limit registers, set + /* VBAT sensor doesn't have limit registers, set to min and max value */ data->in_min[8] = 0; data->in_max[8] = 255; @@ -695,13 +790,25 @@ static void it87_update_client(struct i2c_client *client) i = it87_read_value(client, IT87_REG_FAN_DIV); data->fan_div[0] = i & 0x07; data->fan_div[1] = (i >> 3) & 0x07; - data->fan_div[2] = 1; + data->fan_div[2] = ( (i&0x40)==0x40 ? 3 : 1 ); + for( i = 1; i <= 3; i++ ) { + data->pwm[i-1] = it87_read_value(client, IT87_REG_PWM(i)); + data->sg_tl[i-1][0] = it87_read_value(client, IT87_REG_SG_TL_OFF(i)); + data->sg_tl[i-1][1] = it87_read_value(client, IT87_REG_SG_TL_LOW(i)); + data->sg_tl[i-1][2] = it87_read_value(client, IT87_REG_SG_TL_MED(i)); + data->sg_tl[i-1][3] = it87_read_value(client, IT87_REG_SG_TL_HI(i)); + data->sg_tl[i-1][4] = it87_read_value(client, IT87_REG_SG_TL_OVR(i)); + data->sg_pwm[i-1][0] = it87_read_value(client, IT87_REG_SG_PWM_LOW(i)); + data->sg_pwm[i-1][1] = it87_read_value(client, IT87_REG_SG_PWM_MED(i)); + data->sg_pwm[i-1][2] = it87_read_value(client, IT87_REG_SG_PWM_HI(i)); + } data->alarms = it87_read_value(client, IT87_REG_ALARM1) | (it87_read_value(client, IT87_REG_ALARM2) << 8) | (it87_read_value(client, IT87_REG_ALARM3) << 16); - + data->fan_ctl[0] = it87_read_value(client, IT87_REG_FAN_CTRL); + data->fan_ctl[1] = it87_read_value(client, IT87_REG_FAN_ONOFF); data->last_updated = jiffies; data->valid = 1; } @@ -763,19 +870,14 @@ void it87_fan(struct i2c_client *client, int operation, int ctl_name, else if (operation == SENSORS_PROC_REAL_READ) { it87_update_client(client); results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data-> - fan_div[nr - 1])); - results[1] = - FAN_FROM_REG(data->fan[nr - 1], + DIV_FROM_REG(data->fan_div[nr - 1])); + results[1] = FAN_FROM_REG(data->fan[nr - 1], DIV_FROM_REG(data->fan_div[nr - 1])); *nrels_mag = 2; } else if (operation == SENSORS_PROC_REAL_WRITE) { if (*nrels_mag >= 1) { data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr - - 1])); + DIV_FROM_REG(data->fan_div[nr - 1])); it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr - 1]); } @@ -810,6 +912,93 @@ void it87_temp(struct i2c_client *client, int operation, int ctl_name, } } +void it87_pwm(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct it87_data *data = client->data; + int nr = ctl_name - IT87_SYSCTL_PWM1 + 1; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + it87_update_client(client); + results[0] = data->pwm[nr - 1]; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->pwm[nr - 1] = results[0]; + it87_write_value(client, IT87_REG_PWM(nr), data->pwm[nr - 1]); + } + } +} + +void it87_sgpwm(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct it87_data *data = client->data; + int nr = ctl_name - IT87_SYSCTL_PWM1 + 1; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + it87_update_client(client); + results[0] = data->sg_pwm[nr - 1][0]; + results[1] = data->sg_pwm[nr - 1][1]; + results[2] = data->sg_pwm[nr - 1][2]; + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->sg_pwm[nr - 1][0] = results[0]; + it87_write_value(client, IT87_REG_SG_PWM_LOW(nr), data->sg_pwm[nr - 1][0]); + } + if (*nrels_mag >= 2) { + data->sg_pwm[nr - 1][1] = results[1]; + it87_write_value(client, IT87_REG_SG_PWM_MED(nr), data->sg_pwm[nr - 1][1]); + } + if (*nrels_mag >= 3) { + data->sg_pwm[nr - 1][2] = results[2]; + it87_write_value(client, IT87_REG_SG_PWM_HI(nr), data->sg_pwm[nr - 1][2]); + } + } +} + +void it87_sgtl(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct it87_data *data = client->data; + int nr = ctl_name - IT87_SYSCTL_PWM1 + 1; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 1; + else if (operation == SENSORS_PROC_REAL_READ) { + it87_update_client(client); + results[0] = TEMP_FROM_REG(data->sg_tl[nr - 1][0]); + results[1] = TEMP_FROM_REG(data->sg_tl[nr - 1][1]); + results[2] = TEMP_FROM_REG(data->sg_tl[nr - 1][2]); + results[3] = TEMP_FROM_REG(data->sg_tl[nr - 1][3]); + results[4] = TEMP_FROM_REG(data->sg_tl[nr - 1][4]); + *nrels_mag = 5; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->sg_tl[nr - 1][0] = TEMP_TO_REG(results[0]); + it87_write_value(client, IT87_REG_SG_TL_OFF(nr), data->sg_pwm[nr - 1][0]); + } + if (*nrels_mag >= 2) { + data->sg_tl[nr - 1][1] = TEMP_TO_REG(results[1]); + it87_write_value(client, IT87_REG_SG_TL_LOW(nr), data->sg_pwm[nr - 1][1]); + } + if (*nrels_mag >= 3) { + data->sg_tl[nr - 1][2] = TEMP_TO_REG(results[2]); + it87_write_value(client, IT87_REG_SG_TL_MED(nr), data->sg_pwm[nr - 1][2]); + } + if (*nrels_mag >= 4) { + data->sg_tl[nr - 1][3] = TEMP_TO_REG(results[3]); + it87_write_value(client, IT87_REG_SG_TL_HI(nr), data->sg_pwm[nr - 1][3]); + } + if (*nrels_mag >= 5) { + data->sg_tl[nr - 1][4] = TEMP_TO_REG(results[4]); + it87_write_value(client, IT87_REG_SG_TL_OVR(nr), data->sg_pwm[nr - 1][4]); + } + } +} + void it87_vid(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { @@ -848,10 +1037,19 @@ void it87_fan_div(struct i2c_client *client, int operation, int ctl_name, it87_update_client(client); results[0] = DIV_FROM_REG(data->fan_div[0]); results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = 2; + results[2] = DIV_FROM_REG(data->fan_div[2]);; *nrels_mag = 3; } else if (operation == SENSORS_PROC_REAL_WRITE) { old = it87_read_value(client, IT87_REG_FAN_DIV); + if (*nrels_mag >= 3) { + data->fan_div[2] = DIV_TO_REG(results[2]); + if( data->fan[2]!=3 ) { + data->fan_div[2] = 1; + old = (old & 0xbf); + } else { + old = (old | 0x40); + } + } if (*nrels_mag >= 2) { data->fan_div[1] = DIV_TO_REG(results[1]); old = (old & 0xc3) | (data->fan_div[1] << 3); @@ -864,6 +1062,28 @@ void it87_fan_div(struct i2c_client *client, int operation, int ctl_name, } } +void it87_fan_ctl(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct it87_data *data = client->data; + int index = ctl_name - IT87_SYSCTL_FAN_CTL; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + it87_update_client(client); + results[0] = data->fan_ctl[index]; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->fan_ctl[index] = results[0]; + if( index == 0 ) + it87_write_value(client, IT87_REG_FAN_CTRL, data->fan_ctl[index] ); + else + it87_write_value(client, IT87_REG_FAN_ONOFF, data->fan_ctl[index] ); + } + } +} + static int __init sm_it87_init(void) { printk("it87.o version %s (%s)\n", LM_VERSION, LM_DATE); @@ -883,6 +1103,10 @@ MODULE_PARM(update_vbat, "i"); MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); MODULE_PARM(temp_type, "i"); MODULE_PARM_DESC(temp_type, "Temperature sensor type, normally leave unset"); +MODULE_PARM(init, "i"); +MODULE_PARM_DESC(init, "Initialize the chip's registers, default yes"); +MODULE_PARM(reset_it87, "i"); +MODULE_PARM_DESC(reset_it87, "Reset the chip's registers, default no"); module_init(sm_it87_init); module_exit(sm_it87_exit);