X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fhwmon%2Ff71882fg.c;h=4146105f1a5779a5de55006444b9de99e90e8319;hb=708a62bcd5f699756bae81491e64648fbf19e2a4;hp=345f465aa28887101f6849f00520c1a0b984b1eb;hpb=ce0bfa5ee25ddbe4072b16054e809f552bf72320;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 345f465..4146105 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -1,6 +1,6 @@ /*************************************************************************** * Copyright (C) 2006 by Hans Edgington * - * Copyright (C) 2007,2008 by Hans de Goede * + * Copyright (C) 2007-2009 Hans de Goede * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -28,9 +28,11 @@ #include #include #include +#include #define DRVNAME "f71882fg" +#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */ #define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */ #define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */ #define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */ @@ -43,8 +45,10 @@ #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ +#define SIO_F71858_ID 0x0507 /* Chipset ID */ #define SIO_F71862_ID 0x0601 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */ +#define SIO_F8000_ID 0x0581 /* Chipset ID */ #define REGION_LENGTH 8 #define ADDR_REG_OFFSET 5 @@ -68,8 +72,8 @@ #define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr)) #define F71882FG_REG_TEMP_STATUS 0x62 #define F71882FG_REG_TEMP_BEEP 0x63 -#define F71882FG_REG_TEMP_HYST1 0x6C -#define F71882FG_REG_TEMP_HYST23 0x6D +#define F71882FG_REG_TEMP_CONFIG 0x69 +#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr)) #define F71882FG_REG_TEMP_TYPE 0x6B #define F71882FG_REG_TEMP_DIODE_OPEN 0x6F @@ -77,8 +81,7 @@ #define F71882FG_REG_PWM_TYPE 0x94 #define F71882FG_REG_PWM_ENABLE 0x96 -#define F71882FG_REG_FAN_HYST0 0x98 -#define F71882FG_REG_FAN_HYST1 0x99 +#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr)) #define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm))) #define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm))) @@ -92,17 +95,13 @@ static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); -static int fan_mode[4] = { 0, 0, 0, 0 }; -module_param_array(fan_mode, int, NULL, 0644); -MODULE_PARM_DESC(fan_mode, "List of fan control modes (f71882fg only) " - "(0=don't change, 1=pwm, 2=rpm)\n" - "Note: this needs a write to pwm#_enable to take effect"); - -enum chips { f71862fg, f71882fg }; +enum chips { f71858fg, f71862fg, f71882fg, f8000 }; static const char *f71882fg_names[] = { + "f71858fg", "f71862fg", "f71882fg", + "f8000", }; static struct platform_device *f71882fg_pdev; @@ -124,6 +123,7 @@ struct f71882fg_data { struct device *hwmon_dev; struct mutex update_lock; + int temp_start; /* temp numbering start (0 or 1) */ char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ unsigned long last_limits; /* In jiffies */ @@ -141,14 +141,15 @@ struct f71882fg_data { /* Note: all models have only 3 temperature channels, but on some they are addressed as 0-2 and on others as 1-3, so for coding convenience we reserve space for 4 channels */ - u8 temp[4]; + u16 temp[4]; u8 temp_ovt[4]; u8 temp_high[4]; - u8 temp_hyst[4]; + u8 temp_hyst[2]; /* 2 hysts stored per reg */ u8 temp_type[4]; u8 temp_status; u8 temp_beep; u8 temp_diode_open; + u8 temp_config; u8 pwm[4]; u8 pwm_enable; u8 pwm_auto_point_hyst[2]; @@ -252,11 +253,56 @@ static struct platform_driver f71882fg_driver = { .name = DRVNAME, }, .probe = f71882fg_probe, - .remove = __devexit_p(f71882fg_remove), + .remove = f71882fg_remove, }; static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +/* Temp and in attr for the f71858fg */ +static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = { + SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), + SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1), + SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2), + SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0), + SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 0), + SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0, 0), + SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0), + SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 0), + SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, + 0, 0), + SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4), + SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0), + SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1), + SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 1), + SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0, 1), + SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1), + SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 1), + SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, + 0, 1), + SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5), + SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1), + SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1), + SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2), + SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 2), + SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0, 2), + SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2), + SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 2), + SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, + 0, 2), + SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6), + SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), +}; + +/* Temp and in attr common to both the f71862fg and f71882fg */ static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = { SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1), @@ -272,45 +318,60 @@ static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = { store_temp_max, 0, 1), SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, store_temp_max_hyst, 0, 1), + /* Should really be temp1_max_alarm, but older versions did not handle + the max and crit alarms separately and lm_sensors v2 depends on the + presence of temp#_alarm files. The same goes for temp2/3 _alarm. */ + SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1), + SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 1), SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit, store_temp_crit, 0, 1), SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 0, 1), + SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5), + SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 5), SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1), - SENSOR_ATTR_2(temp1_beep, S_IRUGO|S_IWUSR, show_temp_beep, - store_temp_beep, 0, 1), - SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1), SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1), SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2), SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max, store_temp_max, 0, 2), SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, store_temp_max_hyst, 0, 2), + /* Should be temp2_max_alarm, see temp1_alarm note */ + SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2), + SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 2), SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit, store_temp_crit, 0, 2), SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 0, 2), + SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6), + SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 6), SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2), - SENSOR_ATTR_2(temp2_beep, S_IRUGO|S_IWUSR, show_temp_beep, - store_temp_beep, 0, 2), - SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2), SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3), SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max, store_temp_max, 0, 3), SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, store_temp_max_hyst, 0, 3), + /* Should be temp3_max_alarm, see temp1_alarm note */ + SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3), + SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 3), SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit, store_temp_crit, 0, 3), SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 0, 3), + SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7), + SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 7), SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3), - SENSOR_ATTR_2(temp3_beep, S_IRUGO|S_IWUSR, show_temp_beep, - store_temp_beep, 0, 3), - SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3), SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3), }; +/* Temp and in attr found only on the f71882fg */ static struct sensor_device_attribute_2 f71882fg_in_temp_attr[] = { SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max, 0, 1), @@ -319,27 +380,54 @@ static struct sensor_device_attribute_2 f71882fg_in_temp_attr[] = { SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1), }; -static struct sensor_device_attribute_2 f718x2fg_fan_attr[] = { +/* Temp and in attr for the f8000 + Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max) + is used as hysteresis value to clear alarms + */ +static struct sensor_device_attribute_2 f8000_in_temp_attr[] = { + SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), + SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1), + SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2), + SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0), + SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 0), + SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 0), + SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4), + SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0), + SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1), + SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 1), + SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 1), + SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5), + SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1), + SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1), + SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2), + SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0, 2), + SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0, 2), + SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6), + SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), +}; + +/* Fan / PWM attr common to all models */ +static struct sensor_device_attribute_2 fxxxx_fan_attr[] = { SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0), SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR, show_fan_full_speed, store_fan_full_speed, 0, 0), - SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 0), SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0), SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1), SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR, show_fan_full_speed, store_fan_full_speed, 0, 1), - SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 1), SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1), SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2), SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR, show_fan_full_speed, store_fan_full_speed, 0, 2), - SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 2), SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2), SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0), @@ -370,7 +458,16 @@ static struct sensor_device_attribute_2 f718x2fg_fan_attr[] = { store_pwm_auto_point_channel, 0, 2), }; +/* Fan / PWM attr for the f71862fg, less pwms and less zones per pwm than the + f71882fg */ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = { + SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 0), + SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 1), + SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 2), + SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 1, 0), @@ -408,17 +505,29 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = { 0, 1), SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO, show_pwm_auto_point_temp_hyst, NULL, 3, 1), -}; -static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { - SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), - SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR, - show_fan_full_speed, - store_fan_full_speed, 0, 3), - SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep, - store_fan_beep, 0, 3), - SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3), + SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 1, 2), + SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 4, 2), + SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 0, 2), + SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 3, 2), + SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp_hyst, + store_pwm_auto_point_temp_hyst, + 0, 2), + SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO, + show_pwm_auto_point_temp_hyst, NULL, 3, 2), +}; +/* Fan / PWM attr common to both the f71882fg and f71858fg */ +static struct sensor_device_attribute_2 f71882fg_f71858fg_fan_attr[] = { SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR, show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, 0, 0), @@ -532,6 +641,24 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { show_pwm_auto_point_temp_hyst, NULL, 2, 2), SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO, show_pwm_auto_point_temp_hyst, NULL, 3, 2), +}; + +/* Fan / PWM attr found on the f71882fg but not on the f71858fg */ +static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { + SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 0), + SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 1), + SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 2), + + SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), + SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR, + show_fan_full_speed, + store_fan_full_speed, 0, 3), + SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0, 3), + SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3), SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3), SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable, @@ -580,6 +707,126 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { show_pwm_auto_point_temp_hyst, NULL, 3, 3), }; +/* Fan / PWM attr for the f8000, zones mapped to temp instead of to pwm! + Also the register block at offset A0 maps to TEMP1 (so our temp2, as the + F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */ +static struct sensor_device_attribute_2 f8000_fan_attr[] = { + SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), + + SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 0, 2), + SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 1, 2), + SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 2, 2), + SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 3, 2), + SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 4, 2), + SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 0, 2), + SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 1, 2), + SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 2, 2), + SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 3, 2), + SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp_hyst, + store_pwm_auto_point_temp_hyst, + 0, 2), + SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO, + show_pwm_auto_point_temp_hyst, NULL, 1, 2), + SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO, + show_pwm_auto_point_temp_hyst, NULL, 2, 2), + SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO, + show_pwm_auto_point_temp_hyst, NULL, 3, 2), + + SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 0, 0), + SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 1, 0), + SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 2, 0), + SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 3, 0), + SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 4, 0), + SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 0, 0), + SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 1, 0), + SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 2, 0), + SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 3, 0), + SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp_hyst, + store_pwm_auto_point_temp_hyst, + 0, 0), + SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO, + show_pwm_auto_point_temp_hyst, NULL, 1, 0), + SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO, + show_pwm_auto_point_temp_hyst, NULL, 2, 0), + SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO, + show_pwm_auto_point_temp_hyst, NULL, 3, 0), + + SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 0, 1), + SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 1, 1), + SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 2, 1), + SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 3, 1), + SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR, + show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, + 4, 1), + SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 0, 1), + SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 1, 1), + SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 2, 1), + SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp, store_pwm_auto_point_temp, + 3, 1), + SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR, + show_pwm_auto_point_temp_hyst, + store_pwm_auto_point_temp_hyst, + 0, 1), + SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO, + show_pwm_auto_point_temp_hyst, NULL, 1, 1), + SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO, + show_pwm_auto_point_temp_hyst, NULL, 2, 1), + SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO, + show_pwm_auto_point_temp_hyst, NULL, 3, 1), +}; /* Super I/O functions */ static inline int superio_inb(int base, int reg) @@ -616,12 +863,12 @@ static inline void superio_exit(int base) outb(SIO_LOCK_KEY, base); } -static inline u16 fan_from_reg(u16 reg) +static inline int fan_from_reg(u16 reg) { return reg ? (1500000 / reg) : 0; } -static inline u16 fan_to_reg(u16 fan) +static inline u16 fan_to_reg(int fan) { return fan ? (1500000 / fan) : 0; } @@ -662,11 +909,20 @@ static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val) outb(val & 255, data->addr + DATA_REG_OFFSET); } +static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr) +{ + if (data->type == f71858fg) + return f71882fg_read16(data, F71882FG_REG_TEMP(nr)); + else + return f71882fg_read8(data, F71882FG_REG_TEMP(nr)); +} + static struct f71882fg_data *f71882fg_update_device(struct device *dev) { struct f71882fg_data *data = dev_get_drvdata(dev); - int nr, reg, reg2; - int nr_fans = (data->type == f71862fg) ? 3 : 4; + int nr, reg = 0, reg2; + int nr_fans = (data->type == f71882fg) ? 4 : 3; + int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9; mutex_lock(&data->update_lock); @@ -681,50 +937,53 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) } /* Get High & boundary temps*/ - for (nr = 1; nr < 4; nr++) { + for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) { data->temp_ovt[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_OVT(nr)); data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr)); } - /* Have to hardcode hyst*/ - data->temp_hyst[1] = f71882fg_read8(data, - F71882FG_REG_TEMP_HYST1) >> 4; - /* Hyst temps 2 & 3 stored in same register */ - reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST23); - data->temp_hyst[2] = reg & 0x0F; - data->temp_hyst[3] = reg >> 4; + if (data->type != f8000) { + data->temp_hyst[0] = f71882fg_read8(data, + F71882FG_REG_TEMP_HYST(0)); + data->temp_hyst[1] = f71882fg_read8(data, + F71882FG_REG_TEMP_HYST(1)); + } - /* Have to hardcode type, because temp1 is special */ - reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE); + if (data->type == f71862fg || data->type == f71882fg) { + data->fan_beep = f71882fg_read8(data, + F71882FG_REG_FAN_BEEP); + data->temp_beep = f71882fg_read8(data, + F71882FG_REG_TEMP_BEEP); + /* Have to hardcode type, because temp1 is special */ + reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE); + data->temp_type[2] = (reg & 0x04) ? 2 : 4; + data->temp_type[3] = (reg & 0x08) ? 2 : 4; + } reg2 = f71882fg_read8(data, F71882FG_REG_PECI); if ((reg2 & 0x03) == 0x01) data->temp_type[1] = 6 /* PECI */; else if ((reg2 & 0x03) == 0x02) data->temp_type[1] = 5 /* AMDSI */; - else + else if (data->type == f71862fg || data->type == f71882fg) data->temp_type[1] = (reg & 0x02) ? 2 : 4; - - data->temp_type[2] = (reg & 0x04) ? 2 : 4; - data->temp_type[3] = (reg & 0x08) ? 2 : 4; - - data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP); - - data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP); + else + data->temp_type[1] = 2; /* Only supports BJT */ data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); - data->pwm_auto_point_hyst[0] = f71882fg_read8(data, - F71882FG_REG_FAN_HYST0); - data->pwm_auto_point_hyst[1] = f71882fg_read8(data, - F71882FG_REG_FAN_HYST1); + data->pwm_auto_point_hyst[0] = + f71882fg_read8(data, F71882FG_REG_FAN_HYST(0)); + data->pwm_auto_point_hyst[1] = + f71882fg_read8(data, F71882FG_REG_FAN_HYST(1)); + for (nr = 0; nr < nr_fans; nr++) { data->pwm_auto_point_mapping[nr] = f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr)); - if (data->type == f71882fg) { + if (data->type != f71862fg) { int point; for (point = 0; point < 5; point++) { data->pwm_auto_point_pwm[nr][point] = @@ -766,9 +1025,8 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) F71882FG_REG_TEMP_STATUS); data->temp_diode_open = f71882fg_read8(data, F71882FG_REG_TEMP_DIODE_OPEN); - for (nr = 1; nr < 4; nr++) - data->temp[nr] = f71882fg_read8(data, - F71882FG_REG_TEMP(nr)); + for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) + data->temp[nr] = f71882fg_read_temp(data, nr); data->fan_status = f71882fg_read8(data, F71882FG_REG_FAN_STATUS); @@ -784,10 +1042,14 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) f71882fg_read8(data, F71882FG_REG_PWM(nr)); } + /* The f8000 can monitor 1 more fan, but has no pwm for it */ + if (data->type == f8000) + data->fan[3] = f71882fg_read16(data, + F71882FG_REG_FAN(3)); if (data->type == f71882fg) data->in_status = f71882fg_read8(data, F71882FG_REG_IN_STATUS); - for (nr = 0; nr < 9; nr++) + for (nr = 0; nr < nr_ins; nr++) data->in[nr] = f71882fg_read8(data, F71882FG_REG_IN(nr)); @@ -835,15 +1097,8 @@ static ssize_t store_fan_full_speed(struct device *dev, val = fan_to_reg(val); mutex_lock(&data->update_lock); - data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); - if (data->pwm_enable & (1 << (2 * nr))) - /* PWM mode */ - count = -EINVAL; - else { - /* RPM mode */ - f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val); - data->fan_full_speed[nr] = val; - } + f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val); + data->fan_full_speed[nr] = val; mutex_unlock(&data->update_lock); return count; @@ -974,8 +1229,24 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, { struct f71882fg_data *data = f71882fg_update_device(dev); int nr = to_sensor_dev_attr_2(devattr)->index; + int sign, temp; - return sprintf(buf, "%d\n", data->temp[nr] * 1000); + if (data->type == f71858fg) { + /* TEMP_TABLE_SEL 1 or 3 ? */ + if (data->temp_config & 1) { + sign = data->temp[nr] & 0x0001; + temp = (data->temp[nr] >> 5) & 0x7ff; + } else { + sign = data->temp[nr] & 0x8000; + temp = (data->temp[nr] >> 5) & 0x3ff; + } + temp *= 125; + if (sign) + temp -= 128000; + } else + temp = data->temp[nr] * 1000; + + return sprintf(buf, "%d\n", temp); } static ssize_t show_temp_max(struct device *dev, struct device_attribute @@ -1011,7 +1282,11 @@ static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute int temp_max_hyst; mutex_lock(&data->update_lock); - temp_max_hyst = (data->temp_high[nr] - data->temp_hyst[nr]) * 1000; + if (nr & 1) + temp_max_hyst = data->temp_hyst[nr / 2] >> 4; + else + temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f; + temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000; mutex_unlock(&data->update_lock); return sprintf(buf, "%d\n", temp_max_hyst); @@ -1033,26 +1308,15 @@ static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute val = SENSORS_LIMIT(val, data->temp_high[nr] - 15, data->temp_high[nr]); val = data->temp_high[nr] - val; - data->temp_hyst[nr] = val; /* convert value to register contents */ - switch (nr) { - case 1: - reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST1); - reg = (reg & 0x0f) | (val << 4); - break; - case 2: - reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST23); - reg = (reg & 0xf0) | val; - break; - case 3: - reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST23); - reg = (reg & 0x0f) | (val << 4); - break; - } - - f71882fg_write8(data, (nr <= 1) ? F71882FG_REG_TEMP_HYST1 : - F71882FG_REG_TEMP_HYST23, reg); + reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2)); + if (nr & 1) + reg = (reg & 0x0f) | (val << 4); + else + reg = (reg & 0xf0) | val; + f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg); + data->temp_hyst[nr / 2] = reg; mutex_unlock(&data->update_lock); return ret; @@ -1091,7 +1355,11 @@ static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute int temp_crit_hyst; mutex_lock(&data->update_lock); - temp_crit_hyst = (data->temp_ovt[nr] - data->temp_hyst[nr]) * 1000; + if (nr & 1) + temp_crit_hyst = data->temp_hyst[nr / 2] >> 4; + else + temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f; + temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000; mutex_unlock(&data->update_lock); return sprintf(buf, "%d\n", temp_crit_hyst); @@ -1191,6 +1459,11 @@ static ssize_t store_pwm(struct device *dev, mutex_lock(&data->update_lock); data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); + if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) || + (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) { + count = -EROFS; + goto leave; + } if (data->pwm_enable & (1 << (2 * nr))) { /* PWM mode */ f71882fg_write8(data, F71882FG_REG_PWM(nr), val); @@ -1205,6 +1478,7 @@ static ssize_t store_pwm(struct device *dev, data->fan_target[nr] = target; data->fan_full_speed[nr] = full_speed; } +leave: mutex_unlock(&data->update_lock); return count; @@ -1213,14 +1487,25 @@ static ssize_t store_pwm(struct device *dev, static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *devattr, char *buf) { - int result; + int result = 0; struct f71882fg_data *data = f71882fg_update_device(dev); int nr = to_sensor_dev_attr_2(devattr)->index; - if (data->pwm_enable & (2 << (2 * nr))) - result = 1; - else - result = 2; + switch ((data->pwm_enable >> 2 * nr) & 3) { + case 0: + case 1: + result = 2; /* Normal auto mode */ + break; + case 2: + result = 1; /* Manual mode */ + break; + case 3: + if (data->type == f8000) + result = 3; /* Thermostat mode */ + else + result = 1; /* Manual mode */ + break; + } return sprintf(buf, "%d\n", result); } @@ -1231,30 +1516,47 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute struct f71882fg_data *data = dev_get_drvdata(dev); int nr = to_sensor_dev_attr_2(devattr)->index; long val = simple_strtol(buf, NULL, 10); - if (val < 1 || val > 2) + + /* Special case for F8000 pwm channel 3 which only does auto mode */ + if (data->type == f8000 && nr == 2 && val != 2) return -EINVAL; mutex_lock(&data->update_lock); data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); - switch (val) { - case 1: - data->pwm_enable |= 2 << (2 * nr); - break; /* Manual */ - case 2: - data->pwm_enable &= ~(2 << (2 * nr)); - break; /* Temperature ctrl */ - } - if (data->type == f71882fg) { - switch (fan_mode[nr]) { + /* Special case for F8000 auto PWM mode / Thermostat mode */ + if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) { + switch (val) { + case 2: + data->pwm_enable &= ~(2 << (2 * nr)); + break; /* Normal auto mode */ + case 3: + data->pwm_enable |= 2 << (2 * nr); + break; /* Thermostat mode */ + default: + count = -EINVAL; + goto leave; + } + } else { + switch (val) { case 1: - data->pwm_enable |= 1 << (2 * nr); - break; /* Duty cycle mode */ + /* The f71858fg does not support manual RPM mode */ + if (data->type == f71858fg && + ((data->pwm_enable >> (2 * nr)) & 1)) { + count = -EINVAL; + goto leave; + } + data->pwm_enable |= 2 << (2 * nr); + break; /* Manual */ case 2: - data->pwm_enable &= ~(1 << (2 * nr)); - break; /* RPM mode */ + data->pwm_enable &= ~(2 << (2 * nr)); + break; /* Normal auto mode */ + default: + count = -EINVAL; + goto leave; } } f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable); +leave: mutex_unlock(&data->update_lock); return count; @@ -1320,20 +1622,10 @@ static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev, int point = to_sensor_dev_attr_2(devattr)->nr; mutex_lock(&data->update_lock); - switch (nr) { - case 0: - result = data->pwm_auto_point_hyst[0] & 0x0f; - break; - case 1: - result = data->pwm_auto_point_hyst[0] >> 4; - break; - case 2: - result = data->pwm_auto_point_hyst[1] & 0x0f; - break; - case 3: - result = data->pwm_auto_point_hyst[1] >> 4; - break; - } + if (nr & 1) + result = data->pwm_auto_point_hyst[nr / 2] >> 4; + else + result = data->pwm_auto_point_hyst[nr / 2] & 0x0f; result = 1000 * (data->pwm_auto_point_temp[nr][point] - result); mutex_unlock(&data->update_lock); @@ -1348,6 +1640,7 @@ static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev, int nr = to_sensor_dev_attr_2(devattr)->index; int point = to_sensor_dev_attr_2(devattr)->nr; long val = simple_strtol(buf, NULL, 10) / 1000; + u8 reg; mutex_lock(&data->update_lock); data->pwm_auto_point_temp[nr][point] = @@ -1356,34 +1649,14 @@ static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev, data->pwm_auto_point_temp[nr][point]); val = data->pwm_auto_point_temp[nr][point] - val; - if (nr == 0 || nr == 1) { - data->pwm_auto_point_hyst[0] = - f71882fg_read8(data, F71882FG_REG_FAN_HYST0); - } else { - data->pwm_auto_point_hyst[1] = - f71882fg_read8(data, F71882FG_REG_FAN_HYST1); - } - switch (nr) { - case 0: - val = (data->pwm_auto_point_hyst[0] & 0xf0) | val; - break; - case 1: - val = (data->pwm_auto_point_hyst[0] & 0x0f) | (val << 4); - break; - case 2: - val = (data->pwm_auto_point_hyst[1] & 0xf0) | val; - break; - case 3: - val = (data->pwm_auto_point_hyst[1] & 0x0f) | (val << 4); - break; - } - if (nr == 0 || nr == 1) { - f71882fg_write8(data, F71882FG_REG_FAN_HYST0, val); - data->pwm_auto_point_hyst[0] = val; - } else { - f71882fg_write8(data, F71882FG_REG_FAN_HYST1, val); - data->pwm_auto_point_hyst[1] = val; - } + reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2)); + if (nr & 1) + reg = (reg & 0x0f) | (val << 4); + else + reg = (reg & 0xf0) | val; + + f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg); + data->pwm_auto_point_hyst[nr / 2] = reg; mutex_unlock(&data->update_lock); return count; @@ -1431,7 +1704,8 @@ static ssize_t show_pwm_auto_point_channel(struct device *dev, struct f71882fg_data *data = f71882fg_update_device(dev); int nr = to_sensor_dev_attr_2(devattr)->index; - result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - 1); + result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - + data->temp_start); return sprintf(buf, "%d\n", result); } @@ -1443,19 +1717,21 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev, struct f71882fg_data *data = dev_get_drvdata(dev); int nr = to_sensor_dev_attr_2(devattr)->index; long val = simple_strtol(buf, NULL, 10); + switch (val) { case 1: - val = 1; + val = 0; break; case 2: - val = 2; + val = 1; break; case 4: - val = 3; + val = 2; break; default: return -EINVAL; } + val += data->temp_start; mutex_lock(&data->update_lock); data->pwm_auto_point_mapping[nr] = f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr)); @@ -1522,7 +1798,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) { struct f71882fg_data *data; struct f71882fg_sio_data *sio_data = pdev->dev.platform_data; - int err; + int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3; u8 start_reg; data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL); @@ -1531,66 +1807,132 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; data->type = sio_data->type; + data->temp_start = + (data->type == f71858fg || data->type == f8000) ? 0 : 1; mutex_init(&data->update_lock); platform_set_drvdata(pdev, data); start_reg = f71882fg_read8(data, F71882FG_REG_START); + if (start_reg & 0x04) { + dev_warn(&pdev->dev, "Hardware monitor is powered down\n"); + err = -ENODEV; + goto exit_free; + } if (!(start_reg & 0x03)) { dev_warn(&pdev->dev, "Hardware monitoring not activated\n"); err = -ENODEV; goto exit_free; } - /* If it is a 71862 and the fan / pwm part is enabled sanity check - the pwm settings */ - if (data->type == f71862fg && (start_reg & 0x02)) { - u8 reg = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); - if ((reg & 0x15) != 0x15) { - dev_err(&pdev->dev, - "Invalid (reserved) pwm settings: 0x%02x\n", - (unsigned int)reg); - err = -ENODEV; - goto exit_free; - } - } - /* Register sysfs interface files */ err = device_create_file(&pdev->dev, &dev_attr_name); if (err) goto exit_unregister_sysfs; if (start_reg & 0x01) { - err = f71882fg_create_sysfs_files(pdev, f718x2fg_in_temp_attr, - ARRAY_SIZE(f718x2fg_in_temp_attr)); - if (err) - goto exit_unregister_sysfs; - - if (data->type == f71882fg) { + switch (data->type) { + case f71858fg: + data->temp_config = + f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG); + if (data->temp_config & 0x10) + /* The f71858fg temperature alarms behave as + the f8000 alarms in this mode */ + err = f71882fg_create_sysfs_files(pdev, + f8000_in_temp_attr, + ARRAY_SIZE(f8000_in_temp_attr)); + else + err = f71882fg_create_sysfs_files(pdev, + f71858fg_in_temp_attr, + ARRAY_SIZE(f71858fg_in_temp_attr)); + break; + case f71882fg: err = f71882fg_create_sysfs_files(pdev, f71882fg_in_temp_attr, ARRAY_SIZE(f71882fg_in_temp_attr)); if (err) goto exit_unregister_sysfs; + /* fall through! */ + case f71862fg: + err = f71882fg_create_sysfs_files(pdev, + f718x2fg_in_temp_attr, + ARRAY_SIZE(f718x2fg_in_temp_attr)); + break; + case f8000: + err = f71882fg_create_sysfs_files(pdev, + f8000_in_temp_attr, + ARRAY_SIZE(f8000_in_temp_attr)); + break; } + if (err) + goto exit_unregister_sysfs; } if (start_reg & 0x02) { - err = f71882fg_create_sysfs_files(pdev, f718x2fg_fan_attr, - ARRAY_SIZE(f718x2fg_fan_attr)); + data->pwm_enable = + f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); + + /* Sanity check the pwm settings */ + switch (data->type) { + case f71858fg: + err = 0; + for (i = 0; i < nr_fans; i++) + if (((data->pwm_enable >> (i * 2)) & 3) == 3) + err = 1; + break; + case f71862fg: + err = (data->pwm_enable & 0x15) != 0x15; + break; + case f71882fg: + err = 0; + break; + case f8000: + err = data->pwm_enable & 0x20; + break; + } + if (err) { + dev_err(&pdev->dev, + "Invalid (reserved) pwm settings: 0x%02x\n", + (unsigned int)data->pwm_enable); + err = -ENODEV; + goto exit_unregister_sysfs; + } + + err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr, + ARRAY_SIZE(fxxxx_fan_attr)); if (err) goto exit_unregister_sysfs; - if (data->type == f71862fg) { + switch (data->type) { + case f71862fg: err = f71882fg_create_sysfs_files(pdev, f71862fg_fan_attr, ARRAY_SIZE(f71862fg_fan_attr)); - } else { + break; + case f71882fg: err = f71882fg_create_sysfs_files(pdev, f71882fg_fan_attr, ARRAY_SIZE(f71882fg_fan_attr)); + if (err) + goto exit_unregister_sysfs; + /* fall through! */ + case f71858fg: + err = f71882fg_create_sysfs_files(pdev, + f71882fg_f71858fg_fan_attr, + ARRAY_SIZE(f71882fg_f71858fg_fan_attr)); + break; + case f8000: + err = f71882fg_create_sysfs_files(pdev, + f8000_fan_attr, + ARRAY_SIZE(f8000_fan_attr)); + break; } if (err) goto exit_unregister_sysfs; + + for (i = 0; i < nr_fans; i++) + dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1, + (data->pwm_enable & (1 << 2 * i)) ? + "duty-cycle" : "RPM"); } data->hwmon_dev = hwmon_device_register(&pdev->dev); @@ -1619,6 +1961,8 @@ static int f71882fg_remove(struct platform_device *pdev) if (data->hwmon_dev) hwmon_device_unregister(data->hwmon_dev); + /* Note we are not looping over all attr arrays we have as the ones + below are supersets of the ones skipped. */ device_remove_file(&pdev->dev, &dev_attr_name); for (i = 0; i < ARRAY_SIZE(f718x2fg_in_temp_attr); i++) @@ -1629,15 +1973,15 @@ static int f71882fg_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &f71882fg_in_temp_attr[i].dev_attr); - for (i = 0; i < ARRAY_SIZE(f718x2fg_fan_attr); i++) - device_remove_file(&pdev->dev, &f718x2fg_fan_attr[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(f71862fg_fan_attr); i++) - device_remove_file(&pdev->dev, &f71862fg_fan_attr[i].dev_attr); + for (i = 0; i < ARRAY_SIZE(fxxxx_fan_attr); i++) + device_remove_file(&pdev->dev, &fxxxx_fan_attr[i].dev_attr); for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++) device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr); + for (i = 0; i < ARRAY_SIZE(f8000_fan_attr); i++) + device_remove_file(&pdev->dev, &f8000_fan_attr[i].dev_attr); + kfree(data); return 0; @@ -1653,24 +1997,34 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, devid = superio_inw(sioaddr, SIO_REG_MANID); if (devid != SIO_FINTEK_ID) { - printk(KERN_INFO DRVNAME ": Not a Fintek device\n"); + pr_debug(DRVNAME ": Not a Fintek device\n"); goto exit; } devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID); switch (devid) { + case SIO_F71858_ID: + sio_data->type = f71858fg; + break; case SIO_F71862_ID: sio_data->type = f71862fg; break; case SIO_F71882_ID: sio_data->type = f71882fg; break; + case SIO_F8000_ID: + sio_data->type = f8000; + break; default: printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n"); goto exit; } - superio_select(sioaddr, SIO_F71882FG_LD_HWM); + if (sio_data->type == f71858fg) + superio_select(sioaddr, SIO_F71858FG_LD_HWM); + else + superio_select(sioaddr, SIO_F71882FG_LD_HWM); + if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { printk(KERN_WARNING DRVNAME ": Device not activated\n"); goto exit; @@ -1708,6 +2062,10 @@ static int __init f71882fg_device_add(unsigned short address, return -ENOMEM; res.name = f71882fg_pdev->name; + err = acpi_check_resource_conflict(&res); + if (err) + goto exit_device_put; + err = platform_device_add_resources(f71882fg_pdev, &res, 1); if (err) { printk(KERN_ERR DRVNAME ": Device resource addition failed\n");