From 1704b26ee3fd89c76724cbea238e951dc019faca Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 30 Mar 2009 21:46:42 +0200 Subject: hwmon: (w83627ehf) Invert fan pin variables logic Use positive logic for fan pin variables (variable is set if pin is used for fan), instead of negative logic which is error prone. Signed-off-by: Jean Delvare Cc: Gong Jun --- drivers/hwmon/w83627ehf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/hwmon/w83627ehf.c') diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index feae743ba991..18432e34dc7a 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1317,8 +1317,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) /* fan4 and fan5 share some pins with the GPIO and serial flash */ - fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2; - fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6; + fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x2); + fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x6); superio_exit(sio_data->sioreg); /* It looks like fan4 and fan5 pins can be alternatively used @@ -1329,9 +1329,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) data->has_fan = 0x07; /* fan1, fan2 and fan3 */ i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); - if ((i & (1 << 2)) && (!fan4pin)) + if ((i & (1 << 2)) && fan4pin) data->has_fan |= (1 << 3); - if (!(i & (1 << 1)) && (!fan5pin)) + if (!(i & (1 << 1)) && fan5pin) data->has_fan |= (1 << 4); /* Read fan clock dividers immediately */ -- cgit v1.2.3-59-g8ed1b From 237c8d2f54ff12bd4fea1a9d18a94ae5810271d3 Mon Sep 17 00:00:00 2001 From: Gong Jun Date: Mon, 30 Mar 2009 21:46:42 +0200 Subject: hwmon: (w83627ehf) Add support for W83667HG Add initial support for the Nuvoton W83667HG chip to the w83627ehf driver. It has been tested on ASUS P5QL PRO by Gong Jun. At the moment there is still a usability issue which is that only in6 or temp3 can be present on the W83667HG, so the driver shouldn't expose both. This will be addressed later. Signed-off-by: Gong Jun Acked-by: David Hubbard Signed-off-by: Jean Delvare --- Documentation/hwmon/w83627ehf | 29 ++++++++---- drivers/hwmon/Kconfig | 4 +- drivers/hwmon/w83627ehf.c | 106 +++++++++++++++++++++++++++--------------- 3 files changed, 92 insertions(+), 47 deletions(-) (limited to 'drivers/hwmon/w83627ehf.c') diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf index d6e1ae30fa6e..b6eb59384bb3 100644 --- a/Documentation/hwmon/w83627ehf +++ b/Documentation/hwmon/w83627ehf @@ -2,30 +2,40 @@ Kernel driver w83627ehf ======================= Supported chips: - * Winbond W83627EHF/EHG/DHG (ISA access ONLY) + * Winbond W83627EHF/EHG (ISA access ONLY) Prefix: 'w83627ehf' Addresses scanned: ISA address retrieved from Super I/O registers Datasheet: - http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf - DHG datasheet confidential. + http://www.nuvoton.com.tw/NR/rdonlyres/A6A258F0-F0C9-4F97-81C0-C4D29E7E943E/0/W83627EHF.pdf + * Winbond W83627DHG + Prefix: 'w83627dhg' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: + http://www.nuvoton.com.tw/NR/rdonlyres/7885623D-A487-4CF9-A47F-30C5F73D6FE6/0/W83627DHG.pdf + * Winbond W83667HG + Prefix: 'w83667hg' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: not available Authors: Jean Delvare Yuan Mu (Winbond) Rudolf Marek David Hubbard + Gong Jun Description ----------- -This driver implements support for the Winbond W83627EHF, W83627EHG, and -W83627DHG super I/O chips. We will refer to them collectively as Winbond chips. +This driver implements support for the Winbond W83627EHF, W83627EHG, +W83627DHG and W83667HG super I/O chips. We will refer to them collectively +as Winbond chips. The chips implement three temperature sensors, five fan rotation speed sensors, ten analog voltage sensors (only nine for the 627DHG), one -VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG), alarms with beep -warnings (control unimplemented), and some automatic fan regulation -strategies (plus manual fan control mode). +VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG), alarms +with beep warnings (control unimplemented), and some automatic fan +regulation strategies (plus manual fan control mode). Temperatures are measured in degrees Celsius and measurement resolution is 1 degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when @@ -54,7 +64,8 @@ follows: temp1 -> pwm1 temp2 -> pwm2 temp3 -> pwm3 -prog -> pwm4 (the programmable setting is not supported by the driver) +prog -> pwm4 (not on 667HG; the programmable setting is not supported by + the driver) /sys files ---------- diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index b4eea0292c1a..0eb4170cc4af 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -827,7 +827,7 @@ config SENSORS_W83627HF will be called w83627hf. config SENSORS_W83627EHF - tristate "Winbond W83627EHF/DHG" + tristate "Winbond W83627EHF/EHG/DHG, W83667HG" select HWMON_VID help If you say yes here you get support for the hardware @@ -838,6 +838,8 @@ config SENSORS_W83627EHF chip suited for specific Intel processors that use PECI such as the Core 2 Duo. + This driver also supports the W83667HG chip. + This driver can also be built as a module. If so, the module will be called w83627ehf. diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 18432e34dc7a..20a9332959bb 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -36,6 +36,7 @@ w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 0x8860 0xa1 w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 + w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 */ #include @@ -52,12 +53,13 @@ #include #include "lm75.h" -enum kinds { w83627ehf, w83627dhg }; +enum kinds { w83627ehf, w83627dhg, w83667hg }; /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ static const char * w83627ehf_device_names[] = { "w83627ehf", "w83627dhg", + "w83667hg", }; static unsigned short force_id; @@ -71,6 +73,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID"); */ #define W83627EHF_LD_HWM 0x0b +#define W83667HG_LD_VID 0x0d #define SIO_REG_LDSEL 0x07 /* Logical device select */ #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ @@ -83,6 +86,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID"); #define SIO_W83627EHF_ID 0x8850 #define SIO_W83627EHG_ID 0x8860 #define SIO_W83627DHG_ID 0xa020 +#define SIO_W83667HG_ID 0xa510 #define SIO_ID_MASK 0xFFF0 static inline void @@ -289,6 +293,7 @@ struct w83627ehf_data { u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ u8 pwm_enable[4]; /* 1->manual 2->thermal cruise (also called SmartFan I) */ + u8 pwm_num; /* number of pwm */ u8 pwm[4]; u8 target_temp[4]; u8 tolerance[4]; @@ -1192,7 +1197,7 @@ static void w83627ehf_device_remove_files(struct device *dev) device_remove_file(dev, &sda_fan_div[i].dev_attr); device_remove_file(dev, &sda_fan_min[i].dev_attr); } - for (i = 0; i < 4; i++) { + for (i = 0; i < data->pwm_num; i++) { device_remove_file(dev, &sda_pwm[i].dev_attr); device_remove_file(dev, &sda_pwm_mode[i].dev_attr); device_remove_file(dev, &sda_pwm_enable[i].dev_attr); @@ -1272,8 +1277,10 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) data->name = w83627ehf_device_names[sio_data->kind]; platform_set_drvdata(pdev, data); - /* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */ - data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10; + /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */ + data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9; + /* 667HG has 3 pwms */ + data->pwm_num = (sio_data->kind == w83667hg) ? 3 : 4; /* Initialize the chip */ w83627ehf_init_device(data); @@ -1281,44 +1288,64 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) data->vrm = vid_which_vrm(); superio_enter(sio_data->sioreg); /* Read VID value */ - superio_select(sio_data->sioreg, W83627EHF_LD_HWM); - if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) { - /* Set VID input sensibility if needed. In theory the BIOS - should have set it, but in practice it's not always the - case. We only do it for the W83627EHF/EHG because the - W83627DHG is more complex in this respect. */ - if (sio_data->kind == w83627ehf) { - en_vrm10 = superio_inb(sio_data->sioreg, - SIO_REG_EN_VRM10); - if ((en_vrm10 & 0x08) && data->vrm == 90) { - dev_warn(dev, "Setting VID input voltage to " - "TTL\n"); - superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10, - en_vrm10 & ~0x08); - } else if (!(en_vrm10 & 0x08) && data->vrm == 100) { - dev_warn(dev, "Setting VID input voltage to " - "VRM10\n"); - superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10, - en_vrm10 | 0x08); - } - } - - data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA); - if (sio_data->kind == w83627ehf) /* 6 VID pins only */ - data->vid &= 0x3f; - + if (sio_data->kind == w83667hg) { + /* W83667HG has different pins for VID input and output, so + we can get the VID input values directly at logical device D + 0xe3. */ + superio_select(sio_data->sioreg, W83667HG_LD_VID); + data->vid = superio_inb(sio_data->sioreg, 0xe3); err = device_create_file(dev, &dev_attr_cpu0_vid); if (err) goto exit_release; } else { - dev_info(dev, "VID pins in output mode, CPU VID not " - "available\n"); + superio_select(sio_data->sioreg, W83627EHF_LD_HWM); + if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) { + /* Set VID input sensibility if needed. In theory the + BIOS should have set it, but in practice it's not + always the case. We only do it for the W83627EHF/EHG + because the W83627DHG is more complex in this + respect. */ + if (sio_data->kind == w83627ehf) { + en_vrm10 = superio_inb(sio_data->sioreg, + SIO_REG_EN_VRM10); + if ((en_vrm10 & 0x08) && data->vrm == 90) { + dev_warn(dev, "Setting VID input " + "voltage to TTL\n"); + superio_outb(sio_data->sioreg, + SIO_REG_EN_VRM10, + en_vrm10 & ~0x08); + } else if (!(en_vrm10 & 0x08) + && data->vrm == 100) { + dev_warn(dev, "Setting VID input " + "voltage to VRM10\n"); + superio_outb(sio_data->sioreg, + SIO_REG_EN_VRM10, + en_vrm10 | 0x08); + } + } + + data->vid = superio_inb(sio_data->sioreg, + SIO_REG_VID_DATA); + if (sio_data->kind == w83627ehf) /* 6 VID pins only */ + data->vid &= 0x3f; + + err = device_create_file(dev, &dev_attr_cpu0_vid); + if (err) + goto exit_release; + } else { + dev_info(dev, "VID pins in output mode, CPU VID not " + "available\n"); + } } /* fan4 and fan5 share some pins with the GPIO and serial flash */ - - fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x2); - fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x6); + if (sio_data->kind == w83667hg) { + fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20; + fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40; + } else { + fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02); + fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06); + } superio_exit(sio_data->sioreg); /* It looks like fan4 and fan5 pins can be alternatively used @@ -1344,7 +1371,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) goto exit_remove; /* if fan4 is enabled create the sf3 files for it */ - if (data->has_fan & (1 << 3)) + if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4) for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) { if ((err = device_create_file(dev, &sda_sf3_arrays_fan4[i].dev_attr))) @@ -1372,7 +1399,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) || (err = device_create_file(dev, &sda_fan_min[i].dev_attr))) goto exit_remove; - if (i < 4 && /* w83627ehf only has 4 pwm */ + if (i < data->pwm_num && ((err = device_create_file(dev, &sda_pwm[i].dev_attr)) || (err = device_create_file(dev, @@ -1442,6 +1469,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; + static const char __initdata sio_name_W83667HG[] = "W83667HG"; u16 val; const char *sio_name; @@ -1466,6 +1494,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, sio_data->kind = w83627dhg; sio_name = sio_name_W83627DHG; break; + case SIO_W83667HG_ID: + sio_data->kind = w83667hg; + sio_name = sio_name_W83667HG; + break; default: if (val != 0xffff) pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n", -- cgit v1.2.3-59-g8ed1b From a157d06d4d70318a0818552095071d7430dd5d34 Mon Sep 17 00:00:00 2001 From: Gong Jun Date: Mon, 30 Mar 2009 21:46:43 +0200 Subject: hwmon: (w83627ehf) Only expose in6 or temp3 on the W83667HG The pin for in6 and temp3 is shared on the W83667HG, so only one of these features can be supported on any given system. Let the driver select which one depending on the temp3 disabled bit. Signed-off-by: Gong Jun Signed-off-by: Jean Delvare --- drivers/hwmon/w83627ehf.c | 60 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 6 deletions(-) (limited to 'drivers/hwmon/w83627ehf.c') diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 20a9332959bb..e64b42058b21 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -303,6 +303,9 @@ struct w83627ehf_data { u8 vid; u8 vrm; + + u8 temp3_disable; + u8 in6_skip; }; struct w83627ehf_sio_data { @@ -871,25 +874,37 @@ show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%d\n", (int)data->temp_type[nr]); } -static struct sensor_device_attribute sda_temp[] = { +static struct sensor_device_attribute sda_temp_input[] = { SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0), SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0), SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1), +}; + +static struct sensor_device_attribute sda_temp_max[] = { SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max, store_temp1_max, 0), SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max, store_temp_max, 0), SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max, store_temp_max, 1), +}; + +static struct sensor_device_attribute sda_temp_max_hyst[] = { SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst, store_temp1_max_hyst, 0), SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, store_temp_max_hyst, 0), SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, store_temp_max_hyst, 1), +}; + +static struct sensor_device_attribute sda_temp_alarm[] = { SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4), SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5), SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), +}; + +static struct sensor_device_attribute sda_temp_type[] = { SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0), SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1), SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2), @@ -1186,6 +1201,8 @@ static void w83627ehf_device_remove_files(struct device *dev) for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr); for (i = 0; i < data->in_num; i++) { + if ((i == 6) && data->in6_skip) + continue; device_remove_file(dev, &sda_in_input[i].dev_attr); device_remove_file(dev, &sda_in_alarm[i].dev_attr); device_remove_file(dev, &sda_in_min[i].dev_attr); @@ -1204,8 +1221,15 @@ static void w83627ehf_device_remove_files(struct device *dev) device_remove_file(dev, &sda_target_temp[i].dev_attr); device_remove_file(dev, &sda_tolerance[i].dev_attr); } - for (i = 0; i < ARRAY_SIZE(sda_temp); i++) - device_remove_file(dev, &sda_temp[i].dev_attr); + for (i = 0; i < 3; i++) { + if ((i == 2) && data->temp3_disable) + continue; + device_remove_file(dev, &sda_temp_input[i].dev_attr); + device_remove_file(dev, &sda_temp_max[i].dev_attr); + device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr); + device_remove_file(dev, &sda_temp_alarm[i].dev_attr); + device_remove_file(dev, &sda_temp_type[i].dev_attr); + } device_remove_file(dev, &dev_attr_name); device_remove_file(dev, &dev_attr_cpu0_vid); @@ -1227,6 +1251,8 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data) for (i = 0; i < 2; i++) { tmp = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[i]); + if ((i == 1) && data->temp3_disable) + continue; if (tmp & 0x01) w83627ehf_write_value(data, W83627EHF_REG_TEMP_CONFIG[i], @@ -1282,6 +1308,13 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) /* 667HG has 3 pwms */ data->pwm_num = (sio_data->kind == w83667hg) ? 3 : 4; + /* Check temp3 configuration bit for 667HG */ + if (sio_data->kind == w83667hg) { + data->temp3_disable = w83627ehf_read_value(data, + W83627EHF_REG_TEMP_CONFIG[1]) & 0x01; + data->in6_skip = !data->temp3_disable; + } + /* Initialize the chip */ w83627ehf_init_device(data); @@ -1378,7 +1411,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) goto exit_remove; } - for (i = 0; i < data->in_num; i++) + for (i = 0; i < data->in_num; i++) { + if ((i == 6) && data->in6_skip) + continue; if ((err = device_create_file(dev, &sda_in_input[i].dev_attr)) || (err = device_create_file(dev, &sda_in_alarm[i].dev_attr)) @@ -1387,6 +1422,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) || (err = device_create_file(dev, &sda_in_max[i].dev_attr))) goto exit_remove; + } for (i = 0; i < 5; i++) { if (data->has_fan & (1 << i)) { @@ -1414,9 +1450,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) } } - for (i = 0; i < ARRAY_SIZE(sda_temp); i++) - if ((err = device_create_file(dev, &sda_temp[i].dev_attr))) + for (i = 0; i < 3; i++) { + if ((i == 2) && data->temp3_disable) + continue; + if ((err = device_create_file(dev, + &sda_temp_input[i].dev_attr)) + || (err = device_create_file(dev, + &sda_temp_max[i].dev_attr)) + || (err = device_create_file(dev, + &sda_temp_max_hyst[i].dev_attr)) + || (err = device_create_file(dev, + &sda_temp_alarm[i].dev_attr)) + || (err = device_create_file(dev, + &sda_temp_type[i].dev_attr))) goto exit_remove; + } err = device_create_file(dev, &dev_attr_name); if (err) -- cgit v1.2.3-59-g8ed1b