Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 237c8d2f authored by Gong Jun's avatar Gong Jun Committed by Jean Delvare
Browse files

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: default avatarGong Jun <JGong@nuvoton.com>
Acked-by: default avatarDavid Hubbard <david.c.hubbard@gmail.com>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
parent 1704b26e
Loading
Loading
Loading
Loading
+20 −9
Original line number Original line Diff line number Diff line
@@ -2,30 +2,40 @@ Kernel driver w83627ehf
=======================
=======================


Supported chips:
Supported chips:
  * Winbond W83627EHF/EHG/DHG (ISA access ONLY)
  * Winbond W83627EHF/EHG (ISA access ONLY)
    Prefix: 'w83627ehf'
    Prefix: 'w83627ehf'
    Addresses scanned: ISA address retrieved from Super I/O registers
    Addresses scanned: ISA address retrieved from Super I/O registers
    Datasheet:
    Datasheet:
        http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf
        http://www.nuvoton.com.tw/NR/rdonlyres/A6A258F0-F0C9-4F97-81C0-C4D29E7E943E/0/W83627EHF.pdf
        DHG datasheet confidential.
  * 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:
Authors:
        Jean Delvare <khali@linux-fr.org>
        Jean Delvare <khali@linux-fr.org>
        Yuan Mu (Winbond)
        Yuan Mu (Winbond)
        Rudolf Marek <r.marek@assembler.cz>
        Rudolf Marek <r.marek@assembler.cz>
        David Hubbard <david.c.hubbard@gmail.com>
        David Hubbard <david.c.hubbard@gmail.com>
        Gong Jun <JGong@nuvoton.com>


Description
Description
-----------
-----------


This driver implements support for the Winbond W83627EHF, W83627EHG, and
This driver implements support for the Winbond W83627EHF, W83627EHG,
W83627DHG super I/O chips. We will refer to them collectively as Winbond chips.
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
The chips implement three temperature sensors, five fan rotation
speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
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
VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG), alarms
warnings (control unimplemented), and some automatic fan regulation
with beep warnings (control unimplemented), and some automatic fan
strategies (plus manual fan control mode).
regulation strategies (plus manual fan control mode).


Temperatures are measured in degrees Celsius and measurement resolution is 1
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
degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
@@ -54,7 +64,8 @@ follows:
temp1 -> pwm1
temp1 -> pwm1
temp2 -> pwm2
temp2 -> pwm2
temp3 -> pwm3
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
/sys files
----------
----------
+3 −1
Original line number Original line Diff line number Diff line
@@ -827,7 +827,7 @@ config SENSORS_W83627HF
	  will be called w83627hf.
	  will be called w83627hf.


config SENSORS_W83627EHF
config SENSORS_W83627EHF
	tristate "Winbond W83627EHF/DHG"
	tristate "Winbond W83627EHF/EHG/DHG, W83667HG"
	select HWMON_VID
	select HWMON_VID
	help
	help
	  If you say yes here you get support for the hardware
	  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
	  chip suited for specific Intel processors that use PECI such as
	  the Core 2 Duo.
	  the Core 2 Duo.


	  This driver also supports the W83667HG chip.

	  This driver can also be built as a module.  If so, the module
	  This driver can also be built as a module.  If so, the module
	  will be called w83627ehf.
	  will be called w83627ehf.


+69 −37
Original line number Original line Diff line number Diff line
@@ -36,6 +36,7 @@
    w83627ehf   10      5       4       3      0x8850 0x88    0x5ca3
    w83627ehf   10      5       4       3      0x8850 0x88    0x5ca3
                                               0x8860 0xa1
                                               0x8860 0xa1
    w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
    w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
    w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
*/
*/


#include <linux/module.h>
#include <linux/module.h>
@@ -52,12 +53,13 @@
#include <asm/io.h>
#include <asm/io.h>
#include "lm75.h"
#include "lm75.h"


enum kinds { w83627ehf, w83627dhg };
enum kinds { w83627ehf, w83627dhg, w83667hg };


/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
static const char * w83627ehf_device_names[] = {
static const char * w83627ehf_device_names[] = {
	"w83627ehf",
	"w83627ehf",
	"w83627dhg",
	"w83627dhg",
	"w83667hg",
};
};


static unsigned short force_id;
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 W83627EHF_LD_HWM	0x0b
#define W83667HG_LD_VID 	0x0d


#define SIO_REG_LDSEL		0x07	/* Logical device select */
#define SIO_REG_LDSEL		0x07	/* Logical device select */
#define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
#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_W83627EHF_ID	0x8850
#define SIO_W83627EHG_ID	0x8860
#define SIO_W83627EHG_ID	0x8860
#define SIO_W83627DHG_ID	0xa020
#define SIO_W83627DHG_ID	0xa020
#define SIO_W83667HG_ID 	0xa510
#define SIO_ID_MASK		0xFFF0
#define SIO_ID_MASK		0xFFF0


static inline void
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_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
	u8 pwm_enable[4]; /* 1->manual
	u8 pwm_enable[4]; /* 1->manual
			     2->thermal cruise (also called SmartFan I) */
			     2->thermal cruise (also called SmartFan I) */
	u8 pwm_num;		/* number of pwm */
	u8 pwm[4];
	u8 pwm[4];
	u8 target_temp[4];
	u8 target_temp[4];
	u8 tolerance[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_div[i].dev_attr);
		device_remove_file(dev, &sda_fan_min[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[i].dev_attr);
		device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
		device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
		device_remove_file(dev, &sda_pwm_enable[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];
	data->name = w83627ehf_device_names[sio_data->kind];
	platform_set_drvdata(pdev, data);
	platform_set_drvdata(pdev, data);


	/* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */
	/* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
	data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10;
	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 */
	/* Initialize the chip */
	w83627ehf_init_device(data);
	w83627ehf_init_device(data);
@@ -1281,29 +1288,44 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
	data->vrm = vid_which_vrm();
	data->vrm = vid_which_vrm();
	superio_enter(sio_data->sioreg);
	superio_enter(sio_data->sioreg);
	/* Read VID value */
	/* Read VID value */
	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 {
		superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
		superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
		if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
		if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
		/* Set VID input sensibility if needed. In theory the BIOS
			/* Set VID input sensibility if needed. In theory the
		   should have set it, but in practice it's not always the
			   BIOS should have set it, but in practice it's not
		   case. We only do it for the W83627EHF/EHG because the
			   always the case. We only do it for the W83627EHF/EHG
		   W83627DHG is more complex in this respect. */
			   because the W83627DHG is more complex in this
			   respect. */
			if (sio_data->kind == w83627ehf) {
			if (sio_data->kind == w83627ehf) {
				en_vrm10 = superio_inb(sio_data->sioreg,
				en_vrm10 = superio_inb(sio_data->sioreg,
						       SIO_REG_EN_VRM10);
						       SIO_REG_EN_VRM10);
				if ((en_vrm10 & 0x08) && data->vrm == 90) {
				if ((en_vrm10 & 0x08) && data->vrm == 90) {
				dev_warn(dev, "Setting VID input voltage to "
					dev_warn(dev, "Setting VID input "
					 "TTL\n");
						 "voltage to TTL\n");
				superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
					superio_outb(sio_data->sioreg,
						     SIO_REG_EN_VRM10,
						     en_vrm10 & ~0x08);
						     en_vrm10 & ~0x08);
			} else if (!(en_vrm10 & 0x08) && data->vrm == 100) {
				} else if (!(en_vrm10 & 0x08)
				dev_warn(dev, "Setting VID input voltage to "
					   && data->vrm == 100) {
					 "VRM10\n");
					dev_warn(dev, "Setting VID input "
				superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
						 "voltage to VRM10\n");
					superio_outb(sio_data->sioreg,
						     SIO_REG_EN_VRM10,
						     en_vrm10 | 0x08);
						     en_vrm10 | 0x08);
				}
				}
			}
			}


		data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA);
			data->vid = superio_inb(sio_data->sioreg,
						SIO_REG_VID_DATA);
			if (sio_data->kind == w83627ehf) /* 6 VID pins only */
			if (sio_data->kind == w83627ehf) /* 6 VID pins only */
				data->vid &= 0x3f;
				data->vid &= 0x3f;


@@ -1314,11 +1336,16 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
			dev_info(dev, "VID pins in output mode, CPU VID not "
			dev_info(dev, "VID pins in output mode, CPU VID not "
				 "available\n");
				 "available\n");
		}
		}
	}


	/* fan4 and fan5 share some pins with the GPIO and serial flash */
	/* fan4 and fan5 share some pins with the GPIO and serial flash */

	if (sio_data->kind == w83667hg) {
	fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x2);
		fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
	fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x6);
		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);
	superio_exit(sio_data->sioreg);


	/* It looks like fan4 and fan5 pins can be alternatively used
	/* 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;
			goto exit_remove;


	/* if fan4 is enabled create the sf3 files for it */
	/* 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++) {
		for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
			if ((err = device_create_file(dev,
			if ((err = device_create_file(dev,
				&sda_sf3_arrays_fan4[i].dev_attr)))
				&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,
				|| (err = device_create_file(dev,
					&sda_fan_min[i].dev_attr)))
					&sda_fan_min[i].dev_attr)))
				goto exit_remove;
				goto exit_remove;
			if (i < 4 && /* w83627ehf only has 4 pwm */
			if (i < data->pwm_num &&
				((err = device_create_file(dev,
				((err = device_create_file(dev,
					&sda_pwm[i].dev_attr))
					&sda_pwm[i].dev_attr))
				|| (err = device_create_file(dev,
				|| (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_W83627EHF[] = "W83627EHF";
	static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
	static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
	static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
	static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
	static const char __initdata sio_name_W83667HG[] = "W83667HG";


	u16 val;
	u16 val;
	const char *sio_name;
	const char *sio_name;
@@ -1466,6 +1494,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
		sio_data->kind = w83627dhg;
		sio_data->kind = w83627dhg;
		sio_name = sio_name_W83627DHG;
		sio_name = sio_name_W83627DHG;
		break;
		break;
	case SIO_W83667HG_ID:
		sio_data->kind = w83667hg;
		sio_name = sio_name_W83667HG;
		break;
	default:
	default:
		if (val != 0xffff)
		if (val != 0xffff)
			pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
			pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",