All of lore.kernel.org
 help / color / mirror / Atom feed
* [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
@ 2009-09-10 12:30 Rodolfo Giometti
  2009-09-10 12:56 ` Jean Delvare
                   ` (25 more replies)
  0 siblings, 26 replies; 30+ messages in thread
From: Rodolfo Giometti @ 2009-09-10 12:30 UTC (permalink / raw)
  To: lm-sensors

The file has been splitted up into two parts:

* drivers/mfd/w83627hf.c         - detects the chip and define proper
                                   platform devices into mfd support

* drivers/hwmon/hwmon-w83627hf.c - implements the driver for hwmon
                                   functionality only

The patch also fixes up some non reentrant code and some C-style issues.

Signed-off-by: Rodolfo Giometti <giometti@linux.it>
---
 drivers/hwmon/Kconfig                          |    2 +-
 drivers/hwmon/Makefile                         |    2 +-
 drivers/hwmon/{w83627hf.c => hwmon-w83627hf.c} |  373 +++++-------------------
 drivers/mfd/Kconfig                            |   14 +
 drivers/mfd/Makefile                           |    1 +
 drivers/mfd/w83627hf.c                         |  251 ++++++++++++++++
 include/linux/mfd/w83627hf.h                   |   68 +++++
 7 files changed, 411 insertions(+), 300 deletions(-)
 rename drivers/hwmon/{w83627hf.c => hwmon-w83627hf.c} (85%)
 create mode 100644 drivers/mfd/w83627hf.c
 create mode 100644 include/linux/mfd/w83627hf.h

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 2d50166..ecb4910 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -901,7 +901,7 @@ config SENSORS_W83627HF
 	  W83697HF.
 
 	  This driver can also be built as a module.  If so, the module
-	  will be called w83627hf.
+	  will be called hwmon-w83627hf.
 
 config SENSORS_W83627EHF
 	tristate "Winbond W83627EHF/EHG/DHG, W83667HG"
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index b793dce..c33a0eb 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -7,7 +7,7 @@ obj-$(CONFIG_HWMON_VID)		+= hwmon-vid.o
 
 # asb100, then w83781d go first, as they can override other drivers' addresses.
 obj-$(CONFIG_SENSORS_ASB100)	+= asb100.o
-obj-$(CONFIG_SENSORS_W83627HF)	+= w83627hf.o
+obj-$(CONFIG_SENSORS_W83627HF)	+= hwmon-w83627hf.o
 obj-$(CONFIG_SENSORS_W83792D)	+= w83792d.o
 obj-$(CONFIG_SENSORS_W83793)	+= w83793.o
 obj-$(CONFIG_SENSORS_W83781D)	+= w83781d.o
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/hwmon-w83627hf.c
similarity index 85%
rename from drivers/hwmon/w83627hf.c
rename to drivers/hwmon/hwmon-w83627hf.c
index 389150b..25f35ac 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/hwmon-w83627hf.c
@@ -1,6 +1,6 @@
 /*
     w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware
-                monitoring
+		 monitoring
     Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
     Philip Edelbrock <phil@netroedge.com>,
     and Mark Studebaker <mdsxyz123@yahoo.com>
@@ -51,13 +51,9 @@
 #include <linux/mutex.h>
 #include <linux/ioport.h>
 #include <linux/acpi.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include "lm75.h"
-
-static struct platform_device *pdev;
-
-#define DRVNAME "w83627hf"
-enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
+#include <linux/mfd/w83627hf.h>
 
 static u16 force_addr;
 module_param(force_addr, ushort, 0);
@@ -76,88 +72,8 @@ static unsigned short force_id;
 module_param(force_id, ushort, 0);
 MODULE_PARM_DESC(force_id, "Override the detected device ID");
 
-/* modified from kernel/include/traps.c */
-static int REG;		/* The register to read/write */
-#define	DEV	0x07	/* Register: Logical device select */
-static int VAL;		/* The value to read/write */
-
-/* logical device numbers for superio_select (below) */
-#define W83627HF_LD_FDC		0x00
-#define W83627HF_LD_PRT		0x01
-#define W83627HF_LD_UART1	0x02
-#define W83627HF_LD_UART2	0x03
-#define W83627HF_LD_KBC		0x05
-#define W83627HF_LD_CIR		0x06 /* w83627hf only */
-#define W83627HF_LD_GAME	0x07
-#define W83627HF_LD_MIDI	0x07
-#define W83627HF_LD_GPIO1	0x07
-#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
-#define W83627HF_LD_GPIO2	0x08
-#define W83627HF_LD_GPIO3	0x09
-#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
-#define W83627HF_LD_ACPI	0x0a
-#define W83627HF_LD_HWM		0x0b
-
-#define	DEVID	0x20	/* Register: Device ID */
-
-#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
-#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
-#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
-
-#define W83687THF_VID_EN	0x29 /* w83687thf only */
-#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
-#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
-
-static inline void
-superio_outb(int reg, int val)
-{
-	outb(reg, REG);
-	outb(val, VAL);
-}
-
-static inline int
-superio_inb(int reg)
-{
-	outb(reg, REG);
-	return inb(VAL);
-}
-
-static inline void
-superio_select(int ld)
-{
-	outb(DEV, REG);
-	outb(ld, VAL);
-}
-
-static inline void
-superio_enter(void)
-{
-	outb(0x87, REG);
-	outb(0x87, REG);
-}
-
-static inline void
-superio_exit(void)
-{
-	outb(0xAA, REG);
-}
-
-#define W627_DEVID 0x52
-#define W627THF_DEVID 0x82
-#define W697_DEVID 0x60
-#define W637_DEVID 0x70
-#define W687THF_DEVID 0x85
-#define WINB_ACT_REG 0x30
-#define WINB_BASE_REG 0x60
 /* Constants specified below */
 
-/* Alignment of the base address */
-#define WINB_ALIGNMENT		~7
-
-/* Offset & size of I/O region we are interested in */
-#define WINB_REGION_OFFSET	5
-#define WINB_REGION_SIZE	2
-
 /* Where are the sensors address/data registers relative to the region offset */
 #define W83781D_ADDR_REG_OFFSET 0
 #define W83781D_DATA_REG_OFFSET 1
@@ -221,7 +137,7 @@ static const u8 W83627THF_PWM_ENABLE_SHIFT[] = { 2, 4, 1 };
 
 static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
 static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
-                             W83627THF_REG_PWM3 };
+				W83627THF_REG_PWM3 };
 #define W836X7HF_REG_PWM(type, nr) (((type) = w83627hf) ? \
 				    regpwm_627hf[nr] : regpwm[nr])
 
@@ -251,7 +167,7 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
    variants. Note that you should be a bit careful with which arguments
    these macros are called: arguments may be evaluated more than once.
    Fixing this is just not worth it. */
-#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16),0,255))
+#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16), 0, 255))
 #define IN_FROM_REG(val) ((val) * 16)
 
 static inline u8 FAN_TO_REG(long rpm, int div)
@@ -264,25 +180,26 @@ static inline u8 FAN_TO_REG(long rpm, int div)
 }
 
 #define TEMP_MIN (-128000)
-#define TEMP_MAX ( 127000)
+#define TEMP_MAX (127000)
 
 /* TEMP: 0.001C/bit (-128C to +127C)
    REG: 1C/bit, two's complement */
 static u8 TEMP_TO_REG(long temp)
 {
-        int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
-        ntemp += (ntemp<0 ? -500 : 500);
-        return (u8)(ntemp / 1000);
+	int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
+	ntemp += (ntemp < 0 ? -500 : 500);
+	return (u8)(ntemp / 1000);
 }
 
 static int TEMP_FROM_REG(u8 reg)
 {
-        return (s8)reg * 1000;
+	return (s8)reg * 1000;
 }
 
-#define FAN_FROM_REG(val,div) ((val)=0?-1:(val)=255?0:1350000/((val)*(div)))
+#define FAN_FROM_REG(val, div)	\
+		((val) = 0 ? -1 : (val) = 255 ? 0 : 1350000 / ((val) * (div)))
 
-#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
+#define PWM_TO_REG(val) (SENSORS_LIMIT((val), 0, 255))
 
 static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
 {
@@ -312,7 +229,7 @@ static inline unsigned long pwm_freq_from_reg(u8 reg)
 	/* This should not happen but anyway... */
 	if (reg = 0)
 		reg++;
-	return (clock / (reg << 8));
+	return clock / (reg << 8);
 }
 static inline u8 pwm_freq_to_reg(unsigned long val)
 {
@@ -320,11 +237,11 @@ static inline u8 pwm_freq_to_reg(unsigned long val)
 	if (val >= 93750)	/* The highest we can do */
 		return 0x01;
 	if (val >= 720)	/* Use 24 MHz clock */
-		return (24000000UL / (val << 8));
+		return 24000000UL / (val << 8);
 	if (val < 6)		/* The lowest we can do */
 		return 0xFF;
 	else			/* Use 180 kHz clock */
-		return (0x80 | (180000UL / (val << 8)));
+		return 0x80 | (180000UL / (val << 8));
 }
 
 #define BEEP_MASK_FROM_REG(val)		((val) & 0xff7fff)
@@ -341,7 +258,7 @@ static inline u8 DIV_TO_REG(long val)
 			break;
 		val >>= 1;
 	}
-	return ((u8) i);
+	return (u8) i;
 }
 
 /* For each registered chip, we need to keep some data in memory.
@@ -380,10 +297,6 @@ struct w83627hf_data {
 	u8 vrm_ovt;		/* Register value, 627THF/637HF/687THF only */
 };
 
-struct w83627hf_sio_data {
-	enum chips type;
-};
-
 
 static int w83627hf_probe(struct platform_device *pdev);
 static int __devexit w83627hf_remove(struct platform_device *pdev);
@@ -397,7 +310,7 @@ static void w83627hf_init_device(struct platform_device *pdev);
 static struct platform_driver w83627hf_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
-		.name	= DRVNAME,
+		.name	= DRVNAME "_hwmon",
 	},
 	.probe		= w83627hf_probe,
 	.remove		= __devexit_p(w83627hf_remove),
@@ -484,28 +397,32 @@ static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
 		/* use VRM8 (standard) calculation */
 		in0 = (long)IN_FROM_REG(reg);
 
-	return sprintf(buf,"%ld\n", in0);
+	return sprintf(buf, "%ld\n", in0);
 }
 
-static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_regs_in_0(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct w83627hf_data *data = w83627hf_update_device(dev);
 	return show_in_0(data, buf, data->in[0]);
 }
 
-static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_regs_in_min0(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct w83627hf_data *data = w83627hf_update_device(dev);
 	return show_in_0(data, buf, data->in_min[0]);
 }
 
-static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_regs_in_max0(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct w83627hf_data *data = w83627hf_update_device(dev);
 	return show_in_0(data, buf, data->in_max[0]);
 }
 
-static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
+static ssize_t store_regs_in_min0(struct device *dev,
+				struct device_attribute *attr,
 	const char *buf, size_t count)
 {
 	struct w83627hf_data *data = dev_get_drvdata(dev);
@@ -514,7 +431,7 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a
 	val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
-	
+
 	if ((data->vrm_ovt & 0x01) &&
 		(w83627thf = data->type || w83637hf = data->type
 		 || w83687thf = data->type))
@@ -532,7 +449,8 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a
 	return count;
 }
 
-static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
+static ssize_t store_regs_in_max0(struct device *dev,
+				struct device_attribute *attr,
 	const char *buf, size_t count)
 {
 	struct w83627hf_data *data = dev_get_drvdata(dev);
@@ -545,7 +463,7 @@ static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *a
 	if ((data->vrm_ovt & 0x01) &&
 		(w83627thf = data->type || w83637hf = data->type
 		 || w83687thf = data->type))
-		
+
 		/* use VRM9 calculation */
 		data->in_max[0]  			SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
@@ -701,7 +619,8 @@ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
 	return sprintf(buf, "%ld\n", (long) data->vrm);
 }
 static ssize_t
-store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+store_vrm_reg(struct device *dev, struct device_attribute *attr,
+					const char *buf, size_t count)
 {
 	struct w83627hf_data *data = dev_get_drvdata(dev);
 	u32 val;
@@ -897,14 +816,16 @@ store_fan_div(struct device *dev, struct device_attribute *devattr,
 
 	data->fan_div[nr] = DIV_TO_REG(val);
 
-	reg = (w83627hf_read_value(data, nr=2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
-	       & (nr=0 ? 0xcf : 0x3f))
-	    | ((data->fan_div[nr] & 0x03) << (nr=0 ? 4 : 6));
-	w83627hf_write_value(data, nr=2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
+	reg = (w83627hf_read_value(data,
+		nr = 2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
+		& (nr = 0 ? 0xcf : 0x3f))
+		| ((data->fan_div[nr] & 0x03) << (nr = 0 ? 4 : 6));
+	w83627hf_write_value(data,
+		nr = 2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
 
 	reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
-	       & ~(1 << (5 + nr)))
-	    | ((data->fan_div[nr] & 0x04) << (3 + nr));
+		& ~(1 << (5 + nr)))
+		| ((data->fan_div[nr] & 0x04) << (3 + nr));
 	w83627hf_write_value(data, W83781D_REG_VBAT, reg);
 
 	/* Restore fan_min */
@@ -1018,7 +939,7 @@ store_pwm_freq(struct device *dev, struct device_attribute *devattr,
 {
 	int nr = to_sensor_dev_attr(devattr)->index;
 	struct w83627hf_data *data = dev_get_drvdata(dev);
-	static const u8 mask[]={0xF8, 0x8F};
+	static const u8 mask[] = {0xF8, 0x8F};
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
@@ -1126,80 +1047,6 @@ show_name(struct device *dev, struct device_attribute *devattr, char *buf)
 }
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
-static int __init w83627hf_find(int sioaddr, unsigned short *addr,
-				struct w83627hf_sio_data *sio_data)
-{
-	int err = -ENODEV;
-	u16 val;
-
-	static const __initdata char *names[] = {
-		"W83627HF",
-		"W83627THF",
-		"W83697HF",
-		"W83637HF",
-		"W83687THF",
-	};
-
-	REG = sioaddr;
-	VAL = sioaddr + 1;
-
-	superio_enter();
-	val = force_id ? force_id : superio_inb(DEVID);
-	switch (val) {
-	case W627_DEVID:
-		sio_data->type = w83627hf;
-		break;
-	case W627THF_DEVID:
-		sio_data->type = w83627thf;
-		break;
-	case W697_DEVID:
-		sio_data->type = w83697hf;
-		break;
-	case W637_DEVID:
-		sio_data->type = w83637hf;
-		break;
-	case W687THF_DEVID:
-		sio_data->type = w83687thf;
-		break;
-	case 0xff:	/* No device at all */
-		goto exit;
-	default:
-		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
-		goto exit;
-	}
-
-	superio_select(W83627HF_LD_HWM);
-	force_addr &= WINB_ALIGNMENT;
-	if (force_addr) {
-		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
-		       force_addr);
-		superio_outb(WINB_BASE_REG, force_addr >> 8);
-		superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
-	}
-	val = (superio_inb(WINB_BASE_REG) << 8) |
-	       superio_inb(WINB_BASE_REG + 1);
-	*addr = val & WINB_ALIGNMENT;
-	if (*addr = 0) {
-		printk(KERN_WARNING DRVNAME ": Base address not set, "
-		       "skipping\n");
-		goto exit;
-	}
-
-	val = superio_inb(WINB_ACT_REG);
-	if (!(val & 0x01)) {
-		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
-		superio_outb(WINB_ACT_REG, val | 0x01);
-	}
-
-	err = 0;
-	pr_info(DRVNAME ": Found %s chip at %#x\n",
-		names[sio_data->type], *addr);
-
- exit:
-	superio_exit();
-	return err;
-}
-
 #define VIN_UNIT_ATTRS(_X_)	\
 	&sensor_dev_attr_in##_X_##_input.dev_attr.attr,		\
 	&sensor_dev_attr_in##_X_##_min.dev_attr.attr,		\
@@ -1281,7 +1128,7 @@ static const struct attribute_group w83627hf_group_opt = {
 static int __devinit w83627hf_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct w83627hf_sio_data *sio_data = dev->platform_data;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	struct w83627hf_data *data;
 	struct resource *res;
 	int err, i;
@@ -1435,15 +1282,15 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 
 	return 0;
 
-      ERROR4:
+ERROR4:
 	sysfs_remove_group(&dev->kobj, &w83627hf_group);
 	sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
-      ERROR3:
+ERROR3:
 	platform_set_drvdata(pdev, NULL);
 	kfree(data);
-      ERROR1:
+ERROR1:
 	release_region(res->start, WINB_REGION_SIZE);
-      ERROR0:
+ERROR0:
 	return err;
 }
 
@@ -1511,20 +1358,22 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
 
 static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	int res = 0xff, sel;
 
-	superio_enter();
-	superio_select(W83627HF_LD_GPIO5);
+	superio_enter(sio_data);
+	superio_select(sio_data, W83627HF_LD_GPIO5);
 
 	/* Make sure these GPIO pins are enabled */
-	if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
+	if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) {
 		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
 		goto exit;
 	}
 
 	/* Make sure the pins are configured for input
 	   There must be at least five (VRM 9), and possibly 6 (VRM 10) */
-	sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
+	sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f;
 	if ((sel & 0x1f) != 0x1f) {
 		dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
 			"function\n");
@@ -1532,37 +1381,39 @@ static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
 	}
 
 	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
-	res = superio_inb(W83627THF_GPIO5_DR) & sel;
+	res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel;
 
 exit:
-	superio_exit();
+	superio_exit(sio_data);
 	return res;
 }
 
 static int __devinit w83687thf_read_vid(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	int res = 0xff;
 
-	superio_enter();
-	superio_select(W83627HF_LD_HWM);
+	superio_enter(sio_data);
+	superio_select(sio_data, W83627HF_LD_HWM);
 
 	/* Make sure these GPIO pins are enabled */
-	if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
+	if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) {
 		dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
 		goto exit;
 	}
 
 	/* Make sure the pins are configured for input */
-	if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
+	if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) {
 		dev_dbg(&pdev->dev, "VID configured as output, "
 			"no VID function\n");
 		goto exit;
 	}
 
-	res = superio_inb(W83687THF_VID_DATA) & 0x3f;
+	res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f;
 
 exit:
-	superio_exit();
+	superio_exit(sio_data);
 	return res;
 }
 
@@ -1616,7 +1467,7 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
 
 	/* Read VRM & OVT Config only once */
 	if (type = w83627thf || type = w83637hf || type = w83687thf) {
-		data->vrm_ovt = 
+		data->vrm_ovt  			w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
 	}
 
@@ -1636,7 +1487,7 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
 			break;
 	}
 
-	if(init) {
+	if (init) {
 		/* Enable temp2 */
 		tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG);
 		if (tmp & 0x01) {
@@ -1724,8 +1575,8 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 		for (i = 0; i <= 2; i++) {
 			u8 tmp = w83627hf_read_value(data,
 				W836X7HF_REG_PWM(data->type, i));
- 			/* bits 0-3 are reserved  in 627THF */
- 			if (data->type = w83627thf)
+			/* bits 0-3 are reserved  in 627THF */
+			if (data->type = w83627thf)
 				tmp &= 0xf0;
 			data->pwm[i] = tmp;
 			if (i = 1 &&
@@ -1756,12 +1607,12 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 			}
 		}
 		for (i = 0; i < num_temps; i++) {
-			data->temp[i] = w83627hf_read_value(
-						data, w83627hf_reg_temp[i]);
-			data->temp_max[i] = w83627hf_read_value(
-						data, w83627hf_reg_temp_over[i]);
-			data->temp_max_hyst[i] = w83627hf_read_value(
-						data, w83627hf_reg_temp_hyst[i]);
+			data->temp[i] = w83627hf_read_value(data,
+						w83627hf_reg_temp[i]);
+			data->temp_max[i] = w83627hf_read_value(data,
+						w83627hf_reg_temp_over[i]);
+			data->temp_max_hyst[i] = w83627hf_read_value(data,
+						w83627hf_reg_temp_hyst[i]);
 		}
 
 		w83627hf_update_fan_div(data);
@@ -1783,94 +1634,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 	return data;
 }
 
-static int __init w83627hf_device_add(unsigned short address,
-				      const struct w83627hf_sio_data *sio_data)
-{
-	struct resource res = {
-		.start	= address + WINB_REGION_OFFSET,
-		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
-		.name	= DRVNAME,
-		.flags	= IORESOURCE_IO,
-	};
-	int err;
-
-	err = acpi_check_resource_conflict(&res);
-	if (err)
-		goto exit;
-
-	pdev = platform_device_alloc(DRVNAME, address);
-	if (!pdev) {
-		err = -ENOMEM;
-		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
-		goto exit;
-	}
-
-	err = platform_device_add_resources(pdev, &res, 1);
-	if (err) {
-		printk(KERN_ERR DRVNAME ": Device resource addition failed "
-		       "(%d)\n", err);
-		goto exit_device_put;
-	}
-
-	err = platform_device_add_data(pdev, sio_data,
-				       sizeof(struct w83627hf_sio_data));
-	if (err) {
-		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
-		goto exit_device_put;
-	}
-
-	err = platform_device_add(pdev);
-	if (err) {
-		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
-		       err);
-		goto exit_device_put;
-	}
-
-	return 0;
-
-exit_device_put:
-	platform_device_put(pdev);
-exit:
-	return err;
-}
-
 static int __init sensors_w83627hf_init(void)
 {
-	int err;
-	unsigned short address;
-	struct w83627hf_sio_data sio_data;
-
-	if (w83627hf_find(0x2e, &address, &sio_data)
-	 && w83627hf_find(0x4e, &address, &sio_data))
-		return -ENODEV;
-
-	err = platform_driver_register(&w83627hf_driver);
-	if (err)
-		goto exit;
-
-	/* Sets global pdev as a side effect */
-	err = w83627hf_device_add(address, &sio_data);
-	if (err)
-		goto exit_driver;
-
-	return 0;
-
-exit_driver:
-	platform_driver_unregister(&w83627hf_driver);
-exit:
-	return err;
+	return platform_driver_register(&w83627hf_driver);
 }
 
 static void __exit sensors_w83627hf_exit(void)
 {
-	platform_device_unregister(pdev);
 	platform_driver_unregister(&w83627hf_driver);
 }
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
 	      "Philip Edelbrock <phil@netroedge.com>, "
 	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
-MODULE_DESCRIPTION("W83627HF driver");
+MODULE_DESCRIPTION("W83627HF hwmon driver");
 MODULE_LICENSE("GPL");
 
 module_init(sensors_w83627hf_init);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 491ac0f..9897d5c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -263,6 +263,20 @@ config EZX_PCAP
 	  This enables the PCAP ASIC present on EZX Phones. This is
 	  needed for MMC, TouchScreen, Sound, USB, etc..
 
+config MFD_W83627HF
+	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
+	help
+	  If you say yes here you add support for the Winbond W836X7 series
+	  of sensor chips: the W83627HF, W83627THF, W83637HF, W83687THF and
+	  W83697HF to your platform.
+
+	  This is a multi functional device and this support defines a new
+	  platform device only. See other configurations submenu in order to
+	  enable the drivers of Winbond chip's functionalities.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83627hf.
+
 endmenu
 
 menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 6f8a9a1..e348226 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_TWL4030_CORE)	+= twl4030-core.o twl4030-irq.o
 obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
 
 obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
+obj-$(CONFIG_MFD_W83627HF)	+= w83627hf.o
 
 obj-$(CONFIG_MCP)		+= mcp-core.o
 obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
diff --git a/drivers/mfd/w83627hf.c b/drivers/mfd/w83627hf.c
new file mode 100644
index 0000000..522add7
--- /dev/null
+++ b/drivers/mfd/w83627hf.c
@@ -0,0 +1,251 @@
+/*
+ *  w83627hf.c - platform device support
+ *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
+ *
+ *  Based on drivers/hwmon/w83627hf.c
+ *
+ *  Original copyright note:
+ *    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
+ *    Philip Edelbrock <phil@netroedge.com>,
+ *    and Mark Studebaker <mdsxyz123@yahoo.com>
+ *    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
+ *    Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
+ *
+ *    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
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/w83627hf.h>
+
+static u16 force_addr;
+module_param(force_addr, ushort, 0);
+MODULE_PARM_DESC(force_addr,
+		 "Initialize the base address of the sensors");
+static u8 force_i2c = 0x1f;
+module_param(force_i2c, byte, 0);
+MODULE_PARM_DESC(force_i2c,
+		 "Initialize the i2c address of the sensors");
+
+static int init = 1;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+/*
+ * Devices definitions
+ */
+
+static struct platform_device *pdev;
+
+static struct resource hwmon_res = {
+	.start  = /* address + */ WINB_REGION_OFFSET,
+	.end    = /* address + */ WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
+	.name   = DRVNAME "_hwmon",
+	.flags  = IORESOURCE_IO,
+};
+
+static struct mfd_cell cells[] = {
+	{
+		.name	   = DRVNAME "_hwmon",
+		.num_resources  = 1,
+		.resources      = &hwmon_res,
+	},
+};
+
+/*
+ * Local functions
+ */
+
+#define W627_DEVID 0x52
+#define W627THF_DEVID 0x82
+#define W697_DEVID 0x60
+#define W637_DEVID 0x70
+#define W687THF_DEVID 0x85
+#define WINB_ACT_REG 0x30
+#define WINB_BASE_REG 0x60
+/* Constants specified below */
+
+/* Alignment of the base address */
+#define WINB_ALIGNMENT		(~7)
+
+/* Offset & size of I/O region we are interested in */
+#define WINB_REGION_OFFSET	5
+#define WINB_REGION_SIZE	2
+
+static int __init w83627hf_find(int sioaddr, unsigned short *addr,
+				struct w83627hf_sio_data *sio_data)
+{
+	int err = -ENODEV;
+	u16 val;
+
+	static const __initdata char *names[] = {
+		"W83627HF",
+		"W83627THF",
+		"W83697HF",
+		"W83637HF",
+		"W83687THF",
+	};
+
+	sio_data->sioaddr = sioaddr;
+
+	superio_enter(sio_data);
+	val = force_id ? force_id : superio_inb(sio_data, DEVID);
+	switch (val) {
+	case W627_DEVID:
+		sio_data->type = w83627hf;
+		break;
+	case W627THF_DEVID:
+		sio_data->type = w83627thf;
+		break;
+	case W697_DEVID:
+		sio_data->type = w83697hf;
+		break;
+	case W637_DEVID:
+		sio_data->type = w83637hf;
+		break;
+	case W687THF_DEVID:
+		sio_data->type = w83687thf;
+		break;
+	case 0xff:	/* No device at all */
+		goto exit;
+	default:
+		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
+		goto exit;
+	}
+
+	superio_select(sio_data, W83627HF_LD_HWM);
+	force_addr &= WINB_ALIGNMENT;
+	if (force_addr) {
+		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
+		       force_addr);
+		superio_outb(sio_data, WINB_BASE_REG, force_addr >> 8);
+		superio_outb(sio_data, WINB_BASE_REG + 1, force_addr & 0xff);
+	}
+	val = (superio_inb(sio_data, WINB_BASE_REG) << 8) |
+	       superio_inb(sio_data, WINB_BASE_REG + 1);
+	*addr = val & WINB_ALIGNMENT;
+	if (*addr = 0) {
+		printk(KERN_WARNING DRVNAME ": Base address not set, "
+		       "skipping\n");
+		goto exit;
+	}
+
+	val = superio_inb(sio_data, WINB_ACT_REG);
+	if (!(val & 0x01)) {
+		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
+		superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
+	}
+
+	err = 0;
+	pr_info(DRVNAME ": Found %s chip at %#x\n",
+		names[sio_data->type], *addr);
+
+ exit:
+	superio_exit(sio_data);
+	return err;
+}
+
+static int __init w83627hf_device_add(unsigned short address,
+				      const struct w83627hf_sio_data *sio_data)
+{
+	struct resource res = {
+		.start	= address + WINB_REGION_OFFSET,
+		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
+		.name	= DRVNAME,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	hwmon_res.start += address;
+	hwmon_res.end += address;
+
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto exit;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct w83627hf_sio_data));
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	err = mfd_add_devices(&pdev->dev, pdev->id, cells, ARRAY_SIZE(cells),
+			(struct resource *) (address & 0xffff), -1);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Cannot add sub devices (%d)\n",
+			err);
+		goto exit_device_unregister;
+	}
+
+	return 0;
+
+exit_device_unregister:
+	platform_device_unregister(pdev);
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int __init w83627hf_init(void)
+{
+	unsigned short address;
+	struct w83627hf_sio_data sio_data;
+
+	if (w83627hf_find(0x2e, &address, &sio_data)
+	 && w83627hf_find(0x4e, &address, &sio_data))
+		return -ENODEV;
+
+	/* Sets global pdev as a side effect */
+	return w83627hf_device_add(address, &sio_data);
+}
+
+static void __exit w83627hf_exit(void)
+{
+	platform_device_unregister(pdev);
+}
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("W83627HF platform devices definitions");
+MODULE_LICENSE("GPL");
+
+module_init(w83627hf_init);
+module_exit(w83627hf_exit);
diff --git a/include/linux/mfd/w83627hf.h b/include/linux/mfd/w83627hf.h
new file mode 100644
index 0000000..c41dea1
--- /dev/null
+++ b/include/linux/mfd/w83627hf.h
@@ -0,0 +1,68 @@
+#define DRVNAME "w83627hf"
+
+/* Offset & size of I/O region we are interested in */
+#define WINB_REGION_OFFSET      5
+#define WINB_REGION_SIZE	2
+
+enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
+struct w83627hf_sio_data {
+	int sioaddr;
+	enum chips type;
+};
+
+/* logical device numbers for superio_select (below) */
+#define W83627HF_LD_FDC		0x00
+#define W83627HF_LD_PRT		0x01
+#define W83627HF_LD_UART1	0x02
+#define W83627HF_LD_UART2	0x03
+#define W83627HF_LD_KBC		0x05
+#define W83627HF_LD_CIR		0x06 /* w83627hf only */
+#define W83627HF_LD_GAME	0x07
+#define W83627HF_LD_MIDI	0x07
+#define W83627HF_LD_GPIO1	0x07
+#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
+#define W83627HF_LD_GPIO2	0x08
+#define W83627HF_LD_GPIO3	0x09
+#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
+#define W83627HF_LD_ACPI	0x0a
+#define W83627HF_LD_HWM		0x0b
+
+#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
+#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
+#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
+
+#define W83687THF_VID_EN	0x29 /* w83687thf only */
+#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
+#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
+
+#define DEV			0x07    /* Register: Logical device select */
+#define DEVID			0x20    /* Register: Device ID */
+
+static inline void superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
+{
+	outb(reg, sio->sioaddr);
+	outb(val, sio->sioaddr + 1);
+}
+
+static inline int superio_inb(struct w83627hf_sio_data *sio, int reg)
+{
+	outb(reg, sio->sioaddr);
+	return inb(sio->sioaddr + 1);
+}
+
+static inline void superio_select(struct w83627hf_sio_data *sio, int ld)
+{
+	outb(DEV, sio->sioaddr);
+	outb(ld, sio->sioaddr + 1);
+}
+
+static inline void superio_enter(struct w83627hf_sio_data *sio)
+{
+	outb(0x87, sio->sioaddr);
+	outb(0x87, sio->sioaddr);
+}
+
+static inline void superio_exit(struct w83627hf_sio_data *sio)
+{
+	outb(0xAA, sio->sioaddr);
+}
-- 
1.5.6.5


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
@ 2009-09-10 12:56 ` Jean Delvare
  2009-09-11  7:42 ` Rodolfo Giometti
                   ` (24 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Jean Delvare @ 2009-09-10 12:56 UTC (permalink / raw)
  To: lm-sensors

Hi Rodolfo,

Don't bother including Frodo L. and Mark S. in the discussions, they
have left the lm-sensors project years ago.

On Thu, 10 Sep 2009 14:30:10 +0200, Rodolfo Giometti wrote:
> The file has been splitted up into two parts:
> 
> * drivers/mfd/w83627hf.c         - detects the chip and define proper
>                                    platform devices into mfd support
> 
> * drivers/hwmon/hwmon-w83627hf.c - implements the driver for hwmon
>                                    functionality only
> 
> The patch also fixes up some non reentrant code and some C-style issues.
> 
> Signed-off-by: Rodolfo Giometti <giometti@linux.it>
> ---
>  drivers/hwmon/Kconfig                          |    2 +-
>  drivers/hwmon/Makefile                         |    2 +-
>  drivers/hwmon/{w83627hf.c => hwmon-w83627hf.c} |  373 +++++-------------------

This name change will break all users of the driver. The sensors-detect
script points the user to "w83627hf" and typically writes this value to
an init script or configuration file. The w83627hf driver doesn't
auto-load (yet) so this is a requirement.

Assuming that the hwmon part depends on the MFD part, I'd rather keep
"w83627hf" as the hwmon part name, and name the new MFD part
"w83627hf-core" or similar. I agree it's not so nice but at least it
doesn't break compatibility.

>  drivers/mfd/Kconfig                            |   14 +
>  drivers/mfd/Makefile                           |    1 +
>  drivers/mfd/w83627hf.c                         |  251 ++++++++++++++++
>  include/linux/mfd/w83627hf.h                   |   68 +++++
>  7 files changed, 411 insertions(+), 300 deletions(-)
>  rename drivers/hwmon/{w83627hf.c => hwmon-w83627hf.c} (85%)
>  create mode 100644 drivers/mfd/w83627hf.c
>  create mode 100644 include/linux/mfd/w83627hf.h

-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
  2009-09-10 12:56 ` Jean Delvare
@ 2009-09-11  7:42 ` Rodolfo Giometti
  2009-09-11 10:58 ` Samuel Ortiz
                   ` (23 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Rodolfo Giometti @ 2009-09-11  7:42 UTC (permalink / raw)
  To: lm-sensors


[-- Attachment #1.1: Type: text/plain, Size: 2086 bytes --]

On Thu, Sep 10, 2009 at 02:56:09PM +0200, Jean Delvare wrote:
> Hi Rodolfo,
> 
> Don't bother including Frodo L. and Mark S. in the discussions, they
> have left the lm-sensors project years ago.

Ok. I just sent the letter to them in order to inform about my
proposal...

> On Thu, 10 Sep 2009 14:30:10 +0200, Rodolfo Giometti wrote:
> > The file has been splitted up into two parts:
> > 
> > * drivers/mfd/w83627hf.c         - detects the chip and define proper
> >                                    platform devices into mfd support
> > 
> > * drivers/hwmon/hwmon-w83627hf.c - implements the driver for hwmon
> >                                    functionality only
> > 
> > The patch also fixes up some non reentrant code and some C-style issues.
> > 
> > Signed-off-by: Rodolfo Giometti <giometti@linux.it>
> > ---
> >  drivers/hwmon/Kconfig                          |    2 +-
> >  drivers/hwmon/Makefile                         |    2 +-
> >  drivers/hwmon/{w83627hf.c => hwmon-w83627hf.c} |  373 +++++-------------------
> 
> This name change will break all users of the driver. The sensors-detect
> script points the user to "w83627hf" and typically writes this value to
> an init script or configuration file. The w83627hf driver doesn't
> auto-load (yet) so this is a requirement.
> 
> Assuming that the hwmon part depends on the MFD part, I'd rather keep
> "w83627hf" as the hwmon part name, and name the new MFD part
> "w83627hf-core" or similar. I agree it's not so nice but at least it
> doesn't break compatibility.

I agree. So I'm going to keep w83627hf name for hwmon part name and
using w83627hf-core for the new MFD part. Then I'll repost my patch.

Thanks for your attention,

Rodolfo

-- 

GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming                     skype:  rodolfo.giometti
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 153 bytes --]

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
  2009-09-10 12:56 ` Jean Delvare
  2009-09-11  7:42 ` Rodolfo Giometti
@ 2009-09-11 10:58 ` Samuel Ortiz
  2009-09-11 15:07 ` Rodolfo Giometti
                   ` (22 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2009-09-11 10:58 UTC (permalink / raw)
  To: lm-sensors

Hi Rodolfo,

On Fri, Sep 11, 2009 at 09:42:23AM +0200, Rodolfo Giometti wrote:
> On Thu, Sep 10, 2009 at 02:56:09PM +0200, Jean Delvare wrote:
> > Hi Rodolfo,
> > 
> > Don't bother including Frodo L. and Mark S. in the discussions, they
> > have left the lm-sensors project years ago.
> 
> Ok. I just sent the letter to them in order to inform about my
> proposal...
> 
> > On Thu, 10 Sep 2009 14:30:10 +0200, Rodolfo Giometti wrote:
> > > The file has been splitted up into two parts:
> > > 
> > > * drivers/mfd/w83627hf.c         - detects the chip and define proper
> > >                                    platform devices into mfd support
> > > 
> > > * drivers/hwmon/hwmon-w83627hf.c - implements the driver for hwmon
> > >                                    functionality only
> > > 
> > > The patch also fixes up some non reentrant code and some C-style issues.
> > > 
> > > Signed-off-by: Rodolfo Giometti <giometti@linux.it>
> > > ---
> > >  drivers/hwmon/Kconfig                          |    2 +-
> > >  drivers/hwmon/Makefile                         |    2 +-
> > >  drivers/hwmon/{w83627hf.c => hwmon-w83627hf.c} |  373 +++++-------------------
> > 
> > This name change will break all users of the driver. The sensors-detect
> > script points the user to "w83627hf" and typically writes this value to
> > an init script or configuration file. The w83627hf driver doesn't
> > auto-load (yet) so this is a requirement.
> > 
> > Assuming that the hwmon part depends on the MFD part, I'd rather keep
> > "w83627hf" as the hwmon part name, and name the new MFD part
> > "w83627hf-core" or similar. I agree it's not so nice but at least it
> > doesn't break compatibility.
> 
> I agree. So I'm going to keep w83627hf name for hwmon part name and
> using w83627hf-core for the new MFD part. Then I'll repost my patch.
That would be nice. The MFD part looks good to me, so please post a new patch
and I'll queue it.

Cheers,
Samuel.


> Thanks for your attention,
> 
> Rodolfo
> 
> -- 
> 
> GNU/Linux Solutions                  e-mail: giometti@enneenne.com
> Linux Device Driver                          giometti@linux.it
> Embedded Systems                     phone:  +39 349 2432127
> UNIX programming                     skype:  rodolfo.giometti
> Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it



-- 
Intel Open Source Technology Centre
http://oss.intel.com/

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (2 preceding siblings ...)
  2009-09-11 10:58 ` Samuel Ortiz
@ 2009-09-11 15:07 ` Rodolfo Giometti
  2009-09-15 11:38 ` Samuel Ortiz
                   ` (21 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Rodolfo Giometti @ 2009-09-11 15:07 UTC (permalink / raw)
  To: lm-sensors

The file has been splitted up into two parts:

* drivers/mfd/w83627hf-core.c      - detects the chip and define proper
                                     platform devices into mfd support

* drivers/hwmon/w83627hf.c         - implements the driver for hwmon
                                     functionality only

The patch also fixes up some non reentrant code and some C-style issues.

Signed-off-by: Rodolfo Giometti <giometti@linux.it>
---
 drivers/hwmon/w83627hf.c     |  373 +++++++++---------------------------------
 drivers/mfd/Kconfig          |   14 ++
 drivers/mfd/Makefile         |    1 +
 drivers/mfd/w83627hf-core.c  |  251 ++++++++++++++++++++++++++++
 include/linux/mfd/w83627hf.h |   68 ++++++++
 5 files changed, 409 insertions(+), 298 deletions(-)
 create mode 100644 drivers/mfd/w83627hf-core.c
 create mode 100644 include/linux/mfd/w83627hf.h

diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 389150b..25f35ac 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -1,6 +1,6 @@
 /*
     w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware
-                monitoring
+		 monitoring
     Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
     Philip Edelbrock <phil@netroedge.com>,
     and Mark Studebaker <mdsxyz123@yahoo.com>
@@ -51,13 +51,9 @@
 #include <linux/mutex.h>
 #include <linux/ioport.h>
 #include <linux/acpi.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include "lm75.h"
-
-static struct platform_device *pdev;
-
-#define DRVNAME "w83627hf"
-enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
+#include <linux/mfd/w83627hf.h>
 
 static u16 force_addr;
 module_param(force_addr, ushort, 0);
@@ -76,88 +72,8 @@ static unsigned short force_id;
 module_param(force_id, ushort, 0);
 MODULE_PARM_DESC(force_id, "Override the detected device ID");
 
-/* modified from kernel/include/traps.c */
-static int REG;		/* The register to read/write */
-#define	DEV	0x07	/* Register: Logical device select */
-static int VAL;		/* The value to read/write */
-
-/* logical device numbers for superio_select (below) */
-#define W83627HF_LD_FDC		0x00
-#define W83627HF_LD_PRT		0x01
-#define W83627HF_LD_UART1	0x02
-#define W83627HF_LD_UART2	0x03
-#define W83627HF_LD_KBC		0x05
-#define W83627HF_LD_CIR		0x06 /* w83627hf only */
-#define W83627HF_LD_GAME	0x07
-#define W83627HF_LD_MIDI	0x07
-#define W83627HF_LD_GPIO1	0x07
-#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
-#define W83627HF_LD_GPIO2	0x08
-#define W83627HF_LD_GPIO3	0x09
-#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
-#define W83627HF_LD_ACPI	0x0a
-#define W83627HF_LD_HWM		0x0b
-
-#define	DEVID	0x20	/* Register: Device ID */
-
-#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
-#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
-#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
-
-#define W83687THF_VID_EN	0x29 /* w83687thf only */
-#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
-#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
-
-static inline void
-superio_outb(int reg, int val)
-{
-	outb(reg, REG);
-	outb(val, VAL);
-}
-
-static inline int
-superio_inb(int reg)
-{
-	outb(reg, REG);
-	return inb(VAL);
-}
-
-static inline void
-superio_select(int ld)
-{
-	outb(DEV, REG);
-	outb(ld, VAL);
-}
-
-static inline void
-superio_enter(void)
-{
-	outb(0x87, REG);
-	outb(0x87, REG);
-}
-
-static inline void
-superio_exit(void)
-{
-	outb(0xAA, REG);
-}
-
-#define W627_DEVID 0x52
-#define W627THF_DEVID 0x82
-#define W697_DEVID 0x60
-#define W637_DEVID 0x70
-#define W687THF_DEVID 0x85
-#define WINB_ACT_REG 0x30
-#define WINB_BASE_REG 0x60
 /* Constants specified below */
 
-/* Alignment of the base address */
-#define WINB_ALIGNMENT		~7
-
-/* Offset & size of I/O region we are interested in */
-#define WINB_REGION_OFFSET	5
-#define WINB_REGION_SIZE	2
-
 /* Where are the sensors address/data registers relative to the region offset */
 #define W83781D_ADDR_REG_OFFSET 0
 #define W83781D_DATA_REG_OFFSET 1
@@ -221,7 +137,7 @@ static const u8 W83627THF_PWM_ENABLE_SHIFT[] = { 2, 4, 1 };
 
 static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
 static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
-                             W83627THF_REG_PWM3 };
+				W83627THF_REG_PWM3 };
 #define W836X7HF_REG_PWM(type, nr) (((type) = w83627hf) ? \
 				    regpwm_627hf[nr] : regpwm[nr])
 
@@ -251,7 +167,7 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
    variants. Note that you should be a bit careful with which arguments
    these macros are called: arguments may be evaluated more than once.
    Fixing this is just not worth it. */
-#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16),0,255))
+#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16), 0, 255))
 #define IN_FROM_REG(val) ((val) * 16)
 
 static inline u8 FAN_TO_REG(long rpm, int div)
@@ -264,25 +180,26 @@ static inline u8 FAN_TO_REG(long rpm, int div)
 }
 
 #define TEMP_MIN (-128000)
-#define TEMP_MAX ( 127000)
+#define TEMP_MAX (127000)
 
 /* TEMP: 0.001C/bit (-128C to +127C)
    REG: 1C/bit, two's complement */
 static u8 TEMP_TO_REG(long temp)
 {
-        int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
-        ntemp += (ntemp<0 ? -500 : 500);
-        return (u8)(ntemp / 1000);
+	int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
+	ntemp += (ntemp < 0 ? -500 : 500);
+	return (u8)(ntemp / 1000);
 }
 
 static int TEMP_FROM_REG(u8 reg)
 {
-        return (s8)reg * 1000;
+	return (s8)reg * 1000;
 }
 
-#define FAN_FROM_REG(val,div) ((val)=0?-1:(val)=255?0:1350000/((val)*(div)))
+#define FAN_FROM_REG(val, div)	\
+		((val) = 0 ? -1 : (val) = 255 ? 0 : 1350000 / ((val) * (div)))
 
-#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
+#define PWM_TO_REG(val) (SENSORS_LIMIT((val), 0, 255))
 
 static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
 {
@@ -312,7 +229,7 @@ static inline unsigned long pwm_freq_from_reg(u8 reg)
 	/* This should not happen but anyway... */
 	if (reg = 0)
 		reg++;
-	return (clock / (reg << 8));
+	return clock / (reg << 8);
 }
 static inline u8 pwm_freq_to_reg(unsigned long val)
 {
@@ -320,11 +237,11 @@ static inline u8 pwm_freq_to_reg(unsigned long val)
 	if (val >= 93750)	/* The highest we can do */
 		return 0x01;
 	if (val >= 720)	/* Use 24 MHz clock */
-		return (24000000UL / (val << 8));
+		return 24000000UL / (val << 8);
 	if (val < 6)		/* The lowest we can do */
 		return 0xFF;
 	else			/* Use 180 kHz clock */
-		return (0x80 | (180000UL / (val << 8)));
+		return 0x80 | (180000UL / (val << 8));
 }
 
 #define BEEP_MASK_FROM_REG(val)		((val) & 0xff7fff)
@@ -341,7 +258,7 @@ static inline u8 DIV_TO_REG(long val)
 			break;
 		val >>= 1;
 	}
-	return ((u8) i);
+	return (u8) i;
 }
 
 /* For each registered chip, we need to keep some data in memory.
@@ -380,10 +297,6 @@ struct w83627hf_data {
 	u8 vrm_ovt;		/* Register value, 627THF/637HF/687THF only */
 };
 
-struct w83627hf_sio_data {
-	enum chips type;
-};
-
 
 static int w83627hf_probe(struct platform_device *pdev);
 static int __devexit w83627hf_remove(struct platform_device *pdev);
@@ -397,7 +310,7 @@ static void w83627hf_init_device(struct platform_device *pdev);
 static struct platform_driver w83627hf_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
-		.name	= DRVNAME,
+		.name	= DRVNAME "_hwmon",
 	},
 	.probe		= w83627hf_probe,
 	.remove		= __devexit_p(w83627hf_remove),
@@ -484,28 +397,32 @@ static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
 		/* use VRM8 (standard) calculation */
 		in0 = (long)IN_FROM_REG(reg);
 
-	return sprintf(buf,"%ld\n", in0);
+	return sprintf(buf, "%ld\n", in0);
 }
 
-static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_regs_in_0(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct w83627hf_data *data = w83627hf_update_device(dev);
 	return show_in_0(data, buf, data->in[0]);
 }
 
-static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_regs_in_min0(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct w83627hf_data *data = w83627hf_update_device(dev);
 	return show_in_0(data, buf, data->in_min[0]);
 }
 
-static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_regs_in_max0(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct w83627hf_data *data = w83627hf_update_device(dev);
 	return show_in_0(data, buf, data->in_max[0]);
 }
 
-static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
+static ssize_t store_regs_in_min0(struct device *dev,
+				struct device_attribute *attr,
 	const char *buf, size_t count)
 {
 	struct w83627hf_data *data = dev_get_drvdata(dev);
@@ -514,7 +431,7 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a
 	val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
-	
+
 	if ((data->vrm_ovt & 0x01) &&
 		(w83627thf = data->type || w83637hf = data->type
 		 || w83687thf = data->type))
@@ -532,7 +449,8 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a
 	return count;
 }
 
-static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
+static ssize_t store_regs_in_max0(struct device *dev,
+				struct device_attribute *attr,
 	const char *buf, size_t count)
 {
 	struct w83627hf_data *data = dev_get_drvdata(dev);
@@ -545,7 +463,7 @@ static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *a
 	if ((data->vrm_ovt & 0x01) &&
 		(w83627thf = data->type || w83637hf = data->type
 		 || w83687thf = data->type))
-		
+
 		/* use VRM9 calculation */
 		data->in_max[0]  			SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
@@ -701,7 +619,8 @@ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
 	return sprintf(buf, "%ld\n", (long) data->vrm);
 }
 static ssize_t
-store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+store_vrm_reg(struct device *dev, struct device_attribute *attr,
+					const char *buf, size_t count)
 {
 	struct w83627hf_data *data = dev_get_drvdata(dev);
 	u32 val;
@@ -897,14 +816,16 @@ store_fan_div(struct device *dev, struct device_attribute *devattr,
 
 	data->fan_div[nr] = DIV_TO_REG(val);
 
-	reg = (w83627hf_read_value(data, nr=2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
-	       & (nr=0 ? 0xcf : 0x3f))
-	    | ((data->fan_div[nr] & 0x03) << (nr=0 ? 4 : 6));
-	w83627hf_write_value(data, nr=2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
+	reg = (w83627hf_read_value(data,
+		nr = 2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
+		& (nr = 0 ? 0xcf : 0x3f))
+		| ((data->fan_div[nr] & 0x03) << (nr = 0 ? 4 : 6));
+	w83627hf_write_value(data,
+		nr = 2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
 
 	reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
-	       & ~(1 << (5 + nr)))
-	    | ((data->fan_div[nr] & 0x04) << (3 + nr));
+		& ~(1 << (5 + nr)))
+		| ((data->fan_div[nr] & 0x04) << (3 + nr));
 	w83627hf_write_value(data, W83781D_REG_VBAT, reg);
 
 	/* Restore fan_min */
@@ -1018,7 +939,7 @@ store_pwm_freq(struct device *dev, struct device_attribute *devattr,
 {
 	int nr = to_sensor_dev_attr(devattr)->index;
 	struct w83627hf_data *data = dev_get_drvdata(dev);
-	static const u8 mask[]={0xF8, 0x8F};
+	static const u8 mask[] = {0xF8, 0x8F};
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
@@ -1126,80 +1047,6 @@ show_name(struct device *dev, struct device_attribute *devattr, char *buf)
 }
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
-static int __init w83627hf_find(int sioaddr, unsigned short *addr,
-				struct w83627hf_sio_data *sio_data)
-{
-	int err = -ENODEV;
-	u16 val;
-
-	static const __initdata char *names[] = {
-		"W83627HF",
-		"W83627THF",
-		"W83697HF",
-		"W83637HF",
-		"W83687THF",
-	};
-
-	REG = sioaddr;
-	VAL = sioaddr + 1;
-
-	superio_enter();
-	val = force_id ? force_id : superio_inb(DEVID);
-	switch (val) {
-	case W627_DEVID:
-		sio_data->type = w83627hf;
-		break;
-	case W627THF_DEVID:
-		sio_data->type = w83627thf;
-		break;
-	case W697_DEVID:
-		sio_data->type = w83697hf;
-		break;
-	case W637_DEVID:
-		sio_data->type = w83637hf;
-		break;
-	case W687THF_DEVID:
-		sio_data->type = w83687thf;
-		break;
-	case 0xff:	/* No device at all */
-		goto exit;
-	default:
-		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
-		goto exit;
-	}
-
-	superio_select(W83627HF_LD_HWM);
-	force_addr &= WINB_ALIGNMENT;
-	if (force_addr) {
-		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
-		       force_addr);
-		superio_outb(WINB_BASE_REG, force_addr >> 8);
-		superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
-	}
-	val = (superio_inb(WINB_BASE_REG) << 8) |
-	       superio_inb(WINB_BASE_REG + 1);
-	*addr = val & WINB_ALIGNMENT;
-	if (*addr = 0) {
-		printk(KERN_WARNING DRVNAME ": Base address not set, "
-		       "skipping\n");
-		goto exit;
-	}
-
-	val = superio_inb(WINB_ACT_REG);
-	if (!(val & 0x01)) {
-		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
-		superio_outb(WINB_ACT_REG, val | 0x01);
-	}
-
-	err = 0;
-	pr_info(DRVNAME ": Found %s chip at %#x\n",
-		names[sio_data->type], *addr);
-
- exit:
-	superio_exit();
-	return err;
-}
-
 #define VIN_UNIT_ATTRS(_X_)	\
 	&sensor_dev_attr_in##_X_##_input.dev_attr.attr,		\
 	&sensor_dev_attr_in##_X_##_min.dev_attr.attr,		\
@@ -1281,7 +1128,7 @@ static const struct attribute_group w83627hf_group_opt = {
 static int __devinit w83627hf_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct w83627hf_sio_data *sio_data = dev->platform_data;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	struct w83627hf_data *data;
 	struct resource *res;
 	int err, i;
@@ -1435,15 +1282,15 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 
 	return 0;
 
-      ERROR4:
+ERROR4:
 	sysfs_remove_group(&dev->kobj, &w83627hf_group);
 	sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
-      ERROR3:
+ERROR3:
 	platform_set_drvdata(pdev, NULL);
 	kfree(data);
-      ERROR1:
+ERROR1:
 	release_region(res->start, WINB_REGION_SIZE);
-      ERROR0:
+ERROR0:
 	return err;
 }
 
@@ -1511,20 +1358,22 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
 
 static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	int res = 0xff, sel;
 
-	superio_enter();
-	superio_select(W83627HF_LD_GPIO5);
+	superio_enter(sio_data);
+	superio_select(sio_data, W83627HF_LD_GPIO5);
 
 	/* Make sure these GPIO pins are enabled */
-	if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
+	if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) {
 		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
 		goto exit;
 	}
 
 	/* Make sure the pins are configured for input
 	   There must be at least five (VRM 9), and possibly 6 (VRM 10) */
-	sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
+	sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f;
 	if ((sel & 0x1f) != 0x1f) {
 		dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
 			"function\n");
@@ -1532,37 +1381,39 @@ static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
 	}
 
 	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
-	res = superio_inb(W83627THF_GPIO5_DR) & sel;
+	res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel;
 
 exit:
-	superio_exit();
+	superio_exit(sio_data);
 	return res;
 }
 
 static int __devinit w83687thf_read_vid(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	int res = 0xff;
 
-	superio_enter();
-	superio_select(W83627HF_LD_HWM);
+	superio_enter(sio_data);
+	superio_select(sio_data, W83627HF_LD_HWM);
 
 	/* Make sure these GPIO pins are enabled */
-	if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
+	if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) {
 		dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
 		goto exit;
 	}
 
 	/* Make sure the pins are configured for input */
-	if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
+	if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) {
 		dev_dbg(&pdev->dev, "VID configured as output, "
 			"no VID function\n");
 		goto exit;
 	}
 
-	res = superio_inb(W83687THF_VID_DATA) & 0x3f;
+	res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f;
 
 exit:
-	superio_exit();
+	superio_exit(sio_data);
 	return res;
 }
 
@@ -1616,7 +1467,7 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
 
 	/* Read VRM & OVT Config only once */
 	if (type = w83627thf || type = w83637hf || type = w83687thf) {
-		data->vrm_ovt = 
+		data->vrm_ovt  			w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
 	}
 
@@ -1636,7 +1487,7 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
 			break;
 	}
 
-	if(init) {
+	if (init) {
 		/* Enable temp2 */
 		tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG);
 		if (tmp & 0x01) {
@@ -1724,8 +1575,8 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 		for (i = 0; i <= 2; i++) {
 			u8 tmp = w83627hf_read_value(data,
 				W836X7HF_REG_PWM(data->type, i));
- 			/* bits 0-3 are reserved  in 627THF */
- 			if (data->type = w83627thf)
+			/* bits 0-3 are reserved  in 627THF */
+			if (data->type = w83627thf)
 				tmp &= 0xf0;
 			data->pwm[i] = tmp;
 			if (i = 1 &&
@@ -1756,12 +1607,12 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 			}
 		}
 		for (i = 0; i < num_temps; i++) {
-			data->temp[i] = w83627hf_read_value(
-						data, w83627hf_reg_temp[i]);
-			data->temp_max[i] = w83627hf_read_value(
-						data, w83627hf_reg_temp_over[i]);
-			data->temp_max_hyst[i] = w83627hf_read_value(
-						data, w83627hf_reg_temp_hyst[i]);
+			data->temp[i] = w83627hf_read_value(data,
+						w83627hf_reg_temp[i]);
+			data->temp_max[i] = w83627hf_read_value(data,
+						w83627hf_reg_temp_over[i]);
+			data->temp_max_hyst[i] = w83627hf_read_value(data,
+						w83627hf_reg_temp_hyst[i]);
 		}
 
 		w83627hf_update_fan_div(data);
@@ -1783,94 +1634,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 	return data;
 }
 
-static int __init w83627hf_device_add(unsigned short address,
-				      const struct w83627hf_sio_data *sio_data)
-{
-	struct resource res = {
-		.start	= address + WINB_REGION_OFFSET,
-		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
-		.name	= DRVNAME,
-		.flags	= IORESOURCE_IO,
-	};
-	int err;
-
-	err = acpi_check_resource_conflict(&res);
-	if (err)
-		goto exit;
-
-	pdev = platform_device_alloc(DRVNAME, address);
-	if (!pdev) {
-		err = -ENOMEM;
-		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
-		goto exit;
-	}
-
-	err = platform_device_add_resources(pdev, &res, 1);
-	if (err) {
-		printk(KERN_ERR DRVNAME ": Device resource addition failed "
-		       "(%d)\n", err);
-		goto exit_device_put;
-	}
-
-	err = platform_device_add_data(pdev, sio_data,
-				       sizeof(struct w83627hf_sio_data));
-	if (err) {
-		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
-		goto exit_device_put;
-	}
-
-	err = platform_device_add(pdev);
-	if (err) {
-		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
-		       err);
-		goto exit_device_put;
-	}
-
-	return 0;
-
-exit_device_put:
-	platform_device_put(pdev);
-exit:
-	return err;
-}
-
 static int __init sensors_w83627hf_init(void)
 {
-	int err;
-	unsigned short address;
-	struct w83627hf_sio_data sio_data;
-
-	if (w83627hf_find(0x2e, &address, &sio_data)
-	 && w83627hf_find(0x4e, &address, &sio_data))
-		return -ENODEV;
-
-	err = platform_driver_register(&w83627hf_driver);
-	if (err)
-		goto exit;
-
-	/* Sets global pdev as a side effect */
-	err = w83627hf_device_add(address, &sio_data);
-	if (err)
-		goto exit_driver;
-
-	return 0;
-
-exit_driver:
-	platform_driver_unregister(&w83627hf_driver);
-exit:
-	return err;
+	return platform_driver_register(&w83627hf_driver);
 }
 
 static void __exit sensors_w83627hf_exit(void)
 {
-	platform_device_unregister(pdev);
 	platform_driver_unregister(&w83627hf_driver);
 }
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
 	      "Philip Edelbrock <phil@netroedge.com>, "
 	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
-MODULE_DESCRIPTION("W83627HF driver");
+MODULE_DESCRIPTION("W83627HF hwmon driver");
 MODULE_LICENSE("GPL");
 
 module_init(sensors_w83627hf_init);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 491ac0f..b52d957 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -263,6 +263,20 @@ config EZX_PCAP
 	  This enables the PCAP ASIC present on EZX Phones. This is
 	  needed for MMC, TouchScreen, Sound, USB, etc..
 
+config MFD_W83627HF
+	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
+	help
+	  If you say yes here you add support for the Winbond W836X7 series
+	  of sensor chips: the W83627HF, W83627THF, W83637HF, W83687THF and
+	  W83697HF to your platform.
+
+	  This is a multi functional device and this support defines a new
+	  platform device only. See other configurations submenu in order to
+	  enable the drivers of Winbond chip's functionalities.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83627hf-core.
+
 endmenu
 
 menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 6f8a9a1..1401ac9 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_TWL4030_CORE)	+= twl4030-core.o twl4030-irq.o
 obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
 
 obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
+obj-$(CONFIG_MFD_W83627HF)	+= w83627hf-core.o
 
 obj-$(CONFIG_MCP)		+= mcp-core.o
 obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
diff --git a/drivers/mfd/w83627hf-core.c b/drivers/mfd/w83627hf-core.c
new file mode 100644
index 0000000..522add7
--- /dev/null
+++ b/drivers/mfd/w83627hf-core.c
@@ -0,0 +1,251 @@
+/*
+ *  w83627hf.c - platform device support
+ *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
+ *
+ *  Based on drivers/hwmon/w83627hf.c
+ *
+ *  Original copyright note:
+ *    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
+ *    Philip Edelbrock <phil@netroedge.com>,
+ *    and Mark Studebaker <mdsxyz123@yahoo.com>
+ *    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
+ *    Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
+ *
+ *    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
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/w83627hf.h>
+
+static u16 force_addr;
+module_param(force_addr, ushort, 0);
+MODULE_PARM_DESC(force_addr,
+		 "Initialize the base address of the sensors");
+static u8 force_i2c = 0x1f;
+module_param(force_i2c, byte, 0);
+MODULE_PARM_DESC(force_i2c,
+		 "Initialize the i2c address of the sensors");
+
+static int init = 1;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+/*
+ * Devices definitions
+ */
+
+static struct platform_device *pdev;
+
+static struct resource hwmon_res = {
+	.start  = /* address + */ WINB_REGION_OFFSET,
+	.end    = /* address + */ WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
+	.name   = DRVNAME "_hwmon",
+	.flags  = IORESOURCE_IO,
+};
+
+static struct mfd_cell cells[] = {
+	{
+		.name	   = DRVNAME "_hwmon",
+		.num_resources  = 1,
+		.resources      = &hwmon_res,
+	},
+};
+
+/*
+ * Local functions
+ */
+
+#define W627_DEVID 0x52
+#define W627THF_DEVID 0x82
+#define W697_DEVID 0x60
+#define W637_DEVID 0x70
+#define W687THF_DEVID 0x85
+#define WINB_ACT_REG 0x30
+#define WINB_BASE_REG 0x60
+/* Constants specified below */
+
+/* Alignment of the base address */
+#define WINB_ALIGNMENT		(~7)
+
+/* Offset & size of I/O region we are interested in */
+#define WINB_REGION_OFFSET	5
+#define WINB_REGION_SIZE	2
+
+static int __init w83627hf_find(int sioaddr, unsigned short *addr,
+				struct w83627hf_sio_data *sio_data)
+{
+	int err = -ENODEV;
+	u16 val;
+
+	static const __initdata char *names[] = {
+		"W83627HF",
+		"W83627THF",
+		"W83697HF",
+		"W83637HF",
+		"W83687THF",
+	};
+
+	sio_data->sioaddr = sioaddr;
+
+	superio_enter(sio_data);
+	val = force_id ? force_id : superio_inb(sio_data, DEVID);
+	switch (val) {
+	case W627_DEVID:
+		sio_data->type = w83627hf;
+		break;
+	case W627THF_DEVID:
+		sio_data->type = w83627thf;
+		break;
+	case W697_DEVID:
+		sio_data->type = w83697hf;
+		break;
+	case W637_DEVID:
+		sio_data->type = w83637hf;
+		break;
+	case W687THF_DEVID:
+		sio_data->type = w83687thf;
+		break;
+	case 0xff:	/* No device at all */
+		goto exit;
+	default:
+		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
+		goto exit;
+	}
+
+	superio_select(sio_data, W83627HF_LD_HWM);
+	force_addr &= WINB_ALIGNMENT;
+	if (force_addr) {
+		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
+		       force_addr);
+		superio_outb(sio_data, WINB_BASE_REG, force_addr >> 8);
+		superio_outb(sio_data, WINB_BASE_REG + 1, force_addr & 0xff);
+	}
+	val = (superio_inb(sio_data, WINB_BASE_REG) << 8) |
+	       superio_inb(sio_data, WINB_BASE_REG + 1);
+	*addr = val & WINB_ALIGNMENT;
+	if (*addr = 0) {
+		printk(KERN_WARNING DRVNAME ": Base address not set, "
+		       "skipping\n");
+		goto exit;
+	}
+
+	val = superio_inb(sio_data, WINB_ACT_REG);
+	if (!(val & 0x01)) {
+		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
+		superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
+	}
+
+	err = 0;
+	pr_info(DRVNAME ": Found %s chip at %#x\n",
+		names[sio_data->type], *addr);
+
+ exit:
+	superio_exit(sio_data);
+	return err;
+}
+
+static int __init w83627hf_device_add(unsigned short address,
+				      const struct w83627hf_sio_data *sio_data)
+{
+	struct resource res = {
+		.start	= address + WINB_REGION_OFFSET,
+		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
+		.name	= DRVNAME,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	hwmon_res.start += address;
+	hwmon_res.end += address;
+
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto exit;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct w83627hf_sio_data));
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	err = mfd_add_devices(&pdev->dev, pdev->id, cells, ARRAY_SIZE(cells),
+			(struct resource *) (address & 0xffff), -1);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Cannot add sub devices (%d)\n",
+			err);
+		goto exit_device_unregister;
+	}
+
+	return 0;
+
+exit_device_unregister:
+	platform_device_unregister(pdev);
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int __init w83627hf_init(void)
+{
+	unsigned short address;
+	struct w83627hf_sio_data sio_data;
+
+	if (w83627hf_find(0x2e, &address, &sio_data)
+	 && w83627hf_find(0x4e, &address, &sio_data))
+		return -ENODEV;
+
+	/* Sets global pdev as a side effect */
+	return w83627hf_device_add(address, &sio_data);
+}
+
+static void __exit w83627hf_exit(void)
+{
+	platform_device_unregister(pdev);
+}
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("W83627HF platform devices definitions");
+MODULE_LICENSE("GPL");
+
+module_init(w83627hf_init);
+module_exit(w83627hf_exit);
diff --git a/include/linux/mfd/w83627hf.h b/include/linux/mfd/w83627hf.h
new file mode 100644
index 0000000..c41dea1
--- /dev/null
+++ b/include/linux/mfd/w83627hf.h
@@ -0,0 +1,68 @@
+#define DRVNAME "w83627hf"
+
+/* Offset & size of I/O region we are interested in */
+#define WINB_REGION_OFFSET      5
+#define WINB_REGION_SIZE	2
+
+enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
+struct w83627hf_sio_data {
+	int sioaddr;
+	enum chips type;
+};
+
+/* logical device numbers for superio_select (below) */
+#define W83627HF_LD_FDC		0x00
+#define W83627HF_LD_PRT		0x01
+#define W83627HF_LD_UART1	0x02
+#define W83627HF_LD_UART2	0x03
+#define W83627HF_LD_KBC		0x05
+#define W83627HF_LD_CIR		0x06 /* w83627hf only */
+#define W83627HF_LD_GAME	0x07
+#define W83627HF_LD_MIDI	0x07
+#define W83627HF_LD_GPIO1	0x07
+#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
+#define W83627HF_LD_GPIO2	0x08
+#define W83627HF_LD_GPIO3	0x09
+#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
+#define W83627HF_LD_ACPI	0x0a
+#define W83627HF_LD_HWM		0x0b
+
+#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
+#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
+#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
+
+#define W83687THF_VID_EN	0x29 /* w83687thf only */
+#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
+#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
+
+#define DEV			0x07    /* Register: Logical device select */
+#define DEVID			0x20    /* Register: Device ID */
+
+static inline void superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
+{
+	outb(reg, sio->sioaddr);
+	outb(val, sio->sioaddr + 1);
+}
+
+static inline int superio_inb(struct w83627hf_sio_data *sio, int reg)
+{
+	outb(reg, sio->sioaddr);
+	return inb(sio->sioaddr + 1);
+}
+
+static inline void superio_select(struct w83627hf_sio_data *sio, int ld)
+{
+	outb(DEV, sio->sioaddr);
+	outb(ld, sio->sioaddr + 1);
+}
+
+static inline void superio_enter(struct w83627hf_sio_data *sio)
+{
+	outb(0x87, sio->sioaddr);
+	outb(0x87, sio->sioaddr);
+}
+
+static inline void superio_exit(struct w83627hf_sio_data *sio)
+{
+	outb(0xAA, sio->sioaddr);
+}
-- 
1.6.0.4


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (3 preceding siblings ...)
  2009-09-11 15:07 ` Rodolfo Giometti
@ 2009-09-15 11:38 ` Samuel Ortiz
  2009-09-17 13:34 ` Jean Delvare
                   ` (20 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2009-09-15 11:38 UTC (permalink / raw)
  To: lm-sensors

Hi Rodolfo,

On Fri, Sep 11, 2009 at 05:07:05PM +0200, Rodolfo Giometti wrote:
> The file has been splitted up into two parts:
> 
> * drivers/mfd/w83627hf-core.c      - detects the chip and define proper
>                                      platform devices into mfd support
> 
> * drivers/hwmon/w83627hf.c         - implements the driver for hwmon
>                                      functionality only
> 
> The patch also fixes up some non reentrant code and some C-style issues.
I'm fine with the mfd part.
Jean, are you ok with the hwmon one ? I'm ok with queueing this one up, unless
you want to carry it.

Cheers,
Samuel.


> Signed-off-by: Rodolfo Giometti <giometti@linux.it>
> ---
>  drivers/hwmon/w83627hf.c     |  373 +++++++++---------------------------------
>  drivers/mfd/Kconfig          |   14 ++
>  drivers/mfd/Makefile         |    1 +
>  drivers/mfd/w83627hf-core.c  |  251 ++++++++++++++++++++++++++++
>  include/linux/mfd/w83627hf.h |   68 ++++++++
>  5 files changed, 409 insertions(+), 298 deletions(-)
>  create mode 100644 drivers/mfd/w83627hf-core.c
>  create mode 100644 include/linux/mfd/w83627hf.h
> 
> diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
> index 389150b..25f35ac 100644
> --- a/drivers/hwmon/w83627hf.c
> +++ b/drivers/hwmon/w83627hf.c
> @@ -1,6 +1,6 @@
>  /*
>      w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware
> -                monitoring
> +		 monitoring
>      Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
>      Philip Edelbrock <phil@netroedge.com>,
>      and Mark Studebaker <mdsxyz123@yahoo.com>
> @@ -51,13 +51,9 @@
>  #include <linux/mutex.h>
>  #include <linux/ioport.h>
>  #include <linux/acpi.h>
> -#include <asm/io.h>
> +#include <linux/io.h>
>  #include "lm75.h"
> -
> -static struct platform_device *pdev;
> -
> -#define DRVNAME "w83627hf"
> -enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
> +#include <linux/mfd/w83627hf.h>
>  
>  static u16 force_addr;
>  module_param(force_addr, ushort, 0);
> @@ -76,88 +72,8 @@ static unsigned short force_id;
>  module_param(force_id, ushort, 0);
>  MODULE_PARM_DESC(force_id, "Override the detected device ID");
>  
> -/* modified from kernel/include/traps.c */
> -static int REG;		/* The register to read/write */
> -#define	DEV	0x07	/* Register: Logical device select */
> -static int VAL;		/* The value to read/write */
> -
> -/* logical device numbers for superio_select (below) */
> -#define W83627HF_LD_FDC		0x00
> -#define W83627HF_LD_PRT		0x01
> -#define W83627HF_LD_UART1	0x02
> -#define W83627HF_LD_UART2	0x03
> -#define W83627HF_LD_KBC		0x05
> -#define W83627HF_LD_CIR		0x06 /* w83627hf only */
> -#define W83627HF_LD_GAME	0x07
> -#define W83627HF_LD_MIDI	0x07
> -#define W83627HF_LD_GPIO1	0x07
> -#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
> -#define W83627HF_LD_GPIO2	0x08
> -#define W83627HF_LD_GPIO3	0x09
> -#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
> -#define W83627HF_LD_ACPI	0x0a
> -#define W83627HF_LD_HWM		0x0b
> -
> -#define	DEVID	0x20	/* Register: Device ID */
> -
> -#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
> -#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
> -#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
> -
> -#define W83687THF_VID_EN	0x29 /* w83687thf only */
> -#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
> -#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
> -
> -static inline void
> -superio_outb(int reg, int val)
> -{
> -	outb(reg, REG);
> -	outb(val, VAL);
> -}
> -
> -static inline int
> -superio_inb(int reg)
> -{
> -	outb(reg, REG);
> -	return inb(VAL);
> -}
> -
> -static inline void
> -superio_select(int ld)
> -{
> -	outb(DEV, REG);
> -	outb(ld, VAL);
> -}
> -
> -static inline void
> -superio_enter(void)
> -{
> -	outb(0x87, REG);
> -	outb(0x87, REG);
> -}
> -
> -static inline void
> -superio_exit(void)
> -{
> -	outb(0xAA, REG);
> -}
> -
> -#define W627_DEVID 0x52
> -#define W627THF_DEVID 0x82
> -#define W697_DEVID 0x60
> -#define W637_DEVID 0x70
> -#define W687THF_DEVID 0x85
> -#define WINB_ACT_REG 0x30
> -#define WINB_BASE_REG 0x60
>  /* Constants specified below */
>  
> -/* Alignment of the base address */
> -#define WINB_ALIGNMENT		~7
> -
> -/* Offset & size of I/O region we are interested in */
> -#define WINB_REGION_OFFSET	5
> -#define WINB_REGION_SIZE	2
> -
>  /* Where are the sensors address/data registers relative to the region offset */
>  #define W83781D_ADDR_REG_OFFSET 0
>  #define W83781D_DATA_REG_OFFSET 1
> @@ -221,7 +137,7 @@ static const u8 W83627THF_PWM_ENABLE_SHIFT[] = { 2, 4, 1 };
>  
>  static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
>  static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
> -                             W83627THF_REG_PWM3 };
> +				W83627THF_REG_PWM3 };
>  #define W836X7HF_REG_PWM(type, nr) (((type) = w83627hf) ? \
>  				    regpwm_627hf[nr] : regpwm[nr])
>  
> @@ -251,7 +167,7 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
>     variants. Note that you should be a bit careful with which arguments
>     these macros are called: arguments may be evaluated more than once.
>     Fixing this is just not worth it. */
> -#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16),0,255))
> +#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16), 0, 255))
>  #define IN_FROM_REG(val) ((val) * 16)
>  
>  static inline u8 FAN_TO_REG(long rpm, int div)
> @@ -264,25 +180,26 @@ static inline u8 FAN_TO_REG(long rpm, int div)
>  }
>  
>  #define TEMP_MIN (-128000)
> -#define TEMP_MAX ( 127000)
> +#define TEMP_MAX (127000)
>  
>  /* TEMP: 0.001C/bit (-128C to +127C)
>     REG: 1C/bit, two's complement */
>  static u8 TEMP_TO_REG(long temp)
>  {
> -        int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
> -        ntemp += (ntemp<0 ? -500 : 500);
> -        return (u8)(ntemp / 1000);
> +	int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
> +	ntemp += (ntemp < 0 ? -500 : 500);
> +	return (u8)(ntemp / 1000);
>  }
>  
>  static int TEMP_FROM_REG(u8 reg)
>  {
> -        return (s8)reg * 1000;
> +	return (s8)reg * 1000;
>  }
>  
> -#define FAN_FROM_REG(val,div) ((val)=0?-1:(val)=255?0:1350000/((val)*(div)))
> +#define FAN_FROM_REG(val, div)	\
> +		((val) = 0 ? -1 : (val) = 255 ? 0 : 1350000 / ((val) * (div)))
>  
> -#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
> +#define PWM_TO_REG(val) (SENSORS_LIMIT((val), 0, 255))
>  
>  static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
>  {
> @@ -312,7 +229,7 @@ static inline unsigned long pwm_freq_from_reg(u8 reg)
>  	/* This should not happen but anyway... */
>  	if (reg = 0)
>  		reg++;
> -	return (clock / (reg << 8));
> +	return clock / (reg << 8);
>  }
>  static inline u8 pwm_freq_to_reg(unsigned long val)
>  {
> @@ -320,11 +237,11 @@ static inline u8 pwm_freq_to_reg(unsigned long val)
>  	if (val >= 93750)	/* The highest we can do */
>  		return 0x01;
>  	if (val >= 720)	/* Use 24 MHz clock */
> -		return (24000000UL / (val << 8));
> +		return 24000000UL / (val << 8);
>  	if (val < 6)		/* The lowest we can do */
>  		return 0xFF;
>  	else			/* Use 180 kHz clock */
> -		return (0x80 | (180000UL / (val << 8)));
> +		return 0x80 | (180000UL / (val << 8));
>  }
>  
>  #define BEEP_MASK_FROM_REG(val)		((val) & 0xff7fff)
> @@ -341,7 +258,7 @@ static inline u8 DIV_TO_REG(long val)
>  			break;
>  		val >>= 1;
>  	}
> -	return ((u8) i);
> +	return (u8) i;
>  }
>  
>  /* For each registered chip, we need to keep some data in memory.
> @@ -380,10 +297,6 @@ struct w83627hf_data {
>  	u8 vrm_ovt;		/* Register value, 627THF/637HF/687THF only */
>  };
>  
> -struct w83627hf_sio_data {
> -	enum chips type;
> -};
> -
>  
>  static int w83627hf_probe(struct platform_device *pdev);
>  static int __devexit w83627hf_remove(struct platform_device *pdev);
> @@ -397,7 +310,7 @@ static void w83627hf_init_device(struct platform_device *pdev);
>  static struct platform_driver w83627hf_driver = {
>  	.driver = {
>  		.owner	= THIS_MODULE,
> -		.name	= DRVNAME,
> +		.name	= DRVNAME "_hwmon",
>  	},
>  	.probe		= w83627hf_probe,
>  	.remove		= __devexit_p(w83627hf_remove),
> @@ -484,28 +397,32 @@ static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
>  		/* use VRM8 (standard) calculation */
>  		in0 = (long)IN_FROM_REG(reg);
>  
> -	return sprintf(buf,"%ld\n", in0);
> +	return sprintf(buf, "%ld\n", in0);
>  }
>  
> -static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf)
> +static ssize_t show_regs_in_0(struct device *dev,
> +				struct device_attribute *attr, char *buf)
>  {
>  	struct w83627hf_data *data = w83627hf_update_device(dev);
>  	return show_in_0(data, buf, data->in[0]);
>  }
>  
> -static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf)
> +static ssize_t show_regs_in_min0(struct device *dev,
> +				struct device_attribute *attr, char *buf)
>  {
>  	struct w83627hf_data *data = w83627hf_update_device(dev);
>  	return show_in_0(data, buf, data->in_min[0]);
>  }
>  
> -static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf)
> +static ssize_t show_regs_in_max0(struct device *dev,
> +				struct device_attribute *attr, char *buf)
>  {
>  	struct w83627hf_data *data = w83627hf_update_device(dev);
>  	return show_in_0(data, buf, data->in_max[0]);
>  }
>  
> -static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
> +static ssize_t store_regs_in_min0(struct device *dev,
> +				struct device_attribute *attr,
>  	const char *buf, size_t count)
>  {
>  	struct w83627hf_data *data = dev_get_drvdata(dev);
> @@ -514,7 +431,7 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a
>  	val = simple_strtoul(buf, NULL, 10);
>  
>  	mutex_lock(&data->update_lock);
> -	
> +
>  	if ((data->vrm_ovt & 0x01) &&
>  		(w83627thf = data->type || w83637hf = data->type
>  		 || w83687thf = data->type))
> @@ -532,7 +449,8 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a
>  	return count;
>  }
>  
> -static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
> +static ssize_t store_regs_in_max0(struct device *dev,
> +				struct device_attribute *attr,
>  	const char *buf, size_t count)
>  {
>  	struct w83627hf_data *data = dev_get_drvdata(dev);
> @@ -545,7 +463,7 @@ static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *a
>  	if ((data->vrm_ovt & 0x01) &&
>  		(w83627thf = data->type || w83637hf = data->type
>  		 || w83687thf = data->type))
> -		
> +
>  		/* use VRM9 calculation */
>  		data->in_max[0] >  			SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
> @@ -701,7 +619,8 @@ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
>  	return sprintf(buf, "%ld\n", (long) data->vrm);
>  }
>  static ssize_t
> -store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
> +store_vrm_reg(struct device *dev, struct device_attribute *attr,
> +					const char *buf, size_t count)
>  {
>  	struct w83627hf_data *data = dev_get_drvdata(dev);
>  	u32 val;
> @@ -897,14 +816,16 @@ store_fan_div(struct device *dev, struct device_attribute *devattr,
>  
>  	data->fan_div[nr] = DIV_TO_REG(val);
>  
> -	reg = (w83627hf_read_value(data, nr=2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
> -	       & (nr=0 ? 0xcf : 0x3f))
> -	    | ((data->fan_div[nr] & 0x03) << (nr=0 ? 4 : 6));
> -	w83627hf_write_value(data, nr=2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
> +	reg = (w83627hf_read_value(data,
> +		nr = 2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
> +		& (nr = 0 ? 0xcf : 0x3f))
> +		| ((data->fan_div[nr] & 0x03) << (nr = 0 ? 4 : 6));
> +	w83627hf_write_value(data,
> +		nr = 2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
>  
>  	reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
> -	       & ~(1 << (5 + nr)))
> -	    | ((data->fan_div[nr] & 0x04) << (3 + nr));
> +		& ~(1 << (5 + nr)))
> +		| ((data->fan_div[nr] & 0x04) << (3 + nr));
>  	w83627hf_write_value(data, W83781D_REG_VBAT, reg);
>  
>  	/* Restore fan_min */
> @@ -1018,7 +939,7 @@ store_pwm_freq(struct device *dev, struct device_attribute *devattr,
>  {
>  	int nr = to_sensor_dev_attr(devattr)->index;
>  	struct w83627hf_data *data = dev_get_drvdata(dev);
> -	static const u8 mask[]={0xF8, 0x8F};
> +	static const u8 mask[] = {0xF8, 0x8F};
>  	u32 val;
>  
>  	val = simple_strtoul(buf, NULL, 10);
> @@ -1126,80 +1047,6 @@ show_name(struct device *dev, struct device_attribute *devattr, char *buf)
>  }
>  static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
>  
> -static int __init w83627hf_find(int sioaddr, unsigned short *addr,
> -				struct w83627hf_sio_data *sio_data)
> -{
> -	int err = -ENODEV;
> -	u16 val;
> -
> -	static const __initdata char *names[] = {
> -		"W83627HF",
> -		"W83627THF",
> -		"W83697HF",
> -		"W83637HF",
> -		"W83687THF",
> -	};
> -
> -	REG = sioaddr;
> -	VAL = sioaddr + 1;
> -
> -	superio_enter();
> -	val = force_id ? force_id : superio_inb(DEVID);
> -	switch (val) {
> -	case W627_DEVID:
> -		sio_data->type = w83627hf;
> -		break;
> -	case W627THF_DEVID:
> -		sio_data->type = w83627thf;
> -		break;
> -	case W697_DEVID:
> -		sio_data->type = w83697hf;
> -		break;
> -	case W637_DEVID:
> -		sio_data->type = w83637hf;
> -		break;
> -	case W687THF_DEVID:
> -		sio_data->type = w83687thf;
> -		break;
> -	case 0xff:	/* No device at all */
> -		goto exit;
> -	default:
> -		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
> -		goto exit;
> -	}
> -
> -	superio_select(W83627HF_LD_HWM);
> -	force_addr &= WINB_ALIGNMENT;
> -	if (force_addr) {
> -		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
> -		       force_addr);
> -		superio_outb(WINB_BASE_REG, force_addr >> 8);
> -		superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
> -	}
> -	val = (superio_inb(WINB_BASE_REG) << 8) |
> -	       superio_inb(WINB_BASE_REG + 1);
> -	*addr = val & WINB_ALIGNMENT;
> -	if (*addr = 0) {
> -		printk(KERN_WARNING DRVNAME ": Base address not set, "
> -		       "skipping\n");
> -		goto exit;
> -	}
> -
> -	val = superio_inb(WINB_ACT_REG);
> -	if (!(val & 0x01)) {
> -		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
> -		superio_outb(WINB_ACT_REG, val | 0x01);
> -	}
> -
> -	err = 0;
> -	pr_info(DRVNAME ": Found %s chip at %#x\n",
> -		names[sio_data->type], *addr);
> -
> - exit:
> -	superio_exit();
> -	return err;
> -}
> -
>  #define VIN_UNIT_ATTRS(_X_)	\
>  	&sensor_dev_attr_in##_X_##_input.dev_attr.attr,		\
>  	&sensor_dev_attr_in##_X_##_min.dev_attr.attr,		\
> @@ -1281,7 +1128,7 @@ static const struct attribute_group w83627hf_group_opt = {
>  static int __devinit w83627hf_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> -	struct w83627hf_sio_data *sio_data = dev->platform_data;
> +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
>  	struct w83627hf_data *data;
>  	struct resource *res;
>  	int err, i;
> @@ -1435,15 +1282,15 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
>  
>  	return 0;
>  
> -      ERROR4:
> +ERROR4:
>  	sysfs_remove_group(&dev->kobj, &w83627hf_group);
>  	sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
> -      ERROR3:
> +ERROR3:
>  	platform_set_drvdata(pdev, NULL);
>  	kfree(data);
> -      ERROR1:
> +ERROR1:
>  	release_region(res->start, WINB_REGION_SIZE);
> -      ERROR0:
> +ERROR0:
>  	return err;
>  }
>  
> @@ -1511,20 +1358,22 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
>  
>  static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
>  {
> +	struct device *dev = &pdev->dev;
> +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
>  	int res = 0xff, sel;
>  
> -	superio_enter();
> -	superio_select(W83627HF_LD_GPIO5);
> +	superio_enter(sio_data);
> +	superio_select(sio_data, W83627HF_LD_GPIO5);
>  
>  	/* Make sure these GPIO pins are enabled */
> -	if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
> +	if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) {
>  		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
>  		goto exit;
>  	}
>  
>  	/* Make sure the pins are configured for input
>  	   There must be at least five (VRM 9), and possibly 6 (VRM 10) */
> -	sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
> +	sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f;
>  	if ((sel & 0x1f) != 0x1f) {
>  		dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
>  			"function\n");
> @@ -1532,37 +1381,39 @@ static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
>  	}
>  
>  	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
> -	res = superio_inb(W83627THF_GPIO5_DR) & sel;
> +	res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel;
>  
>  exit:
> -	superio_exit();
> +	superio_exit(sio_data);
>  	return res;
>  }
>  
>  static int __devinit w83687thf_read_vid(struct platform_device *pdev)
>  {
> +	struct device *dev = &pdev->dev;
> +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
>  	int res = 0xff;
>  
> -	superio_enter();
> -	superio_select(W83627HF_LD_HWM);
> +	superio_enter(sio_data);
> +	superio_select(sio_data, W83627HF_LD_HWM);
>  
>  	/* Make sure these GPIO pins are enabled */
> -	if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
> +	if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) {
>  		dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
>  		goto exit;
>  	}
>  
>  	/* Make sure the pins are configured for input */
> -	if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
> +	if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) {
>  		dev_dbg(&pdev->dev, "VID configured as output, "
>  			"no VID function\n");
>  		goto exit;
>  	}
>  
> -	res = superio_inb(W83687THF_VID_DATA) & 0x3f;
> +	res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f;
>  
>  exit:
> -	superio_exit();
> +	superio_exit(sio_data);
>  	return res;
>  }
>  
> @@ -1616,7 +1467,7 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
>  
>  	/* Read VRM & OVT Config only once */
>  	if (type = w83627thf || type = w83637hf || type = w83687thf) {
> -		data->vrm_ovt = 
> +		data->vrm_ovt >  			w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
>  	}
>  
> @@ -1636,7 +1487,7 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
>  			break;
>  	}
>  
> -	if(init) {
> +	if (init) {
>  		/* Enable temp2 */
>  		tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG);
>  		if (tmp & 0x01) {
> @@ -1724,8 +1575,8 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
>  		for (i = 0; i <= 2; i++) {
>  			u8 tmp = w83627hf_read_value(data,
>  				W836X7HF_REG_PWM(data->type, i));
> - 			/* bits 0-3 are reserved  in 627THF */
> - 			if (data->type = w83627thf)
> +			/* bits 0-3 are reserved  in 627THF */
> +			if (data->type = w83627thf)
>  				tmp &= 0xf0;
>  			data->pwm[i] = tmp;
>  			if (i = 1 &&
> @@ -1756,12 +1607,12 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
>  			}
>  		}
>  		for (i = 0; i < num_temps; i++) {
> -			data->temp[i] = w83627hf_read_value(
> -						data, w83627hf_reg_temp[i]);
> -			data->temp_max[i] = w83627hf_read_value(
> -						data, w83627hf_reg_temp_over[i]);
> -			data->temp_max_hyst[i] = w83627hf_read_value(
> -						data, w83627hf_reg_temp_hyst[i]);
> +			data->temp[i] = w83627hf_read_value(data,
> +						w83627hf_reg_temp[i]);
> +			data->temp_max[i] = w83627hf_read_value(data,
> +						w83627hf_reg_temp_over[i]);
> +			data->temp_max_hyst[i] = w83627hf_read_value(data,
> +						w83627hf_reg_temp_hyst[i]);
>  		}
>  
>  		w83627hf_update_fan_div(data);
> @@ -1783,94 +1634,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
>  	return data;
>  }
>  
> -static int __init w83627hf_device_add(unsigned short address,
> -				      const struct w83627hf_sio_data *sio_data)
> -{
> -	struct resource res = {
> -		.start	= address + WINB_REGION_OFFSET,
> -		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
> -		.name	= DRVNAME,
> -		.flags	= IORESOURCE_IO,
> -	};
> -	int err;
> -
> -	err = acpi_check_resource_conflict(&res);
> -	if (err)
> -		goto exit;
> -
> -	pdev = platform_device_alloc(DRVNAME, address);
> -	if (!pdev) {
> -		err = -ENOMEM;
> -		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
> -		goto exit;
> -	}
> -
> -	err = platform_device_add_resources(pdev, &res, 1);
> -	if (err) {
> -		printk(KERN_ERR DRVNAME ": Device resource addition failed "
> -		       "(%d)\n", err);
> -		goto exit_device_put;
> -	}
> -
> -	err = platform_device_add_data(pdev, sio_data,
> -				       sizeof(struct w83627hf_sio_data));
> -	if (err) {
> -		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
> -		goto exit_device_put;
> -	}
> -
> -	err = platform_device_add(pdev);
> -	if (err) {
> -		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
> -		       err);
> -		goto exit_device_put;
> -	}
> -
> -	return 0;
> -
> -exit_device_put:
> -	platform_device_put(pdev);
> -exit:
> -	return err;
> -}
> -
>  static int __init sensors_w83627hf_init(void)
>  {
> -	int err;
> -	unsigned short address;
> -	struct w83627hf_sio_data sio_data;
> -
> -	if (w83627hf_find(0x2e, &address, &sio_data)
> -	 && w83627hf_find(0x4e, &address, &sio_data))
> -		return -ENODEV;
> -
> -	err = platform_driver_register(&w83627hf_driver);
> -	if (err)
> -		goto exit;
> -
> -	/* Sets global pdev as a side effect */
> -	err = w83627hf_device_add(address, &sio_data);
> -	if (err)
> -		goto exit_driver;
> -
> -	return 0;
> -
> -exit_driver:
> -	platform_driver_unregister(&w83627hf_driver);
> -exit:
> -	return err;
> +	return platform_driver_register(&w83627hf_driver);
>  }
>  
>  static void __exit sensors_w83627hf_exit(void)
>  {
> -	platform_device_unregister(pdev);
>  	platform_driver_unregister(&w83627hf_driver);
>  }
>  
>  MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
>  	      "Philip Edelbrock <phil@netroedge.com>, "
>  	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
> -MODULE_DESCRIPTION("W83627HF driver");
> +MODULE_DESCRIPTION("W83627HF hwmon driver");
>  MODULE_LICENSE("GPL");
>  
>  module_init(sensors_w83627hf_init);
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 491ac0f..b52d957 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -263,6 +263,20 @@ config EZX_PCAP
>  	  This enables the PCAP ASIC present on EZX Phones. This is
>  	  needed for MMC, TouchScreen, Sound, USB, etc..
>  
> +config MFD_W83627HF
> +	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
> +	help
> +	  If you say yes here you add support for the Winbond W836X7 series
> +	  of sensor chips: the W83627HF, W83627THF, W83637HF, W83687THF and
> +	  W83697HF to your platform.
> +
> +	  This is a multi functional device and this support defines a new
> +	  platform device only. See other configurations submenu in order to
> +	  enable the drivers of Winbond chip's functionalities.
> +
> +	  This driver can also be built as a module.  If so, the module
> +	  will be called w83627hf-core.
> +
>  endmenu
>  
>  menu "Multimedia Capabilities Port drivers"
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 6f8a9a1..1401ac9 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -27,6 +27,7 @@ obj-$(CONFIG_TWL4030_CORE)	+= twl4030-core.o twl4030-irq.o
>  obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
>  
>  obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
> +obj-$(CONFIG_MFD_W83627HF)	+= w83627hf-core.o
>  
>  obj-$(CONFIG_MCP)		+= mcp-core.o
>  obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
> diff --git a/drivers/mfd/w83627hf-core.c b/drivers/mfd/w83627hf-core.c
> new file mode 100644
> index 0000000..522add7
> --- /dev/null
> +++ b/drivers/mfd/w83627hf-core.c
> @@ -0,0 +1,251 @@
> +/*
> + *  w83627hf.c - platform device support
> + *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
> + *
> + *  Based on drivers/hwmon/w83627hf.c
> + *
> + *  Original copyright note:
> + *    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
> + *    Philip Edelbrock <phil@netroedge.com>,
> + *    and Mark Studebaker <mdsxyz123@yahoo.com>
> + *    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
> + *    Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
> + *
> + *    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
> + *    the Free Software Foundation; either version 2 of the License, or
> + *    (at your option) any later version.
> + *
> + *    This program is distributed in the hope that it will be useful,
> + *    but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *    GNU General Public License for more details.
> + *
> + *    You should have received a copy of the GNU General Public License
> + *    along with this program; if not, write to the Free Software
> + *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> +*/
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/ioport.h>
> +#include <linux/acpi.h>
> +#include <linux/io.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/w83627hf.h>
> +
> +static u16 force_addr;
> +module_param(force_addr, ushort, 0);
> +MODULE_PARM_DESC(force_addr,
> +		 "Initialize the base address of the sensors");
> +static u8 force_i2c = 0x1f;
> +module_param(force_i2c, byte, 0);
> +MODULE_PARM_DESC(force_i2c,
> +		 "Initialize the i2c address of the sensors");
> +
> +static int init = 1;
> +module_param(init, bool, 0);
> +MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
> +
> +static unsigned short force_id;
> +module_param(force_id, ushort, 0);
> +MODULE_PARM_DESC(force_id, "Override the detected device ID");
> +
> +/*
> + * Devices definitions
> + */
> +
> +static struct platform_device *pdev;
> +
> +static struct resource hwmon_res = {
> +	.start  = /* address + */ WINB_REGION_OFFSET,
> +	.end    = /* address + */ WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
> +	.name   = DRVNAME "_hwmon",
> +	.flags  = IORESOURCE_IO,
> +};
> +
> +static struct mfd_cell cells[] = {
> +	{
> +		.name	   = DRVNAME "_hwmon",
> +		.num_resources  = 1,
> +		.resources      = &hwmon_res,
> +	},
> +};
> +
> +/*
> + * Local functions
> + */
> +
> +#define W627_DEVID 0x52
> +#define W627THF_DEVID 0x82
> +#define W697_DEVID 0x60
> +#define W637_DEVID 0x70
> +#define W687THF_DEVID 0x85
> +#define WINB_ACT_REG 0x30
> +#define WINB_BASE_REG 0x60
> +/* Constants specified below */
> +
> +/* Alignment of the base address */
> +#define WINB_ALIGNMENT		(~7)
> +
> +/* Offset & size of I/O region we are interested in */
> +#define WINB_REGION_OFFSET	5
> +#define WINB_REGION_SIZE	2
> +
> +static int __init w83627hf_find(int sioaddr, unsigned short *addr,
> +				struct w83627hf_sio_data *sio_data)
> +{
> +	int err = -ENODEV;
> +	u16 val;
> +
> +	static const __initdata char *names[] = {
> +		"W83627HF",
> +		"W83627THF",
> +		"W83697HF",
> +		"W83637HF",
> +		"W83687THF",
> +	};
> +
> +	sio_data->sioaddr = sioaddr;
> +
> +	superio_enter(sio_data);
> +	val = force_id ? force_id : superio_inb(sio_data, DEVID);
> +	switch (val) {
> +	case W627_DEVID:
> +		sio_data->type = w83627hf;
> +		break;
> +	case W627THF_DEVID:
> +		sio_data->type = w83627thf;
> +		break;
> +	case W697_DEVID:
> +		sio_data->type = w83697hf;
> +		break;
> +	case W637_DEVID:
> +		sio_data->type = w83637hf;
> +		break;
> +	case W687THF_DEVID:
> +		sio_data->type = w83687thf;
> +		break;
> +	case 0xff:	/* No device at all */
> +		goto exit;
> +	default:
> +		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
> +		goto exit;
> +	}
> +
> +	superio_select(sio_data, W83627HF_LD_HWM);
> +	force_addr &= WINB_ALIGNMENT;
> +	if (force_addr) {
> +		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
> +		       force_addr);
> +		superio_outb(sio_data, WINB_BASE_REG, force_addr >> 8);
> +		superio_outb(sio_data, WINB_BASE_REG + 1, force_addr & 0xff);
> +	}
> +	val = (superio_inb(sio_data, WINB_BASE_REG) << 8) |
> +	       superio_inb(sio_data, WINB_BASE_REG + 1);
> +	*addr = val & WINB_ALIGNMENT;
> +	if (*addr = 0) {
> +		printk(KERN_WARNING DRVNAME ": Base address not set, "
> +		       "skipping\n");
> +		goto exit;
> +	}
> +
> +	val = superio_inb(sio_data, WINB_ACT_REG);
> +	if (!(val & 0x01)) {
> +		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
> +		superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
> +	}
> +
> +	err = 0;
> +	pr_info(DRVNAME ": Found %s chip at %#x\n",
> +		names[sio_data->type], *addr);
> +
> + exit:
> +	superio_exit(sio_data);
> +	return err;
> +}
> +
> +static int __init w83627hf_device_add(unsigned short address,
> +				      const struct w83627hf_sio_data *sio_data)
> +{
> +	struct resource res = {
> +		.start	= address + WINB_REGION_OFFSET,
> +		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
> +		.name	= DRVNAME,
> +		.flags	= IORESOURCE_IO,
> +	};
> +	int err;
> +
> +	hwmon_res.start += address;
> +	hwmon_res.end += address;
> +
> +	err = acpi_check_resource_conflict(&res);
> +	if (err)
> +		goto exit;
> +
> +	pdev = platform_device_alloc(DRVNAME, address);
> +	if (!pdev) {
> +		err = -ENOMEM;
> +		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
> +		goto exit;
> +	}
> +
> +	err = platform_device_add_data(pdev, sio_data,
> +				       sizeof(struct w83627hf_sio_data));
> +	if (err) {
> +		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
> +		goto exit_device_put;
> +	}
> +
> +	err = platform_device_add(pdev);
> +	if (err) {
> +		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
> +		       err);
> +		goto exit_device_put;
> +	}
> +
> +	err = mfd_add_devices(&pdev->dev, pdev->id, cells, ARRAY_SIZE(cells),
> +			(struct resource *) (address & 0xffff), -1);
> +	if (err) {
> +		printk(KERN_ERR DRVNAME ": Cannot add sub devices (%d)\n",
> +			err);
> +		goto exit_device_unregister;
> +	}
> +
> +	return 0;
> +
> +exit_device_unregister:
> +	platform_device_unregister(pdev);
> +exit_device_put:
> +	platform_device_put(pdev);
> +exit:
> +	return err;
> +}
> +
> +static int __init w83627hf_init(void)
> +{
> +	unsigned short address;
> +	struct w83627hf_sio_data sio_data;
> +
> +	if (w83627hf_find(0x2e, &address, &sio_data)
> +	 && w83627hf_find(0x4e, &address, &sio_data))
> +		return -ENODEV;
> +
> +	/* Sets global pdev as a side effect */
> +	return w83627hf_device_add(address, &sio_data);
> +}
> +
> +static void __exit w83627hf_exit(void)
> +{
> +	platform_device_unregister(pdev);
> +}
> +
> +MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
> +MODULE_DESCRIPTION("W83627HF platform devices definitions");
> +MODULE_LICENSE("GPL");
> +
> +module_init(w83627hf_init);
> +module_exit(w83627hf_exit);
> diff --git a/include/linux/mfd/w83627hf.h b/include/linux/mfd/w83627hf.h
> new file mode 100644
> index 0000000..c41dea1
> --- /dev/null
> +++ b/include/linux/mfd/w83627hf.h
> @@ -0,0 +1,68 @@
> +#define DRVNAME "w83627hf"
> +
> +/* Offset & size of I/O region we are interested in */
> +#define WINB_REGION_OFFSET      5
> +#define WINB_REGION_SIZE	2
> +
> +enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
> +struct w83627hf_sio_data {
> +	int sioaddr;
> +	enum chips type;
> +};
> +
> +/* logical device numbers for superio_select (below) */
> +#define W83627HF_LD_FDC		0x00
> +#define W83627HF_LD_PRT		0x01
> +#define W83627HF_LD_UART1	0x02
> +#define W83627HF_LD_UART2	0x03
> +#define W83627HF_LD_KBC		0x05
> +#define W83627HF_LD_CIR		0x06 /* w83627hf only */
> +#define W83627HF_LD_GAME	0x07
> +#define W83627HF_LD_MIDI	0x07
> +#define W83627HF_LD_GPIO1	0x07
> +#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
> +#define W83627HF_LD_GPIO2	0x08
> +#define W83627HF_LD_GPIO3	0x09
> +#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
> +#define W83627HF_LD_ACPI	0x0a
> +#define W83627HF_LD_HWM		0x0b
> +
> +#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
> +#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
> +#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
> +
> +#define W83687THF_VID_EN	0x29 /* w83687thf only */
> +#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
> +#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
> +
> +#define DEV			0x07    /* Register: Logical device select */
> +#define DEVID			0x20    /* Register: Device ID */
> +
> +static inline void superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
> +{
> +	outb(reg, sio->sioaddr);
> +	outb(val, sio->sioaddr + 1);
> +}
> +
> +static inline int superio_inb(struct w83627hf_sio_data *sio, int reg)
> +{
> +	outb(reg, sio->sioaddr);
> +	return inb(sio->sioaddr + 1);
> +}
> +
> +static inline void superio_select(struct w83627hf_sio_data *sio, int ld)
> +{
> +	outb(DEV, sio->sioaddr);
> +	outb(ld, sio->sioaddr + 1);
> +}
> +
> +static inline void superio_enter(struct w83627hf_sio_data *sio)
> +{
> +	outb(0x87, sio->sioaddr);
> +	outb(0x87, sio->sioaddr);
> +}
> +
> +static inline void superio_exit(struct w83627hf_sio_data *sio)
> +{
> +	outb(0xAA, sio->sioaddr);
> +}
> -- 
> 1.6.0.4
> 

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (4 preceding siblings ...)
  2009-09-15 11:38 ` Samuel Ortiz
@ 2009-09-17 13:34 ` Jean Delvare
  2009-09-17 13:51 ` Rodolfo Giometti
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Jean Delvare @ 2009-09-17 13:34 UTC (permalink / raw)
  To: lm-sensors

Hi Rodolfo,

On Fri, 11 Sep 2009 17:07:05 +0200, Rodolfo Giometti wrote:
> The file has been splitted up into two parts:

Spelling: split (it's an irregular verb.)

> 
> * drivers/mfd/w83627hf-core.c      - detects the chip and define proper
>                                      platform devices into mfd support
> 
> * drivers/hwmon/w83627hf.c         - implements the driver for hwmon
>                                      functionality only
> 
> The patch also fixes up some non reentrant code and some C-style issues.

Sounds wrong. Mixing coding style cleanups with real changes makes
reviewing much harder. You'll have to move these changes to a separate
patch I'm afraid.

> 
> Signed-off-by: Rodolfo Giometti <giometti@linux.it>
> ---
>  drivers/hwmon/w83627hf.c     |  373 +++++++++---------------------------------
>  drivers/mfd/Kconfig          |   14 ++
>  drivers/mfd/Makefile         |    1 +
>  drivers/mfd/w83627hf-core.c  |  251 ++++++++++++++++++++++++++++
>  include/linux/mfd/w83627hf.h |   68 ++++++++
>  5 files changed, 409 insertions(+), 298 deletions(-)
>  create mode 100644 drivers/mfd/w83627hf-core.c
>  create mode 100644 include/linux/mfd/w83627hf.h

Review:

> 
> diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
> index 389150b..25f35ac 100644
> --- a/drivers/hwmon/w83627hf.c
> +++ b/drivers/hwmon/w83627hf.c
> @@ -1,6 +1,6 @@
>  /*
>      w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware
> -                monitoring
> +		 monitoring

This kind of clean up is better done in a separate patch.

>      Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
>      Philip Edelbrock <phil@netroedge.com>,
>      and Mark Studebaker <mdsxyz123@yahoo.com>
> @@ -51,13 +51,9 @@
>  #include <linux/mutex.h>
>  #include <linux/ioport.h>
>  #include <linux/acpi.h>
> -#include <asm/io.h>
> +#include <linux/io.h>

This is already fixed in my hwmon tree.

>  #include "lm75.h"
> -
> -static struct platform_device *pdev;
> -
> -#define DRVNAME "w83627hf"
> -enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
> +#include <linux/mfd/w83627hf.h>
>  
>  static u16 force_addr;
>  module_param(force_addr, ushort, 0);
> @@ -76,88 +72,8 @@ static unsigned short force_id;
>  module_param(force_id, ushort, 0);
>  MODULE_PARM_DESC(force_id, "Override the detected device ID");

You have left module parameters force_addr and force_id in this driver
while they are no longer used anywhere. This is confusing.

>  
> -/* modified from kernel/include/traps.c */
> -static int REG;		/* The register to read/write */
> -#define	DEV	0x07	/* Register: Logical device select */
> -static int VAL;		/* The value to read/write */
> -
> -/* logical device numbers for superio_select (below) */
> -#define W83627HF_LD_FDC		0x00
> -#define W83627HF_LD_PRT		0x01
> -#define W83627HF_LD_UART1	0x02
> -#define W83627HF_LD_UART2	0x03
> -#define W83627HF_LD_KBC		0x05
> -#define W83627HF_LD_CIR		0x06 /* w83627hf only */
> -#define W83627HF_LD_GAME	0x07
> -#define W83627HF_LD_MIDI	0x07
> -#define W83627HF_LD_GPIO1	0x07
> -#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
> -#define W83627HF_LD_GPIO2	0x08
> -#define W83627HF_LD_GPIO3	0x09
> -#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
> -#define W83627HF_LD_ACPI	0x0a
> -#define W83627HF_LD_HWM		0x0b
> -
> -#define	DEVID	0x20	/* Register: Device ID */
> -
> -#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
> -#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
> -#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
> -
> -#define W83687THF_VID_EN	0x29 /* w83687thf only */
> -#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
> -#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
> -
> -static inline void
> -superio_outb(int reg, int val)
> -{
> -	outb(reg, REG);
> -	outb(val, VAL);
> -}
> -
> -static inline int
> -superio_inb(int reg)
> -{
> -	outb(reg, REG);
> -	return inb(VAL);
> -}
> -
> -static inline void
> -superio_select(int ld)
> -{
> -	outb(DEV, REG);
> -	outb(ld, VAL);
> -}
> -
> -static inline void
> -superio_enter(void)
> -{
> -	outb(0x87, REG);
> -	outb(0x87, REG);
> -}
> -
> -static inline void
> -superio_exit(void)
> -{
> -	outb(0xAA, REG);
> -}
> -
> -#define W627_DEVID 0x52
> -#define W627THF_DEVID 0x82
> -#define W697_DEVID 0x60
> -#define W637_DEVID 0x70
> -#define W687THF_DEVID 0x85
> -#define WINB_ACT_REG 0x30
> -#define WINB_BASE_REG 0x60
>  /* Constants specified below */
>  
> -/* Alignment of the base address */
> -#define WINB_ALIGNMENT		~7
> -
> -/* Offset & size of I/O region we are interested in */
> -#define WINB_REGION_OFFSET	5
> -#define WINB_REGION_SIZE	2
> -
>  /* Where are the sensors address/data registers relative to the region offset */
>  #define W83781D_ADDR_REG_OFFSET 0
>  #define W83781D_DATA_REG_OFFSET 1
> @@ -221,7 +137,7 @@ static const u8 W83627THF_PWM_ENABLE_SHIFT[] = { 2, 4, 1 };
>  
>  static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
>  static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
> -                             W83627THF_REG_PWM3 };
> +				W83627THF_REG_PWM3 };
>  #define W836X7HF_REG_PWM(type, nr) (((type) = w83627hf) ? \
>  				    regpwm_627hf[nr] : regpwm[nr])
>  
> @@ -251,7 +167,7 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
>     variants. Note that you should be a bit careful with which arguments
>     these macros are called: arguments may be evaluated more than once.
>     Fixing this is just not worth it. */
> -#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16),0,255))
> +#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16), 0, 255))
>  #define IN_FROM_REG(val) ((val) * 16)
>  
>  static inline u8 FAN_TO_REG(long rpm, int div)
> @@ -264,25 +180,26 @@ static inline u8 FAN_TO_REG(long rpm, int div)
>  }
>  
>  #define TEMP_MIN (-128000)
> -#define TEMP_MAX ( 127000)
> +#define TEMP_MAX (127000)
>  
>  /* TEMP: 0.001C/bit (-128C to +127C)
>     REG: 1C/bit, two's complement */
>  static u8 TEMP_TO_REG(long temp)
>  {
> -        int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
> -        ntemp += (ntemp<0 ? -500 : 500);
> -        return (u8)(ntemp / 1000);
> +	int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
> +	ntemp += (ntemp < 0 ? -500 : 500);
> +	return (u8)(ntemp / 1000);
>  }
>  
>  static int TEMP_FROM_REG(u8 reg)
>  {
> -        return (s8)reg * 1000;
> +	return (s8)reg * 1000;
>  }
>  
> -#define FAN_FROM_REG(val,div) ((val)=0?-1:(val)=255?0:1350000/((val)*(div)))
> +#define FAN_FROM_REG(val, div)	\
> +		((val) = 0 ? -1 : (val) = 255 ? 0 : 1350000 / ((val) * (div)))
>  
> -#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
> +#define PWM_TO_REG(val) (SENSORS_LIMIT((val), 0, 255))
>  
>  static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
>  {
> @@ -312,7 +229,7 @@ static inline unsigned long pwm_freq_from_reg(u8 reg)
>  	/* This should not happen but anyway... */
>  	if (reg = 0)
>  		reg++;
> -	return (clock / (reg << 8));
> +	return clock / (reg << 8);
>  }
>  static inline u8 pwm_freq_to_reg(unsigned long val)
>  {
> @@ -320,11 +237,11 @@ static inline u8 pwm_freq_to_reg(unsigned long val)
>  	if (val >= 93750)	/* The highest we can do */
>  		return 0x01;
>  	if (val >= 720)	/* Use 24 MHz clock */
> -		return (24000000UL / (val << 8));
> +		return 24000000UL / (val << 8);
>  	if (val < 6)		/* The lowest we can do */
>  		return 0xFF;
>  	else			/* Use 180 kHz clock */
> -		return (0x80 | (180000UL / (val << 8)));
> +		return 0x80 | (180000UL / (val << 8));
>  }
>  
>  #define BEEP_MASK_FROM_REG(val)		((val) & 0xff7fff)
> @@ -341,7 +258,7 @@ static inline u8 DIV_TO_REG(long val)
>  			break;
>  		val >>= 1;
>  	}
> -	return ((u8) i);
> +	return (u8) i;
>  }
>  
>  /* For each registered chip, we need to keep some data in memory.
> @@ -380,10 +297,6 @@ struct w83627hf_data {
>  	u8 vrm_ovt;		/* Register value, 627THF/637HF/687THF only */
>  };
>  
> -struct w83627hf_sio_data {
> -	enum chips type;
> -};
> -
>  
>  static int w83627hf_probe(struct platform_device *pdev);
>  static int __devexit w83627hf_remove(struct platform_device *pdev);
> @@ -397,7 +310,7 @@ static void w83627hf_init_device(struct platform_device *pdev);
>  static struct platform_driver w83627hf_driver = {
>  	.driver = {
>  		.owner	= THIS_MODULE,
> -		.name	= DRVNAME,
> +		.name	= DRVNAME "_hwmon",
>  	},
>  	.probe		= w83627hf_probe,
>  	.remove		= __devexit_p(w83627hf_remove),
> @@ -484,28 +397,32 @@ static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
>  		/* use VRM8 (standard) calculation */
>  		in0 = (long)IN_FROM_REG(reg);
>  
> -	return sprintf(buf,"%ld\n", in0);
> +	return sprintf(buf, "%ld\n", in0);
>  }
>  
> -static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf)
> +static ssize_t show_regs_in_0(struct device *dev,
> +				struct device_attribute *attr, char *buf)
>  {
>  	struct w83627hf_data *data = w83627hf_update_device(dev);
>  	return show_in_0(data, buf, data->in[0]);
>  }
>  
> -static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf)
> +static ssize_t show_regs_in_min0(struct device *dev,
> +				struct device_attribute *attr, char *buf)
>  {
>  	struct w83627hf_data *data = w83627hf_update_device(dev);
>  	return show_in_0(data, buf, data->in_min[0]);
>  }
>  
> -static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf)
> +static ssize_t show_regs_in_max0(struct device *dev,
> +				struct device_attribute *attr, char *buf)
>  {
>  	struct w83627hf_data *data = w83627hf_update_device(dev);
>  	return show_in_0(data, buf, data->in_max[0]);
>  }
>  
> -static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
> +static ssize_t store_regs_in_min0(struct device *dev,
> +				struct device_attribute *attr,
>  	const char *buf, size_t count)
>  {
>  	struct w83627hf_data *data = dev_get_drvdata(dev);
> @@ -514,7 +431,7 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a
>  	val = simple_strtoul(buf, NULL, 10);
>  
>  	mutex_lock(&data->update_lock);
> -	
> +
>  	if ((data->vrm_ovt & 0x01) &&
>  		(w83627thf = data->type || w83637hf = data->type
>  		 || w83687thf = data->type))
> @@ -532,7 +449,8 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a
>  	return count;
>  }
>  
> -static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
> +static ssize_t store_regs_in_max0(struct device *dev,
> +				struct device_attribute *attr,
>  	const char *buf, size_t count)
>  {
>  	struct w83627hf_data *data = dev_get_drvdata(dev);
> @@ -545,7 +463,7 @@ static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *a
>  	if ((data->vrm_ovt & 0x01) &&
>  		(w83627thf = data->type || w83637hf = data->type
>  		 || w83687thf = data->type))
> -		
> +
>  		/* use VRM9 calculation */
>  		data->in_max[0] >  			SENSORS_LIMIT(((val * 100) - 70000 + 244) / 488, 0,
> @@ -701,7 +619,8 @@ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
>  	return sprintf(buf, "%ld\n", (long) data->vrm);
>  }
>  static ssize_t
> -store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
> +store_vrm_reg(struct device *dev, struct device_attribute *attr,
> +					const char *buf, size_t count)
>  {
>  	struct w83627hf_data *data = dev_get_drvdata(dev);
>  	u32 val;
> @@ -897,14 +816,16 @@ store_fan_div(struct device *dev, struct device_attribute *devattr,
>  
>  	data->fan_div[nr] = DIV_TO_REG(val);
>  
> -	reg = (w83627hf_read_value(data, nr=2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
> -	       & (nr=0 ? 0xcf : 0x3f))
> -	    | ((data->fan_div[nr] & 0x03) << (nr=0 ? 4 : 6));
> -	w83627hf_write_value(data, nr=2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
> +	reg = (w83627hf_read_value(data,
> +		nr = 2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
> +		& (nr = 0 ? 0xcf : 0x3f))
> +		| ((data->fan_div[nr] & 0x03) << (nr = 0 ? 4 : 6));

You are turning a properly indented expression into an unreadable mess,
I don't call this a improvement. Please revert.

> +	w83627hf_write_value(data,
> +		nr = 2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
>  
>  	reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
> -	       & ~(1 << (5 + nr)))
> -	    | ((data->fan_div[nr] & 0x04) << (3 + nr));
> +		& ~(1 << (5 + nr)))
> +		| ((data->fan_div[nr] & 0x04) << (3 + nr));

Same here, the original code was much easier to read.

>  	w83627hf_write_value(data, W83781D_REG_VBAT, reg);
>  
>  	/* Restore fan_min */
> @@ -1018,7 +939,7 @@ store_pwm_freq(struct device *dev, struct device_attribute *devattr,
>  {
>  	int nr = to_sensor_dev_attr(devattr)->index;
>  	struct w83627hf_data *data = dev_get_drvdata(dev);
> -	static const u8 mask[]={0xF8, 0x8F};
> +	static const u8 mask[] = {0xF8, 0x8F};
>  	u32 val;
>  
>  	val = simple_strtoul(buf, NULL, 10);
> @@ -1126,80 +1047,6 @@ show_name(struct device *dev, struct device_attribute *devattr, char *buf)
>  }
>  static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
>  
> -static int __init w83627hf_find(int sioaddr, unsigned short *addr,
> -				struct w83627hf_sio_data *sio_data)
> -{
> -	int err = -ENODEV;
> -	u16 val;
> -
> -	static const __initdata char *names[] = {
> -		"W83627HF",
> -		"W83627THF",
> -		"W83697HF",
> -		"W83637HF",
> -		"W83687THF",
> -	};
> -
> -	REG = sioaddr;
> -	VAL = sioaddr + 1;
> -
> -	superio_enter();
> -	val = force_id ? force_id : superio_inb(DEVID);
> -	switch (val) {
> -	case W627_DEVID:
> -		sio_data->type = w83627hf;
> -		break;
> -	case W627THF_DEVID:
> -		sio_data->type = w83627thf;
> -		break;
> -	case W697_DEVID:
> -		sio_data->type = w83697hf;
> -		break;
> -	case W637_DEVID:
> -		sio_data->type = w83637hf;
> -		break;
> -	case W687THF_DEVID:
> -		sio_data->type = w83687thf;
> -		break;
> -	case 0xff:	/* No device at all */
> -		goto exit;
> -	default:
> -		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
> -		goto exit;
> -	}
> -
> -	superio_select(W83627HF_LD_HWM);
> -	force_addr &= WINB_ALIGNMENT;
> -	if (force_addr) {
> -		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
> -		       force_addr);
> -		superio_outb(WINB_BASE_REG, force_addr >> 8);
> -		superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
> -	}
> -	val = (superio_inb(WINB_BASE_REG) << 8) |
> -	       superio_inb(WINB_BASE_REG + 1);
> -	*addr = val & WINB_ALIGNMENT;
> -	if (*addr = 0) {
> -		printk(KERN_WARNING DRVNAME ": Base address not set, "
> -		       "skipping\n");
> -		goto exit;
> -	}
> -
> -	val = superio_inb(WINB_ACT_REG);
> -	if (!(val & 0x01)) {
> -		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
> -		superio_outb(WINB_ACT_REG, val | 0x01);
> -	}
> -
> -	err = 0;
> -	pr_info(DRVNAME ": Found %s chip at %#x\n",
> -		names[sio_data->type], *addr);
> -
> - exit:
> -	superio_exit();
> -	return err;
> -}
> -
>  #define VIN_UNIT_ATTRS(_X_)	\
>  	&sensor_dev_attr_in##_X_##_input.dev_attr.attr,		\
>  	&sensor_dev_attr_in##_X_##_min.dev_attr.attr,		\
> @@ -1281,7 +1128,7 @@ static const struct attribute_group w83627hf_group_opt = {
>  static int __devinit w83627hf_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> -	struct w83627hf_sio_data *sio_data = dev->platform_data;
> +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
>  	struct w83627hf_data *data;
>  	struct resource *res;
>  	int err, i;
> @@ -1435,15 +1282,15 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
>  
>  	return 0;
>  
> -      ERROR4:
> +ERROR4:
>  	sysfs_remove_group(&dev->kobj, &w83627hf_group);
>  	sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
> -      ERROR3:
> +ERROR3:
>  	platform_set_drvdata(pdev, NULL);
>  	kfree(data);
> -      ERROR1:
> +ERROR1:
>  	release_region(res->start, WINB_REGION_SIZE);
> -      ERROR0:
> +ERROR0:

Nack. Labels aligned on column 0 make future patches harder to read.

>  	return err;
>  }
>  
> @@ -1511,20 +1358,22 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
>  
>  static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
>  {
> +	struct device *dev = &pdev->dev;
> +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
>  	int res = 0xff, sel;
>  
> -	superio_enter();
> -	superio_select(W83627HF_LD_GPIO5);
> +	superio_enter(sio_data);
> +	superio_select(sio_data, W83627HF_LD_GPIO5);
>  
>  	/* Make sure these GPIO pins are enabled */
> -	if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
> +	if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) {
>  		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
>  		goto exit;
>  	}
>  
>  	/* Make sure the pins are configured for input
>  	   There must be at least five (VRM 9), and possibly 6 (VRM 10) */
> -	sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
> +	sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f;
>  	if ((sel & 0x1f) != 0x1f) {
>  		dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
>  			"function\n");
> @@ -1532,37 +1381,39 @@ static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
>  	}
>  
>  	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
> -	res = superio_inb(W83627THF_GPIO5_DR) & sel;
> +	res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel;
>  
>  exit:
> -	superio_exit();
> +	superio_exit(sio_data);
>  	return res;
>  }

This looks wrong. The whole point of the MFD infrastructure is to
control who is accessing the common registers. Here you let the hwmon
driver access the Super-I/O configuration registers without any kind of
synchronisation. What if another user of w83627hf-core does the same at
the same moment?

You need a way to protect common registers. You'll need a mutex, for
sure. Then you can either export this mutex and count on all "children"
drivers' cooperation to properly request and release it. Or you can
move all the code accessing the common registers into w83627hf-core,
and stop exporting the superio_* functions. I don't know if there is a
recommended practice for MFD drivers. Samuel?

>  
>  static int __devinit w83687thf_read_vid(struct platform_device *pdev)
>  {
> +	struct device *dev = &pdev->dev;
> +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
>  	int res = 0xff;
>  
> -	superio_enter();
> -	superio_select(W83627HF_LD_HWM);
> +	superio_enter(sio_data);
> +	superio_select(sio_data, W83627HF_LD_HWM);
>  
>  	/* Make sure these GPIO pins are enabled */
> -	if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
> +	if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) {
>  		dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
>  		goto exit;
>  	}
>  
>  	/* Make sure the pins are configured for input */
> -	if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
> +	if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) {
>  		dev_dbg(&pdev->dev, "VID configured as output, "
>  			"no VID function\n");
>  		goto exit;
>  	}
>  
> -	res = superio_inb(W83687THF_VID_DATA) & 0x3f;
> +	res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f;
>  
>  exit:
> -	superio_exit();
> +	superio_exit(sio_data);
>  	return res;
>  }

Same problem here. And with proper locking, we would finally be able to
refresh the VID reading at run-time, instead of a one-shot at
initialization time!

>  
> @@ -1616,7 +1467,7 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
>  
>  	/* Read VRM & OVT Config only once */
>  	if (type = w83627thf || type = w83637hf || type = w83687thf) {
> -		data->vrm_ovt = 
> +		data->vrm_ovt >  			w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
>  	}
>  
> @@ -1636,7 +1487,7 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
>  			break;
>  	}
>  
> -	if(init) {
> +	if (init) {
>  		/* Enable temp2 */
>  		tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG);
>  		if (tmp & 0x01) {
> @@ -1724,8 +1575,8 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
>  		for (i = 0; i <= 2; i++) {
>  			u8 tmp = w83627hf_read_value(data,
>  				W836X7HF_REG_PWM(data->type, i));
> - 			/* bits 0-3 are reserved  in 627THF */
> - 			if (data->type = w83627thf)
> +			/* bits 0-3 are reserved  in 627THF */

While you're here: double space before "in".

> +			if (data->type = w83627thf)
>  				tmp &= 0xf0;
>  			data->pwm[i] = tmp;
>  			if (i = 1 &&
> @@ -1756,12 +1607,12 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
>  			}
>  		}
>  		for (i = 0; i < num_temps; i++) {
> -			data->temp[i] = w83627hf_read_value(
> -						data, w83627hf_reg_temp[i]);
> -			data->temp_max[i] = w83627hf_read_value(
> -						data, w83627hf_reg_temp_over[i]);
> -			data->temp_max_hyst[i] = w83627hf_read_value(
> -						data, w83627hf_reg_temp_hyst[i]);
> +			data->temp[i] = w83627hf_read_value(data,
> +						w83627hf_reg_temp[i]);
> +			data->temp_max[i] = w83627hf_read_value(data,
> +						w83627hf_reg_temp_over[i]);
> +			data->temp_max_hyst[i] = w83627hf_read_value(data,
> +						w83627hf_reg_temp_hyst[i]);
>  		}
>  
>  		w83627hf_update_fan_div(data);
> @@ -1783,94 +1634,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
>  	return data;
>  }
>  
> -static int __init w83627hf_device_add(unsigned short address,
> -				      const struct w83627hf_sio_data *sio_data)
> -{
> -	struct resource res = {
> -		.start	= address + WINB_REGION_OFFSET,
> -		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
> -		.name	= DRVNAME,
> -		.flags	= IORESOURCE_IO,
> -	};
> -	int err;
> -
> -	err = acpi_check_resource_conflict(&res);
> -	if (err)
> -		goto exit;
> -
> -	pdev = platform_device_alloc(DRVNAME, address);
> -	if (!pdev) {
> -		err = -ENOMEM;
> -		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
> -		goto exit;
> -	}
> -
> -	err = platform_device_add_resources(pdev, &res, 1);
> -	if (err) {
> -		printk(KERN_ERR DRVNAME ": Device resource addition failed "
> -		       "(%d)\n", err);
> -		goto exit_device_put;
> -	}
> -
> -	err = platform_device_add_data(pdev, sio_data,
> -				       sizeof(struct w83627hf_sio_data));
> -	if (err) {
> -		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
> -		goto exit_device_put;
> -	}
> -
> -	err = platform_device_add(pdev);
> -	if (err) {
> -		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
> -		       err);
> -		goto exit_device_put;
> -	}
> -
> -	return 0;
> -
> -exit_device_put:
> -	platform_device_put(pdev);
> -exit:
> -	return err;
> -}
> -
>  static int __init sensors_w83627hf_init(void)
>  {
> -	int err;
> -	unsigned short address;
> -	struct w83627hf_sio_data sio_data;
> -
> -	if (w83627hf_find(0x2e, &address, &sio_data)
> -	 && w83627hf_find(0x4e, &address, &sio_data))
> -		return -ENODEV;
> -
> -	err = platform_driver_register(&w83627hf_driver);
> -	if (err)
> -		goto exit;
> -
> -	/* Sets global pdev as a side effect */
> -	err = w83627hf_device_add(address, &sio_data);
> -	if (err)
> -		goto exit_driver;
> -
> -	return 0;
> -
> -exit_driver:
> -	platform_driver_unregister(&w83627hf_driver);
> -exit:
> -	return err;
> +	return platform_driver_register(&w83627hf_driver);
>  }
>  
>  static void __exit sensors_w83627hf_exit(void)
>  {
> -	platform_device_unregister(pdev);
>  	platform_driver_unregister(&w83627hf_driver);
>  }
>  
>  MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
>  	      "Philip Edelbrock <phil@netroedge.com>, "
>  	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
> -MODULE_DESCRIPTION("W83627HF driver");
> +MODULE_DESCRIPTION("W83627HF hwmon driver");
>  MODULE_LICENSE("GPL");
>  
>  module_init(sensors_w83627hf_init);
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 491ac0f..b52d957 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -263,6 +263,20 @@ config EZX_PCAP
>  	  This enables the PCAP ASIC present on EZX Phones. This is
>  	  needed for MMC, TouchScreen, Sound, USB, etc..
>  
> +config MFD_W83627HF
> +	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
> +	help
> +	  If you say yes here you add support for the Winbond W836X7 series
> +	  of sensor chips: the W83627HF, W83627THF, W83637HF, W83687THF and

Super-I/O chips, not sensor chips.

> +	  W83697HF to your platform.
> +
> +	  This is a multi functional device and this support defines a new
> +	  platform device only. See other configurations submenu in order to

Spelling: configuration submenus?

> +	  enable the drivers of Winbond chip's functionalities.
> +
> +	  This driver can also be built as a module.  If so, the module
> +	  will be called w83627hf-core.
> +

Shouldn't this option be selected automatically by the w83627hf (hwmon)
driver? Currently it is possible to select only the hwmon driver, but
that driver will never work because the required platform driver won't
be created. This is a problem for current users upgrading to a new
kernel, as CONFIG_MFD_W83627HF defaults to N.

But then again I don't know if there is already a policy regarding this
for MFD drivers. Samuel?

>  endmenu
>  
>  menu "Multimedia Capabilities Port drivers"
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 6f8a9a1..1401ac9 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -27,6 +27,7 @@ obj-$(CONFIG_TWL4030_CORE)	+= twl4030-core.o twl4030-irq.o
>  obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
>  
>  obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
> +obj-$(CONFIG_MFD_W83627HF)	+= w83627hf-core.o
>  
>  obj-$(CONFIG_MCP)		+= mcp-core.o
>  obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
> diff --git a/drivers/mfd/w83627hf-core.c b/drivers/mfd/w83627hf-core.c
> new file mode 100644
> index 0000000..522add7
> --- /dev/null
> +++ b/drivers/mfd/w83627hf-core.c
> @@ -0,0 +1,251 @@
> +/*
> + *  w83627hf.c - platform device support
> + *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
> + *
> + *  Based on drivers/hwmon/w83627hf.c
> + *
> + *  Original copyright note:
> + *    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
> + *    Philip Edelbrock <phil@netroedge.com>,
> + *    and Mark Studebaker <mdsxyz123@yahoo.com>
> + *    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
> + *    Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
> + *
> + *    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
> + *    the Free Software Foundation; either version 2 of the License, or
> + *    (at your option) any later version.
> + *
> + *    This program is distributed in the hope that it will be useful,
> + *    but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *    GNU General Public License for more details.
> + *
> + *    You should have received a copy of the GNU General Public License
> + *    along with this program; if not, write to the Free Software
> + *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> +*/
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/ioport.h>
> +#include <linux/acpi.h>
> +#include <linux/io.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/w83627hf.h>
> +
> +static u16 force_addr;
> +module_param(force_addr, ushort, 0);
> +MODULE_PARM_DESC(force_addr,
> +		 "Initialize the base address of the sensors");

This needs to be renamed. The address in question is specific to the
hwmon part.

> +static u8 force_i2c = 0x1f;
> +module_param(force_i2c, byte, 0);
> +MODULE_PARM_DESC(force_i2c,
> +		 "Initialize the i2c address of the sensors");

Not used anywhere.

> +
> +static int init = 1;
> +module_param(init, bool, 0);
> +MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");

Ditto.

> +
> +static unsigned short force_id;
> +module_param(force_id, ushort, 0);
> +MODULE_PARM_DESC(force_id, "Override the detected device ID");

Note: I am curious how this will fly in practice. Originally this
option was meant to force on of the 5 available hardware monitoring
implementations. It didn't assume much about the other functions of the
chips. Now that the option moved to the core MFD w83627hf driver, it
would affect all "children" drivers, not only the hwmon one. This might
not be fine-grained enough.

> +
> +/*
> + * Devices definitions
> + */
> +
> +static struct platform_device *pdev;
> +
> +static struct resource hwmon_res = {
> +	.start  = /* address + */ WINB_REGION_OFFSET,
> +	.end    = /* address + */ WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
> +	.name   = DRVNAME "_hwmon",
> +	.flags  = IORESOURCE_IO,
> +};
> +
> +static struct mfd_cell cells[] = {
> +	{
> +		.name	   = DRVNAME "_hwmon",
> +		.num_resources  = 1,
> +		.resources      = &hwmon_res,
> +	},
> +};
> +
> +/*
> + * Local functions
> + */
> +
> +#define W627_DEVID 0x52
> +#define W627THF_DEVID 0x82
> +#define W697_DEVID 0x60
> +#define W637_DEVID 0x70
> +#define W687THF_DEVID 0x85
> +#define WINB_ACT_REG 0x30
> +#define WINB_BASE_REG 0x60
> +/* Constants specified below */
> +
> +/* Alignment of the base address */
> +#define WINB_ALIGNMENT		(~7)
> +
> +/* Offset & size of I/O region we are interested in */
> +#define WINB_REGION_OFFSET	5
> +#define WINB_REGION_SIZE	2
> +
> +static int __init w83627hf_find(int sioaddr, unsigned short *addr,
> +				struct w83627hf_sio_data *sio_data)
> +{
> +	int err = -ENODEV;
> +	u16 val;
> +
> +	static const __initdata char *names[] = {
> +		"W83627HF",
> +		"W83627THF",
> +		"W83697HF",
> +		"W83637HF",
> +		"W83687THF",
> +	};
> +
> +	sio_data->sioaddr = sioaddr;
> +
> +	superio_enter(sio_data);
> +	val = force_id ? force_id : superio_inb(sio_data, DEVID);
> +	switch (val) {
> +	case W627_DEVID:
> +		sio_data->type = w83627hf;
> +		break;
> +	case W627THF_DEVID:
> +		sio_data->type = w83627thf;
> +		break;
> +	case W697_DEVID:
> +		sio_data->type = w83697hf;
> +		break;
> +	case W637_DEVID:
> +		sio_data->type = w83637hf;
> +		break;
> +	case W687THF_DEVID:
> +		sio_data->type = w83687thf;
> +		break;
> +	case 0xff:	/* No device at all */
> +		goto exit;
> +	default:
> +		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
> +		goto exit;
> +	}
> +
> +	superio_select(sio_data, W83627HF_LD_HWM);
> +	force_addr &= WINB_ALIGNMENT;
> +	if (force_addr) {
> +		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
> +		       force_addr);
> +		superio_outb(sio_data, WINB_BASE_REG, force_addr >> 8);
> +		superio_outb(sio_data, WINB_BASE_REG + 1, force_addr & 0xff);
> +	}
> +	val = (superio_inb(sio_data, WINB_BASE_REG) << 8) |
> +	       superio_inb(sio_data, WINB_BASE_REG + 1);
> +	*addr = val & WINB_ALIGNMENT;
> +	if (*addr = 0) {
> +		printk(KERN_WARNING DRVNAME ": Base address not set, "
> +		       "skipping\n");
> +		goto exit;
> +	}
> +
> +	val = superio_inb(sio_data, WINB_ACT_REG);
> +	if (!(val & 0x01)) {
> +		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
> +		superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
> +	}
> +
> +	err = 0;
> +	pr_info(DRVNAME ": Found %s chip at %#x\n",
> +		names[sio_data->type], *addr);
> +
> + exit:
> +	superio_exit(sio_data);
> +	return err;
> +}
> +
> +static int __init w83627hf_device_add(unsigned short address,
> +				      const struct w83627hf_sio_data *sio_data)
> +{
> +	struct resource res = {
> +		.start	= address + WINB_REGION_OFFSET,
> +		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
> +		.name	= DRVNAME,
> +		.flags	= IORESOURCE_IO,
> +	};
> +	int err;
> +
> +	hwmon_res.start += address;
> +	hwmon_res.end += address;

This is bad. The second time you enter this function, you add address
again and get totally wrong values. Why don't you just _set_ start and
end, instead of altering a pre-set value?

Anyway I don't get the point of the global hwmon_res resource, as you
have a local one (res). One should be enough, and less error-prone.

> +
> +	err = acpi_check_resource_conflict(&res);
> +	if (err)
> +		goto exit;

This should prevent the hwmon platform device from being registered,
_not_ the main MFD device.

> +
> +	pdev = platform_device_alloc(DRVNAME, address);
> +	if (!pdev) {
> +		err = -ENOMEM;
> +		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
> +		goto exit;
> +	}
> +
> +	err = platform_device_add_data(pdev, sio_data,
> +				       sizeof(struct w83627hf_sio_data));
> +	if (err) {
> +		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
> +		goto exit_device_put;
> +	}
> +
> +	err = platform_device_add(pdev);
> +	if (err) {
> +		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
> +		       err);
> +		goto exit_device_put;
> +	}
> +
> +	err = mfd_add_devices(&pdev->dev, pdev->id, cells, ARRAY_SIZE(cells),
> +			(struct resource *) (address & 0xffff), -1);
> +	if (err) {
> +		printk(KERN_ERR DRVNAME ": Cannot add sub devices (%d)\n",
> +			err);
> +		goto exit_device_unregister;
> +	}

You never delete these devices? This means that unloading and reloading
the driver will fail.

> +
> +	return 0;
> +
> +exit_device_unregister:
> +	platform_device_unregister(pdev);
> +exit_device_put:
> +	platform_device_put(pdev);
> +exit:
> +	return err;
> +}
> +
> +static int __init w83627hf_init(void)
> +{
> +	unsigned short address;
> +	struct w83627hf_sio_data sio_data;
> +
> +	if (w83627hf_find(0x2e, &address, &sio_data)
> +	 && w83627hf_find(0x4e, &address, &sio_data))
> +		return -ENODEV;
> +
> +	/* Sets global pdev as a side effect */
> +	return w83627hf_device_add(address, &sio_data);
> +}
> +
> +static void __exit w83627hf_exit(void)
> +{
> +	platform_device_unregister(pdev);
> +}
> +
> +MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
> +MODULE_DESCRIPTION("W83627HF platform devices definitions");
> +MODULE_LICENSE("GPL");
> +
> +module_init(w83627hf_init);
> +module_exit(w83627hf_exit);
> diff --git a/include/linux/mfd/w83627hf.h b/include/linux/mfd/w83627hf.h
> new file mode 100644
> index 0000000..c41dea1
> --- /dev/null
> +++ b/include/linux/mfd/w83627hf.h
> @@ -0,0 +1,68 @@

No header comment? No description of what this file is for? No author,
no copyright?

> +#define DRVNAME "w83627hf"
> +
> +/* Offset & size of I/O region we are interested in */
> +#define WINB_REGION_OFFSET      5
> +#define WINB_REGION_SIZE	2

You should come up with a more unique prefix, and better names
altogether: these defines are specific to the hwmon part of the chips!

> +
> +enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
> +struct w83627hf_sio_data {
> +	int sioaddr;
> +	enum chips type;
> +};
> +
> +/* logical device numbers for superio_select (below) */
> +#define W83627HF_LD_FDC		0x00
> +#define W83627HF_LD_PRT		0x01
> +#define W83627HF_LD_UART1	0x02
> +#define W83627HF_LD_UART2	0x03
> +#define W83627HF_LD_KBC		0x05
> +#define W83627HF_LD_CIR		0x06 /* w83627hf only */
> +#define W83627HF_LD_GAME	0x07
> +#define W83627HF_LD_MIDI	0x07
> +#define W83627HF_LD_GPIO1	0x07
> +#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
> +#define W83627HF_LD_GPIO2	0x08
> +#define W83627HF_LD_GPIO3	0x09
> +#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
> +#define W83627HF_LD_ACPI	0x0a
> +#define W83627HF_LD_HWM		0x0b
> +
> +#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
> +#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
> +#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
> +
> +#define W83687THF_VID_EN	0x29 /* w83687thf only */
> +#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
> +#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
> +
> +#define DEV			0x07    /* Register: Logical device select */

You don't really need a define for this register number: it's used only
once, and isn't particularly interesting.

> +#define DEVID			0x20    /* Register: Device ID */

This is only used by the core mfd driver, so there's no need to have it
in this header file.

> +
> +static inline void superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
> +{
> +	outb(reg, sio->sioaddr);
> +	outb(val, sio->sioaddr + 1);
> +}

You need to include <linux/io.h> to have access to outb() and inb().

> +
> +static inline int superio_inb(struct w83627hf_sio_data *sio, int reg)
> +{
> +	outb(reg, sio->sioaddr);
> +	return inb(sio->sioaddr + 1);
> +}
> +
> +static inline void superio_select(struct w83627hf_sio_data *sio, int ld)
> +{
> +	outb(DEV, sio->sioaddr);
> +	outb(ld, sio->sioaddr + 1);
> +}
> +
> +static inline void superio_enter(struct w83627hf_sio_data *sio)
> +{
> +	outb(0x87, sio->sioaddr);
> +	outb(0x87, sio->sioaddr);
> +}
> +
> +static inline void superio_exit(struct w83627hf_sio_data *sio)
> +{
> +	outb(0xAA, sio->sioaddr);
> +}


-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (5 preceding siblings ...)
  2009-09-17 13:34 ` Jean Delvare
@ 2009-09-17 13:51 ` Rodolfo Giometti
  2009-09-17 13:57 ` Jean Delvare
                   ` (18 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Rodolfo Giometti @ 2009-09-17 13:51 UTC (permalink / raw)
  To: lm-sensors


[-- Attachment #1.1: Type: text/plain, Size: 1294 bytes --]

On Thu, Sep 17, 2009 at 03:34:50PM +0200, Jean Delvare wrote:
> Hi Rodolfo,
> 
> On Fri, 11 Sep 2009 17:07:05 +0200, Rodolfo Giometti wrote:
> > The file has been splitted up into two parts:
> 
> Spelling: split (it's an irregular verb.)
> 
> > 
> > * drivers/mfd/w83627hf-core.c      - detects the chip and define proper
> >                                      platform devices into mfd support
> > 
> > * drivers/hwmon/w83627hf.c         - implements the driver for hwmon
> >                                      functionality only
> > 
> > The patch also fixes up some non reentrant code and some C-style issues.
> 
> Sounds wrong. Mixing coding style cleanups with real changes makes
> reviewing much harder. You'll have to move these changes to a separate
> patch I'm afraid.

Ok, I'll repropose a patch.

I prefer propose a patch with real changes only, is that correct even
if checkpatch.pl says no? :)

Thanks,

Rodolfo

-- 

GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming                     skype:  rodolfo.giometti
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 153 bytes --]

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (6 preceding siblings ...)
  2009-09-17 13:51 ` Rodolfo Giometti
@ 2009-09-17 13:57 ` Jean Delvare
  2009-09-17 14:03 ` Rodolfo Giometti
                   ` (17 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Jean Delvare @ 2009-09-17 13:57 UTC (permalink / raw)
  To: lm-sensors

On Thu, 17 Sep 2009 15:51:20 +0200, Rodolfo Giometti wrote:
> On Thu, Sep 17, 2009 at 03:34:50PM +0200, Jean Delvare wrote:
> > Hi Rodolfo,
> > 
> > On Fri, 11 Sep 2009 17:07:05 +0200, Rodolfo Giometti wrote:
> > > The file has been splitted up into two parts:
> > 
> > Spelling: split (it's an irregular verb.)
> > 
> > > 
> > > * drivers/mfd/w83627hf-core.c      - detects the chip and define proper
> > >                                      platform devices into mfd support
> > > 
> > > * drivers/hwmon/w83627hf.c         - implements the driver for hwmon
> > >                                      functionality only
> > > 
> > > The patch also fixes up some non reentrant code and some C-style issues.
> > 
> > Sounds wrong. Mixing coding style cleanups with real changes makes
> > reviewing much harder. You'll have to move these changes to a separate
> > patch I'm afraid.
> 
> Ok, I'll repropose a patch.
> 
> I prefer propose a patch with real changes only, is that correct even
> if checkpatch.pl says no? :)

If you run checkpath.pl on the patch and not the source files, it won't
complain about the parts you're not touching.

-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (7 preceding siblings ...)
  2009-09-17 13:57 ` Jean Delvare
@ 2009-09-17 14:03 ` Rodolfo Giometti
  2009-09-17 14:07 ` Jean Delvare
                   ` (16 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Rodolfo Giometti @ 2009-09-17 14:03 UTC (permalink / raw)
  To: lm-sensors


[-- Attachment #1.1: Type: text/plain, Size: 1839 bytes --]

On Thu, Sep 17, 2009 at 03:57:55PM +0200, Jean Delvare wrote:
> On Thu, 17 Sep 2009 15:51:20 +0200, Rodolfo Giometti wrote:
> > On Thu, Sep 17, 2009 at 03:34:50PM +0200, Jean Delvare wrote:
> > > Hi Rodolfo,
> > > 
> > > On Fri, 11 Sep 2009 17:07:05 +0200, Rodolfo Giometti wrote:
> > > > The file has been splitted up into two parts:
> > > 
> > > Spelling: split (it's an irregular verb.)
> > > 
> > > > 
> > > > * drivers/mfd/w83627hf-core.c      - detects the chip and define proper
> > > >                                      platform devices into mfd support
> > > > 
> > > > * drivers/hwmon/w83627hf.c         - implements the driver for hwmon
> > > >                                      functionality only
> > > > 
> > > > The patch also fixes up some non reentrant code and some C-style issues.
> > > 
> > > Sounds wrong. Mixing coding style cleanups with real changes makes
> > > reviewing much harder. You'll have to move these changes to a separate
> > > patch I'm afraid.
> > 
> > Ok, I'll repropose a patch.
> > 
> > I prefer propose a patch with real changes only, is that correct even
> > if checkpatch.pl says no? :)
> 
> If you run checkpath.pl on the patch and not the source files, it won't
> complain about the parts you're not touching.

I agree, but I'm going to create a new file by splitting an old one
and during such split I can just copy code from the old file which may
have a wrong style... should this code be fixed?

Ciao,

Rodolfo

-- 

GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming                     skype:  rodolfo.giometti
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 153 bytes --]

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (8 preceding siblings ...)
  2009-09-17 14:03 ` Rodolfo Giometti
@ 2009-09-17 14:07 ` Jean Delvare
  2009-09-17 14:34 ` Samuel Ortiz
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Jean Delvare @ 2009-09-17 14:07 UTC (permalink / raw)
  To: lm-sensors

On Thu, 17 Sep 2009 16:03:03 +0200, Rodolfo Giometti wrote:
> On Thu, Sep 17, 2009 at 03:57:55PM +0200, Jean Delvare wrote:
> > On Thu, 17 Sep 2009 15:51:20 +0200, Rodolfo Giometti wrote:
> > > I prefer propose a patch with real changes only, is that correct even
> > > if checkpatch.pl says no? :)
> > 
> > If you run checkpath.pl on the patch and not the source files, it won't
> > complain about the parts you're not touching.
> 
> I agree, but I'm going to create a new file by splitting an old one
> and during such split I can just copy code from the old file which may
> have a wrong style... should this code be fixed?

Yes, that one can be fixed on the fly. It won't make the patch any
larger.

-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (9 preceding siblings ...)
  2009-09-17 14:07 ` Jean Delvare
@ 2009-09-17 14:34 ` Samuel Ortiz
  2009-09-18  7:42 ` Jean Delvare
                   ` (14 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2009-09-17 14:34 UTC (permalink / raw)
  To: lm-sensors

Hi Jean,

On Thu, Sep 17, 2009 at 03:34:50PM +0200, Jean Delvare wrote:
> Hi Rodolfo,
> 
> On Fri, 11 Sep 2009 17:07:05 +0200, Rodolfo Giometti wrote:
> > The file has been splitted up into two parts:
> 
> Spelling: split (it's an irregular verb.)
> 
> > 
> > * drivers/mfd/w83627hf-core.c      - detects the chip and define proper
> >                                      platform devices into mfd support
> > 
> > * drivers/hwmon/w83627hf.c         - implements the driver for hwmon
> >                                      functionality only
> > 
> > The patch also fixes up some non reentrant code and some C-style issues.
> 
> Sounds wrong. Mixing coding style cleanups with real changes makes
> reviewing much harder. You'll have to move these changes to a separate
> patch I'm afraid.
> 
> > 
> > Signed-off-by: Rodolfo Giometti <giometti@linux.it>
> > ---
> >  drivers/hwmon/w83627hf.c     |  373 +++++++++---------------------------------
> >  drivers/mfd/Kconfig          |   14 ++
> >  drivers/mfd/Makefile         |    1 +
> >  drivers/mfd/w83627hf-core.c  |  251 ++++++++++++++++++++++++++++
> >  include/linux/mfd/w83627hf.h |   68 ++++++++
> >  5 files changed, 409 insertions(+), 298 deletions(-)
> >  create mode 100644 drivers/mfd/w83627hf-core.c
> >  create mode 100644 include/linux/mfd/w83627hf.h
> 
> Review:
Thanks a lot for the review. Here go my comments: 

> > @@ -1532,37 +1381,39 @@ static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
> >  	}
> >  
> >  	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
> > -	res = superio_inb(W83627THF_GPIO5_DR) & sel;
> > +	res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel;
> >  
> >  exit:
> > -	superio_exit();
> > +	superio_exit(sio_data);
> >  	return res;
> >  }
> 
> This looks wrong. The whole point of the MFD infrastructure is to
> control who is accessing the common registers. Here you let the hwmon
> driver access the Super-I/O configuration registers without any kind of
> synchronisation. What if another user of w83627hf-core does the same at
> the same moment?
> 
> You need a way to protect common registers. You'll need a mutex, for
> sure. Then you can either export this mutex and count on all "children"
> drivers' cooperation to properly request and release it. Or you can
> move all the code accessing the common registers into w83627hf-core,
> and stop exporting the superio_* functions. I don't know if there is a
> recommended practice for MFD drivers. Samuel?
The recommended practice is definitely to have your register accessing
routines defined from the MFD core. That's what all MFD drivers do.

 
> 
> > +	  enable the drivers of Winbond chip's functionalities.
> > +
> > +	  This driver can also be built as a module.  If so, the module
> > +	  will be called w83627hf-core.
> > +
> 
> Shouldn't this option be selected automatically by the w83627hf (hwmon)
> driver? Currently it is possible to select only the hwmon driver, but
> that driver will never work because the required platform driver won't
> be created. This is a problem for current users upgrading to a new
> kernel, as CONFIG_MFD_W83627HF defaults to N.
> 
> But then again I don't know if there is already a policy regarding this
> for MFD drivers. Samuel?
If your subdevice driver is calling some of the MFD core routines, or if
there's a platform dependency, then your subdevice driver (w83627hf in that
case) Kconfig should depend on MFD_W83627HF.

Cheers,
Samuel. 

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (10 preceding siblings ...)
  2009-09-17 14:34 ` Samuel Ortiz
@ 2009-09-18  7:42 ` Jean Delvare
  2009-09-18  8:01 ` Samuel Ortiz
                   ` (13 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Jean Delvare @ 2009-09-18  7:42 UTC (permalink / raw)
  To: lm-sensors

Hello Samuel,

On Thu, 17 Sep 2009 16:34:45 +0200, Samuel Ortiz wrote:
> On Thu, Sep 17, 2009 at 03:34:50PM +0200, Jean Delvare wrote:
> > But then again I don't know if there is already a policy regarding this
> > for MFD drivers. Samuel?
>
> If your subdevice driver is calling some of the MFD core routines, or if
> there's a platform dependency, then your subdevice driver (w83627hf in that
> case) Kconfig should depend on MFD_W83627HF.

Isn't it allowed to do it the other way around, using select? Due to
the history of the w83627hf driver, I fear that users will just see the
hwmon driver they were using disappear, and they will not necessarily
think of checking in MFD. So I expect a high number of support requests
about this.

-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (11 preceding siblings ...)
  2009-09-18  7:42 ` Jean Delvare
@ 2009-09-18  8:01 ` Samuel Ortiz
  2009-09-18 11:02 ` Rodolfo Giometti
                   ` (12 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2009-09-18  8:01 UTC (permalink / raw)
  To: lm-sensors

On Fri, Sep 18, 2009 at 09:42:41AM +0200, Jean Delvare wrote:
> Hello Samuel,
> 
> On Thu, 17 Sep 2009 16:34:45 +0200, Samuel Ortiz wrote:
> > On Thu, Sep 17, 2009 at 03:34:50PM +0200, Jean Delvare wrote:
> > > But then again I don't know if there is already a policy regarding this
> > > for MFD drivers. Samuel?
> >
> > If your subdevice driver is calling some of the MFD core routines, or if
> > there's a platform dependency, then your subdevice driver (w83627hf in that
> > case) Kconfig should depend on MFD_W83627HF.
> 
> Isn't it allowed to do it the other way around, using select? Due to
> the history of the w83627hf driver, I fear that users will just see the
> hwmon driver they were using disappear, and they will not necessarily
> think of checking in MFD. So I expect a high number of support requests
> about this.
Makes sense. In that case, it'd be perfectly fine to select the MFD core from
the hwmon Kconfig entry, yes.

Cheers,
Samuel.


> -- 
> Jean Delvare

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (12 preceding siblings ...)
  2009-09-18  8:01 ` Samuel Ortiz
@ 2009-09-18 11:02 ` Rodolfo Giometti
  2009-09-18 12:09 ` Rodolfo Giometti
                   ` (11 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Rodolfo Giometti @ 2009-09-18 11:02 UTC (permalink / raw)
  To: lm-sensors


[-- Attachment #1.1: Type: text/plain, Size: 2942 bytes --]

On Thu, Sep 17, 2009 at 04:34:45PM +0200, Samuel Ortiz wrote:
> On Thu, Sep 17, 2009 at 03:34:50PM +0200, Jean Delvare wrote:
> 
> > > @@ -1532,37 +1381,39 @@ static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
> > >  	}
> > >  
> > >  	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
> > > -	res = superio_inb(W83627THF_GPIO5_DR) & sel;
> > > +	res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel;
> > >  
> > >  exit:
> > > -	superio_exit();
> > > +	superio_exit(sio_data);
> > >  	return res;
> > >  }
> > 
> > This looks wrong. The whole point of the MFD infrastructure is to
> > control who is accessing the common registers. Here you let the hwmon
> > driver access the Super-I/O configuration registers without any kind of
> > synchronisation. What if another user of w83627hf-core does the same at
> > the same moment?
> > 
> > You need a way to protect common registers. You'll need a mutex, for
> > sure. Then you can either export this mutex and count on all "children"
> > drivers' cooperation to properly request and release it. Or you can
> > move all the code accessing the common registers into w83627hf-core,
> > and stop exporting the superio_* functions. I don't know if there is a
> > recommended practice for MFD drivers. Samuel?
> The recommended practice is definitely to have your register accessing
> routines defined from the MFD core. That's what all MFD drivers do.

Looking at chip's documentation I suppose I have to add a mutex and
then count on all "children" drivers' cooperation to properly request
and release the configuration register access. I cannot define
functions to manage such registers since a children may do several
reads/writes to complish its task.

> > > +	  This driver can also be built as a module.  If so, the module
> > > +	  will be called w83627hf-core.
> > > +
> > 
> > Shouldn't this option be selected automatically by the w83627hf (hwmon)
> > driver? Currently it is possible to select only the hwmon driver, but
> > that driver will never work because the required platform driver won't
> > be created. This is a problem for current users upgrading to a new
> > kernel, as CONFIG_MFD_W83627HF defaults to N.
> > 
> > But then again I don't know if there is already a policy regarding this
> > for MFD drivers. Samuel?
> If your subdevice driver is calling some of the MFD core routines, or if
> there's a platform dependency, then your subdevice driver (w83627hf in that
> case) Kconfig should depend on MFD_W83627HF.

Ok!

Thanks for your suggestions,

Rodolfo

-- 

GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming                     skype:  rodolfo.giometti
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 153 bytes --]

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (13 preceding siblings ...)
  2009-09-18 11:02 ` Rodolfo Giometti
@ 2009-09-18 12:09 ` Rodolfo Giometti
  2009-09-18 14:42 ` Samuel Ortiz
                   ` (10 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Rodolfo Giometti @ 2009-09-18 12:09 UTC (permalink / raw)
  To: lm-sensors


[-- Attachment #1.1: Type: text/plain, Size: 24233 bytes --]

Hi Jean,

this new proposal patch sounds better to you? :)

Ciao,

Rodolfo

--

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 2d50166..bc7058f 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -894,6 +894,7 @@ config SENSORS_W83L786NG
 
 config SENSORS_W83627HF
 	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
+	depends on 83627HF
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the Winbond W836X7 series
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 389150b..4757668 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -51,18 +51,10 @@
 #include <linux/mutex.h>
 #include <linux/ioport.h>
 #include <linux/acpi.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include "lm75.h"
+#include <linux/mfd/w83627hf.h>
 
-static struct platform_device *pdev;
-
-#define DRVNAME "w83627hf"
-enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
-
-static u16 force_addr;
-module_param(force_addr, ushort, 0);
-MODULE_PARM_DESC(force_addr,
-		 "Initialize the base address of the sensors");
 static u8 force_i2c = 0x1f;
 module_param(force_i2c, byte, 0);
 MODULE_PARM_DESC(force_i2c,
@@ -72,92 +64,8 @@ static int init = 1;
 module_param(init, bool, 0);
 MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
 
-static unsigned short force_id;
-module_param(force_id, ushort, 0);
-MODULE_PARM_DESC(force_id, "Override the detected device ID");
-
-/* modified from kernel/include/traps.c */
-static int REG;		/* The register to read/write */
-#define	DEV	0x07	/* Register: Logical device select */
-static int VAL;		/* The value to read/write */
-
-/* logical device numbers for superio_select (below) */
-#define W83627HF_LD_FDC		0x00
-#define W83627HF_LD_PRT		0x01
-#define W83627HF_LD_UART1	0x02
-#define W83627HF_LD_UART2	0x03
-#define W83627HF_LD_KBC		0x05
-#define W83627HF_LD_CIR		0x06 /* w83627hf only */
-#define W83627HF_LD_GAME	0x07
-#define W83627HF_LD_MIDI	0x07
-#define W83627HF_LD_GPIO1	0x07
-#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
-#define W83627HF_LD_GPIO2	0x08
-#define W83627HF_LD_GPIO3	0x09
-#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
-#define W83627HF_LD_ACPI	0x0a
-#define W83627HF_LD_HWM		0x0b
-
-#define	DEVID	0x20	/* Register: Device ID */
-
-#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
-#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
-#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
-
-#define W83687THF_VID_EN	0x29 /* w83687thf only */
-#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
-#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
-
-static inline void
-superio_outb(int reg, int val)
-{
-	outb(reg, REG);
-	outb(val, VAL);
-}
-
-static inline int
-superio_inb(int reg)
-{
-	outb(reg, REG);
-	return inb(VAL);
-}
-
-static inline void
-superio_select(int ld)
-{
-	outb(DEV, REG);
-	outb(ld, VAL);
-}
-
-static inline void
-superio_enter(void)
-{
-	outb(0x87, REG);
-	outb(0x87, REG);
-}
-
-static inline void
-superio_exit(void)
-{
-	outb(0xAA, REG);
-}
-
-#define W627_DEVID 0x52
-#define W627THF_DEVID 0x82
-#define W697_DEVID 0x60
-#define W637_DEVID 0x70
-#define W687THF_DEVID 0x85
-#define WINB_ACT_REG 0x30
-#define WINB_BASE_REG 0x60
 /* Constants specified below */
 
-/* Alignment of the base address */
-#define WINB_ALIGNMENT		~7
-
-/* Offset & size of I/O region we are interested in */
-#define WINB_REGION_OFFSET	5
-#define WINB_REGION_SIZE	2
-
 /* Where are the sensors address/data registers relative to the region offset */
 #define W83781D_ADDR_REG_OFFSET 0
 #define W83781D_DATA_REG_OFFSET 1
@@ -380,10 +288,6 @@ struct w83627hf_data {
 	u8 vrm_ovt;		/* Register value, 627THF/637HF/687THF only */
 };
 
-struct w83627hf_sio_data {
-	enum chips type;
-};
-
 
 static int w83627hf_probe(struct platform_device *pdev);
 static int __devexit w83627hf_remove(struct platform_device *pdev);
@@ -397,7 +301,7 @@ static void w83627hf_init_device(struct platform_device *pdev);
 static struct platform_driver w83627hf_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
-		.name	= DRVNAME,
+		.name	= DRVNAME "_hwmon",
 	},
 	.probe		= w83627hf_probe,
 	.remove		= __devexit_p(w83627hf_remove),
@@ -1126,80 +1030,6 @@ show_name(struct device *dev, struct device_attribute *devattr, char *buf)
 }
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
-static int __init w83627hf_find(int sioaddr, unsigned short *addr,
-				struct w83627hf_sio_data *sio_data)
-{
-	int err = -ENODEV;
-	u16 val;
-
-	static const __initdata char *names[] = {
-		"W83627HF",
-		"W83627THF",
-		"W83697HF",
-		"W83637HF",
-		"W83687THF",
-	};
-
-	REG = sioaddr;
-	VAL = sioaddr + 1;
-
-	superio_enter();
-	val = force_id ? force_id : superio_inb(DEVID);
-	switch (val) {
-	case W627_DEVID:
-		sio_data->type = w83627hf;
-		break;
-	case W627THF_DEVID:
-		sio_data->type = w83627thf;
-		break;
-	case W697_DEVID:
-		sio_data->type = w83697hf;
-		break;
-	case W637_DEVID:
-		sio_data->type = w83637hf;
-		break;
-	case W687THF_DEVID:
-		sio_data->type = w83687thf;
-		break;
-	case 0xff:	/* No device at all */
-		goto exit;
-	default:
-		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
-		goto exit;
-	}
-
-	superio_select(W83627HF_LD_HWM);
-	force_addr &= WINB_ALIGNMENT;
-	if (force_addr) {
-		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
-		       force_addr);
-		superio_outb(WINB_BASE_REG, force_addr >> 8);
-		superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
-	}
-	val = (superio_inb(WINB_BASE_REG) << 8) |
-	       superio_inb(WINB_BASE_REG + 1);
-	*addr = val & WINB_ALIGNMENT;
-	if (*addr == 0) {
-		printk(KERN_WARNING DRVNAME ": Base address not set, "
-		       "skipping\n");
-		goto exit;
-	}
-
-	val = superio_inb(WINB_ACT_REG);
-	if (!(val & 0x01)) {
-		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
-		superio_outb(WINB_ACT_REG, val | 0x01);
-	}
-
-	err = 0;
-	pr_info(DRVNAME ": Found %s chip at %#x\n",
-		names[sio_data->type], *addr);
-
- exit:
-	superio_exit();
-	return err;
-}
-
 #define VIN_UNIT_ATTRS(_X_)	\
 	&sensor_dev_attr_in##_X_##_input.dev_attr.attr,		\
 	&sensor_dev_attr_in##_X_##_min.dev_attr.attr,		\
@@ -1281,20 +1111,17 @@ static const struct attribute_group w83627hf_group_opt = {
 static int __devinit w83627hf_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct w83627hf_sio_data *sio_data = dev->platform_data;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	struct w83627hf_data *data;
 	struct resource *res;
 	int err, i;
 
-	static const char *names[] = {
-		"w83627hf",
-		"w83627thf",
-		"w83697hf",
-		"w83637hf",
-		"w83687thf",
-	};
-
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto ERROR0;
+
 	if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
 		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
 			(unsigned long)res->start,
@@ -1309,7 +1136,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 	}
 	data->addr = res->start;
 	data->type = sio_data->type;
-	data->name = names[sio_data->type];
+	data->name = sio_data->name;
 	mutex_init(&data->lock);
 	mutex_init(&data->update_lock);
 	platform_set_drvdata(pdev, data);
@@ -1511,20 +1338,22 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
 
 static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	int res = 0xff, sel;
 
-	superio_enter();
-	superio_select(W83627HF_LD_GPIO5);
+	superio_enter(sio_data);
+	superio_select(sio_data, W83627HF_LD_GPIO5);
 
 	/* Make sure these GPIO pins are enabled */
-	if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
+	if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) {
 		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
 		goto exit;
 	}
 
 	/* Make sure the pins are configured for input
 	   There must be at least five (VRM 9), and possibly 6 (VRM 10) */
-	sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
+	sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f;
 	if ((sel & 0x1f) != 0x1f) {
 		dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
 			"function\n");
@@ -1532,37 +1361,39 @@ static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
 	}
 
 	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
-	res = superio_inb(W83627THF_GPIO5_DR) & sel;
+	res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel;
 
 exit:
-	superio_exit();
+	superio_exit(sio_data);
 	return res;
 }
 
 static int __devinit w83687thf_read_vid(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	int res = 0xff;
 
-	superio_enter();
-	superio_select(W83627HF_LD_HWM);
+	superio_enter(sio_data);
+	superio_select(sio_data, W83627HF_LD_HWM);
 
 	/* Make sure these GPIO pins are enabled */
-	if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
+	if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) {
 		dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
 		goto exit;
 	}
 
 	/* Make sure the pins are configured for input */
-	if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
+	if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) {
 		dev_dbg(&pdev->dev, "VID configured as output, "
 			"no VID function\n");
 		goto exit;
 	}
 
-	res = superio_inb(W83687THF_VID_DATA) & 0x3f;
+	res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f;
 
 exit:
-	superio_exit();
+	superio_exit(sio_data);
 	return res;
 }
 
@@ -1783,94 +1614,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 	return data;
 }
 
-static int __init w83627hf_device_add(unsigned short address,
-				      const struct w83627hf_sio_data *sio_data)
-{
-	struct resource res = {
-		.start	= address + WINB_REGION_OFFSET,
-		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
-		.name	= DRVNAME,
-		.flags	= IORESOURCE_IO,
-	};
-	int err;
-
-	err = acpi_check_resource_conflict(&res);
-	if (err)
-		goto exit;
-
-	pdev = platform_device_alloc(DRVNAME, address);
-	if (!pdev) {
-		err = -ENOMEM;
-		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
-		goto exit;
-	}
-
-	err = platform_device_add_resources(pdev, &res, 1);
-	if (err) {
-		printk(KERN_ERR DRVNAME ": Device resource addition failed "
-		       "(%d)\n", err);
-		goto exit_device_put;
-	}
-
-	err = platform_device_add_data(pdev, sio_data,
-				       sizeof(struct w83627hf_sio_data));
-	if (err) {
-		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
-		goto exit_device_put;
-	}
-
-	err = platform_device_add(pdev);
-	if (err) {
-		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
-		       err);
-		goto exit_device_put;
-	}
-
-	return 0;
-
-exit_device_put:
-	platform_device_put(pdev);
-exit:
-	return err;
-}
-
 static int __init sensors_w83627hf_init(void)
 {
-	int err;
-	unsigned short address;
-	struct w83627hf_sio_data sio_data;
-
-	if (w83627hf_find(0x2e, &address, &sio_data)
-	 && w83627hf_find(0x4e, &address, &sio_data))
-		return -ENODEV;
-
-	err = platform_driver_register(&w83627hf_driver);
-	if (err)
-		goto exit;
-
-	/* Sets global pdev as a side effect */
-	err = w83627hf_device_add(address, &sio_data);
-	if (err)
-		goto exit_driver;
-
-	return 0;
-
-exit_driver:
-	platform_driver_unregister(&w83627hf_driver);
-exit:
-	return err;
+	return platform_driver_register(&w83627hf_driver);
 }
 
 static void __exit sensors_w83627hf_exit(void)
 {
-	platform_device_unregister(pdev);
 	platform_driver_unregister(&w83627hf_driver);
 }
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
 	      "Philip Edelbrock <phil@netroedge.com>, "
 	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
-MODULE_DESCRIPTION("W83627HF driver");
+MODULE_DESCRIPTION("W83627HF hwmon driver");
 MODULE_LICENSE("GPL");
 
 module_init(sensors_w83627hf_init);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 491ac0f..784a892 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -263,6 +263,20 @@ config EZX_PCAP
 	  This enables the PCAP ASIC present on EZX Phones. This is
 	  needed for MMC, TouchScreen, Sound, USB, etc..
 
+config MFD_W83627HF
+	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
+	help
+	  If you say yes here you add support for the Winbond W836X7 series
+	  of super-IO chips: the W83627HF, W83627THF, W83637HF, W83687THF and
+	  W83697HF to your platform.
+
+	  This is a multi functional device and this support defines a new
+	  platform device only. See other configuration submenus in order to
+	  enable the drivers of Winbond chip's functionalities.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83627hf-core.
+
 endmenu
 
 menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 6f8a9a1..1401ac9 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_TWL4030_CORE)	+= twl4030-core.o twl4030-irq.o
 obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
 
 obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
+obj-$(CONFIG_MFD_W83627HF)	+= w83627hf-core.o
 
 obj-$(CONFIG_MCP)		+= mcp-core.o
 obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
diff --git a/drivers/mfd/w83627hf-core.c b/drivers/mfd/w83627hf-core.c
new file mode 100644
index 0000000..39b6190
--- /dev/null
+++ b/drivers/mfd/w83627hf-core.c
@@ -0,0 +1,236 @@
+/*
+ *  w83627hf.c - platform device support
+ *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
+ *
+ *  Based on drivers/hwmon/w83627hf.c
+ *
+ *  Original copyright note:
+ *    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
+ *    Philip Edelbrock <phil@netroedge.com>,
+ *    and Mark Studebaker <mdsxyz123@yahoo.com>
+ *    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
+ *    Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
+ *
+ *    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
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/w83627hf.h>
+
+static u16 force_hwmon_addr;
+module_param(force_hwmon_addr, ushort, 0);
+MODULE_PARM_DESC(force_hwmon_addr,
+		 "Initialize the base address of the hwmon sensors");
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+/*
+ * Devices definitions
+ */
+
+static struct platform_device *pdev;
+
+static char *names[] = {
+	"w83627hf",
+	"w83627thf",
+	"w83697hf",
+	"w83637hf",
+	"w83687thf",
+};
+
+static struct resource hwmon_res = {
+	/* .start  = ? - NOTE: set at runtime */
+	/* .end    = ? - NOTE: set at runtime */
+	.name   = DRVNAME "_hwmon",
+	.flags  = IORESOURCE_IO,
+};
+
+static struct mfd_cell cells[] = {
+	{
+		.name	   = DRVNAME "_hwmon",
+		.num_resources  = 1,
+		.resources      = &hwmon_res,
+	},
+};
+
+/*
+ * Local functions
+ */
+
+#define W627_DEVID		0x52
+#define W627THF_DEVID		0x82
+#define W697_DEVID		0x60
+#define W637_DEVID		0x70
+#define W687THF_DEVID		0x85
+#define WINB_ACT_REG		0x30
+#define WINB_BASE_REG		0x60
+/* Constants specified below */
+
+/* Offset & size of I/O region we are interested in */
+#define WINB_REGION_OFFSET	5
+#define WINB_REGION_SIZE	2
+
+static int __init w83627hf_find(int sioaddr, unsigned short *addr,
+				struct w83627hf_sio_data *sio_data)
+{
+	int err = -ENODEV;
+	u16 val;
+
+	sio_data->sioaddr = sioaddr;
+
+	superio_enter(sio_data);
+	val = force_id ? force_id : superio_inb(sio_data, 0x20);
+	switch (val) {
+	case W627_DEVID:
+		sio_data->type = w83627hf;
+		break;
+	case W627THF_DEVID:
+		sio_data->type = w83627thf;
+		break;
+	case W697_DEVID:
+		sio_data->type = w83697hf;
+		break;
+	case W637_DEVID:
+		sio_data->type = w83637hf;
+		break;
+	case W687THF_DEVID:
+		sio_data->type = w83687thf;
+		break;
+	case 0xff:	/* No device at all */
+		goto exit;
+	default:
+		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
+		goto exit;
+	}
+
+	sio_data->name = names[sio_data->type];
+
+	superio_select(sio_data, W83627HF_LD_HWM);
+	force_hwmon_addr &= (~7);
+	if (force_hwmon_addr) {
+		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
+		       force_hwmon_addr);
+		superio_outb(sio_data, WINB_BASE_REG, force_hwmon_addr >> 8);
+		superio_outb(sio_data, WINB_BASE_REG + 1,
+					force_hwmon_addr & 0xff);
+	}
+	val = (superio_inb(sio_data, WINB_BASE_REG) << 8) |
+	       superio_inb(sio_data, WINB_BASE_REG + 1);
+	*addr = val & (~7);
+	if (*addr == 0) {
+		printk(KERN_WARNING DRVNAME ": Base address not set, "
+		       "skipping\n");
+		goto exit;
+	}
+
+	val = superio_inb(sio_data, WINB_ACT_REG);
+	if (!(val & 0x01)) {
+		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
+		superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
+	}
+
+	err = 0;
+	pr_info(DRVNAME ": Found %s chip at %#x\n",
+		names[sio_data->type], *addr);
+
+ exit:
+	superio_exit(sio_data);
+	return err;
+}
+
+static int __init w83627hf_device_add(unsigned short address,
+				      const struct w83627hf_sio_data *sio_data)
+{
+	int err;
+
+	hwmon_res.start = address + WINB_REGION_OFFSET;
+	hwmon_res.end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct w83627hf_sio_data));
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	err = mfd_add_devices(&pdev->dev, pdev->id, cells, ARRAY_SIZE(cells),
+			(struct resource *) (address & 0xffff), -1);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Cannot add sub devices (%d)\n",
+			err);
+		goto exit_device_unregister;
+	}
+
+	return 0;
+
+exit_device_unregister:
+	platform_device_unregister(pdev);
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int __init w83627hf_init(void)
+{
+	unsigned short address;
+	struct w83627hf_sio_data sio_data;
+
+	mutex_init(&sio_data.lock);
+
+	if (w83627hf_find(0x2e, &address, &sio_data)
+	 && w83627hf_find(0x4e, &address, &sio_data))
+		return -ENODEV;
+
+	/* Sets global pdev as a side effect */
+	return w83627hf_device_add(address, &sio_data);
+}
+
+static void __exit w83627hf_exit(void)
+{
+	mfd_remove_devices(&pdev->dev);
+	platform_device_unregister(pdev);
+}
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("W83627HF platform devices definitions");
+MODULE_LICENSE("GPL");
+
+module_init(w83627hf_init);
+module_exit(w83627hf_exit);
diff --git a/include/linux/mfd/w83627hf.h b/include/linux/mfd/w83627hf.h
new file mode 100644
index 0000000..c9f537d
--- /dev/null
+++ b/include/linux/mfd/w83627hf.h
@@ -0,0 +1,112 @@
+/*
+ *  w83627hf.h - platform device support, header file
+ *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
+ *
+ *  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
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#define DRVNAME "w83627hf"
+
+enum chips {
+	w83627hf,
+	w83627thf,
+	w83697hf,
+	w83637hf,
+	w83687thf
+};
+
+struct w83627hf_sio_data {
+	int sioaddr;
+	enum chips type;
+	char *name;
+
+	struct mutex lock;
+};
+
+/* logical device numbers for superio_select (below) */
+#define W83627HF_LD_FDC		0x00
+#define W83627HF_LD_PRT		0x01
+#define W83627HF_LD_UART1	0x02
+#define W83627HF_LD_UART2	0x03
+#define W83627HF_LD_KBC		0x05
+#define W83627HF_LD_CIR		0x06 /* w83627hf only */
+#define W83627HF_LD_GAME	0x07
+#define W83627HF_LD_MIDI	0x07
+#define W83627HF_LD_GPIO1	0x07
+#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
+#define W83627HF_LD_GPIO2	0x08
+#define W83627HF_LD_GPIO3	0x09
+#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
+#define W83627HF_LD_ACPI	0x0a
+#define W83627HF_LD_HWM		0x0b
+
+#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
+#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
+#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
+
+#define W83687THF_VID_EN	0x29 /* w83687thf only */
+#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
+#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
+
+/*
+ * Common configuration registers access functions.
+ *
+ * These registers are special and they must me accessed by using a well
+ * specified protocol. Client drivers __must__ do as follow in order to
+ * get access correctly to these registers:
+ *
+ *	superio_enter()
+ *
+ *	superio_select()/superio_outb()/superio_inb()
+ *
+ *	superio_exit();
+ *
+ */
+
+static inline void superio_enter(struct w83627hf_sio_data *sio)
+{
+	mutex_lock(&sio->lock);
+
+	outb(0x87, sio->sioaddr);
+	outb(0x87, sio->sioaddr);
+}
+
+static inline void superio_select(struct w83627hf_sio_data *sio, int ld)
+{
+	outb(0x07, sio->sioaddr);
+	outb(ld, sio->sioaddr + 1);
+}
+
+static inline void superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
+{
+	outb(reg, sio->sioaddr);
+	outb(val, sio->sioaddr + 1);
+}
+
+static inline int superio_inb(struct w83627hf_sio_data *sio, int reg)
+{
+	outb(reg, sio->sioaddr);
+	return inb(sio->sioaddr + 1);
+}
+
+static inline void superio_exit(struct w83627hf_sio_data *sio)
+{
+	outb(0xAA, sio->sioaddr);
+
+	mutex_unlock(&sio->lock);
+}


-- 

GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming                     skype:  rodolfo.giometti
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 153 bytes --]

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (14 preceding siblings ...)
  2009-09-18 12:09 ` Rodolfo Giometti
@ 2009-09-18 14:42 ` Samuel Ortiz
  2009-09-18 14:49 ` Jean Delvare
                   ` (9 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2009-09-18 14:42 UTC (permalink / raw)
  To: lm-sensors

Hi Rodolfo,

Some comments on the MFD related parts:

On Fri, Sep 18, 2009 at 02:09:23PM +0200, Rodolfo Giometti wrote:
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 2d50166..bc7058f 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -894,6 +894,7 @@ config SENSORS_W83L786NG
>  
>  config SENSORS_W83627HF
>  	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
> +	depends on 83627HF
Use select here, as the hwmon W83627HF current users are not really supposed
to know that they have to go an manually select an obscure MFD core for their
driver to build.
Moreover, the symbol is MFD_W83627HF, not 83627HF.

> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 491ac0f..784a892 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -263,6 +263,20 @@ config EZX_PCAP
>  	  This enables the PCAP ASIC present on EZX Phones. This is
>  	  needed for MMC, TouchScreen, Sound, USB, etc..
>  
> +config MFD_W83627HF
> +	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
You must depend on MFD_CORE here.

> +	help
> +	  If you say yes here you add support for the Winbond W836X7 series
> +	  of super-IO chips: the W83627HF, W83627THF, W83637HF, W83687THF and
> +	  W83697HF to your platform.
> +
> +	  This is a multi functional device and this support defines a new
> +	  platform device only. See other configuration submenus in order to
> +	  enable the drivers of Winbond chip's functionalities.
> +
> +	  This driver can also be built as a module.  If so, the module
> +	  will be called w83627hf-core.
> +
>  endmenu
>  
>  menu "Multimedia Capabilities Port drivers"
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 6f8a9a1..1401ac9 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -27,6 +27,7 @@ obj-$(CONFIG_TWL4030_CORE)	+= twl4030-core.o twl4030-irq.o
>  obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
>  
>  obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
> +obj-$(CONFIG_MFD_W83627HF)	+= w83627hf-core.o
>  
>  obj-$(CONFIG_MCP)		+= mcp-core.o
>  obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
> diff --git a/drivers/mfd/w83627hf-core.c b/drivers/mfd/w83627hf-core.c
> new file mode 100644
> index 0000000..39b6190
> --- /dev/null
> +++ b/drivers/mfd/w83627hf-core.c
> @@ -0,0 +1,236 @@
> +/*
> + *  w83627hf.c - platform device support
> + *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
> + *
> + *  Based on drivers/hwmon/w83627hf.c
> + *
> + *  Original copyright note:
> + *    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
> + *    Philip Edelbrock <phil@netroedge.com>,
> + *    and Mark Studebaker <mdsxyz123@yahoo.com>
> + *    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
> + *    Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
> + *
> + *    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
> + *    the Free Software Foundation; either version 2 of the License, or
> + *    (at your option) any later version.
> + *
> + *    This program is distributed in the hope that it will be useful,
> + *    but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *    GNU General Public License for more details.
> + *
> + *    You should have received a copy of the GNU General Public License
> + *    along with this program; if not, write to the Free Software
> + *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/ioport.h>
> +#include <linux/acpi.h>
> +#include <linux/io.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/w83627hf.h>
> +
> +static u16 force_hwmon_addr;
> +module_param(force_hwmon_addr, ushort, 0);
> +MODULE_PARM_DESC(force_hwmon_addr,
> +		 "Initialize the base address of the hwmon sensors");
> +
> +static unsigned short force_id;
> +module_param(force_id, ushort, 0);
> +MODULE_PARM_DESC(force_id, "Override the detected device ID");
> +
> +/*
> + * Devices definitions
> + */
> +
> +static struct platform_device *pdev;
> +
> +static char *names[] = {
> +	"w83627hf",
> +	"w83627thf",
> +	"w83697hf",
> +	"w83637hf",
> +	"w83687thf",
> +};
> +
> +static struct resource hwmon_res = {
> +	/* .start  = ? - NOTE: set at runtime */
> +	/* .end    = ? - NOTE: set at runtime */
> +	.name   = DRVNAME "_hwmon",
> +	.flags  = IORESOURCE_IO,
> +};
> +
> +static struct mfd_cell cells[] = {
> +	{
> +		.name	   = DRVNAME "_hwmon",
> +		.num_resources  = 1,
> +		.resources      = &hwmon_res,
> +	},
> +};
> +
> +/*
> + * Local functions
> + */
Local functions ?


> +
> +#define W627_DEVID		0x52
> +#define W627THF_DEVID		0x82
> +#define W697_DEVID		0x60
> +#define W637_DEVID		0x70
> +#define W687THF_DEVID		0x85
> +#define WINB_ACT_REG		0x30
> +#define WINB_BASE_REG		0x60
Are those 2 last ones HWMON specific. If that's so, please be more specific
about it.


> +/* Constants specified below */
> +
> +/* Offset & size of I/O region we are interested in */
This seems to be the hwmon region, so please be more specific about it in the
comments and in the naming below.

> +#define WINB_REGION_OFFSET	5
> +#define WINB_REGION_SIZE	2
> +
> +static int __init w83627hf_find(int sioaddr, unsigned short *addr,
> +				struct w83627hf_sio_data *sio_data)
> +{
> +	int err = -ENODEV;
> +	u16 val;
> +
> +	sio_data->sioaddr = sioaddr;
> +
> +	superio_enter(sio_data);
> +	val = force_id ? force_id : superio_inb(sio_data, 0x20);
> +	switch (val) {
> +	case W627_DEVID:
> +		sio_data->type = w83627hf;
> +		break;
> +	case W627THF_DEVID:
> +		sio_data->type = w83627thf;
> +		break;
> +	case W697_DEVID:
> +		sio_data->type = w83697hf;
> +		break;
> +	case W637_DEVID:
> +		sio_data->type = w83637hf;
> +		break;
> +	case W687THF_DEVID:
> +		sio_data->type = w83687thf;
> +		break;
> +	case 0xff:	/* No device at all */
> +		goto exit;
> +	default:
> +		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
> +		goto exit;
> +	}
> +
> +	sio_data->name = names[sio_data->type];
> +
> +	superio_select(sio_data, W83627HF_LD_HWM);
> +	force_hwmon_addr &= (~7);
> +	if (force_hwmon_addr) {
> +		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
> +		       force_hwmon_addr);
> +		superio_outb(sio_data, WINB_BASE_REG, force_hwmon_addr >> 8);
> +		superio_outb(sio_data, WINB_BASE_REG + 1,
> +					force_hwmon_addr & 0xff);
> +	}
> +	val = (superio_inb(sio_data, WINB_BASE_REG) << 8) |
> +	       superio_inb(sio_data, WINB_BASE_REG + 1);
> +	*addr = val & (~7);
> +	if (*addr = 0) {
> +		printk(KERN_WARNING DRVNAME ": Base address not set, "
> +		       "skipping\n");
> +		goto exit;
> +	}
> +
> +	val = superio_inb(sio_data, WINB_ACT_REG);
> +	if (!(val & 0x01)) {
> +		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
> +		superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
> +	}
> +
> +	err = 0;
> +	pr_info(DRVNAME ": Found %s chip at %#x\n",
> +		names[sio_data->type], *addr);
I'm not familiar with this chip, but although the function is called
w83627hf_find(), it seems to me that what we're doing here is enabling the
hwmon subdevice. Am I correct ? If that's so, could we split this function,
and maybe even move the hwmon specific part into the hwmon driver.


> + exit:
> +	superio_exit(sio_data);
> +	return err;
> +}
> +
> +static int __init w83627hf_device_add(unsigned short address,
> +				      const struct w83627hf_sio_data *sio_data)
> +{
> +	int err;
> +
> +	hwmon_res.start = address + WINB_REGION_OFFSET;
> +	hwmon_res.end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1;
> +
> +	pdev = platform_device_alloc(DRVNAME, address);
> +	if (!pdev) {
> +		err = -ENOMEM;
> +		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
> +		goto exit;
> +	}
> +
> +	err = platform_device_add_data(pdev, sio_data,
> +				       sizeof(struct w83627hf_sio_data));
> +	if (err) {
> +		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
> +		goto exit_device_put;
> +	}
> +
> +	err = platform_device_add(pdev);
> +	if (err) {
> +		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
> +		       err);
> +		goto exit_device_put;
> +	}
> +
> +	err = mfd_add_devices(&pdev->dev, pdev->id, cells, ARRAY_SIZE(cells),
> +			(struct resource *) (address & 0xffff), -1);
> +	if (err) {
> +		printk(KERN_ERR DRVNAME ": Cannot add sub devices (%d)\n",
> +			err);
> +		goto exit_device_unregister;
> +	}
> +
> +	return 0;
> +
> +exit_device_unregister:
> +	platform_device_unregister(pdev);
> +exit_device_put:
> +	platform_device_put(pdev);
> +exit:
> +	return err;
> +}
> +
> +static int __init w83627hf_init(void)
> +{
> +	unsigned short address;
> +	struct w83627hf_sio_data sio_data;
> +
> +	mutex_init(&sio_data.lock);
> +
> +	if (w83627hf_find(0x2e, &address, &sio_data)
> +	 && w83627hf_find(0x4e, &address, &sio_data))
> +		return -ENODEV;
> +
> +	/* Sets global pdev as a side effect */
> +	return w83627hf_device_add(address, &sio_data);
> +}
> +
> +static void __exit w83627hf_exit(void)
> +{
> +	mfd_remove_devices(&pdev->dev);
> +	platform_device_unregister(pdev);
> +}
> +
> +MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
> +MODULE_DESCRIPTION("W83627HF platform devices definitions");
> +MODULE_LICENSE("GPL");
> +
> +module_init(w83627hf_init);
> +module_exit(w83627hf_exit);
> diff --git a/include/linux/mfd/w83627hf.h b/include/linux/mfd/w83627hf.h
> new file mode 100644
> index 0000000..c9f537d
> --- /dev/null
> +++ b/include/linux/mfd/w83627hf.h
> @@ -0,0 +1,112 @@
> +/*
> + *  w83627hf.h - platform device support, header file
> + *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
> + *
> + *  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
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, write to the Free Software
> + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <linux/mutex.h>
> +#include <linux/io.h>
> +
> +#define DRVNAME "w83627hf"
> +
> +enum chips {
> +	w83627hf,
> +	w83627thf,
> +	w83697hf,
> +	w83637hf,
> +	w83687thf
> +};
> +
> +struct w83627hf_sio_data {
> +	int sioaddr;
> +	enum chips type;
> +	char *name;
> +
> +	struct mutex lock;
> +};
> +
> +/* logical device numbers for superio_select (below) */
> +#define W83627HF_LD_FDC		0x00
> +#define W83627HF_LD_PRT		0x01
> +#define W83627HF_LD_UART1	0x02
> +#define W83627HF_LD_UART2	0x03
> +#define W83627HF_LD_KBC		0x05
> +#define W83627HF_LD_CIR		0x06 /* w83627hf only */
> +#define W83627HF_LD_GAME	0x07
> +#define W83627HF_LD_MIDI	0x07
> +#define W83627HF_LD_GPIO1	0x07
> +#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
> +#define W83627HF_LD_GPIO2	0x08
> +#define W83627HF_LD_GPIO3	0x09
> +#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
> +#define W83627HF_LD_ACPI	0x0a
> +#define W83627HF_LD_HWM		0x0b
> +
> +#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
> +#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
> +#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
> +
> +#define W83687THF_VID_EN	0x29 /* w83687thf only */
> +#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
> +#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
> +
> +/*
> + * Common configuration registers access functions.
> + *
> + * These registers are special and they must me accessed by using a well
> + * specified protocol. Client drivers __must__ do as follow in order to
> + * get access correctly to these registers:
> + *
> + *	superio_enter()
> + *
> + *	superio_select()/superio_outb()/superio_inb()
> + *
> + *	superio_exit();
> + *
> + */
> +
> +static inline void superio_enter(struct w83627hf_sio_data *sio)
> +{
> +	mutex_lock(&sio->lock);
> +
> +	outb(0x87, sio->sioaddr);
> +	outb(0x87, sio->sioaddr);
I'm not really happy with this one. The unbalanced locking here makes me feel
unconfortable.

Something like that:

void superio_outb(struct w83627hf_sio_data *sio, int ld, int reg, int val)
{
	mutex_lock(&sio->lock);

	/* Enter */
	outb(0x87, sio->sioaddr)
	outb(0x87, sio->sioaddr)

	/* Select module */
	outb(0x07, sio->sioaddr);
	outb(ld, sio->sioaddr + 1);

	/* Write */
	outb(reg, sio->sioaddr);
	outb(val, sio->sioaddr + 1);

	/* Exit */
	outb(0xAA, sio->sioaddr);

	mutex_unlock(&sio->lock);
}

would look saner to me. I know we're wasting many IO ops here, but it seems to
me that the subdevices get to call the superio API only at init time.
I think it's worth it as your subdevices wouldnt have to care about following
these error prone steps, and you wouldnt have any more unbalanced locking
risks.

> +}
> +
> +static inline void superio_select(struct w83627hf_sio_data *sio, int ld)
> +{
> +	outb(0x07, sio->sioaddr);
> +	outb(ld, sio->sioaddr + 1);
> +}
> +
> +static inline void superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
> +{
> +	outb(reg, sio->sioaddr);
> +	outb(val, sio->sioaddr + 1);
> +}
> +
> +static inline int superio_inb(struct w83627hf_sio_data *sio, int reg)
> +{
> +	outb(reg, sio->sioaddr);
> +	return inb(sio->sioaddr + 1);
> +}
> +
> +static inline void superio_exit(struct w83627hf_sio_data *sio)
> +{
> +	outb(0xAA, sio->sioaddr);
> +
> +	mutex_unlock(&sio->lock);
> +}
> 
> 
> -- 
> 
> GNU/Linux Solutions                  e-mail: giometti@enneenne.com
> Linux Device Driver                          giometti@linux.it
> Embedded Systems                     phone:  +39 349 2432127
> UNIX programming                     skype:  rodolfo.giometti
> Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it



-- 
Intel Open Source Technology Centre
http://oss.intel.com/

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (15 preceding siblings ...)
  2009-09-18 14:42 ` Samuel Ortiz
@ 2009-09-18 14:49 ` Jean Delvare
  2009-09-18 16:16 ` Jean Delvare
                   ` (8 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Jean Delvare @ 2009-09-18 14:49 UTC (permalink / raw)
  To: lm-sensors

On Fri, 18 Sep 2009 14:09:23 +0200, Rodolfo Giometti wrote:
> Hi Jean,
> 
> this new proposal patch sounds better to you? :)
> 
> Ciao,
> 
> Rodolfo
> 
> --
> 
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 2d50166..bc7058f 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -894,6 +894,7 @@ config SENSORS_W83L786NG
>  
>  config SENSORS_W83627HF
>  	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
> +	depends on 83627HF

Which doesn't exist, so the driver can't be selected. Obviously you
meant: depends on MFD_W83627HF.

But please also see my discussion with Samuel on depends vs. select.
I'd prefer that you use select. Especially given that the MFD
configuration entry is _after_ the hwmon configuration entry in
Kconfig, I fear that even if users see and select MFD_W83627HF, they
won't walk back to the W83627HF entry to select it.

Samuel, wouldn't it make sense to move the MFD section up in the Device
Drivers section?

Even after fixing this so that I could select the driver, I'm hitting
build problems:

  CC [M]  drivers/hwmon/w83627hf.o
drivers/hwmon/w83627hf.c: In function ‘w83627hf_probe’:
drivers/hwmon/w83627hf.c:1121: warning: passing argument 1 of ‘acpi_check_resource_conflict’ from incompatible pointer type
drivers/hwmon/w83627hf.c:1125: error: ‘WINB_REGION_SIZE’ undeclared (first use in this function)
drivers/hwmon/w83627hf.c:1125: error: (Each undeclared identifier is reported only once
drivers/hwmon/w83627hf.c:1125: error: for each function it appears in.)
drivers/hwmon/w83627hf.c: In function ‘w83627hf_remove’:
drivers/hwmon/w83627hf.c:1290: error: ‘WINB_REGION_SIZE’ undeclared (first use in this function)

Please build-test your patches before you send them.

>  	select HWMON_VID
>  	help
>  	  If you say yes here you get support for the Winbond W836X7 series
> diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
> index 389150b..4757668 100644
> --- a/drivers/hwmon/w83627hf.c
> +++ b/drivers/hwmon/w83627hf.c
> @@ -51,18 +51,10 @@
>  #include <linux/mutex.h>
>  #include <linux/ioport.h>
>  #include <linux/acpi.h>
> -#include <asm/io.h>
> +#include <linux/io.h>

As I said before, this change is already upstream, so please don't
include it in your patch.

>  #include "lm75.h"
> +#include <linux/mfd/w83627hf.h>

Global includes must be listed before local ones.

I'll go on with the review when you provide a patch I can build.

-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (16 preceding siblings ...)
  2009-09-18 14:49 ` Jean Delvare
@ 2009-09-18 16:16 ` Jean Delvare
  2009-09-20 23:48 ` Samuel Ortiz
                   ` (7 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Jean Delvare @ 2009-09-18 16:16 UTC (permalink / raw)
  To: lm-sensors

Hi Samuel,

On Fri, 18 Sep 2009 16:42:49 +0200, Samuel Ortiz wrote:
> On Fri, Sep 18, 2009 at 02:09:23PM +0200, Rodolfo Giometti wrote:
> > +#define W627_DEVID		0x52
> > +#define W627THF_DEVID		0x82
> > +#define W697_DEVID		0x60
> > +#define W637_DEVID		0x70
> > +#define W687THF_DEVID		0x85
> > +#define WINB_ACT_REG		0x30
> > +#define WINB_BASE_REG		0x60
> Are those 2 last ones HWMON specific. If that's so, please be more specific
> about it.

No, these are standard registers common to all logical devices.

> > +/* Constants specified below */
> > +
> > +/* Offset & size of I/O region we are interested in */
> This seems to be the hwmon region, so please be more specific about it in the
> comments and in the naming below.

Correct.

> > +#define WINB_REGION_OFFSET	5
> > +#define WINB_REGION_SIZE	2
> > +
> > +static int __init w83627hf_find(int sioaddr, unsigned short *addr,
> > +				struct w83627hf_sio_data *sio_data)
> > +{
> > +	int err = -ENODEV;
> > +	u16 val;
> > +
> > +	sio_data->sioaddr = sioaddr;
> > +
> > +	superio_enter(sio_data);
> > +	val = force_id ? force_id : superio_inb(sio_data, 0x20);
> > +	switch (val) {
> > +	case W627_DEVID:
> > +		sio_data->type = w83627hf;
> > +		break;
> > +	case W627THF_DEVID:
> > +		sio_data->type = w83627thf;
> > +		break;
> > +	case W697_DEVID:
> > +		sio_data->type = w83697hf;
> > +		break;
> > +	case W637_DEVID:
> > +		sio_data->type = w83637hf;
> > +		break;
> > +	case W687THF_DEVID:
> > +		sio_data->type = w83687thf;
> > +		break;
> > +	case 0xff:	/* No device at all */
> > +		goto exit;
> > +	default:
> > +		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
> > +		goto exit;
> > +	}
> > +
> > +	sio_data->name = names[sio_data->type];
> > +
> > +	superio_select(sio_data, W83627HF_LD_HWM);
> > +	force_hwmon_addr &= (~7);
> > +	if (force_hwmon_addr) {
> > +		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
> > +		       force_hwmon_addr);
> > +		superio_outb(sio_data, WINB_BASE_REG, force_hwmon_addr >> 8);
> > +		superio_outb(sio_data, WINB_BASE_REG + 1,
> > +					force_hwmon_addr & 0xff);
> > +	}
> > +	val = (superio_inb(sio_data, WINB_BASE_REG) << 8) |
> > +	       superio_inb(sio_data, WINB_BASE_REG + 1);
> > +	*addr = val & (~7);
> > +	if (*addr = 0) {
> > +		printk(KERN_WARNING DRVNAME ": Base address not set, "
> > +		       "skipping\n");
> > +		goto exit;
> > +	}
> > +
> > +	val = superio_inb(sio_data, WINB_ACT_REG);
> > +	if (!(val & 0x01)) {
> > +		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
> > +		superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
> > +	}
> > +
> > +	err = 0;
> > +	pr_info(DRVNAME ": Found %s chip at %#x\n",
> > +		names[sio_data->type], *addr);
>
> I'm not familiar with this chip, but although the function is called
> w83627hf_find(), it seems to me that what we're doing here is enabling the
> hwmon subdevice. Am I correct ? If that's so, could we split this function,
> and maybe even move the hwmon specific part into the hwmon driver.

The enablement of the hwmon logical device is only a side effect. The
main goal of the function is to figure out whether a supported chip is
present, and which one. The original reason to put everything is the
same function is so that we don't have to enter and exit the super-io
config mode twice.

But I wouldn't object to it being split into two separate functions,
each one doing just one thing. That would be cleaner, and speed isn't
critical.

> > + exit:
> > +	superio_exit(sio_data);
> > +	return err;
> > +}

> > (...)
> > +static inline void superio_enter(struct w83627hf_sio_data *sio)
> > +{
> > +	mutex_lock(&sio->lock);
> > +
> > +	outb(0x87, sio->sioaddr);
> > +	outb(0x87, sio->sioaddr);
>
> I'm not really happy with this one. The unbalanced locking here makes me feel
> unconfortable.

Me, I don't have any objection. Callers will have to balance
superio_enter and superio_exit anyway. So hiding the mutex in there
seems reasonable.

> Something like that:
> 
> void superio_outb(struct w83627hf_sio_data *sio, int ld, int reg, int val)
> {
> 	mutex_lock(&sio->lock);
> 
> 	/* Enter */
> 	outb(0x87, sio->sioaddr)
> 	outb(0x87, sio->sioaddr)
> 
> 	/* Select module */
> 	outb(0x07, sio->sioaddr);
> 	outb(ld, sio->sioaddr + 1);
> 
> 	/* Write */
> 	outb(reg, sio->sioaddr);
> 	outb(val, sio->sioaddr + 1);
> 
> 	/* Exit */
> 	outb(0xAA, sio->sioaddr);
> 
> 	mutex_unlock(&sio->lock);
> }
> 
> would look saner to me. I know we're wasting many IO ops here, but it seems to
> me that the subdevices get to call the superio API only at init time.
> I think it's worth it as your subdevices wouldnt have to care about following
> these error prone steps, and you wouldnt have any more unbalanced locking
> risks.

The above has limitations. Think of the hwmon logical device enablement
function which we discussed above. In this function we must read a
register, and depending on the value, maybe write to it, but altering
only one bit (so based on the original value.)

There is no way to achieve this in a race-free manner with your
proposed superio_outb() function and the equivalent superio_inb()
implementation. Even a superio_alterb() function wouldn't do, because
we want to print a message.

At least with Rodolfo's proposal, this can be done. With your approach,
we'd need dedicated functions for every non-trivial register access.

As far as speed is concerned, I agree it's not critical, at least for
the use cases I know of. 


-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (17 preceding siblings ...)
  2009-09-18 16:16 ` Jean Delvare
@ 2009-09-20 23:48 ` Samuel Ortiz
  2009-09-22  8:22 ` Rodolfo Giometti
                   ` (6 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2009-09-20 23:48 UTC (permalink / raw)
  To: lm-sensors

Hi Jean,

On Fri, Sep 18, 2009 at 06:16:38PM +0200, Jean Delvare wrote:
> > > +static inline void superio_enter(struct w83627hf_sio_data *sio)
> > > +{
> > > +	mutex_lock(&sio->lock);
> > > +
> > > +	outb(0x87, sio->sioaddr);
> > > +	outb(0x87, sio->sioaddr);
> >
> > I'm not really happy with this one. The unbalanced locking here makes me feel
> > unconfortable.
> 
> Me, I don't have any objection. Callers will have to balance
> superio_enter and superio_exit anyway. So hiding the mutex in there
> seems reasonable.
Oh, hiding the mutex from the callers makes perfect sense to me. What I dont
really like is the fact that it's so easy to screw the locking (unbalance it,
unlock while not locking, unlock from a different process than the one that
locked, etc...) with this API. In fact, it doesnt bring much compared to
letting callers handling the locking by themselves.
Obviously, the only thing it brings is not having the callers know or care
about the MFD core locking. More comments below...

 
> > Something like that:
> > 
> > void superio_outb(struct w83627hf_sio_data *sio, int ld, int reg, int val)
> > {
> > 	mutex_lock(&sio->lock);
> > 
> > 	/* Enter */
> > 	outb(0x87, sio->sioaddr)
> > 	outb(0x87, sio->sioaddr)
> > 
> > 	/* Select module */
> > 	outb(0x07, sio->sioaddr);
> > 	outb(ld, sio->sioaddr + 1);
> > 
> > 	/* Write */
> > 	outb(reg, sio->sioaddr);
> > 	outb(val, sio->sioaddr + 1);
> > 
> > 	/* Exit */
> > 	outb(0xAA, sio->sioaddr);
> > 
> > 	mutex_unlock(&sio->lock);
> > }
> > 
> > would look saner to me. I know we're wasting many IO ops here, but it seems to
> > me that the subdevices get to call the superio API only at init time.
> > I think it's worth it as your subdevices wouldnt have to care about following
> > these error prone steps, and you wouldnt have any more unbalanced locking
> > risks.
> 
> The above has limitations. Think of the hwmon logical device enablement
> function which we discussed above. In this function we must read a
> register, and depending on the value, maybe write to it, but altering
> only one bit (so based on the original value.)
> 
> There is no way to achieve this in a race-free manner with your
> proposed superio_outb() function and the equivalent superio_inb()
> implementation. Even a superio_alterb() function wouldn't do, because
> we want to print a message.
I agree about that. But since this API is supposed to be used by subdevices, I
looked at what the only available one (w83627hf.c) would do with it. It seems
to me that this API would work well for w83627thf_read_gpio5() and
w83627thf_read_vid(). The more complex register manipulations found in
w83627hf_find() wouldnt have to use this API since it's an MFD core routine.
I definitely see the limitation of the above API, but it looks like it fills
the current need without introducing potential locking issues.
Now, you guys know way better the HW than me and can tell if this API will be
too limited for future subdevices. If that's the case, then let's go with
Rodolfo's proposal but I'd like to have an additional check for all the
superio_* routines (except superio_enter()), which would be a:
WARN_ON(!mutex_is_locked(&sio->lock));

That wont protect us from the "unlocking from a different process" bug, but it
would still be a progress.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (18 preceding siblings ...)
  2009-09-20 23:48 ` Samuel Ortiz
@ 2009-09-22  8:22 ` Rodolfo Giometti
  2009-09-22  8:26 ` Rodolfo Giometti
                   ` (5 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Rodolfo Giometti @ 2009-09-22  8:22 UTC (permalink / raw)
  To: lm-sensors


[-- Attachment #1.1: Type: text/plain, Size: 16183 bytes --]

On Fri, Sep 18, 2009 at 04:42:49PM +0200, Samuel Ortiz wrote:
> Hi Rodolfo,
> 
> Some comments on the MFD related parts:
> 
> On Fri, Sep 18, 2009 at 02:09:23PM +0200, Rodolfo Giometti wrote:
> > diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> > index 2d50166..bc7058f 100644
> > --- a/drivers/hwmon/Kconfig
> > +++ b/drivers/hwmon/Kconfig
> > @@ -894,6 +894,7 @@ config SENSORS_W83L786NG
> >  
> >  config SENSORS_W83627HF
> >  	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
> > +	depends on 83627HF
> Use select here, as the hwmon W83627HF current users are not really supposed
> to know that they have to go an manually select an obscure MFD core for their
> driver to build.
> Moreover, the symbol is MFD_W83627HF, not 83627HF.

Fixed.

> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index 491ac0f..784a892 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -263,6 +263,20 @@ config EZX_PCAP
> >  	  This enables the PCAP ASIC present on EZX Phones. This is
> >  	  needed for MMC, TouchScreen, Sound, USB, etc..
> >  
> > +config MFD_W83627HF
> > +	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
> You must depend on MFD_CORE here.

Fixed.

> > +	help
> > +	  If you say yes here you add support for the Winbond W836X7 series
> > +	  of super-IO chips: the W83627HF, W83627THF, W83637HF, W83687THF and
> > +	  W83697HF to your platform.
> > +
> > +	  This is a multi functional device and this support defines a new
> > +	  platform device only. See other configuration submenus in order to
> > +	  enable the drivers of Winbond chip's functionalities.
> > +
> > +	  This driver can also be built as a module.  If so, the module
> > +	  will be called w83627hf-core.
> > +
> >  endmenu
> >  
> >  menu "Multimedia Capabilities Port drivers"
> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > index 6f8a9a1..1401ac9 100644
> > --- a/drivers/mfd/Makefile
> > +++ b/drivers/mfd/Makefile
> > @@ -27,6 +27,7 @@ obj-$(CONFIG_TWL4030_CORE)	+= twl4030-core.o twl4030-irq.o
> >  obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
> >  
> >  obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
> > +obj-$(CONFIG_MFD_W83627HF)	+= w83627hf-core.o
> >  
> >  obj-$(CONFIG_MCP)		+= mcp-core.o
> >  obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
> > diff --git a/drivers/mfd/w83627hf-core.c b/drivers/mfd/w83627hf-core.c
> > new file mode 100644
> > index 0000000..39b6190
> > --- /dev/null
> > +++ b/drivers/mfd/w83627hf-core.c
> > @@ -0,0 +1,236 @@
> > +/*
> > + *  w83627hf.c - platform device support
> > + *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
> > + *
> > + *  Based on drivers/hwmon/w83627hf.c
> > + *
> > + *  Original copyright note:
> > + *    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
> > + *    Philip Edelbrock <phil@netroedge.com>,
> > + *    and Mark Studebaker <mdsxyz123@yahoo.com>
> > + *    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
> > + *    Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
> > + *
> > + *    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
> > + *    the Free Software Foundation; either version 2 of the License, or
> > + *    (at your option) any later version.
> > + *
> > + *    This program is distributed in the hope that it will be useful,
> > + *    but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + *    GNU General Public License for more details.
> > + *
> > + *    You should have received a copy of the GNU General Public License
> > + *    along with this program; if not, write to the Free Software
> > + *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> > + */
> > +
> > +#include <linux/module.h>
> > +#include <linux/init.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/err.h>
> > +#include <linux/mutex.h>
> > +#include <linux/ioport.h>
> > +#include <linux/acpi.h>
> > +#include <linux/io.h>
> > +#include <linux/mfd/core.h>
> > +#include <linux/mfd/w83627hf.h>
> > +
> > +static u16 force_hwmon_addr;
> > +module_param(force_hwmon_addr, ushort, 0);
> > +MODULE_PARM_DESC(force_hwmon_addr,
> > +		 "Initialize the base address of the hwmon sensors");
> > +
> > +static unsigned short force_id;
> > +module_param(force_id, ushort, 0);
> > +MODULE_PARM_DESC(force_id, "Override the detected device ID");
> > +
> > +/*
> > + * Devices definitions
> > + */
> > +
> > +static struct platform_device *pdev;
> > +
> > +static char *names[] = {
> > +	"w83627hf",
> > +	"w83627thf",
> > +	"w83697hf",
> > +	"w83637hf",
> > +	"w83687thf",
> > +};
> > +
> > +static struct resource hwmon_res = {
> > +	/* .start  = ? - NOTE: set at runtime */
> > +	/* .end    = ? - NOTE: set at runtime */
> > +	.name   = DRVNAME "_hwmon",
> > +	.flags  = IORESOURCE_IO,
> > +};
> > +
> > +static struct mfd_cell cells[] = {
> > +	{
> > +		.name	   = DRVNAME "_hwmon",
> > +		.num_resources  = 1,
> > +		.resources      = &hwmon_res,
> > +	},
> > +};
> > +
> > +/*
> > + * Local functions
> > + */
> Local functions ?

Fixed.

> > +
> > +#define W627_DEVID		0x52
> > +#define W627THF_DEVID		0x82
> > +#define W697_DEVID		0x60
> > +#define W637_DEVID		0x70
> > +#define W687THF_DEVID		0x85
> > +#define WINB_ACT_REG		0x30
> > +#define WINB_BASE_REG		0x60
> Are those 2 last ones HWMON specific. If that's so, please be more specific
> about it.

Fixed.

> > +/* Constants specified below */
> > +
> > +/* Offset & size of I/O region we are interested in */
> This seems to be the hwmon region, so please be more specific about it in the
> comments and in the naming below.

Fixed.

> > +#define WINB_REGION_OFFSET	5
> > +#define WINB_REGION_SIZE	2
> > +
> > +static int __init w83627hf_find(int sioaddr, unsigned short *addr,
> > +				struct w83627hf_sio_data *sio_data)
> > +{
> > +	int err = -ENODEV;
> > +	u16 val;
> > +
> > +	sio_data->sioaddr = sioaddr;
> > +
> > +	superio_enter(sio_data);
> > +	val = force_id ? force_id : superio_inb(sio_data, 0x20);
> > +	switch (val) {
> > +	case W627_DEVID:
> > +		sio_data->type = w83627hf;
> > +		break;
> > +	case W627THF_DEVID:
> > +		sio_data->type = w83627thf;
> > +		break;
> > +	case W697_DEVID:
> > +		sio_data->type = w83697hf;
> > +		break;
> > +	case W637_DEVID:
> > +		sio_data->type = w83637hf;
> > +		break;
> > +	case W687THF_DEVID:
> > +		sio_data->type = w83687thf;
> > +		break;
> > +	case 0xff:	/* No device at all */
> > +		goto exit;
> > +	default:
> > +		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
> > +		goto exit;
> > +	}
> > +
> > +	sio_data->name = names[sio_data->type];
> > +
> > +	superio_select(sio_data, W83627HF_LD_HWM);
> > +	force_hwmon_addr &= (~7);
> > +	if (force_hwmon_addr) {
> > +		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
> > +		       force_hwmon_addr);
> > +		superio_outb(sio_data, WINB_BASE_REG, force_hwmon_addr >> 8);
> > +		superio_outb(sio_data, WINB_BASE_REG + 1,
> > +					force_hwmon_addr & 0xff);
> > +	}
> > +	val = (superio_inb(sio_data, WINB_BASE_REG) << 8) |
> > +	       superio_inb(sio_data, WINB_BASE_REG + 1);
> > +	*addr = val & (~7);
> > +	if (*addr == 0) {
> > +		printk(KERN_WARNING DRVNAME ": Base address not set, "
> > +		       "skipping\n");
> > +		goto exit;
> > +	}
> > +
> > +	val = superio_inb(sio_data, WINB_ACT_REG);
> > +	if (!(val & 0x01)) {
> > +		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
> > +		superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
> > +	}
> > +
> > +	err = 0;
> > +	pr_info(DRVNAME ": Found %s chip at %#x\n",
> > +		names[sio_data->type], *addr);
> I'm not familiar with this chip, but although the function is called
> w83627hf_find(), it seems to me that what we're doing here is enabling the
> hwmon subdevice. Am I correct ? If that's so, could we split this function,
> and maybe even move the hwmon specific part into the hwmon driver.

Fixed.

> > + exit:
> > +	superio_exit(sio_data);
> > +	return err;
> > +}
> > +
> > +static int __init w83627hf_device_add(unsigned short address,
> > +				      const struct w83627hf_sio_data *sio_data)
> > +{
> > +	int err;
> > +
> > +	hwmon_res.start = address + WINB_REGION_OFFSET;
> > +	hwmon_res.end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1;
> > +
> > +	pdev = platform_device_alloc(DRVNAME, address);
> > +	if (!pdev) {
> > +		err = -ENOMEM;
> > +		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
> > +		goto exit;
> > +	}
> > +
> > +	err = platform_device_add_data(pdev, sio_data,
> > +				       sizeof(struct w83627hf_sio_data));
> > +	if (err) {
> > +		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
> > +		goto exit_device_put;
> > +	}
> > +
> > +	err = platform_device_add(pdev);
> > +	if (err) {
> > +		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
> > +		       err);
> > +		goto exit_device_put;
> > +	}
> > +
> > +	err = mfd_add_devices(&pdev->dev, pdev->id, cells, ARRAY_SIZE(cells),
> > +			(struct resource *) (address & 0xffff), -1);
> > +	if (err) {
> > +		printk(KERN_ERR DRVNAME ": Cannot add sub devices (%d)\n",
> > +			err);
> > +		goto exit_device_unregister;
> > +	}
> > +
> > +	return 0;
> > +
> > +exit_device_unregister:
> > +	platform_device_unregister(pdev);
> > +exit_device_put:
> > +	platform_device_put(pdev);
> > +exit:
> > +	return err;
> > +}
> > +
> > +static int __init w83627hf_init(void)
> > +{
> > +	unsigned short address;
> > +	struct w83627hf_sio_data sio_data;
> > +
> > +	mutex_init(&sio_data.lock);
> > +
> > +	if (w83627hf_find(0x2e, &address, &sio_data)
> > +	 && w83627hf_find(0x4e, &address, &sio_data))
> > +		return -ENODEV;
> > +
> > +	/* Sets global pdev as a side effect */
> > +	return w83627hf_device_add(address, &sio_data);
> > +}
> > +
> > +static void __exit w83627hf_exit(void)
> > +{
> > +	mfd_remove_devices(&pdev->dev);
> > +	platform_device_unregister(pdev);
> > +}
> > +
> > +MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
> > +MODULE_DESCRIPTION("W83627HF platform devices definitions");
> > +MODULE_LICENSE("GPL");
> > +
> > +module_init(w83627hf_init);
> > +module_exit(w83627hf_exit);
> > diff --git a/include/linux/mfd/w83627hf.h b/include/linux/mfd/w83627hf.h
> > new file mode 100644
> > index 0000000..c9f537d
> > --- /dev/null
> > +++ b/include/linux/mfd/w83627hf.h
> > @@ -0,0 +1,112 @@
> > +/*
> > + *  w83627hf.h - platform device support, header file
> > + *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
> > + *
> > + *  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
> > + *  the Free Software Foundation; either version 2 of the License, or
> > + *  (at your option) any later version.
> > + *
> > + *  This program is distributed in the hope that it will be useful,
> > + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + *  GNU General Public License for more details.
> > + *
> > + *  You should have received a copy of the GNU General Public License
> > + *  along with this program; if not, write to the Free Software
> > + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> > + */
> > +
> > +#include <linux/mutex.h>
> > +#include <linux/io.h>
> > +
> > +#define DRVNAME "w83627hf"
> > +
> > +enum chips {
> > +	w83627hf,
> > +	w83627thf,
> > +	w83697hf,
> > +	w83637hf,
> > +	w83687thf
> > +};
> > +
> > +struct w83627hf_sio_data {
> > +	int sioaddr;
> > +	enum chips type;
> > +	char *name;
> > +
> > +	struct mutex lock;
> > +};
> > +
> > +/* logical device numbers for superio_select (below) */
> > +#define W83627HF_LD_FDC		0x00
> > +#define W83627HF_LD_PRT		0x01
> > +#define W83627HF_LD_UART1	0x02
> > +#define W83627HF_LD_UART2	0x03
> > +#define W83627HF_LD_KBC		0x05
> > +#define W83627HF_LD_CIR		0x06 /* w83627hf only */
> > +#define W83627HF_LD_GAME	0x07
> > +#define W83627HF_LD_MIDI	0x07
> > +#define W83627HF_LD_GPIO1	0x07
> > +#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
> > +#define W83627HF_LD_GPIO2	0x08
> > +#define W83627HF_LD_GPIO3	0x09
> > +#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
> > +#define W83627HF_LD_ACPI	0x0a
> > +#define W83627HF_LD_HWM		0x0b
> > +
> > +#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
> > +#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
> > +#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
> > +
> > +#define W83687THF_VID_EN	0x29 /* w83687thf only */
> > +#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
> > +#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
> > +
> > +/*
> > + * Common configuration registers access functions.
> > + *
> > + * These registers are special and they must me accessed by using a well
> > + * specified protocol. Client drivers __must__ do as follow in order to
> > + * get access correctly to these registers:
> > + *
> > + *	superio_enter()
> > + *
> > + *	superio_select()/superio_outb()/superio_inb()
> > + *
> > + *	superio_exit();
> > + *
> > + */
> > +
> > +static inline void superio_enter(struct w83627hf_sio_data *sio)
> > +{
> > +	mutex_lock(&sio->lock);
> > +
> > +	outb(0x87, sio->sioaddr);
> > +	outb(0x87, sio->sioaddr);
> I'm not really happy with this one. The unbalanced locking here makes me feel
> unconfortable.
> 
> Something like that:
> 
> void superio_outb(struct w83627hf_sio_data *sio, int ld, int reg, int val)
> {
> 	mutex_lock(&sio->lock);
> 
> 	/* Enter */
> 	outb(0x87, sio->sioaddr)
> 	outb(0x87, sio->sioaddr)
> 
> 	/* Select module */
> 	outb(0x07, sio->sioaddr);
> 	outb(ld, sio->sioaddr + 1);
> 
> 	/* Write */
> 	outb(reg, sio->sioaddr);
> 	outb(val, sio->sioaddr + 1);
> 
> 	/* Exit */
> 	outb(0xAA, sio->sioaddr);
> 
> 	mutex_unlock(&sio->lock);
> }
> 
> would look saner to me. I know we're wasting many IO ops here, but it seems to
> me that the subdevices get to call the superio API only at init time.

This is not true for all sub-devices. GPIOs sub-device, for instance,
uses such functions to reads/writes data.

> I think it's worth it as your subdevices wouldnt have to care about following
> these error prone steps, and you wouldnt have any more unbalanced locking
> risks.

Unluckely this not possible. Once we do superio_enter() we should be
able to do several reads and writes whose are not easily fixed in the
above function.

Clients devices must have the possibility to mix several calls of
superio_outb()/superio_inb(), so device drivers must use them properly.

> > +}
> > +
> > +static inline void superio_select(struct w83627hf_sio_data *sio, int ld)
> > +{
> > +	outb(0x07, sio->sioaddr);
> > +	outb(ld, sio->sioaddr + 1);
> > +}
> > +
> > +static inline void superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
> > +{
> > +	outb(reg, sio->sioaddr);
> > +	outb(val, sio->sioaddr + 1);
> > +}
> > +
> > +static inline int superio_inb(struct w83627hf_sio_data *sio, int reg)
> > +{
> > +	outb(reg, sio->sioaddr);
> > +	return inb(sio->sioaddr + 1);
> > +}
> > +
> > +static inline void superio_exit(struct w83627hf_sio_data *sio)
> > +{
> > +	outb(0xAA, sio->sioaddr);
> > +
> > +	mutex_unlock(&sio->lock);
> > +}

I'll repropose a new patch ASAP.

Thanks,

Rodolfo

-- 

GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming                     skype:  rodolfo.giometti
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 153 bytes --]

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (19 preceding siblings ...)
  2009-09-22  8:22 ` Rodolfo Giometti
@ 2009-09-22  8:26 ` Rodolfo Giometti
  2009-09-22  8:33 ` Rodolfo Giometti
                   ` (4 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Rodolfo Giometti @ 2009-09-22  8:26 UTC (permalink / raw)
  To: lm-sensors


[-- Attachment #1.1: Type: text/plain, Size: 3142 bytes --]

On Fri, Sep 18, 2009 at 04:49:02PM +0200, Jean Delvare wrote:
> On Fri, 18 Sep 2009 14:09:23 +0200, Rodolfo Giometti wrote:
> > Hi Jean,
> > 
> > this new proposal patch sounds better to you? :)
> > 
> > Ciao,
> > 
> > Rodolfo
> > 
> > --
> > 
> > diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> > index 2d50166..bc7058f 100644
> > --- a/drivers/hwmon/Kconfig
> > +++ b/drivers/hwmon/Kconfig
> > @@ -894,6 +894,7 @@ config SENSORS_W83L786NG
> >  
> >  config SENSORS_W83627HF
> >  	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
> > +	depends on 83627HF
> 
> Which doesn't exist, so the driver can't be selected. Obviously you
> meant: depends on MFD_W83627HF.
> 
> But please also see my discussion with Samuel on depends vs. select.
> I'd prefer that you use select. Especially given that the MFD
> configuration entry is _after_ the hwmon configuration entry in
> Kconfig, I fear that even if users see and select MFD_W83627HF, they
> won't walk back to the W83627HF entry to select it.
> 
> Samuel, wouldn't it make sense to move the MFD section up in the Device
> Drivers section?
> 
> Even after fixing this so that I could select the driver, I'm hitting
> build problems:
> 
>   CC [M]  drivers/hwmon/w83627hf.o
> drivers/hwmon/w83627hf.c: In function ???w83627hf_probe???:
> drivers/hwmon/w83627hf.c:1121: warning: passing argument 1 of ???acpi_check_resource_conflict??? from incompatible pointer type
> drivers/hwmon/w83627hf.c:1125: error: ???WINB_REGION_SIZE??? undeclared (first use in this function)
> drivers/hwmon/w83627hf.c:1125: error: (Each undeclared identifier is reported only once
> drivers/hwmon/w83627hf.c:1125: error: for each function it appears in.)
> drivers/hwmon/w83627hf.c: In function ???w83627hf_remove???:
> drivers/hwmon/w83627hf.c:1290: error: ???WINB_REGION_SIZE??? undeclared (first use in this function)
> 
> Please build-test your patches before you send them.

Yes, sorry. Fixed.

> >  	select HWMON_VID
> >  	help
> >  	  If you say yes here you get support for the Winbond W836X7 series
> > diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
> > index 389150b..4757668 100644
> > --- a/drivers/hwmon/w83627hf.c
> > +++ b/drivers/hwmon/w83627hf.c
> > @@ -51,18 +51,10 @@
> >  #include <linux/mutex.h>
> >  #include <linux/ioport.h>
> >  #include <linux/acpi.h>
> > -#include <asm/io.h>
> > +#include <linux/io.h>
> 
> As I said before, this change is already upstream, so please don't
> include it in your patch.
> 
> >  #include "lm75.h"
> > +#include <linux/mfd/w83627hf.h>
> 
> Global includes must be listed before local ones.

Both fixed.

> I'll go on with the review when you provide a patch I can build.

Ok, thanks.

Rodolfo

-- 

GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming                     skype:  rodolfo.giometti
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 153 bytes --]

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (20 preceding siblings ...)
  2009-09-22  8:26 ` Rodolfo Giometti
@ 2009-09-22  8:33 ` Rodolfo Giometti
  2009-10-01 13:23 ` Jean Delvare
                   ` (3 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Rodolfo Giometti @ 2009-09-22  8:33 UTC (permalink / raw)
  To: lm-sensors


[-- Attachment #1.1: Type: text/plain, Size: 3046 bytes --]

On Mon, Sep 21, 2009 at 01:48:37AM +0200, Samuel Ortiz wrote:
> > > Something like that:
> > > 
> > > void superio_outb(struct w83627hf_sio_data *sio, int ld, int reg, int val)
> > > {
> > > 	mutex_lock(&sio->lock);
> > > 
> > > 	/* Enter */
> > > 	outb(0x87, sio->sioaddr)
> > > 	outb(0x87, sio->sioaddr)
> > > 
> > > 	/* Select module */
> > > 	outb(0x07, sio->sioaddr);
> > > 	outb(ld, sio->sioaddr + 1);
> > > 
> > > 	/* Write */
> > > 	outb(reg, sio->sioaddr);
> > > 	outb(val, sio->sioaddr + 1);
> > > 
> > > 	/* Exit */
> > > 	outb(0xAA, sio->sioaddr);
> > > 
> > > 	mutex_unlock(&sio->lock);
> > > }
> > > 
> > > would look saner to me. I know we're wasting many IO ops here, but it seems to
> > > me that the subdevices get to call the superio API only at init time.
> > > I think it's worth it as your subdevices wouldnt have to care about following
> > > these error prone steps, and you wouldnt have any more unbalanced locking
> > > risks.
> > 
> > The above has limitations. Think of the hwmon logical device enablement
> > function which we discussed above. In this function we must read a
> > register, and depending on the value, maybe write to it, but altering
> > only one bit (so based on the original value.)
> > 
> > There is no way to achieve this in a race-free manner with your
> > proposed superio_outb() function and the equivalent superio_inb()
> > implementation. Even a superio_alterb() function wouldn't do, because
> > we want to print a message.
> I agree about that. But since this API is supposed to be used by subdevices, I
> looked at what the only available one (w83627hf.c) would do with it. It seems
> to me that this API would work well for w83627thf_read_gpio5() and
> w83627thf_read_vid(). The more complex register manipulations found in
> w83627hf_find() wouldnt have to use this API since it's an MFD core routine.
> I definitely see the limitation of the above API, but it looks like it fills
> the current need without introducing potential locking issues.
> Now, you guys know way better the HW than me and can tell if this API will be
> too limited for future subdevices. If that's the case, then let's go with
> Rodolfo's proposal but I'd like to have an additional check for all the
> superio_* routines (except superio_enter()), which would be a:
> WARN_ON(!mutex_is_locked(&sio->lock));
> That wont protect us from the "unlocking from a different process"
> > bug, but it
> would still be a progress.

If you can read chip's datasheet you may see that GPIOs sub-device
doesn't fix with your proposal. So I'm going to use my proposal but I
add your check about mutex locking.

Thanks,

Rodolfo

-- 

GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming                     skype:  rodolfo.giometti
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 153 bytes --]

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (21 preceding siblings ...)
  2009-09-22  8:33 ` Rodolfo Giometti
@ 2009-10-01 13:23 ` Jean Delvare
  2009-10-01 13:53 ` Samuel Ortiz
                   ` (2 subsequent siblings)
  25 siblings, 0 replies; 30+ messages in thread
From: Jean Delvare @ 2009-10-01 13:23 UTC (permalink / raw)
  To: lm-sensors

Hi Rodolfo,

On Thu, 24 Sep 2009 14:01:11 +0200, Rodolfo Giometti wrote:
> The file has been splitted up into two parts:
> 
> * drivers/mfd/w83627hf-core.c      - detects the chip and define proper
>                                      platform devices into mfd support
> 
> * drivers/hwmon/w83627hf.c         - implements the driver for hwmon
>                                      functionality only
> 
> Signed-off-by: Rodolfo Giometti <giometti@linux.it>
> ---
>  drivers/hwmon/Kconfig        |    1 +
>  drivers/hwmon/w83627hf.c     |  376 ++++++++++++------------------------------
>  drivers/mfd/Kconfig          |   15 ++
>  drivers/mfd/Makefile         |    1 +
>  drivers/mfd/w83627hf-core.c  |  186 +++++++++++++++++++++
>  include/linux/mfd/w83627hf.h |  118 +++++++++++++
>  6 files changed, 428 insertions(+), 269 deletions(-)
>  create mode 100644 drivers/mfd/w83627hf-core.c
>  create mode 100644 include/linux/mfd/w83627hf.h

Sorry for the late review...

> 
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 2d50166..f6cf2af 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -894,6 +894,7 @@ config SENSORS_W83L786NG
>  
>  config SENSORS_W83627HF
>  	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
> +	select MFD_W83627HF
>  	select HWMON_VID
>  	help
>  	  If you say yes here you get support for the Winbond W836X7 series
> diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
> index 389150b..748f77a 100644
> --- a/drivers/hwmon/w83627hf.c
> +++ b/drivers/hwmon/w83627hf.c
> @@ -52,13 +52,9 @@
>  #include <linux/ioport.h>
>  #include <linux/acpi.h>
>  #include <asm/io.h>
> +#include <linux/mfd/w83627hf.h>
>  #include "lm75.h"
>  
> -static struct platform_device *pdev;
> -
> -#define DRVNAME "w83627hf"
> -enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
> -
>  static u16 force_addr;
>  module_param(force_addr, ushort, 0);
>  MODULE_PARM_DESC(force_addr,
> @@ -72,87 +68,11 @@ static int init = 1;
>  module_param(init, bool, 0);
>  MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
>  
> -static unsigned short force_id;
> -module_param(force_id, ushort, 0);
> -MODULE_PARM_DESC(force_id, "Override the detected device ID");
> -
> -/* modified from kernel/include/traps.c */
> -static int REG;		/* The register to read/write */
> -#define	DEV	0x07	/* Register: Logical device select */
> -static int VAL;		/* The value to read/write */
> -
> -/* logical device numbers for superio_select (below) */
> -#define W83627HF_LD_FDC		0x00
> -#define W83627HF_LD_PRT		0x01
> -#define W83627HF_LD_UART1	0x02
> -#define W83627HF_LD_UART2	0x03
> -#define W83627HF_LD_KBC		0x05
> -#define W83627HF_LD_CIR		0x06 /* w83627hf only */
> -#define W83627HF_LD_GAME	0x07
> -#define W83627HF_LD_MIDI	0x07
> -#define W83627HF_LD_GPIO1	0x07
> -#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
> -#define W83627HF_LD_GPIO2	0x08
> -#define W83627HF_LD_GPIO3	0x09
> -#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
> -#define W83627HF_LD_ACPI	0x0a
> -#define W83627HF_LD_HWM		0x0b
> -
> -#define	DEVID	0x20	/* Register: Device ID */
> -
> -#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
> -#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
> -#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
> -
> -#define W83687THF_VID_EN	0x29 /* w83687thf only */
> -#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
> -#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
> -
> -static inline void
> -superio_outb(int reg, int val)
> -{
> -	outb(reg, REG);
> -	outb(val, VAL);
> -}
> -
> -static inline int
> -superio_inb(int reg)
> -{
> -	outb(reg, REG);
> -	return inb(VAL);
> -}
> -
> -static inline void
> -superio_select(int ld)
> -{
> -	outb(DEV, REG);
> -	outb(ld, VAL);
> -}
> -
> -static inline void
> -superio_enter(void)
> -{
> -	outb(0x87, REG);
> -	outb(0x87, REG);
> -}
> -
> -static inline void
> -superio_exit(void)
> -{
> -	outb(0xAA, REG);
> -}
> -
> -#define W627_DEVID 0x52
> -#define W627THF_DEVID 0x82
> -#define W697_DEVID 0x60
> -#define W637_DEVID 0x70
> -#define W687THF_DEVID 0x85
> -#define WINB_ACT_REG 0x30
> -#define WINB_BASE_REG 0x60
>  /* Constants specified below */
>  
> -/* Alignment of the base address */
> -#define WINB_ALIGNMENT		~7

Not sure why you removed that one while your code still uses it.

> +#define HWMON_CR30		0x30
> +#define   ACTIVATION_CTRL	  (1 << 0)
> +#define HWMON_CR60		0x60

Why are you changing the name of these registers from meaningful ones
to meaningless ones?

>  
>  /* Offset & size of I/O region we are interested in */
>  #define WINB_REGION_OFFSET	5
> @@ -380,10 +300,6 @@ struct w83627hf_data {
>  	u8 vrm_ovt;		/* Register value, 627THF/637HF/687THF only */
>  };
>  
> -struct w83627hf_sio_data {
> -	enum chips type;
> -};
> -
>  
>  static int w83627hf_probe(struct platform_device *pdev);
>  static int __devexit w83627hf_remove(struct platform_device *pdev);
> @@ -397,7 +313,7 @@ static void w83627hf_init_device(struct platform_device *pdev);
>  static struct platform_driver w83627hf_driver = {
>  	.driver = {
>  		.owner	= THIS_MODULE,
> -		.name	= DRVNAME,
> +		.name	= DRVNAME "_hwmon",
>  	},
>  	.probe		= w83627hf_probe,
>  	.remove		= __devexit_p(w83627hf_remove),
> @@ -1126,80 +1042,6 @@ show_name(struct device *dev, struct device_attribute *devattr, char *buf)
>  }
>  static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
>  
> -static int __init w83627hf_find(int sioaddr, unsigned short *addr,
> -				struct w83627hf_sio_data *sio_data)
> -{
> -	int err = -ENODEV;
> -	u16 val;
> -
> -	static const __initdata char *names[] = {
> -		"W83627HF",
> -		"W83627THF",
> -		"W83697HF",
> -		"W83637HF",
> -		"W83687THF",
> -	};
> -
> -	REG = sioaddr;
> -	VAL = sioaddr + 1;
> -
> -	superio_enter();
> -	val = force_id ? force_id : superio_inb(DEVID);
> -	switch (val) {
> -	case W627_DEVID:
> -		sio_data->type = w83627hf;
> -		break;
> -	case W627THF_DEVID:
> -		sio_data->type = w83627thf;
> -		break;
> -	case W697_DEVID:
> -		sio_data->type = w83697hf;
> -		break;
> -	case W637_DEVID:
> -		sio_data->type = w83637hf;
> -		break;
> -	case W687THF_DEVID:
> -		sio_data->type = w83687thf;
> -		break;
> -	case 0xff:	/* No device at all */
> -		goto exit;
> -	default:
> -		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
> -		goto exit;
> -	}
> -
> -	superio_select(W83627HF_LD_HWM);
> -	force_addr &= WINB_ALIGNMENT;
> -	if (force_addr) {
> -		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
> -		       force_addr);
> -		superio_outb(WINB_BASE_REG, force_addr >> 8);
> -		superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
> -	}
> -	val = (superio_inb(WINB_BASE_REG) << 8) |
> -	       superio_inb(WINB_BASE_REG + 1);
> -	*addr = val & WINB_ALIGNMENT;
> -	if (*addr = 0) {
> -		printk(KERN_WARNING DRVNAME ": Base address not set, "
> -		       "skipping\n");
> -		goto exit;
> -	}
> -
> -	val = superio_inb(WINB_ACT_REG);
> -	if (!(val & 0x01)) {
> -		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
> -		superio_outb(WINB_ACT_REG, val | 0x01);
> -	}
> -
> -	err = 0;
> -	pr_info(DRVNAME ": Found %s chip at %#x\n",
> -		names[sio_data->type], *addr);
> -
> - exit:
> -	superio_exit();
> -	return err;
> -}
> -
>  #define VIN_UNIT_ATTRS(_X_)	\
>  	&sensor_dev_attr_in##_X_##_input.dev_attr.attr,		\
>  	&sensor_dev_attr_in##_X_##_min.dev_attr.attr,		\
> @@ -1278,27 +1120,89 @@ static const struct attribute_group w83627hf_group_opt = {
>  	.attrs = w83627hf_attributes_opt,
>  };
>  
> +static int w83627hf_enable_hwmon(struct w83627hf_sio_data *sio_data)
> +{
> +	u16 val;
> +	int ret;
> +
> +	superio_enter(sio_data);
> +
> +	superio_select(sio_data, W83627HF_LD_HWM);
> +
> +	force_addr &= (~7);
> +	if (force_addr) {
> +		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
> +			force_addr);
> +		superio_outb(sio_data, HWMON_CR60, force_addr >> 8);
> +		superio_outb(sio_data, HWMON_CR60 + 1, force_addr & 0xff);
> +	}
> +
> +	val = (superio_inb(sio_data, HWMON_CR60) << 8) |
> +	       superio_inb(sio_data, HWMON_CR60 + 1);
> +	ret = val & (~7);
> +	pr_info(DRVNAME ": hwmon chip %s at %#x\n", sio_data->name, ret);
> +
> +	if (ret = 0) {
> +		printk(KERN_WARNING DRVNAME ": Base address not set, "
> +		       "skipping\n");
> +		ret = -EINVAL;
> +		goto exit;
> +	}
> +
> +	val = superio_inb(sio_data, HWMON_CR30);
> +	superio_outb(sio_data, HWMON_CR30, val | ACTIVATION_CTRL);
> +
> +exit:
> +	superio_exit(sio_data);
> +
> +	return ret;
> +}

If this function was moved where w83627hf_find() was before, your patch
would be somewhat smaller and easier to review.

> +
> +static void w83627hf_disable_hwmon(struct w83627hf_sio_data *sio_data)
> +{
> +	u16 val;
> +
> +	superio_enter(sio_data);
> +
> +	superio_select(sio_data, W83627HF_LD_HWM);
> +
> +	val = superio_inb(sio_data, HWMON_CR30);
> +	superio_outb(sio_data, HWMON_CR30, val & ~ACTIVATION_CTRL);
> +
> +	superio_exit(sio_data);
> +}

No, we don't want to do this. Most systems boot with hardware
monitoring enabled, and the fact of loading then unloading a driver
should not change this. It only makes sense to disable hwmon on the few
systems where we had to enable it ourselves when loading the driver,
but your code doesn't check for this.

> +
>  static int __devinit w83627hf_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> -	struct w83627hf_sio_data *sio_data = dev->platform_data;
> +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
>  	struct w83627hf_data *data;
> -	struct resource *res;
>  	int err, i;
>  
> -	static const char *names[] = {
> -		"w83627hf",
> -		"w83627thf",
> -		"w83697hf",
> -		"w83637hf",
> -		"w83687thf",
> +	struct resource res = {
> +		.start  = /* address + */ WINB_REGION_OFFSET,
> +		.end    = /* address + */ WINB_REGION_OFFSET +
> +						WINB_REGION_SIZE - 1,
> +		.name   = DRVNAME "_hwmon",
> +		.flags  = IORESOURCE_IO,
>  	};
>  
> -	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
> -	if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
> +	err = w83627hf_enable_hwmon(sio_data);
> +	if (err < 0)
> +		return err;
> +
> +	/* Before doing our job we should fixup ioport range */
> +	res.start += err;
> +	res.end += err;

Again, I don't get the point of this relative adjustment. Just
omit .start and .end in the original resource declaration, and set them
when you have all the required information.

But more importantly, I don't get why you are creating a new resource
here, instead of getting it from the platform device? This is how
things are supposed to work.

Ah yes... You need to do this or you can't implement the force_addr
module parameter. Hmpf. You know what? I think it's about time to get
rid of this parameter. It just doesn't fit in the MFD design, and I'm
not even sure why needs this. If some board needs to force the address,
it should get fixed in the BIOS, or it can be done from user-space
(using isaset) or in a platform-specific quirk. Or if we want to have a
module parameter, that would be a generic one in the MFD driver (so
that you can force the address of any LD, nor just the hwmon one.

So I'd say, just drop the force_addr module parameter for now.
Preferably in a separate patch. Or I can even do it myself if you want.
That way you can really stick to the MFD design and this will be a much
better base for the future.

BTW I am sorry that this is such a long process to get your patch
right. But this is the first Super-I/O driver we convert to the MFD
design, so it was somewhat expected it would take some tries before we
got everything right.

> +
> +	err = acpi_check_resource_conflict(&res);
> +	if (err)
> +		goto ERROR0;

I don't understand why this happens only now, rather than in
mfd_w83627hf? If there is a resource conflict then there is no point in
instantiating the (hwmon) w83627hf platform device at all.

> +
> +	if (!request_region(res.start, WINB_REGION_SIZE, DRVNAME "_hwmon")) {
>  		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
> -			(unsigned long)res->start,
> -			(unsigned long)(res->start + WINB_REGION_SIZE - 1));
> +			(unsigned long) res.start,
> +			(unsigned long) (res.start + WINB_REGION_SIZE - 1));
>  		err = -EBUSY;
>  		goto ERROR0;
>  	}
> @@ -1307,9 +1211,9 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
>  		err = -ENOMEM;
>  		goto ERROR1;
>  	}
> -	data->addr = res->start;
> +	data->addr = res.start;
>  	data->type = sio_data->type;
> -	data->name = names[sio_data->type];
> +	data->name = sio_data->name;
>  	mutex_init(&data->lock);
>  	mutex_init(&data->update_lock);
>  	platform_set_drvdata(pdev, data);
> @@ -1442,15 +1346,20 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
>  	platform_set_drvdata(pdev, NULL);
>  	kfree(data);
>        ERROR1:
> -	release_region(res->start, WINB_REGION_SIZE);
> +	release_region(res.start, WINB_REGION_SIZE);
>        ERROR0:
> +	w83627hf_disable_hwmon(sio_data);
>  	return err;
>  }
>  
>  static int __devexit w83627hf_remove(struct platform_device *pdev)
>  {
> +	struct device *dev = &pdev->dev;
> +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
>  	struct w83627hf_data *data = platform_get_drvdata(pdev);
> -	struct resource *res;
> +	unsigned int addr = data->addr;
> +
> +	w83627hf_disable_hwmon(sio_data);
>  
>  	hwmon_device_unregister(data->hwmon_dev);
>  
> @@ -1459,8 +1368,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
>  	platform_set_drvdata(pdev, NULL);
>  	kfree(data);
>  
> -	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
> -	release_region(res->start, WINB_REGION_SIZE);
> +	release_region(addr, WINB_REGION_SIZE);
>  
>  	return 0;
>  }
> @@ -1511,20 +1419,22 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
>  
>  static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
>  {
> +	struct device *dev = &pdev->dev;
> +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
>  	int res = 0xff, sel;
>  
> -	superio_enter();
> -	superio_select(W83627HF_LD_GPIO5);
> +	superio_enter(sio_data);
> +	superio_select(sio_data, W83627HF_LD_GPIO5);
>  
>  	/* Make sure these GPIO pins are enabled */
> -	if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
> +	if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) {
>  		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
>  		goto exit;
>  	}
>  
>  	/* Make sure the pins are configured for input
>  	   There must be at least five (VRM 9), and possibly 6 (VRM 10) */
> -	sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
> +	sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f;
>  	if ((sel & 0x1f) != 0x1f) {
>  		dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
>  			"function\n");
> @@ -1532,37 +1442,39 @@ static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
>  	}
>  
>  	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
> -	res = superio_inb(W83627THF_GPIO5_DR) & sel;
> +	res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel;
>  
>  exit:
> -	superio_exit();
> +	superio_exit(sio_data);
>  	return res;
>  }
>  
>  static int __devinit w83687thf_read_vid(struct platform_device *pdev)
>  {
> +	struct device *dev = &pdev->dev;
> +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
>  	int res = 0xff;
>  
> -	superio_enter();
> -	superio_select(W83627HF_LD_HWM);
> +	superio_enter(sio_data);
> +	superio_select(sio_data, W83627HF_LD_HWM);
>  
>  	/* Make sure these GPIO pins are enabled */
> -	if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
> +	if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) {
>  		dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
>  		goto exit;
>  	}
>  
>  	/* Make sure the pins are configured for input */
> -	if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
> +	if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) {
>  		dev_dbg(&pdev->dev, "VID configured as output, "
>  			"no VID function\n");
>  		goto exit;
>  	}
>  
> -	res = superio_inb(W83687THF_VID_DATA) & 0x3f;
> +	res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f;
>  
>  exit:
> -	superio_exit();
> +	superio_exit(sio_data);
>  	return res;
>  }

BTW, all these changes would make a very nice preliminary patch, to
make the main patch smaller and more readable.

>  
> @@ -1783,94 +1695,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
>  	return data;
>  }
>  
> -static int __init w83627hf_device_add(unsigned short address,
> -				      const struct w83627hf_sio_data *sio_data)
> -{
> -	struct resource res = {
> -		.start	= address + WINB_REGION_OFFSET,
> -		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
> -		.name	= DRVNAME,
> -		.flags	= IORESOURCE_IO,
> -	};
> -	int err;
> -
> -	err = acpi_check_resource_conflict(&res);
> -	if (err)
> -		goto exit;
> -
> -	pdev = platform_device_alloc(DRVNAME, address);
> -	if (!pdev) {
> -		err = -ENOMEM;
> -		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
> -		goto exit;
> -	}
> -
> -	err = platform_device_add_resources(pdev, &res, 1);
> -	if (err) {
> -		printk(KERN_ERR DRVNAME ": Device resource addition failed "
> -		       "(%d)\n", err);
> -		goto exit_device_put;
> -	}
> -
> -	err = platform_device_add_data(pdev, sio_data,
> -				       sizeof(struct w83627hf_sio_data));
> -	if (err) {
> -		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
> -		goto exit_device_put;
> -	}
> -
> -	err = platform_device_add(pdev);
> -	if (err) {
> -		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
> -		       err);
> -		goto exit_device_put;
> -	}
> -
> -	return 0;
> -
> -exit_device_put:
> -	platform_device_put(pdev);
> -exit:
> -	return err;
> -}
> -
>  static int __init sensors_w83627hf_init(void)
>  {
> -	int err;
> -	unsigned short address;
> -	struct w83627hf_sio_data sio_data;
> -
> -	if (w83627hf_find(0x2e, &address, &sio_data)
> -	 && w83627hf_find(0x4e, &address, &sio_data))
> -		return -ENODEV;
> -
> -	err = platform_driver_register(&w83627hf_driver);
> -	if (err)
> -		goto exit;
> -
> -	/* Sets global pdev as a side effect */
> -	err = w83627hf_device_add(address, &sio_data);
> -	if (err)
> -		goto exit_driver;
> -
> -	return 0;
> -
> -exit_driver:
> -	platform_driver_unregister(&w83627hf_driver);
> -exit:
> -	return err;
> +	return platform_driver_register(&w83627hf_driver);
>  }
>  
>  static void __exit sensors_w83627hf_exit(void)
>  {
> -	platform_device_unregister(pdev);
>  	platform_driver_unregister(&w83627hf_driver);
>  }
>  
>  MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
>  	      "Philip Edelbrock <phil@netroedge.com>, "
>  	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
> -MODULE_DESCRIPTION("W83627HF driver");
> +MODULE_DESCRIPTION("W83627HF hwmon driver");
>  MODULE_LICENSE("GPL");
>  
>  module_init(sensors_w83627hf_init);
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 491ac0f..b20d6e5 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -263,6 +263,21 @@ config EZX_PCAP
>  	  This enables the PCAP ASIC present on EZX Phones. This is
>  	  needed for MMC, TouchScreen, Sound, USB, etc..
>  
> +config MFD_W83627HF
> +	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
> +	depends on MFD_CORE
> +	help
> +	  If you say yes here you add support for the Winbond W836X7 series
> +	  of super-IO chips: the W83627HF, W83627THF, W83637HF, W83687THF and
> +	  W83697HF to your platform.
> +
> +	  This is a multi functional device and this support defines a new
> +	  platform device only. See other configuration submenus in order to
> +	  enable the drivers of Winbond chip's functionalities.
> +
> +	  This driver can also be built as a module.  If so, the module
> +	  will be called w83627hf-core.
> +
>  endmenu
>  
>  menu "Multimedia Capabilities Port drivers"
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 6f8a9a1..1401ac9 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -27,6 +27,7 @@ obj-$(CONFIG_TWL4030_CORE)	+= twl4030-core.o twl4030-irq.o
>  obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
>  
>  obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
> +obj-$(CONFIG_MFD_W83627HF)	+= w83627hf-core.o
>  
>  obj-$(CONFIG_MCP)		+= mcp-core.o
>  obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
> diff --git a/drivers/mfd/w83627hf-core.c b/drivers/mfd/w83627hf-core.c
> new file mode 100644
> index 0000000..0fc0b6b
> --- /dev/null
> +++ b/drivers/mfd/w83627hf-core.c
> @@ -0,0 +1,186 @@
> +/*
> + *  w83627hf.c - platform device support
> + *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
> + *
> + *  Based on drivers/hwmon/w83627hf.c
> + *
> + *  Original copyright note:
> + *    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
> + *    Philip Edelbrock <phil@netroedge.com>,
> + *    and Mark Studebaker <mdsxyz123@yahoo.com>
> + *    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
> + *    Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
> + *
> + *    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
> + *    the Free Software Foundation; either version 2 of the License, or
> + *    (at your option) any later version.
> + *
> + *    This program is distributed in the hope that it will be useful,
> + *    but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *    GNU General Public License for more details.
> + *
> + *    You should have received a copy of the GNU General Public License
> + *    along with this program; if not, write to the Free Software
> + *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/ioport.h>
> +#include <linux/acpi.h>
> +#include <linux/io.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/w83627hf.h>
> +
> +static unsigned short force_id;
> +module_param(force_id, ushort, 0);
> +MODULE_PARM_DESC(force_id, "Override the detected device ID");
> +
> +/*
> + * Devices definitions
> + */
> +
> +static struct platform_device *pdev;
> +
> +static char *names[] = {

Couldn't these be made const char *?

> +	"w83627hf",
> +	"w83627thf",
> +	"w83697hf",
> +	"w83637hf",
> +	"w83687thf",
> +};

Would probably be worth a note that this array must stay in sync with
enum chips (and vice-versa.)

> +
> +static struct mfd_cell cells[] = {
> +	{
> +		.name	   = DRVNAME "_hwmon",
> +	},
> +};
> +
> +#define W627_DEVID		0x52
> +#define W627THF_DEVID		0x82
> +#define W697_DEVID		0x60
> +#define W637_DEVID		0x70
> +#define W687THF_DEVID		0x85
> +
> +static int __init w83627hf_find(int sioaddr, struct w83627hf_sio_data *sio_data)
> +{
> +	int err = -ENODEV;
> +	u16 val;
> +
> +	sio_data->sioaddr = sioaddr;
> +
> +	superio_enter(sio_data);
> +
> +	val = force_id ? force_id : superio_inb(sio_data, 0x20);
> +	switch (val) {
> +	case W627_DEVID:
> +		sio_data->type = w83627hf;
> +		break;
> +	case W627THF_DEVID:
> +		sio_data->type = w83627thf;
> +		break;
> +	case W697_DEVID:
> +		sio_data->type = w83697hf;
> +		break;
> +	case W637_DEVID:
> +		sio_data->type = w83637hf;
> +		break;
> +	case W687THF_DEVID:
> +		sio_data->type = w83687thf;
> +		break;
> +	case 0xff:	/* No device at all */
> +		goto exit;
> +	default:
> +		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
> +		goto exit;
> +	}
> +
> +	err = 0;
> +	sio_data->name = names[sio_data->type];
> +
> +	pr_info(DRVNAME ": Found %s chip at %#x\n", sio_data->name, sioaddr);
> +
> +exit:
> +	superio_exit(sio_data);
> +
> +	return err;
> +}
> +
> +static int __init w83627hf_device_add(const struct w83627hf_sio_data *sio_data)
> +{
> +	int err;
> +
> +	pdev = platform_device_alloc(DRVNAME, 0);
> +	if (!pdev) {
> +		err = -ENOMEM;
> +		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
> +		goto exit;
> +	}
> +
> +	err = platform_device_add_data(pdev, sio_data,
> +				       sizeof(struct w83627hf_sio_data));
> +	if (err) {
> +		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
> +		goto exit_device_put;
> +	}
> +
> +	err = platform_device_add(pdev);
> +	if (err) {
> +		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
> +		       err);
> +		goto exit_device_put;
> +	}
> +
> +	err = mfd_add_devices(&pdev->dev, pdev->id, cells, ARRAY_SIZE(cells),
> +			0, -1);
> +	if (err) {
> +		printk(KERN_ERR DRVNAME ": Cannot add sub devices (%d)\n",
> +			err);
> +		goto exit_device_unregister;
> +	}
> +
> +	return 0;
> +
> +exit_device_unregister:
> +	platform_device_unregister(pdev);
> +exit_device_put:
> +	platform_device_put(pdev);
> +exit:
> +	return err;
> +}
> +
> +static int __init w83627hf_init(void)
> +{
> +	struct w83627hf_sio_data sio_data;
> +	int ret;
> +
> +	mutex_init(&sio_data.lock);
> +
> +	ret = w83627hf_find(0x2e, &sio_data);
> +	if (ret) {
> +		ret = w83627hf_find(0x4e, &sio_data);
> +		if (ret)
> +			return -ENODEV;
> +	}
> +
> +	/* Sets global pdev as a side effect */
> +	return w83627hf_device_add(&sio_data);
> +}
> +
> +static void __exit w83627hf_exit(void)
> +{
> +	mfd_remove_devices(&pdev->dev);
> +	platform_device_unregister(pdev);
> +}
> +
> +MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
> +MODULE_DESCRIPTION("W83627HF platform devices definitions");
> +MODULE_LICENSE("GPL");
> +
> +module_init(w83627hf_init);
> +module_exit(w83627hf_exit);
> diff --git a/include/linux/mfd/w83627hf.h b/include/linux/mfd/w83627hf.h
> new file mode 100644
> index 0000000..5f4200b
> --- /dev/null
> +++ b/include/linux/mfd/w83627hf.h
> @@ -0,0 +1,118 @@
> +/*
> + *  w83627hf.h - platform device support, header file
> + *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
> + *
> + *  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
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, write to the Free Software
> + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <linux/mutex.h>
> +#include <linux/io.h>
> +
> +#define DRVNAME "w83627hf"
> +
> +enum chips {
> +	w83627hf,
> +	w83627thf,
> +	w83697hf,
> +	w83637hf,
> +	w83687thf
> +};
> +
> +struct w83627hf_sio_data {
> +	int sioaddr;
> +	enum chips type;
> +	char *name;
> +
> +	struct mutex lock;
> +};
> +
> +/* logical device numbers for superio_select (below) */
> +#define W83627HF_LD_FDC		0x00
> +#define W83627HF_LD_PRT		0x01
> +#define W83627HF_LD_UART1	0x02
> +#define W83627HF_LD_UART2	0x03
> +#define W83627HF_LD_KBC		0x05
> +#define W83627HF_LD_CIR		0x06 /* w83627hf only */
> +#define W83627HF_LD_GAME	0x07
> +#define W83627HF_LD_MIDI	0x07
> +#define W83627HF_LD_GPIO1	0x07
> +#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
> +#define W83627HF_LD_GPIO2	0x08
> +#define W83627HF_LD_GPIO3	0x09
> +#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
> +#define W83627HF_LD_ACPI	0x0a
> +#define W83627HF_LD_HWM		0x0b
> +
> +#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
> +#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
> +#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
> +
> +#define W83687THF_VID_EN	0x29 /* w83687thf only */
> +#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
> +#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
> +
> +/*
> + * Common configuration registers access functions.
> + *
> + * These registers are special and they must me accessed by using a well
> + * specified protocol. Client drivers __must__ do as follow in order to
> + * get access correctly to these registers:
> + *
> + *	superio_enter()
> + *
> + *	superio_select()/superio_outb()/superio_inb()
> + *
> + *	superio_exit();
> + *
> + */
> +
> +static inline void superio_enter(struct w83627hf_sio_data *sio)
> +{
> +	mutex_lock(&sio->lock);
> +
> +	outb(0x87, sio->sioaddr);
> +	outb(0x87, sio->sioaddr);
> +}
> +
> +static inline void superio_select(struct w83627hf_sio_data *sio, int ld)
> +{
> +	WARN_ON(!mutex_is_locked(&sio->lock));
> +
> +	outb(0x07, sio->sioaddr);
> +	outb(ld, sio->sioaddr + 1);
> +}
> +
> +static inline void superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
> +{
> +	WARN_ON(!mutex_is_locked(&sio->lock));
> +
> +	outb(reg, sio->sioaddr);
> +	outb(val, sio->sioaddr + 1);
> +}
> +
> +static inline int superio_inb(struct w83627hf_sio_data *sio, int reg)
> +{
> +	WARN_ON(!mutex_is_locked(&sio->lock));
> +
> +	outb(reg, sio->sioaddr);
> +	return inb(sio->sioaddr + 1);
> +}
> +
> +static inline void superio_exit(struct w83627hf_sio_data *sio)
> +{
> +	outb(0xAA, sio->sioaddr);
> +
> +	mutex_unlock(&sio->lock);
> +}

The rest starts looking good.

-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (22 preceding siblings ...)
  2009-10-01 13:23 ` Jean Delvare
@ 2009-10-01 13:53 ` Samuel Ortiz
  2009-11-02 13:23 ` Jean Delvare
  2009-11-03  8:17 ` Rodolfo Giometti
  25 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2009-10-01 13:53 UTC (permalink / raw)
  To: lm-sensors

Hi Jean, Rodolfo,

On Thu, Oct 01, 2009 at 03:23:51PM +0200, Jean Delvare wrote:
> Hi Rodolfo,
> 
> On Thu, 24 Sep 2009 14:01:11 +0200, Rodolfo Giometti wrote:
> > The file has been splitted up into two parts:
> > 
> > * drivers/mfd/w83627hf-core.c      - detects the chip and define proper
> >                                      platform devices into mfd support
> > 
> > * drivers/hwmon/w83627hf.c         - implements the driver for hwmon
> >                                      functionality only
> > 
> > Signed-off-by: Rodolfo Giometti <giometti@linux.it>
> > ---
> >  drivers/hwmon/Kconfig        |    1 +
> >  drivers/hwmon/w83627hf.c     |  376 ++++++++++++------------------------------
> >  drivers/mfd/Kconfig          |   15 ++
> >  drivers/mfd/Makefile         |    1 +
> >  drivers/mfd/w83627hf-core.c  |  186 +++++++++++++++++++++
> >  include/linux/mfd/w83627hf.h |  118 +++++++++++++
> >  6 files changed, 428 insertions(+), 269 deletions(-)
> >  create mode 100644 drivers/mfd/w83627hf-core.c
> >  create mode 100644 include/linux/mfd/w83627hf.h
> 
> Sorry for the late review...
> 
> > 
> > diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> > index 2d50166..f6cf2af 100644
> > --- a/drivers/hwmon/Kconfig
> > +++ b/drivers/hwmon/Kconfig
> > @@ -894,6 +894,7 @@ config SENSORS_W83L786NG
> >  
> >  config SENSORS_W83627HF
> >  	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
> > +	select MFD_W83627HF
> >  	select HWMON_VID
> >  	help
> >  	  If you say yes here you get support for the Winbond W836X7 series
> > diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
> > index 389150b..748f77a 100644
> > --- a/drivers/hwmon/w83627hf.c
> > +++ b/drivers/hwmon/w83627hf.c
> > @@ -52,13 +52,9 @@
> >  #include <linux/ioport.h>
> >  #include <linux/acpi.h>
> >  #include <asm/io.h>
> > +#include <linux/mfd/w83627hf.h>
> >  #include "lm75.h"
> >  
> > -static struct platform_device *pdev;
> > -
> > -#define DRVNAME "w83627hf"
> > -enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
> > -
> >  static u16 force_addr;
> >  module_param(force_addr, ushort, 0);
> >  MODULE_PARM_DESC(force_addr,
> > @@ -72,87 +68,11 @@ static int init = 1;
> >  module_param(init, bool, 0);
> >  MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
> >  
> > -static unsigned short force_id;
> > -module_param(force_id, ushort, 0);
> > -MODULE_PARM_DESC(force_id, "Override the detected device ID");
> > -
> > -/* modified from kernel/include/traps.c */
> > -static int REG;		/* The register to read/write */
> > -#define	DEV	0x07	/* Register: Logical device select */
> > -static int VAL;		/* The value to read/write */
> > -
> > -/* logical device numbers for superio_select (below) */
> > -#define W83627HF_LD_FDC		0x00
> > -#define W83627HF_LD_PRT		0x01
> > -#define W83627HF_LD_UART1	0x02
> > -#define W83627HF_LD_UART2	0x03
> > -#define W83627HF_LD_KBC		0x05
> > -#define W83627HF_LD_CIR		0x06 /* w83627hf only */
> > -#define W83627HF_LD_GAME	0x07
> > -#define W83627HF_LD_MIDI	0x07
> > -#define W83627HF_LD_GPIO1	0x07
> > -#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
> > -#define W83627HF_LD_GPIO2	0x08
> > -#define W83627HF_LD_GPIO3	0x09
> > -#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
> > -#define W83627HF_LD_ACPI	0x0a
> > -#define W83627HF_LD_HWM		0x0b
> > -
> > -#define	DEVID	0x20	/* Register: Device ID */
> > -
> > -#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
> > -#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
> > -#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
> > -
> > -#define W83687THF_VID_EN	0x29 /* w83687thf only */
> > -#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
> > -#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
> > -
> > -static inline void
> > -superio_outb(int reg, int val)
> > -{
> > -	outb(reg, REG);
> > -	outb(val, VAL);
> > -}
> > -
> > -static inline int
> > -superio_inb(int reg)
> > -{
> > -	outb(reg, REG);
> > -	return inb(VAL);
> > -}
> > -
> > -static inline void
> > -superio_select(int ld)
> > -{
> > -	outb(DEV, REG);
> > -	outb(ld, VAL);
> > -}
> > -
> > -static inline void
> > -superio_enter(void)
> > -{
> > -	outb(0x87, REG);
> > -	outb(0x87, REG);
> > -}
> > -
> > -static inline void
> > -superio_exit(void)
> > -{
> > -	outb(0xAA, REG);
> > -}
> > -
> > -#define W627_DEVID 0x52
> > -#define W627THF_DEVID 0x82
> > -#define W697_DEVID 0x60
> > -#define W637_DEVID 0x70
> > -#define W687THF_DEVID 0x85
> > -#define WINB_ACT_REG 0x30
> > -#define WINB_BASE_REG 0x60
> >  /* Constants specified below */
> >  
> > -/* Alignment of the base address */
> > -#define WINB_ALIGNMENT		~7
> 
> Not sure why you removed that one while your code still uses it.
> 
> > +#define HWMON_CR30		0x30
> > +#define   ACTIVATION_CTRL	  (1 << 0)
> > +#define HWMON_CR60		0x60
> 
> Why are you changing the name of these registers from meaningful ones
> to meaningless ones?
> 
> >  
> >  /* Offset & size of I/O region we are interested in */
> >  #define WINB_REGION_OFFSET	5
> > @@ -380,10 +300,6 @@ struct w83627hf_data {
> >  	u8 vrm_ovt;		/* Register value, 627THF/637HF/687THF only */
> >  };
> >  
> > -struct w83627hf_sio_data {
> > -	enum chips type;
> > -};
> > -
> >  
> >  static int w83627hf_probe(struct platform_device *pdev);
> >  static int __devexit w83627hf_remove(struct platform_device *pdev);
> > @@ -397,7 +313,7 @@ static void w83627hf_init_device(struct platform_device *pdev);
> >  static struct platform_driver w83627hf_driver = {
> >  	.driver = {
> >  		.owner	= THIS_MODULE,
> > -		.name	= DRVNAME,
> > +		.name	= DRVNAME "_hwmon",
> >  	},
> >  	.probe		= w83627hf_probe,
> >  	.remove		= __devexit_p(w83627hf_remove),
> > @@ -1126,80 +1042,6 @@ show_name(struct device *dev, struct device_attribute *devattr, char *buf)
> >  }
> >  static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
> >  
> > -static int __init w83627hf_find(int sioaddr, unsigned short *addr,
> > -				struct w83627hf_sio_data *sio_data)
> > -{
> > -	int err = -ENODEV;
> > -	u16 val;
> > -
> > -	static const __initdata char *names[] = {
> > -		"W83627HF",
> > -		"W83627THF",
> > -		"W83697HF",
> > -		"W83637HF",
> > -		"W83687THF",
> > -	};
> > -
> > -	REG = sioaddr;
> > -	VAL = sioaddr + 1;
> > -
> > -	superio_enter();
> > -	val = force_id ? force_id : superio_inb(DEVID);
> > -	switch (val) {
> > -	case W627_DEVID:
> > -		sio_data->type = w83627hf;
> > -		break;
> > -	case W627THF_DEVID:
> > -		sio_data->type = w83627thf;
> > -		break;
> > -	case W697_DEVID:
> > -		sio_data->type = w83697hf;
> > -		break;
> > -	case W637_DEVID:
> > -		sio_data->type = w83637hf;
> > -		break;
> > -	case W687THF_DEVID:
> > -		sio_data->type = w83687thf;
> > -		break;
> > -	case 0xff:	/* No device at all */
> > -		goto exit;
> > -	default:
> > -		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
> > -		goto exit;
> > -	}
> > -
> > -	superio_select(W83627HF_LD_HWM);
> > -	force_addr &= WINB_ALIGNMENT;
> > -	if (force_addr) {
> > -		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
> > -		       force_addr);
> > -		superio_outb(WINB_BASE_REG, force_addr >> 8);
> > -		superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
> > -	}
> > -	val = (superio_inb(WINB_BASE_REG) << 8) |
> > -	       superio_inb(WINB_BASE_REG + 1);
> > -	*addr = val & WINB_ALIGNMENT;
> > -	if (*addr = 0) {
> > -		printk(KERN_WARNING DRVNAME ": Base address not set, "
> > -		       "skipping\n");
> > -		goto exit;
> > -	}
> > -
> > -	val = superio_inb(WINB_ACT_REG);
> > -	if (!(val & 0x01)) {
> > -		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
> > -		superio_outb(WINB_ACT_REG, val | 0x01);
> > -	}
> > -
> > -	err = 0;
> > -	pr_info(DRVNAME ": Found %s chip at %#x\n",
> > -		names[sio_data->type], *addr);
> > -
> > - exit:
> > -	superio_exit();
> > -	return err;
> > -}
> > -
> >  #define VIN_UNIT_ATTRS(_X_)	\
> >  	&sensor_dev_attr_in##_X_##_input.dev_attr.attr,		\
> >  	&sensor_dev_attr_in##_X_##_min.dev_attr.attr,		\
> > @@ -1278,27 +1120,89 @@ static const struct attribute_group w83627hf_group_opt = {
> >  	.attrs = w83627hf_attributes_opt,
> >  };
> >  
> > +static int w83627hf_enable_hwmon(struct w83627hf_sio_data *sio_data)
> > +{
> > +	u16 val;
> > +	int ret;
> > +
> > +	superio_enter(sio_data);
> > +
> > +	superio_select(sio_data, W83627HF_LD_HWM);
> > +
> > +	force_addr &= (~7);
> > +	if (force_addr) {
> > +		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
> > +			force_addr);
> > +		superio_outb(sio_data, HWMON_CR60, force_addr >> 8);
> > +		superio_outb(sio_data, HWMON_CR60 + 1, force_addr & 0xff);
> > +	}
> > +
> > +	val = (superio_inb(sio_data, HWMON_CR60) << 8) |
> > +	       superio_inb(sio_data, HWMON_CR60 + 1);
> > +	ret = val & (~7);
> > +	pr_info(DRVNAME ": hwmon chip %s at %#x\n", sio_data->name, ret);
> > +
> > +	if (ret = 0) {
> > +		printk(KERN_WARNING DRVNAME ": Base address not set, "
> > +		       "skipping\n");
> > +		ret = -EINVAL;
> > +		goto exit;
> > +	}
> > +
> > +	val = superio_inb(sio_data, HWMON_CR30);
> > +	superio_outb(sio_data, HWMON_CR30, val | ACTIVATION_CTRL);
> > +
> > +exit:
> > +	superio_exit(sio_data);
> > +
> > +	return ret;
> > +}
> 
> If this function was moved where w83627hf_find() was before, your patch
> would be somewhat smaller and easier to review.
> 
> > +
> > +static void w83627hf_disable_hwmon(struct w83627hf_sio_data *sio_data)
> > +{
> > +	u16 val;
> > +
> > +	superio_enter(sio_data);
> > +
> > +	superio_select(sio_data, W83627HF_LD_HWM);
> > +
> > +	val = superio_inb(sio_data, HWMON_CR30);
> > +	superio_outb(sio_data, HWMON_CR30, val & ~ACTIVATION_CTRL);
> > +
> > +	superio_exit(sio_data);
> > +}
> 
> No, we don't want to do this. Most systems boot with hardware
> monitoring enabled, and the fact of loading then unloading a driver
> should not change this. It only makes sense to disable hwmon on the few
> systems where we had to enable it ourselves when loading the driver,
> but your code doesn't check for this.
> 
> > +
> >  static int __devinit w83627hf_probe(struct platform_device *pdev)
> >  {
> >  	struct device *dev = &pdev->dev;
> > -	struct w83627hf_sio_data *sio_data = dev->platform_data;
> > +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
> >  	struct w83627hf_data *data;
> > -	struct resource *res;
> >  	int err, i;
> >  
> > -	static const char *names[] = {
> > -		"w83627hf",
> > -		"w83627thf",
> > -		"w83697hf",
> > -		"w83637hf",
> > -		"w83687thf",
> > +	struct resource res = {
> > +		.start  = /* address + */ WINB_REGION_OFFSET,
> > +		.end    = /* address + */ WINB_REGION_OFFSET +
> > +						WINB_REGION_SIZE - 1,
> > +		.name   = DRVNAME "_hwmon",
> > +		.flags  = IORESOURCE_IO,
> >  	};
> >  
> > -	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
> > -	if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
> > +	err = w83627hf_enable_hwmon(sio_data);
> > +	if (err < 0)
> > +		return err;
> > +
> > +	/* Before doing our job we should fixup ioport range */
> > +	res.start += err;
> > +	res.end += err;
> 
> Again, I don't get the point of this relative adjustment. Just
> omit .start and .end in the original resource declaration, and set them
> when you have all the required information.
> 
> But more importantly, I don't get why you are creating a new resource
> here, instead of getting it from the platform device? This is how
> things are supposed to work.
> 
> Ah yes... You need to do this or you can't implement the force_addr
> module parameter. Hmpf. You know what? I think it's about time to get
> rid of this parameter. It just doesn't fit in the MFD design, and I'm
> not even sure why needs this. If some board needs to force the address,
> it should get fixed in the BIOS, or it can be done from user-space
> (using isaset) or in a platform-specific quirk. Or if we want to have a
> module parameter, that would be a generic one in the MFD driver (so
> that you can force the address of any LD, nor just the hwmon one.
> 
> So I'd say, just drop the force_addr module parameter for now.
> Preferably in a separate patch. Or I can even do it myself if you want.
> That way you can really stick to the MFD design and this will be a much
> better base for the future.
> 
> BTW I am sorry that this is such a long process to get your patch
> right. But this is the first Super-I/O driver we convert to the MFD
> design, so it was somewhat expected it would take some tries before we
> got everything right.
> 
> > +
> > +	err = acpi_check_resource_conflict(&res);
> > +	if (err)
> > +		goto ERROR0;
> 
> I don't understand why this happens only now, rather than in
> mfd_w83627hf? If there is a resource conflict then there is no point in
> instantiating the (hwmon) w83627hf platform device at all.
> 
> > +
> > +	if (!request_region(res.start, WINB_REGION_SIZE, DRVNAME "_hwmon")) {
> >  		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
> > -			(unsigned long)res->start,
> > -			(unsigned long)(res->start + WINB_REGION_SIZE - 1));
> > +			(unsigned long) res.start,
> > +			(unsigned long) (res.start + WINB_REGION_SIZE - 1));
> >  		err = -EBUSY;
> >  		goto ERROR0;
> >  	}
> > @@ -1307,9 +1211,9 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
> >  		err = -ENOMEM;
> >  		goto ERROR1;
> >  	}
> > -	data->addr = res->start;
> > +	data->addr = res.start;
> >  	data->type = sio_data->type;
> > -	data->name = names[sio_data->type];
> > +	data->name = sio_data->name;
> >  	mutex_init(&data->lock);
> >  	mutex_init(&data->update_lock);
> >  	platform_set_drvdata(pdev, data);
> > @@ -1442,15 +1346,20 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
> >  	platform_set_drvdata(pdev, NULL);
> >  	kfree(data);
> >        ERROR1:
> > -	release_region(res->start, WINB_REGION_SIZE);
> > +	release_region(res.start, WINB_REGION_SIZE);
> >        ERROR0:
> > +	w83627hf_disable_hwmon(sio_data);
> >  	return err;
> >  }
> >  
> >  static int __devexit w83627hf_remove(struct platform_device *pdev)
> >  {
> > +	struct device *dev = &pdev->dev;
> > +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
> >  	struct w83627hf_data *data = platform_get_drvdata(pdev);
> > -	struct resource *res;
> > +	unsigned int addr = data->addr;
> > +
> > +	w83627hf_disable_hwmon(sio_data);
> >  
> >  	hwmon_device_unregister(data->hwmon_dev);
> >  
> > @@ -1459,8 +1368,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
> >  	platform_set_drvdata(pdev, NULL);
> >  	kfree(data);
> >  
> > -	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
> > -	release_region(res->start, WINB_REGION_SIZE);
> > +	release_region(addr, WINB_REGION_SIZE);
> >  
> >  	return 0;
> >  }
> > @@ -1511,20 +1419,22 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
> >  
> >  static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
> >  {
> > +	struct device *dev = &pdev->dev;
> > +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
> >  	int res = 0xff, sel;
> >  
> > -	superio_enter();
> > -	superio_select(W83627HF_LD_GPIO5);
> > +	superio_enter(sio_data);
> > +	superio_select(sio_data, W83627HF_LD_GPIO5);
> >  
> >  	/* Make sure these GPIO pins are enabled */
> > -	if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
> > +	if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) {
> >  		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
> >  		goto exit;
> >  	}
> >  
> >  	/* Make sure the pins are configured for input
> >  	   There must be at least five (VRM 9), and possibly 6 (VRM 10) */
> > -	sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
> > +	sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f;
> >  	if ((sel & 0x1f) != 0x1f) {
> >  		dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
> >  			"function\n");
> > @@ -1532,37 +1442,39 @@ static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
> >  	}
> >  
> >  	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
> > -	res = superio_inb(W83627THF_GPIO5_DR) & sel;
> > +	res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel;
> >  
> >  exit:
> > -	superio_exit();
> > +	superio_exit(sio_data);
> >  	return res;
> >  }
> >  
> >  static int __devinit w83687thf_read_vid(struct platform_device *pdev)
> >  {
> > +	struct device *dev = &pdev->dev;
> > +	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
> >  	int res = 0xff;
> >  
> > -	superio_enter();
> > -	superio_select(W83627HF_LD_HWM);
> > +	superio_enter(sio_data);
> > +	superio_select(sio_data, W83627HF_LD_HWM);
> >  
> >  	/* Make sure these GPIO pins are enabled */
> > -	if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
> > +	if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) {
> >  		dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
> >  		goto exit;
> >  	}
> >  
> >  	/* Make sure the pins are configured for input */
> > -	if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
> > +	if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) {
> >  		dev_dbg(&pdev->dev, "VID configured as output, "
> >  			"no VID function\n");
> >  		goto exit;
> >  	}
> >  
> > -	res = superio_inb(W83687THF_VID_DATA) & 0x3f;
> > +	res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f;
> >  
> >  exit:
> > -	superio_exit();
> > +	superio_exit(sio_data);
> >  	return res;
> >  }
> 
> BTW, all these changes would make a very nice preliminary patch, to
> make the main patch smaller and more readable.
> 
> >  
> > @@ -1783,94 +1695,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
> >  	return data;
> >  }
> >  
> > -static int __init w83627hf_device_add(unsigned short address,
> > -				      const struct w83627hf_sio_data *sio_data)
> > -{
> > -	struct resource res = {
> > -		.start	= address + WINB_REGION_OFFSET,
> > -		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
> > -		.name	= DRVNAME,
> > -		.flags	= IORESOURCE_IO,
> > -	};
> > -	int err;
> > -
> > -	err = acpi_check_resource_conflict(&res);
> > -	if (err)
> > -		goto exit;
> > -
> > -	pdev = platform_device_alloc(DRVNAME, address);
> > -	if (!pdev) {
> > -		err = -ENOMEM;
> > -		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
> > -		goto exit;
> > -	}
> > -
> > -	err = platform_device_add_resources(pdev, &res, 1);
> > -	if (err) {
> > -		printk(KERN_ERR DRVNAME ": Device resource addition failed "
> > -		       "(%d)\n", err);
> > -		goto exit_device_put;
> > -	}
> > -
> > -	err = platform_device_add_data(pdev, sio_data,
> > -				       sizeof(struct w83627hf_sio_data));
> > -	if (err) {
> > -		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
> > -		goto exit_device_put;
> > -	}
> > -
> > -	err = platform_device_add(pdev);
> > -	if (err) {
> > -		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
> > -		       err);
> > -		goto exit_device_put;
> > -	}
> > -
> > -	return 0;
> > -
> > -exit_device_put:
> > -	platform_device_put(pdev);
> > -exit:
> > -	return err;
> > -}
> > -
> >  static int __init sensors_w83627hf_init(void)
> >  {
> > -	int err;
> > -	unsigned short address;
> > -	struct w83627hf_sio_data sio_data;
> > -
> > -	if (w83627hf_find(0x2e, &address, &sio_data)
> > -	 && w83627hf_find(0x4e, &address, &sio_data))
> > -		return -ENODEV;
> > -
> > -	err = platform_driver_register(&w83627hf_driver);
> > -	if (err)
> > -		goto exit;
> > -
> > -	/* Sets global pdev as a side effect */
> > -	err = w83627hf_device_add(address, &sio_data);
> > -	if (err)
> > -		goto exit_driver;
> > -
> > -	return 0;
> > -
> > -exit_driver:
> > -	platform_driver_unregister(&w83627hf_driver);
> > -exit:
> > -	return err;
> > +	return platform_driver_register(&w83627hf_driver);
> >  }
> >  
> >  static void __exit sensors_w83627hf_exit(void)
> >  {
> > -	platform_device_unregister(pdev);
> >  	platform_driver_unregister(&w83627hf_driver);
> >  }
> >  
> >  MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
> >  	      "Philip Edelbrock <phil@netroedge.com>, "
> >  	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
> > -MODULE_DESCRIPTION("W83627HF driver");
> > +MODULE_DESCRIPTION("W83627HF hwmon driver");
> >  MODULE_LICENSE("GPL");
> >  
> >  module_init(sensors_w83627hf_init);
> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index 491ac0f..b20d6e5 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -263,6 +263,21 @@ config EZX_PCAP
> >  	  This enables the PCAP ASIC present on EZX Phones. This is
> >  	  needed for MMC, TouchScreen, Sound, USB, etc..
> >  
> > +config MFD_W83627HF
> > +	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
> > +	depends on MFD_CORE
> > +	help
> > +	  If you say yes here you add support for the Winbond W836X7 series
> > +	  of super-IO chips: the W83627HF, W83627THF, W83637HF, W83687THF and
> > +	  W83697HF to your platform.
> > +
> > +	  This is a multi functional device and this support defines a new
> > +	  platform device only. See other configuration submenus in order to
> > +	  enable the drivers of Winbond chip's functionalities.
> > +
> > +	  This driver can also be built as a module.  If so, the module
> > +	  will be called w83627hf-core.
> > +
> >  endmenu
> >  
> >  menu "Multimedia Capabilities Port drivers"
> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > index 6f8a9a1..1401ac9 100644
> > --- a/drivers/mfd/Makefile
> > +++ b/drivers/mfd/Makefile
> > @@ -27,6 +27,7 @@ obj-$(CONFIG_TWL4030_CORE)	+= twl4030-core.o twl4030-irq.o
> >  obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
> >  
> >  obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
> > +obj-$(CONFIG_MFD_W83627HF)	+= w83627hf-core.o
> >  
> >  obj-$(CONFIG_MCP)		+= mcp-core.o
> >  obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
> > diff --git a/drivers/mfd/w83627hf-core.c b/drivers/mfd/w83627hf-core.c
> > new file mode 100644
> > index 0000000..0fc0b6b
> > --- /dev/null
> > +++ b/drivers/mfd/w83627hf-core.c
> > @@ -0,0 +1,186 @@
> > +/*
> > + *  w83627hf.c - platform device support
> > + *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
> > + *
> > + *  Based on drivers/hwmon/w83627hf.c
> > + *
> > + *  Original copyright note:
> > + *    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
> > + *    Philip Edelbrock <phil@netroedge.com>,
> > + *    and Mark Studebaker <mdsxyz123@yahoo.com>
> > + *    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
> > + *    Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
> > + *
> > + *    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
> > + *    the Free Software Foundation; either version 2 of the License, or
> > + *    (at your option) any later version.
> > + *
> > + *    This program is distributed in the hope that it will be useful,
> > + *    but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + *    GNU General Public License for more details.
> > + *
> > + *    You should have received a copy of the GNU General Public License
> > + *    along with this program; if not, write to the Free Software
> > + *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> > + */
> > +
> > +#include <linux/module.h>
> > +#include <linux/init.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/err.h>
> > +#include <linux/mutex.h>
> > +#include <linux/ioport.h>
> > +#include <linux/acpi.h>
> > +#include <linux/io.h>
> > +#include <linux/mfd/core.h>
> > +#include <linux/mfd/w83627hf.h>
> > +
> > +static unsigned short force_id;
> > +module_param(force_id, ushort, 0);
> > +MODULE_PARM_DESC(force_id, "Override the detected device ID");
> > +
> > +/*
> > + * Devices definitions
> > + */
> > +
> > +static struct platform_device *pdev;
> > +
> > +static char *names[] = {
> 
> Couldn't these be made const char *?
> 
> > +	"w83627hf",
> > +	"w83627thf",
> > +	"w83697hf",
> > +	"w83637hf",
> > +	"w83687thf",
> > +};
> 
> Would probably be worth a note that this array must stay in sync with
> enum chips (and vice-versa.)
> 
> > +
> > +static struct mfd_cell cells[] = {
> > +	{
> > +		.name	   = DRVNAME "_hwmon",
> > +	},
> > +};
> > +
> > +#define W627_DEVID		0x52
> > +#define W627THF_DEVID		0x82
> > +#define W697_DEVID		0x60
> > +#define W637_DEVID		0x70
> > +#define W687THF_DEVID		0x85
> > +
> > +static int __init w83627hf_find(int sioaddr, struct w83627hf_sio_data *sio_data)
> > +{
> > +	int err = -ENODEV;
> > +	u16 val;
> > +
> > +	sio_data->sioaddr = sioaddr;
> > +
> > +	superio_enter(sio_data);
> > +
> > +	val = force_id ? force_id : superio_inb(sio_data, 0x20);
> > +	switch (val) {
> > +	case W627_DEVID:
> > +		sio_data->type = w83627hf;
> > +		break;
> > +	case W627THF_DEVID:
> > +		sio_data->type = w83627thf;
> > +		break;
> > +	case W697_DEVID:
> > +		sio_data->type = w83697hf;
> > +		break;
> > +	case W637_DEVID:
> > +		sio_data->type = w83637hf;
> > +		break;
> > +	case W687THF_DEVID:
> > +		sio_data->type = w83687thf;
> > +		break;
> > +	case 0xff:	/* No device at all */
> > +		goto exit;
> > +	default:
> > +		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
> > +		goto exit;
> > +	}
> > +
> > +	err = 0;
> > +	sio_data->name = names[sio_data->type];
> > +
> > +	pr_info(DRVNAME ": Found %s chip at %#x\n", sio_data->name, sioaddr);
> > +
> > +exit:
> > +	superio_exit(sio_data);
> > +
> > +	return err;
> > +}
> > +
> > +static int __init w83627hf_device_add(const struct w83627hf_sio_data *sio_data)
> > +{
> > +	int err;
> > +
> > +	pdev = platform_device_alloc(DRVNAME, 0);
> > +	if (!pdev) {
> > +		err = -ENOMEM;
> > +		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
> > +		goto exit;
> > +	}
> > +
> > +	err = platform_device_add_data(pdev, sio_data,
> > +				       sizeof(struct w83627hf_sio_data));
> > +	if (err) {
> > +		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
> > +		goto exit_device_put;
> > +	}
> > +
> > +	err = platform_device_add(pdev);
> > +	if (err) {
> > +		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
> > +		       err);
> > +		goto exit_device_put;
> > +	}
> > +
> > +	err = mfd_add_devices(&pdev->dev, pdev->id, cells, ARRAY_SIZE(cells),
> > +			0, -1);
> > +	if (err) {
> > +		printk(KERN_ERR DRVNAME ": Cannot add sub devices (%d)\n",
> > +			err);
> > +		goto exit_device_unregister;
> > +	}
> > +
> > +	return 0;
> > +
> > +exit_device_unregister:
> > +	platform_device_unregister(pdev);
> > +exit_device_put:
> > +	platform_device_put(pdev);
> > +exit:
> > +	return err;
> > +}
> > +
> > +static int __init w83627hf_init(void)
> > +{
> > +	struct w83627hf_sio_data sio_data;
> > +	int ret;
> > +
> > +	mutex_init(&sio_data.lock);
> > +
> > +	ret = w83627hf_find(0x2e, &sio_data);
> > +	if (ret) {
> > +		ret = w83627hf_find(0x4e, &sio_data);
> > +		if (ret)
> > +			return -ENODEV;
> > +	}
> > +
> > +	/* Sets global pdev as a side effect */
> > +	return w83627hf_device_add(&sio_data);
> > +}
> > +
> > +static void __exit w83627hf_exit(void)
> > +{
> > +	mfd_remove_devices(&pdev->dev);
> > +	platform_device_unregister(pdev);
> > +}
> > +
> > +MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
> > +MODULE_DESCRIPTION("W83627HF platform devices definitions");
> > +MODULE_LICENSE("GPL");
> > +
> > +module_init(w83627hf_init);
> > +module_exit(w83627hf_exit);
> > diff --git a/include/linux/mfd/w83627hf.h b/include/linux/mfd/w83627hf.h
> > new file mode 100644
> > index 0000000..5f4200b
> > --- /dev/null
> > +++ b/include/linux/mfd/w83627hf.h
> > @@ -0,0 +1,118 @@
> > +/*
> > + *  w83627hf.h - platform device support, header file
> > + *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
> > + *
> > + *  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
> > + *  the Free Software Foundation; either version 2 of the License, or
> > + *  (at your option) any later version.
> > + *
> > + *  This program is distributed in the hope that it will be useful,
> > + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + *  GNU General Public License for more details.
> > + *
> > + *  You should have received a copy of the GNU General Public License
> > + *  along with this program; if not, write to the Free Software
> > + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> > + */
> > +
> > +#include <linux/mutex.h>
> > +#include <linux/io.h>
> > +
> > +#define DRVNAME "w83627hf"
> > +
> > +enum chips {
> > +	w83627hf,
> > +	w83627thf,
> > +	w83697hf,
> > +	w83637hf,
> > +	w83687thf
> > +};
> > +
> > +struct w83627hf_sio_data {
> > +	int sioaddr;
> > +	enum chips type;
> > +	char *name;
> > +
> > +	struct mutex lock;
> > +};
> > +
> > +/* logical device numbers for superio_select (below) */
> > +#define W83627HF_LD_FDC		0x00
> > +#define W83627HF_LD_PRT		0x01
> > +#define W83627HF_LD_UART1	0x02
> > +#define W83627HF_LD_UART2	0x03
> > +#define W83627HF_LD_KBC		0x05
> > +#define W83627HF_LD_CIR		0x06 /* w83627hf only */
> > +#define W83627HF_LD_GAME	0x07
> > +#define W83627HF_LD_MIDI	0x07
> > +#define W83627HF_LD_GPIO1	0x07
> > +#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
> > +#define W83627HF_LD_GPIO2	0x08
> > +#define W83627HF_LD_GPIO3	0x09
> > +#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
> > +#define W83627HF_LD_ACPI	0x0a
> > +#define W83627HF_LD_HWM		0x0b
> > +
> > +#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
> > +#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
> > +#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
> > +
> > +#define W83687THF_VID_EN	0x29 /* w83687thf only */
> > +#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
> > +#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
> > +
> > +/*
> > + * Common configuration registers access functions.
> > + *
> > + * These registers are special and they must me accessed by using a well
> > + * specified protocol. Client drivers __must__ do as follow in order to
> > + * get access correctly to these registers:
> > + *
> > + *	superio_enter()
> > + *
> > + *	superio_select()/superio_outb()/superio_inb()
> > + *
> > + *	superio_exit();
> > + *
> > + */
> > +
> > +static inline void superio_enter(struct w83627hf_sio_data *sio)
> > +{
> > +	mutex_lock(&sio->lock);
> > +
> > +	outb(0x87, sio->sioaddr);
> > +	outb(0x87, sio->sioaddr);
> > +}
> > +
> > +static inline void superio_select(struct w83627hf_sio_data *sio, int ld)
> > +{
> > +	WARN_ON(!mutex_is_locked(&sio->lock));
> > +
> > +	outb(0x07, sio->sioaddr);
> > +	outb(ld, sio->sioaddr + 1);
> > +}
> > +
> > +static inline void superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
> > +{
> > +	WARN_ON(!mutex_is_locked(&sio->lock));
> > +
> > +	outb(reg, sio->sioaddr);
> > +	outb(val, sio->sioaddr + 1);
> > +}
> > +
> > +static inline int superio_inb(struct w83627hf_sio_data *sio, int reg)
> > +{
> > +	WARN_ON(!mutex_is_locked(&sio->lock));
> > +
> > +	outb(reg, sio->sioaddr);
> > +	return inb(sio->sioaddr + 1);
> > +}
> > +
> > +static inline void superio_exit(struct w83627hf_sio_data *sio)
> > +{
You should add a WARN_ON(!mutex_is_locked(&sio->lock)); here as well.


> > +	outb(0xAA, sio->sioaddr);
> > +
> > +	mutex_unlock(&sio->lock);
> > +}
> 
> The rest starts looking good.
Same here. As far as the MFD part is concerned, it's fine with me except for
this one missing WARN_ON().
I'll wait until we get Jean's ack for the hwmon part, and push it through my
for-next branch.

Cheers,
Samuel.

 
> -- 
> Jean Delvare

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (23 preceding siblings ...)
  2009-10-01 13:53 ` Samuel Ortiz
@ 2009-11-02 13:23 ` Jean Delvare
  2009-11-03  8:17 ` Rodolfo Giometti
  25 siblings, 0 replies; 30+ messages in thread
From: Jean Delvare @ 2009-11-02 13:23 UTC (permalink / raw)
  To: lm-sensors

Hi Rodolfo,

On Thu, 1 Oct 2009 15:53:50 +0200, Samuel Ortiz wrote:
> > On Thu, 24 Sep 2009 14:01:11 +0200, Rodolfo Giometti wrote:
> > > The file has been splitted up into two parts:
> > > 
> > > * drivers/mfd/w83627hf-core.c      - detects the chip and define proper
> > >                                      platform devices into mfd support
> > > 
> > > * drivers/hwmon/w83627hf.c         - implements the driver for hwmon
> > >                                      functionality only
> > > 
> > > Signed-off-by: Rodolfo Giometti <giometti@linux.it>
> > > ---
> > >  drivers/hwmon/Kconfig        |    1 +
> > >  drivers/hwmon/w83627hf.c     |  376 ++++++++++++------------------------------
> > >  drivers/mfd/Kconfig          |   15 ++
> > >  drivers/mfd/Makefile         |    1 +
> > >  drivers/mfd/w83627hf-core.c  |  186 +++++++++++++++++++++
> > >  include/linux/mfd/w83627hf.h |  118 +++++++++++++
> > >  6 files changed, 428 insertions(+), 269 deletions(-)
> > >  create mode 100644 drivers/mfd/w83627hf-core.c
> > >  create mode 100644 include/linux/mfd/w83627hf.h
> > (...)
> > The rest starts looking good.
>
> Same here. As far as the MFD part is concerned, it's fine with me except for
> this one missing WARN_ON().
> I'll wait until we get Jean's ack for the hwmon part, and push it through my
> for-next branch.

Any news from this patch? It would be great to have it ready for merge
in kernel 2.6.33.

-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support.
  2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
                   ` (24 preceding siblings ...)
  2009-11-02 13:23 ` Jean Delvare
@ 2009-11-03  8:17 ` Rodolfo Giometti
  25 siblings, 0 replies; 30+ messages in thread
From: Rodolfo Giometti @ 2009-11-03  8:17 UTC (permalink / raw)
  To: lm-sensors

On Mon, Nov 02, 2009 at 02:23:28PM +0100, Jean Delvare wrote:
> Hi Rodolfo,
> 
> On Thu, 1 Oct 2009 15:53:50 +0200, Samuel Ortiz wrote:
> > > On Thu, 24 Sep 2009 14:01:11 +0200, Rodolfo Giometti wrote:
> > > > The file has been splitted up into two parts:
> > > > 
> > > > * drivers/mfd/w83627hf-core.c      - detects the chip and define proper
> > > >                                      platform devices into mfd support
> > > > 
> > > > * drivers/hwmon/w83627hf.c         - implements the driver for hwmon
> > > >                                      functionality only
> > > > 
> > > > Signed-off-by: Rodolfo Giometti <giometti@linux.it>
> > > > ---
> > > >  drivers/hwmon/Kconfig        |    1 +
> > > >  drivers/hwmon/w83627hf.c     |  376 ++++++++++++------------------------------
> > > >  drivers/mfd/Kconfig          |   15 ++
> > > >  drivers/mfd/Makefile         |    1 +
> > > >  drivers/mfd/w83627hf-core.c  |  186 +++++++++++++++++++++
> > > >  include/linux/mfd/w83627hf.h |  118 +++++++++++++
> > > >  6 files changed, 428 insertions(+), 269 deletions(-)
> > > >  create mode 100644 drivers/mfd/w83627hf-core.c
> > > >  create mode 100644 include/linux/mfd/w83627hf.h
> > > (...)
> > > The rest starts looking good.
> >
> > Same here. As far as the MFD part is concerned, it's fine with me except for
> > this one missing WARN_ON().
> > I'll wait until we get Jean's ack for the hwmon part, and push it through my
> > for-next branch.
> 
> Any news from this patch? It would be great to have it ready for merge
> in kernel 2.6.33.

I see, but unfortunately I'm stuck on other issues with higher
priority... I'm trying to fix up the patch ASAP even if I don't
guarantee to be in time for kernel 2.6.33. I'm sorry for that.

Ciao,

Rodolfo

-- 

GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming                     skype:  rodolfo.giometti
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support
  2010-02-10 12:18 Rodolfo Giometti
  2010-02-27 10:58 ` Jean Delvare
@ 2011-09-22  9:11 ` Rodolfo Giometti
  1 sibling, 0 replies; 30+ messages in thread
From: Rodolfo Giometti @ 2011-09-22  9:11 UTC (permalink / raw)
  To: lm-sensors

[-- Attachment #1: Type: text/plain, Size: 861 bytes --]

On Sat, Feb 27, 2010 at 11:58:59AM +0100, Jean Delvare wrote:
> Are you sure you sent the latest version of your patch? It doesn't
> apply on top of 2.6.33, there are 6 FAILED on drivers/hwmon/w83627hf.c.
> I will try fixing them myself if I must, but if you happen to have an
> updated version already...

Hi Jean,

finally I resumed this old project! :) I just updated it to latest
kernel release... can you please trying to apply it again?

If everything goes wrong, please, let me know and I'll try to fix it
up.

Ciao,

Rodolfo

-- 

GNU/Linux Solutions                  e-mail: giometti@enneenne.com
Linux Device Driver                          giometti@linux.it
Embedded Systems                     phone:  +39 349 2432127
UNIX programming                     skype:  rodolfo.giometti
Freelance ICT Italia - Consulente ICT Italia - www.consulenti-ict.it

[-- Attachment #2: 0001-hwmon-w83627hf-add-mfd-support.patch --]
[-- Type: text/x-diff, Size: 23110 bytes --]

From 922cf9c086bc405db8024b65b3a2537cc7262f61 Mon Sep 17 00:00:00 2001
From: Rodolfo Giometti <giometti@linux.it>
Date: Mon, 29 Aug 2011 14:41:48 +0200
Subject: [PATCH 1/2] hwmon w83627hf: add mfd support

The drivers has been splitted up into two parts:

* drivers/mfd/w83627hf-core.c      - detects the chip and define proper
                                     platform devices into mfd support

* drivers/hwmon/w83627hf.c         - implements the driver for hwmon
                                     functionality only

Signed-off-by: Rodolfo Giometti <giometti@linux.it>
---
 drivers/hwmon/Kconfig        |    1 +
 drivers/hwmon/w83627hf.c     |  331 +++++++++++-------------------------------
 drivers/mfd/Kconfig          |   15 ++
 drivers/mfd/Makefile         |    1 +
 drivers/mfd/w83627hf-core.c  |  186 +++++++++++++++++++++++
 include/linux/mfd/w83627hf.h |  118 +++++++++++++++
 6 files changed, 407 insertions(+), 245 deletions(-)
 create mode 100644 drivers/mfd/w83627hf-core.c
 create mode 100644 include/linux/mfd/w83627hf.h

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 5f888f7..fb5b5b3 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1271,6 +1271,7 @@ config SENSORS_W83L786NG
 
 config SENSORS_W83627HF
 	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
+	select MFD_W83627HF
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the Winbond W836X7 series
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index bde50e3..18711fe 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -6,6 +6,8 @@
     and Mark Studebaker <mdsxyz123@yahoo.com>
     Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
     Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
+    MFD support added by Rodolfo Giometti <giometti@linux.it>
+    Copyright (c) 2010 Rodolfo Giometti <giometti@linux.it>
 
     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
@@ -54,17 +56,10 @@
 #include <linux/ioport.h>
 #include <linux/acpi.h>
 #include <linux/io.h>
+#include <linux/mfd/w83627hf.h>
 #include "lm75.h"
 
-static struct platform_device *pdev;
 
-#define DRVNAME "w83627hf"
-enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
-
-struct w83627hf_sio_data {
-	enum chips type;
-	int sioaddr;
-};
 
 static u8 force_i2c = 0x1f;
 module_param(force_i2c, byte, 0);
@@ -75,86 +70,8 @@ static int init = 1;
 module_param(init, bool, 0);
 MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
 
-static unsigned short force_id;
-module_param(force_id, ushort, 0);
-MODULE_PARM_DESC(force_id, "Override the detected device ID");
-
-/* modified from kernel/include/traps.c */
-#define	DEV	0x07	/* Register: Logical device select */
-
-/* logical device numbers for superio_select (below) */
-#define W83627HF_LD_FDC		0x00
-#define W83627HF_LD_PRT		0x01
-#define W83627HF_LD_UART1	0x02
-#define W83627HF_LD_UART2	0x03
-#define W83627HF_LD_KBC		0x05
-#define W83627HF_LD_CIR		0x06 /* w83627hf only */
-#define W83627HF_LD_GAME	0x07
-#define W83627HF_LD_MIDI	0x07
-#define W83627HF_LD_GPIO1	0x07
-#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
-#define W83627HF_LD_GPIO2	0x08
-#define W83627HF_LD_GPIO3	0x09
-#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
-#define W83627HF_LD_ACPI	0x0a
-#define W83627HF_LD_HWM		0x0b
-
-#define	DEVID	0x20	/* Register: Device ID */
-
-#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
-#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
-#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
-
-#define W83687THF_VID_EN	0x29 /* w83687thf only */
-#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
-#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
-
-static inline void
-superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
-{
-	outb(reg, sio->sioaddr);
-	outb(val, sio->sioaddr + 1);
-}
-
-static inline int
-superio_inb(struct w83627hf_sio_data *sio, int reg)
-{
-	outb(reg, sio->sioaddr);
-	return inb(sio->sioaddr + 1);
-}
-
-static inline void
-superio_select(struct w83627hf_sio_data *sio, int ld)
-{
-	outb(DEV, sio->sioaddr);
-	outb(ld,  sio->sioaddr + 1);
-}
-
-static inline void
-superio_enter(struct w83627hf_sio_data *sio)
-{
-	outb(0x87, sio->sioaddr);
-	outb(0x87, sio->sioaddr);
-}
-
-static inline void
-superio_exit(struct w83627hf_sio_data *sio)
-{
-	outb(0xAA, sio->sioaddr);
-}
-
-#define W627_DEVID 0x52
-#define W627THF_DEVID 0x82
-#define W697_DEVID 0x60
-#define W637_DEVID 0x70
-#define W687THF_DEVID 0x85
-#define WINB_ACT_REG 0x30
-#define WINB_BASE_REG 0x60
 /* Constants specified below */
 
-/* Alignment of the base address */
-#define WINB_ALIGNMENT		~7
-
 /* Offset & size of I/O region we are interested in */
 #define WINB_REGION_OFFSET	5
 #define WINB_REGION_SIZE	2
@@ -394,7 +311,7 @@ static void w83627hf_init_device(struct platform_device *pdev);
 static struct platform_driver w83627hf_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
-		.name	= DRVNAME,
+		.name	= DRVNAME "_hwmon",
 	},
 	.probe		= w83627hf_probe,
 	.remove		= __devexit_p(w83627hf_remove),
@@ -1123,70 +1040,6 @@ show_name(struct device *dev, struct device_attribute *devattr, char *buf)
 }
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
-static int __init w83627hf_find(int sioaddr, unsigned short *addr,
-				struct w83627hf_sio_data *sio_data)
-{
-	int err = -ENODEV;
-	u16 val;
-
-	static const __initdata char *names[] = {
-		"W83627HF",
-		"W83627THF",
-		"W83697HF",
-		"W83637HF",
-		"W83687THF",
-	};
-
-	sio_data->sioaddr = sioaddr;
-	superio_enter(sio_data);
-	val = force_id ? force_id : superio_inb(sio_data, DEVID);
-	switch (val) {
-	case W627_DEVID:
-		sio_data->type = w83627hf;
-		break;
-	case W627THF_DEVID:
-		sio_data->type = w83627thf;
-		break;
-	case W697_DEVID:
-		sio_data->type = w83697hf;
-		break;
-	case W637_DEVID:
-		sio_data->type = w83637hf;
-		break;
-	case W687THF_DEVID:
-		sio_data->type = w83687thf;
-		break;
-	case 0xff:	/* No device at all */
-		goto exit;
-	default:
-		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
-		goto exit;
-	}
-
-	superio_select(sio_data, W83627HF_LD_HWM);
-	val = (superio_inb(sio_data, WINB_BASE_REG) << 8) |
-	       superio_inb(sio_data, WINB_BASE_REG + 1);
-	*addr = val & WINB_ALIGNMENT;
-	if (*addr == 0) {
-		pr_warn("Base address not set, skipping\n");
-		goto exit;
-	}
-
-	val = superio_inb(sio_data, WINB_ACT_REG);
-	if (!(val & 0x01)) {
-		pr_warn("Enabling HWM logical device\n");
-		superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
-	}
-
-	err = 0;
-	pr_info(DRVNAME ": Found %s chip at %#x\n",
-		names[sio_data->type], *addr);
-
- exit:
-	superio_exit(sio_data);
-	return err;
-}
-
 #define VIN_UNIT_ATTRS(_X_)	\
 	&sensor_dev_attr_in##_X_##_input.dev_attr.attr,		\
 	&sensor_dev_attr_in##_X_##_min.dev_attr.attr,		\
@@ -1265,27 +1118,81 @@ static const struct attribute_group w83627hf_group_opt = {
 	.attrs = w83627hf_attributes_opt,
 };
 
+static int w83627hf_enable_hwmon(struct w83627hf_sio_data *sio_data)
+{
+	u16 val;
+	int ret;
+
+	superio_enter(sio_data);
+
+	superio_select(sio_data, W83627HF_LD_HWM);
+
+	val = (superio_inb(sio_data, 0x60) << 8) |
+	       superio_inb(sio_data, 0x60 + 1);
+	ret = val & (~7);
+	pr_info(DRVNAME ": hwmon chip %s at %#x\n", sio_data->name, ret);
+
+	if (ret == 0) {
+		printk(KERN_WARNING DRVNAME ": Base address not set, "
+		       "skipping\n");
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	val = superio_inb(sio_data, 0x30);
+	superio_outb(sio_data, 0x30, val | 0x01);
+
+exit:
+	superio_exit(sio_data);
+
+	return ret;
+}
+
+static void w83627hf_disable_hwmon(struct w83627hf_sio_data *sio_data)
+{
+	u16 val;
+
+	superio_enter(sio_data);
+
+	superio_select(sio_data, W83627HF_LD_HWM);
+
+	val = superio_inb(sio_data, 0x30);
+	superio_outb(sio_data, 0x30, val & ~0x01);
+
+	superio_exit(sio_data);
+}
+
 static int __devinit w83627hf_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct w83627hf_sio_data *sio_data = dev->platform_data;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	struct w83627hf_data *data;
-	struct resource *res;
 	int err, i;
 
-	static const char *names[] = {
-		"w83627hf",
-		"w83627thf",
-		"w83697hf",
-		"w83637hf",
-		"w83687thf",
+	struct resource res = {
+		.start  = /* address + */ WINB_REGION_OFFSET,
+		.end    = /* address + */ WINB_REGION_OFFSET +
+						WINB_REGION_SIZE - 1,
+		.name   = DRVNAME "_hwmon",
+		.flags  = IORESOURCE_IO,
 	};
 
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
+	err = w83627hf_enable_hwmon(sio_data);
+	if (err < 0)
+		return err;
+
+	/* Before doing our job we should fixup ioport range */
+	res.start += err;
+	res.end += err;
+
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto ERROR0;
+
+	if (!request_region(res.start, WINB_REGION_SIZE, DRVNAME "_hwmon")) {
 		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
-			(unsigned long)res->start,
-			(unsigned long)(res->start + WINB_REGION_SIZE - 1));
+			(unsigned long) res.start,
+			(unsigned long) (res.start + WINB_REGION_SIZE - 1));
 		err = -EBUSY;
 		goto ERROR0;
 	}
@@ -1294,9 +1201,9 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 		err = -ENOMEM;
 		goto ERROR1;
 	}
-	data->addr = res->start;
+	data->addr = res.start;
 	data->type = sio_data->type;
-	data->name = names[sio_data->type];
+	data->name = sio_data->name;
 	mutex_init(&data->lock);
 	mutex_init(&data->update_lock);
 	platform_set_drvdata(pdev, data);
@@ -1429,15 +1336,20 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, NULL);
 	kfree(data);
       ERROR1:
-	release_region(res->start, WINB_REGION_SIZE);
+	release_region(res.start, WINB_REGION_SIZE);
       ERROR0:
+	w83627hf_disable_hwmon(sio_data);
 	return err;
 }
 
 static int __devexit w83627hf_remove(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	struct w83627hf_data *data = platform_get_drvdata(pdev);
-	struct resource *res;
+	unsigned int addr = data->addr;
+
+	w83627hf_disable_hwmon(sio_data);
 
 	hwmon_device_unregister(data->hwmon_dev);
 
@@ -1446,8 +1358,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
 	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	release_region(res->start, WINB_REGION_SIZE);
+	release_region(addr, WINB_REGION_SIZE);
 
 	return 0;
 }
@@ -1498,7 +1409,8 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
 
 static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
 {
-	struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	int res = 0xff, sel;
 
 	superio_enter(sio_data);
@@ -1529,7 +1441,8 @@ exit:
 
 static int __devinit w83687thf_read_vid(struct platform_device *pdev)
 {
-	struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	int res = 0xff;
 
 	superio_enter(sio_data);
@@ -1772,92 +1685,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 	return data;
 }
 
-static int __init w83627hf_device_add(unsigned short address,
-				      const struct w83627hf_sio_data *sio_data)
-{
-	struct resource res = {
-		.start	= address + WINB_REGION_OFFSET,
-		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
-		.name	= DRVNAME,
-		.flags	= IORESOURCE_IO,
-	};
-	int err;
-
-	err = acpi_check_resource_conflict(&res);
-	if (err)
-		goto exit;
-
-	pdev = platform_device_alloc(DRVNAME, address);
-	if (!pdev) {
-		err = -ENOMEM;
-		pr_err("Device allocation failed\n");
-		goto exit;
-	}
-
-	err = platform_device_add_resources(pdev, &res, 1);
-	if (err) {
-		pr_err("Device resource addition failed (%d)\n", err);
-		goto exit_device_put;
-	}
-
-	err = platform_device_add_data(pdev, sio_data,
-				       sizeof(struct w83627hf_sio_data));
-	if (err) {
-		pr_err("Platform data allocation failed\n");
-		goto exit_device_put;
-	}
-
-	err = platform_device_add(pdev);
-	if (err) {
-		pr_err("Device addition failed (%d)\n", err);
-		goto exit_device_put;
-	}
-
-	return 0;
-
-exit_device_put:
-	platform_device_put(pdev);
-exit:
-	return err;
-}
-
 static int __init sensors_w83627hf_init(void)
 {
-	int err;
-	unsigned short address;
-	struct w83627hf_sio_data sio_data;
-
-	if (w83627hf_find(0x2e, &address, &sio_data)
-	 && w83627hf_find(0x4e, &address, &sio_data))
-		return -ENODEV;
-
-	err = platform_driver_register(&w83627hf_driver);
-	if (err)
-		goto exit;
-
-	/* Sets global pdev as a side effect */
-	err = w83627hf_device_add(address, &sio_data);
-	if (err)
-		goto exit_driver;
-
-	return 0;
-
-exit_driver:
-	platform_driver_unregister(&w83627hf_driver);
-exit:
-	return err;
+	return platform_driver_register(&w83627hf_driver);
 }
 
 static void __exit sensors_w83627hf_exit(void)
 {
-	platform_device_unregister(pdev);
 	platform_driver_unregister(&w83627hf_driver);
 }
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
 	      "Philip Edelbrock <phil@netroedge.com>, "
 	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
-MODULE_DESCRIPTION("W83627HF driver");
+MODULE_DESCRIPTION("W83627HF hwmon driver");
 MODULE_LICENSE("GPL");
 
 module_init(sensors_w83627hf_init);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6ca938a..22b536e 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -731,6 +731,21 @@ config MFD_TPS65910
 config TPS65911_COMPARATOR
 	tristate
 
+config MFD_W83627HF
+	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
+	depends on MFD_CORE
+	help
+	  If you say yes here you add support for the Winbond W836X7 series
+	  of super-IO chips: the W83627HF, W83627THF, W83637HF, W83687THF and
+	  W83697HF to your platform.
+
+	  This is a multi functional device and this support defines a new
+	  platform device only. See other configuration submenus in order to
+	  enable the drivers of Winbond chip's functionalities.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83627hf-core.
+
 endif # MFD_SUPPORT
 
 menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index d7d47d2..b59e1db 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_MFD_MC13XXX)	+= mc13xxx-core.o
 obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
 
 obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
+obj-$(CONFIG_MFD_W83627HF)	+= w83627hf-core.o
 
 obj-$(CONFIG_MCP)		+= mcp-core.o
 obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
diff --git a/drivers/mfd/w83627hf-core.c b/drivers/mfd/w83627hf-core.c
new file mode 100644
index 0000000..3496a6b
--- /dev/null
+++ b/drivers/mfd/w83627hf-core.c
@@ -0,0 +1,186 @@
+/*
+ *  w83627hf.c - platform device support
+ *  Copyright (c) 2009-2011 Rodolfo Giometti <giometti@linux.it>
+ *
+ *  Based on drivers/hwmon/w83627hf.c
+ *
+ *  Original copyright note:
+ *    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
+ *    Philip Edelbrock <phil@netroedge.com>,
+ *    and Mark Studebaker <mdsxyz123@yahoo.com>
+ *    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
+ *    Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
+ *
+ *    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
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/w83627hf.h>
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+/*
+ * Devices definitions
+ */
+
+static struct platform_device *pdev;
+
+static char *names[] = {
+	"w83627hf",
+	"w83627thf",
+	"w83697hf",
+	"w83637hf",
+	"w83687thf",
+};
+
+static struct mfd_cell cells[] = {
+	{
+		.name		= DRVNAME "_hwmon",
+	},
+};
+
+#define W627_DEVID		0x52
+#define W627THF_DEVID		0x82
+#define W697_DEVID		0x60
+#define W637_DEVID		0x70
+#define W687THF_DEVID		0x85
+
+static int __init w83627hf_find(int sioaddr, struct w83627hf_sio_data *sio_data)
+{
+	int err = -ENODEV;
+	u16 val;
+
+	sio_data->sioaddr = sioaddr;
+
+	superio_enter(sio_data);
+
+	val = force_id ? force_id : superio_inb(sio_data, 0x20);
+	switch (val) {
+	case W627_DEVID:
+		sio_data->type = w83627hf;
+		break;
+	case W627THF_DEVID:
+		sio_data->type = w83627thf;
+		break;
+	case W697_DEVID:
+		sio_data->type = w83697hf;
+		break;
+	case W637_DEVID:
+		sio_data->type = w83637hf;
+		break;
+	case W687THF_DEVID:
+		sio_data->type = w83687thf;
+		break;
+	case 0xff:	/* No device at all */
+		goto exit;
+	default:
+		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
+		goto exit;
+	}
+
+	err = 0;
+	sio_data->name = names[sio_data->type];
+
+	pr_info(DRVNAME ": Found %s chip at %#x\n", sio_data->name, sioaddr);
+
+exit:
+	superio_exit(sio_data);
+
+	return err;
+}
+
+static int __init w83627hf_device_add(const struct w83627hf_sio_data *sio_data)
+{
+	int err;
+
+	pdev = platform_device_alloc(DRVNAME, 0);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct w83627hf_sio_data));
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	err = mfd_add_devices(&pdev->dev, pdev->id, cells, ARRAY_SIZE(cells),
+			0, -1);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Cannot add sub devices (%d)\n",
+			err);
+		goto exit_device_unregister;
+	}
+
+	return 0;
+
+exit_device_unregister:
+	platform_device_unregister(pdev);
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int __init w83627hf_init(void)
+{
+	struct w83627hf_sio_data sio_data;
+	int ret;
+
+	mutex_init(&sio_data.lock);
+
+	ret = w83627hf_find(0x2e, &sio_data);
+	if (ret) {
+		ret = w83627hf_find(0x4e, &sio_data);
+		if (ret)
+			return -ENODEV;
+	}
+
+	/* Sets global pdev as a side effect */
+	return w83627hf_device_add(&sio_data);
+}
+
+static void __exit w83627hf_exit(void)
+{
+	mfd_remove_devices(&pdev->dev);
+	platform_device_unregister(pdev);
+}
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("W83627HF platform devices definitions");
+MODULE_LICENSE("GPL");
+
+module_init(w83627hf_init);
+module_exit(w83627hf_exit);
diff --git a/include/linux/mfd/w83627hf.h b/include/linux/mfd/w83627hf.h
new file mode 100644
index 0000000..5f4200b
--- /dev/null
+++ b/include/linux/mfd/w83627hf.h
@@ -0,0 +1,118 @@
+/*
+ *  w83627hf.h - platform device support, header file
+ *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
+ *
+ *  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
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#define DRVNAME "w83627hf"
+
+enum chips {
+	w83627hf,
+	w83627thf,
+	w83697hf,
+	w83637hf,
+	w83687thf
+};
+
+struct w83627hf_sio_data {
+	int sioaddr;
+	enum chips type;
+	char *name;
+
+	struct mutex lock;
+};
+
+/* logical device numbers for superio_select (below) */
+#define W83627HF_LD_FDC		0x00
+#define W83627HF_LD_PRT		0x01
+#define W83627HF_LD_UART1	0x02
+#define W83627HF_LD_UART2	0x03
+#define W83627HF_LD_KBC		0x05
+#define W83627HF_LD_CIR		0x06 /* w83627hf only */
+#define W83627HF_LD_GAME	0x07
+#define W83627HF_LD_MIDI	0x07
+#define W83627HF_LD_GPIO1	0x07
+#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
+#define W83627HF_LD_GPIO2	0x08
+#define W83627HF_LD_GPIO3	0x09
+#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
+#define W83627HF_LD_ACPI	0x0a
+#define W83627HF_LD_HWM		0x0b
+
+#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
+#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
+#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
+
+#define W83687THF_VID_EN	0x29 /* w83687thf only */
+#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
+#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
+
+/*
+ * Common configuration registers access functions.
+ *
+ * These registers are special and they must me accessed by using a well
+ * specified protocol. Client drivers __must__ do as follow in order to
+ * get access correctly to these registers:
+ *
+ *	superio_enter()
+ *
+ *	superio_select()/superio_outb()/superio_inb()
+ *
+ *	superio_exit();
+ *
+ */
+
+static inline void superio_enter(struct w83627hf_sio_data *sio)
+{
+	mutex_lock(&sio->lock);
+
+	outb(0x87, sio->sioaddr);
+	outb(0x87, sio->sioaddr);
+}
+
+static inline void superio_select(struct w83627hf_sio_data *sio, int ld)
+{
+	WARN_ON(!mutex_is_locked(&sio->lock));
+
+	outb(0x07, sio->sioaddr);
+	outb(ld, sio->sioaddr + 1);
+}
+
+static inline void superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
+{
+	WARN_ON(!mutex_is_locked(&sio->lock));
+
+	outb(reg, sio->sioaddr);
+	outb(val, sio->sioaddr + 1);
+}
+
+static inline int superio_inb(struct w83627hf_sio_data *sio, int reg)
+{
+	WARN_ON(!mutex_is_locked(&sio->lock));
+
+	outb(reg, sio->sioaddr);
+	return inb(sio->sioaddr + 1);
+}
+
+static inline void superio_exit(struct w83627hf_sio_data *sio)
+{
+	outb(0xAA, sio->sioaddr);
+
+	mutex_unlock(&sio->lock);
+}
-- 
1.7.0.4


[-- Attachment #3: 0002-gpio-w83627hf-add-gpio-support.patch --]
[-- Type: text/x-diff, Size: 12813 bytes --]

From f5044c05376e7d515a2d8a9b854784307dba3a18 Mon Sep 17 00:00:00 2001
From: Rodolfo Giometti <giometti@linux.it>
Date: Mon, 29 Aug 2011 15:14:29 +0200
Subject: [PATCH 2/2] gpio w83627hf: add gpio support

Signed-off-by: Rodolfo Giometti <giometti@linux.it>
---
 drivers/gpio/Kconfig         |   12 +
 drivers/gpio/Makefile        |    1 +
 drivers/gpio/w83627hf_gpio.c |  492 ++++++++++++++++++++++++++++++++++++++++++
 drivers/mfd/w83627hf-core.c  |    3 +
 4 files changed, 508 insertions(+), 0 deletions(-)
 create mode 100644 drivers/gpio/w83627hf_gpio.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 2967002..065cf5b 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -152,6 +152,18 @@ config GPIO_VX855
 	  additional drivers must be enabled in order to use the
 	  functionality of the device.
 
+config GPIO_W83627HF
+	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
+	select MFD_CORE
+	select MFD_W83627HF
+	help
+	  If you say yes here you get support for the Winbond W836X7 series
+	  of sensor chips: the W83627HF, W83627THF, W83637HF, W83687THF and
+	  W83697HF.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83627hf.
+
 comment "I2C GPIO expanders:"
 
 config GPIO_MAX7300
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index b605f8e..df527d0 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_GPIO_RDC321X)	+= rdc321x-gpio.o
 obj-$(CONFIG_GPIO_JANZ_TTL)	+= janz-ttl.o
 obj-$(CONFIG_GPIO_SX150X)	+= sx150x.o
 obj-$(CONFIG_GPIO_VX855)	+= vx855_gpio.o
+obj-$(CONFIG_GPIO_W83627HF)	+= w83627hf_gpio.o
 obj-$(CONFIG_GPIO_ML_IOH)	+= ml_ioh_gpio.o
 obj-$(CONFIG_AB8500_GPIO)       += ab8500-gpio.o
 obj-$(CONFIG_GPIO_TPS65910)	+= tps65910-gpio.o
diff --git a/drivers/gpio/w83627hf_gpio.c b/drivers/gpio/w83627hf_gpio.c
new file mode 100644
index 0000000..12d6c73
--- /dev/null
+++ b/drivers/gpio/w83627hf_gpio.c
@@ -0,0 +1,492 @@
+/*
+ *  w83627hf_gpio.c - GPIO support for w83627hf chip
+ *
+ *  Copyright (c) 2010-2011  Rodolfo Giometti <giometti@linux.it>
+ *
+ *  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
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/mfd/w83627hf.h>
+
+/* Constants specified below */
+
+#define W83627HF_LD_GPIO3_MUX	0x29
+#define W83627HF_LD_GPIO1_MUX	0x2a
+#define W83627HF_LD_GPIO2_MUX	0x2b
+
+static const unsigned int ngpio[] = {
+	/* port 1 - port 2 - port 3 */
+	    8 +      8 +      6,
+	    0,
+	    0,
+	    0,
+	    0,
+};
+
+struct w83627hf_data {
+	struct gpio_chip chip;
+	struct bitmap {
+		unsigned long status:1;
+	} bit[3 * 8];
+};
+
+/*
+ * Local functions
+ */
+
+static void gpio_mode(struct w83627hf_sio_data *sio,
+				unsigned int bit, unsigned int mode)
+{
+	u8 val;
+
+	val = superio_inb(sio, 0xf0);
+	if (mode == 0)
+		val &= ~(1 << bit);
+	else
+		val |= (1 << bit);
+	superio_outb(sio, 0xf0, val);
+}
+
+static int gpio_get(struct w83627hf_sio_data *sio, unsigned int bit)
+{
+	u8 val;
+
+	val = superio_inb(sio, 0xf1);
+	val &= (1 << bit);
+
+	return val;
+}
+
+static void gpio_set(struct w83627hf_sio_data *sio,
+				unsigned int bit, unsigned int status)
+{
+	u8 val;
+
+	val = superio_inb(sio, 0xf1);
+	if (status)
+		val |= (1 << bit);
+	else
+		val &= ~(1 << bit);
+	superio_outb(sio, 0xf1, val);
+}
+
+static void gpio1_enable(struct w83627hf_sio_data *sio)
+{
+	u8 val;
+
+	superio_enter(sio);
+
+	/* Select GPIO1 into pins multiplxer */
+	val = superio_inb(sio, W83627HF_LD_GPIO1_MUX);
+	superio_outb(sio, W83627HF_LD_GPIO1_MUX, val | 0xfc);
+
+	/* Enable GPIO1 */
+	superio_select(sio, W83627HF_LD_GPIO1);
+	val = superio_inb(sio, 0x30);
+	superio_outb(sio, 0x30, val | 0x01);
+
+	superio_exit(sio);
+}
+
+static void gpio1_disable(struct w83627hf_sio_data *sio)
+{
+	u8 val;
+
+	superio_enter(sio);
+
+	/* Disable GPIO1 */
+	superio_select(sio, W83627HF_LD_GPIO1);
+	val = superio_inb(sio, 0x30);
+	superio_outb(sio, 0x30, val & ~0x01);
+
+	superio_exit(sio);
+}
+
+static void gpio2_enable(struct w83627hf_sio_data *sio)
+{
+	u8 val;
+
+	superio_enter(sio);
+
+	/* Select GPIO2 into pins multiplxer */
+	val = superio_inb(sio, W83627HF_LD_GPIO1_MUX);
+	superio_outb(sio, W83627HF_LD_GPIO1_MUX, val | 0x01);
+	val = superio_inb(sio, W83627HF_LD_GPIO2_MUX);
+	superio_outb(sio, W83627HF_LD_GPIO2_MUX, val | 0xff);
+
+	/* Enable GPIO2 */
+	superio_select(sio, W83627HF_LD_GPIO2);
+	val = superio_inb(sio, 0x30);
+	superio_outb(sio, 0x30, val | 0x01);
+
+	superio_exit(sio);
+}
+
+static void gpio2_disable(struct w83627hf_sio_data *sio)
+{
+	u8 val;
+
+	superio_enter(sio);
+
+	/* Disable GPIO2 */
+	superio_select(sio, W83627HF_LD_GPIO2);
+	val = superio_inb(sio, 0x30);
+	superio_outb(sio, 0x30, val & ~0x01);
+
+	superio_exit(sio);
+}
+
+static void gpio3_enable(struct w83627hf_sio_data *sio)
+{
+	u8 val;
+
+	superio_enter(sio);
+
+	/* Select GPIO3 into pins multiplxer */
+	val = superio_inb(sio, W83627HF_LD_GPIO3_MUX);
+	superio_outb(sio, W83627HF_LD_GPIO3_MUX, val | 0xfc);
+
+	/* Enable GPIO3 */
+	superio_select(sio, W83627HF_LD_GPIO3);
+	val = superio_inb(sio, 0x30);
+	superio_outb(sio, 0x30, val | 0x01);
+
+	superio_exit(sio);
+}
+
+static void gpio3_disable(struct w83627hf_sio_data *sio)
+{
+	u8 val;
+
+	superio_enter(sio);
+
+	/* Disable GPIO3 */
+	superio_select(sio, W83627HF_LD_GPIO3);
+	val = superio_inb(sio, 0x30);
+	superio_outb(sio, 0x30, val & ~0x01);
+
+	superio_exit(sio);
+}
+
+/*
+ * GPIOs methods
+ */
+
+static int w83627hf_request(struct gpio_chip *chip, unsigned offset)
+{
+	struct device *dev = chip->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
+	struct w83627hf_data *data = container_of(chip,
+						struct w83627hf_data, chip);
+	struct bitmap *bit = data->bit;
+
+	switch (offset) {
+	case 0 ... 7:
+		gpio1_enable(sio_data);
+		break;
+
+	case 8 ... 15:
+		/* Port2 is currently not supported */
+		gpio2_enable(sio_data);
+		break;
+
+	case 16 ... 21:
+		gpio3_enable(sio_data);
+		break;
+
+	default:
+		BUG();
+		return -EINVAL;
+	}
+
+	bit[offset].status = 1;
+
+	return 0;
+}
+
+static void w83627hf_free(struct gpio_chip *chip, unsigned offset)
+{
+	struct device *dev = chip->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
+	struct w83627hf_data *data = container_of(chip,
+						struct w83627hf_data, chip);
+	struct bitmap *bit = data->bit;
+	int i;
+
+	switch (offset) {
+	case 0 ... 7:
+		bit[offset].status = 0;
+		for (i = 0; i < 8; i++)
+			if (bit[i].status)
+				break;
+		if (i == 8)
+			gpio1_disable(sio_data);
+		break;
+
+	case 8 ... 15:
+		bit[offset].status = 0;
+		for (i = 8; i < 16; i++)
+			if (bit[i].status)
+				break;
+		if (i == 16)
+			gpio2_disable(sio_data);
+		break;
+
+	case 16 ... 21:
+		bit[offset].status = 0;
+		for (i = 16; i < 22; i++)
+			if (bit[i].status)
+				break;
+		if (i == 22)
+			gpio3_disable(sio_data);
+		break;
+
+	default:
+		BUG();
+	}
+}
+
+static int w83627hf_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+	struct device *dev = chip->dev;
+	struct w83627hf_sio_data *sio = dev->parent->platform_data;
+
+	superio_enter(sio);
+
+	switch (offset) {
+	case 0 ... 7:
+		superio_select(sio, W83627HF_LD_GPIO1);
+		gpio_mode(sio, offset, 1);
+		break;
+
+	case 8 ... 15:
+		superio_select(sio, W83627HF_LD_GPIO2);
+		gpio_mode(sio, offset - 8, 1);
+		break;
+
+	case 16 ... 21:
+		superio_select(sio, W83627HF_LD_GPIO3);
+		gpio_mode(sio, offset - 16, 1);
+		break;
+
+	default:
+		BUG();
+	}
+
+	superio_exit(sio);
+
+	return 0;
+}
+
+static int w83627hf_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct device *dev = chip->dev;
+	struct w83627hf_sio_data *sio = dev->parent->platform_data;
+	u8 val;
+
+	superio_enter(sio);
+
+	switch (offset) {
+	case 0 ... 7:
+		superio_select(sio, W83627HF_LD_GPIO1);
+		val = gpio_get(sio, offset);
+		break;
+
+	case 8 ... 15:
+		superio_select(sio, W83627HF_LD_GPIO2);
+		val = gpio_get(sio, offset - 8);
+		break;
+
+	case 16 ... 21:
+		superio_select(sio, W83627HF_LD_GPIO3);
+		val = gpio_get(sio, offset - 16);
+		break;
+
+	default:
+		BUG();
+		val = -EINVAL;
+	}
+
+	superio_exit(sio);
+
+	return val;
+}
+
+static int w83627hf_direction_out(struct gpio_chip *chip,
+						unsigned offset, int value)
+{
+	struct device *dev = chip->dev;
+	struct w83627hf_sio_data *sio = dev->parent->platform_data;
+	int ret = 0;
+
+	superio_enter(sio);
+
+	switch (offset) {
+	case 0 ... 7:
+		superio_select(sio, W83627HF_LD_GPIO1);
+		gpio_mode(sio, offset, 0);
+		break;
+
+	case 8 ... 15:
+		superio_select(sio, W83627HF_LD_GPIO2);
+		gpio_mode(sio, offset - 8, value);
+		break;
+
+	case 16 ... 21:
+		superio_select(sio, W83627HF_LD_GPIO3);
+		gpio_mode(sio, offset - 16, value);
+		break;
+
+	default:
+		BUG();
+	}
+
+	superio_exit(sio);
+
+	return ret;
+}
+
+static void w83627hf_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct device *dev = chip->dev;
+	struct w83627hf_sio_data *sio = dev->parent->platform_data;
+
+	superio_enter(sio);
+
+	switch (offset) {
+	case 0 ... 7:
+		superio_select(sio, W83627HF_LD_GPIO1);
+		gpio_set(sio, offset, value);
+		break;
+
+	case 8 ... 15:
+		superio_select(sio, W83627HF_LD_GPIO2);
+		gpio_set(sio, offset - 8, value);
+		break;
+
+	case 16 ... 21:
+		superio_select(sio, W83627HF_LD_GPIO3);
+		gpio_set(sio, offset - 16, value);
+		break;
+
+	default:
+		BUG();
+	}
+
+	superio_exit(sio);
+}
+
+static int __devinit w83627hf_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
+	struct w83627hf_data *data;
+	int err;
+
+	if (ngpio[sio_data->type] == 0) {
+		dev_err(&pdev->dev, "gpio support not available "
+					"for this chip type\n");
+		return -ENODEV;
+	}
+
+	data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, data);
+
+	data->chip.base = -1;
+	data->chip.ngpio = ngpio[sio_data->type];
+	data->chip.label = sio_data->name;
+	data->chip.dev = dev;
+
+	data->chip.owner = THIS_MODULE;
+	data->chip.request = w83627hf_request;
+	data->chip.free = w83627hf_free;
+	data->chip.direction_input = w83627hf_direction_in;
+	data->chip.get = w83627hf_get;
+	data->chip.direction_output = w83627hf_direction_out;
+	data->chip.set = w83627hf_set;
+	data->chip.can_sleep = 1;
+
+	err = gpiochip_add(&data->chip);
+	if (err < 0) {
+		dev_err(&pdev->dev, "could not register gpiochip, %d\n", err);
+		goto free_platform_data;
+	}
+
+	return 0;
+
+free_platform_data:
+	kfree(data);
+	platform_set_drvdata(pdev, NULL);
+
+	return err;
+}
+
+static int __devexit w83627hf_remove(struct platform_device *pdev)
+{
+	struct w83627hf_data *data = platform_get_drvdata(pdev);
+	int err;
+
+	err = gpiochip_remove(&data->chip);
+	if (err < 0) {
+		dev_err(&pdev->dev, "could not deregister gpiochip, %d\n", err);
+		return err;
+	}
+
+	kfree(data);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver w83627hf_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= DRVNAME "_gpio",
+	},
+	.probe		= w83627hf_probe,
+	.remove		= __devexit_p(w83627hf_remove),
+};
+
+/*
+ * Module stuff
+ */
+
+static int __init gpio_w83627hf_init(void)
+{
+	return platform_driver_register(&w83627hf_driver);
+}
+
+static void __exit gpio_w83627hf_exit(void)
+{
+	platform_driver_unregister(&w83627hf_driver);
+}
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("W83627HF gpio driver");
+MODULE_LICENSE("GPL");
+
+module_init(gpio_w83627hf_init);
+module_exit(gpio_w83627hf_exit);
diff --git a/drivers/mfd/w83627hf-core.c b/drivers/mfd/w83627hf-core.c
index 3496a6b..41a4764 100644
--- a/drivers/mfd/w83627hf-core.c
+++ b/drivers/mfd/w83627hf-core.c
@@ -59,6 +59,9 @@ static struct mfd_cell cells[] = {
 	{
 		.name		= DRVNAME "_hwmon",
 	},
+	{
+		.name		= DRVNAME "_gpio",
+	},
 };
 
 #define W627_DEVID		0x52
-- 
1.7.0.4


[-- Attachment #4: Type: text/plain, Size: 153 bytes --]

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [lm-sensors] [PATCH] hwmon w83627hf: add mfd support
  2010-02-10 12:18 Rodolfo Giometti
@ 2010-02-27 10:58 ` Jean Delvare
  2011-09-22  9:11 ` Rodolfo Giometti
  1 sibling, 0 replies; 30+ messages in thread
From: Jean Delvare @ 2010-02-27 10:58 UTC (permalink / raw)
  To: lm-sensors

Hi Rodolfo,

On Wed, 10 Feb 2010 13:18:33 +0100, Rodolfo Giometti wrote:
> The drivers has been splitted up into two parts:
> 
> * drivers/mfd/w83627hf-core.c 	   - detects the chip and define proper
>   				     platform devices into mfd support
> 
> * drivers/hwmon/w83627hf.c	   - implements the driver for hwmon
>   				     functionality only
> 
> Signed-off-by: Rodolfo Giometti <giometti@linux.it>
> ---
> 
> Jean, can you please take a look at this patch? It should apply over
> your last patch.

Are you sure you sent the latest version of your patch? It doesn't
apply on top of 2.6.33, there are 6 FAILED on drivers/hwmon/w83627hf.c.
I will try fixing them myself if I must, but if you happen to have an
updated version already...

-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [lm-sensors] [PATCH] hwmon w83627hf: add mfd support
@ 2010-02-10 12:18 Rodolfo Giometti
  2010-02-27 10:58 ` Jean Delvare
  2011-09-22  9:11 ` Rodolfo Giometti
  0 siblings, 2 replies; 30+ messages in thread
From: Rodolfo Giometti @ 2010-02-10 12:18 UTC (permalink / raw)
  To: lm-sensors

The drivers has been splitted up into two parts:

* drivers/mfd/w83627hf-core.c 	   - detects the chip and define proper
  				     platform devices into mfd support

* drivers/hwmon/w83627hf.c	   - implements the driver for hwmon
  				     functionality only

Signed-off-by: Rodolfo Giometti <giometti@linux.it>
---

Jean, can you please take a look at this patch? It should apply over
your last patch.

If everything is ok I'm going to produce GPIO support too.

Rodolfo

 drivers/hwmon/Kconfig        |    1 +
 drivers/hwmon/w83627hf.c     |  374 ++++++++++++------------------------------
 drivers/mfd/Kconfig          |   15 ++
 drivers/mfd/Makefile         |    1 +
 drivers/mfd/w83627hf-core.c  |  186 +++++++++++++++++++++
 include/linux/mfd/w83627hf.h |  118 +++++++++++++
 6 files changed, 427 insertions(+), 268 deletions(-)
 create mode 100644 drivers/mfd/w83627hf-core.c
 create mode 100644 include/linux/mfd/w83627hf.h

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 700e93a..3d9b883 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -892,6 +892,7 @@ config SENSORS_W83L786NG
 
 config SENSORS_W83627HF
 	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
+	select MFD_W83627HF
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the Winbond W836X7 series
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 2be28ac..811011e 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -6,6 +6,8 @@
     and Mark Studebaker <mdsxyz123@yahoo.com>
     Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
     Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
+    MFD support added by Rodolfo Giometti <giometti@linux.it>
+    Copyright (c) 2010 Rodolfo Giometti <giometti@linux.it>
 
     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
@@ -52,13 +54,11 @@
 #include <linux/ioport.h>
 #include <linux/acpi.h>
 #include <asm/io.h>
+#include <linux/mfd/w83627hf.h>
 #include "lm75.h"
 
 static struct platform_device *pdev;
 
-#define DRVNAME "w83627hf"
-enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
-
 static u16 force_addr;
 module_param(force_addr, ushort, 0);
 MODULE_PARM_DESC(force_addr,
@@ -72,88 +72,8 @@ static int init = 1;
 module_param(init, bool, 0);
 MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
 
-static unsigned short force_id;
-module_param(force_id, ushort, 0);
-MODULE_PARM_DESC(force_id, "Override the detected device ID");
-
-/* modified from kernel/include/traps.c */
-static int REG;		/* The register to read/write */
-#define	DEV	0x07	/* Register: Logical device select */
-static int VAL;		/* The value to read/write */
-
-/* logical device numbers for superio_select (below) */
-#define W83627HF_LD_FDC		0x00
-#define W83627HF_LD_PRT		0x01
-#define W83627HF_LD_UART1	0x02
-#define W83627HF_LD_UART2	0x03
-#define W83627HF_LD_KBC		0x05
-#define W83627HF_LD_CIR		0x06 /* w83627hf only */
-#define W83627HF_LD_GAME	0x07
-#define W83627HF_LD_MIDI	0x07
-#define W83627HF_LD_GPIO1	0x07
-#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
-#define W83627HF_LD_GPIO2	0x08
-#define W83627HF_LD_GPIO3	0x09
-#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
-#define W83627HF_LD_ACPI	0x0a
-#define W83627HF_LD_HWM		0x0b
-
-#define	DEVID	0x20	/* Register: Device ID */
-
-#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
-#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
-#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
-
-#define W83687THF_VID_EN	0x29 /* w83687thf only */
-#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
-#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
-
-static inline void
-superio_outb(int reg, int val)
-{
-	outb(reg, REG);
-	outb(val, VAL);
-}
-
-static inline int
-superio_inb(int reg)
-{
-	outb(reg, REG);
-	return inb(VAL);
-}
-
-static inline void
-superio_select(int ld)
-{
-	outb(DEV, REG);
-	outb(ld, VAL);
-}
-
-static inline void
-superio_enter(void)
-{
-	outb(0x87, REG);
-	outb(0x87, REG);
-}
-
-static inline void
-superio_exit(void)
-{
-	outb(0xAA, REG);
-}
-
-#define W627_DEVID 0x52
-#define W627THF_DEVID 0x82
-#define W697_DEVID 0x60
-#define W637_DEVID 0x70
-#define W687THF_DEVID 0x85
-#define WINB_ACT_REG 0x30
-#define WINB_BASE_REG 0x60
 /* Constants specified below */
 
-/* Alignment of the base address */
-#define WINB_ALIGNMENT		~7
-
 /* Offset & size of I/O region we are interested in */
 #define WINB_REGION_OFFSET	5
 #define WINB_REGION_SIZE	2
@@ -380,10 +300,6 @@ struct w83627hf_data {
 	u8 vrm_ovt;		/* Register value, 627THF/637HF/687THF only */
 };
 
-struct w83627hf_sio_data {
-	enum chips type;
-};
-
 
 static int w83627hf_probe(struct platform_device *pdev);
 static int __devexit w83627hf_remove(struct platform_device *pdev);
@@ -397,7 +313,7 @@ static void w83627hf_init_device(struct platform_device *pdev);
 static struct platform_driver w83627hf_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
-		.name	= DRVNAME,
+		.name	= DRVNAME "_hwmon",
 	},
 	.probe		= w83627hf_probe,
 	.remove		= __devexit_p(w83627hf_remove),
@@ -1126,80 +1042,6 @@ show_name(struct device *dev, struct device_attribute *devattr, char *buf)
 }
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
-static int __init w83627hf_find(int sioaddr, unsigned short *addr,
-				struct w83627hf_sio_data *sio_data)
-{
-	int err = -ENODEV;
-	u16 val;
-
-	static const __initdata char *names[] = {
-		"W83627HF",
-		"W83627THF",
-		"W83697HF",
-		"W83637HF",
-		"W83687THF",
-	};
-
-	REG = sioaddr;
-	VAL = sioaddr + 1;
-
-	superio_enter();
-	val = force_id ? force_id : superio_inb(DEVID);
-	switch (val) {
-	case W627_DEVID:
-		sio_data->type = w83627hf;
-		break;
-	case W627THF_DEVID:
-		sio_data->type = w83627thf;
-		break;
-	case W697_DEVID:
-		sio_data->type = w83697hf;
-		break;
-	case W637_DEVID:
-		sio_data->type = w83637hf;
-		break;
-	case W687THF_DEVID:
-		sio_data->type = w83687thf;
-		break;
-	case 0xff:	/* No device at all */
-		goto exit;
-	default:
-		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
-		goto exit;
-	}
-
-	superio_select(W83627HF_LD_HWM);
-	force_addr &= WINB_ALIGNMENT;
-	if (force_addr) {
-		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
-		       force_addr);
-		superio_outb(WINB_BASE_REG, force_addr >> 8);
-		superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
-	}
-	val = (superio_inb(WINB_BASE_REG) << 8) |
-	       superio_inb(WINB_BASE_REG + 1);
-	*addr = val & WINB_ALIGNMENT;
-	if (*addr = 0) {
-		printk(KERN_WARNING DRVNAME ": Base address not set, "
-		       "skipping\n");
-		goto exit;
-	}
-
-	val = superio_inb(WINB_ACT_REG);
-	if (!(val & 0x01)) {
-		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
-		superio_outb(WINB_ACT_REG, val | 0x01);
-	}
-
-	err = 0;
-	pr_info(DRVNAME ": Found %s chip at %#x\n",
-		names[sio_data->type], *addr);
-
- exit:
-	superio_exit();
-	return err;
-}
-
 #define VIN_UNIT_ATTRS(_X_)	\
 	&sensor_dev_attr_in##_X_##_input.dev_attr.attr,		\
 	&sensor_dev_attr_in##_X_##_min.dev_attr.attr,		\
@@ -1278,27 +1120,89 @@ static const struct attribute_group w83627hf_group_opt = {
 	.attrs = w83627hf_attributes_opt,
 };
 
+static int w83627hf_enable_hwmon(struct w83627hf_sio_data *sio_data)
+{
+	u16 val;
+	int ret;
+
+	superio_enter(sio_data);
+
+	superio_select(sio_data, W83627HF_LD_HWM);
+
+	force_addr &= (~7);
+	if (force_addr) {
+		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
+			force_addr);
+		superio_outb(sio_data, 0x60, force_addr >> 8);
+		superio_outb(sio_data, 0x60 + 1, force_addr & 0xff);
+	}
+
+	val = (superio_inb(sio_data, 0x60) << 8) |
+	       superio_inb(sio_data, 0x60 + 1);
+	ret = val & (~7);
+	pr_info(DRVNAME ": hwmon chip %s at %#x\n", sio_data->name, ret);
+
+	if (ret = 0) {
+		printk(KERN_WARNING DRVNAME ": Base address not set, "
+		       "skipping\n");
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	val = superio_inb(sio_data, 0x30);
+	superio_outb(sio_data, 0x30, val | 0x01);
+
+exit:
+	superio_exit(sio_data);
+
+	return ret;
+}
+
+static void w83627hf_disable_hwmon(struct w83627hf_sio_data *sio_data)
+{
+	u16 val;
+
+	superio_enter(sio_data);
+
+	superio_select(sio_data, W83627HF_LD_HWM);
+
+	val = superio_inb(sio_data, 0x30);
+	superio_outb(sio_data, 0x30, val & ~0x01);
+
+	superio_exit(sio_data);
+}
+
 static int __devinit w83627hf_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct w83627hf_sio_data *sio_data = dev->platform_data;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	struct w83627hf_data *data;
-	struct resource *res;
 	int err, i;
 
-	static const char *names[] = {
-		"w83627hf",
-		"w83627thf",
-		"w83697hf",
-		"w83637hf",
-		"w83687thf",
+	struct resource res = {
+		.start  = /* address + */ WINB_REGION_OFFSET,
+		.end    = /* address + */ WINB_REGION_OFFSET +
+						WINB_REGION_SIZE - 1,
+		.name   = DRVNAME "_hwmon",
+		.flags  = IORESOURCE_IO,
 	};
 
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
+	err = w83627hf_enable_hwmon(sio_data);
+	if (err < 0)
+		return err;
+
+	/* Before doing our job we should fixup ioport range */
+	res.start += err;
+	res.end += err;
+
+	err = acpi_check_resource_conflict(&res);
+	if (err)
+		goto ERROR0;
+
+	if (!request_region(res.start, WINB_REGION_SIZE, DRVNAME "_hwmon")) {
 		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
-			(unsigned long)res->start,
-			(unsigned long)(res->start + WINB_REGION_SIZE - 1));
+			(unsigned long) res.start,
+			(unsigned long) (res.start + WINB_REGION_SIZE - 1));
 		err = -EBUSY;
 		goto ERROR0;
 	}
@@ -1307,9 +1211,9 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 		err = -ENOMEM;
 		goto ERROR1;
 	}
-	data->addr = res->start;
+	data->addr = res.start;
 	data->type = sio_data->type;
-	data->name = names[sio_data->type];
+	data->name = sio_data->name;
 	mutex_init(&data->lock);
 	mutex_init(&data->update_lock);
 	platform_set_drvdata(pdev, data);
@@ -1442,15 +1346,20 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, NULL);
 	kfree(data);
       ERROR1:
-	release_region(res->start, WINB_REGION_SIZE);
+	release_region(res.start, WINB_REGION_SIZE);
       ERROR0:
+	w83627hf_disable_hwmon(sio_data);
 	return err;
 }
 
 static int __devexit w83627hf_remove(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	struct w83627hf_data *data = platform_get_drvdata(pdev);
-	struct resource *res;
+	unsigned int addr = data->addr;
+
+	w83627hf_disable_hwmon(sio_data);
 
 	hwmon_device_unregister(data->hwmon_dev);
 
@@ -1459,8 +1368,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
 	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	release_region(res->start, WINB_REGION_SIZE);
+	release_region(addr, WINB_REGION_SIZE);
 
 	return 0;
 }
@@ -1511,20 +1419,22 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
 
 static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	int res = 0xff, sel;
 
-	superio_enter();
-	superio_select(W83627HF_LD_GPIO5);
+	superio_enter(sio_data);
+	superio_select(sio_data, W83627HF_LD_GPIO5);
 
 	/* Make sure these GPIO pins are enabled */
-	if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
+	if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) {
 		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
 		goto exit;
 	}
 
 	/* Make sure the pins are configured for input
 	   There must be at least five (VRM 9), and possibly 6 (VRM 10) */
-	sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
+	sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f;
 	if ((sel & 0x1f) != 0x1f) {
 		dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
 			"function\n");
@@ -1532,37 +1442,39 @@ static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
 	}
 
 	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
-	res = superio_inb(W83627THF_GPIO5_DR) & sel;
+	res = superio_inb(sio_data, W83627THF_GPIO5_DR) & sel;
 
 exit:
-	superio_exit();
+	superio_exit(sio_data);
 	return res;
 }
 
 static int __devinit w83687thf_read_vid(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
 	int res = 0xff;
 
-	superio_enter();
-	superio_select(W83627HF_LD_HWM);
+	superio_enter(sio_data);
+	superio_select(sio_data, W83627HF_LD_HWM);
 
 	/* Make sure these GPIO pins are enabled */
-	if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
+	if (!(superio_inb(sio_data, W83687THF_VID_EN) & (1 << 2))) {
 		dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
 		goto exit;
 	}
 
 	/* Make sure the pins are configured for input */
-	if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
+	if (!(superio_inb(sio_data, W83687THF_VID_CFG) & (1 << 4))) {
 		dev_dbg(&pdev->dev, "VID configured as output, "
 			"no VID function\n");
 		goto exit;
 	}
 
-	res = superio_inb(W83687THF_VID_DATA) & 0x3f;
+	res = superio_inb(sio_data, W83687THF_VID_DATA) & 0x3f;
 
 exit:
-	superio_exit();
+	superio_exit(sio_data);
 	return res;
 }
 
@@ -1783,94 +1695,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 	return data;
 }
 
-static int __init w83627hf_device_add(unsigned short address,
-				      const struct w83627hf_sio_data *sio_data)
-{
-	struct resource res = {
-		.start	= address + WINB_REGION_OFFSET,
-		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
-		.name	= DRVNAME,
-		.flags	= IORESOURCE_IO,
-	};
-	int err;
-
-	err = acpi_check_resource_conflict(&res);
-	if (err)
-		goto exit;
-
-	pdev = platform_device_alloc(DRVNAME, address);
-	if (!pdev) {
-		err = -ENOMEM;
-		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
-		goto exit;
-	}
-
-	err = platform_device_add_resources(pdev, &res, 1);
-	if (err) {
-		printk(KERN_ERR DRVNAME ": Device resource addition failed "
-		       "(%d)\n", err);
-		goto exit_device_put;
-	}
-
-	err = platform_device_add_data(pdev, sio_data,
-				       sizeof(struct w83627hf_sio_data));
-	if (err) {
-		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
-		goto exit_device_put;
-	}
-
-	err = platform_device_add(pdev);
-	if (err) {
-		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
-		       err);
-		goto exit_device_put;
-	}
-
-	return 0;
-
-exit_device_put:
-	platform_device_put(pdev);
-exit:
-	return err;
-}
-
 static int __init sensors_w83627hf_init(void)
 {
-	int err;
-	unsigned short address;
-	struct w83627hf_sio_data sio_data;
-
-	if (w83627hf_find(0x2e, &address, &sio_data)
-	 && w83627hf_find(0x4e, &address, &sio_data))
-		return -ENODEV;
-
-	err = platform_driver_register(&w83627hf_driver);
-	if (err)
-		goto exit;
-
-	/* Sets global pdev as a side effect */
-	err = w83627hf_device_add(address, &sio_data);
-	if (err)
-		goto exit_driver;
-
-	return 0;
-
-exit_driver:
-	platform_driver_unregister(&w83627hf_driver);
-exit:
-	return err;
+	return platform_driver_register(&w83627hf_driver);
 }
 
 static void __exit sensors_w83627hf_exit(void)
 {
-	platform_device_unregister(pdev);
 	platform_driver_unregister(&w83627hf_driver);
 }
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
 	      "Philip Edelbrock <phil@netroedge.com>, "
 	      "and Mark Studebaker <mdsxyz123@yahoo.com>");
-MODULE_DESCRIPTION("W83627HF driver");
+MODULE_DESCRIPTION("W83627HF hwmon driver");
 MODULE_LICENSE("GPL");
 
 module_init(sensors_w83627hf_init);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 570be13..1c875ed 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -305,6 +305,21 @@ config EZX_PCAP
 	  This enables the PCAP ASIC present on EZX Phones. This is
 	  needed for MMC, TouchScreen, Sound, USB, etc..
 
+config MFD_W83627HF
+	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
+	depends on MFD_CORE
+	help
+	  If you say yes here you add support for the Winbond W836X7 series
+	  of super-IO chips: the W83627HF, W83627THF, W83637HF, W83687THF and
+	  W83697HF to your platform.
+
+	  This is a multi functional device and this support defines a new
+	  platform device only. See other configuration submenus in order to
+	  enable the drivers of Winbond chip's functionalities.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83627hf-core.
+
 endmenu
 
 menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f3b277b..1b25d37 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_MFD_MC13783)	+= mc13783-core.o
 obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
 
 obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
+obj-$(CONFIG_MFD_W83627HF)	+= w83627hf-core.o
 
 obj-$(CONFIG_MCP)		+= mcp-core.o
 obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
diff --git a/drivers/mfd/w83627hf-core.c b/drivers/mfd/w83627hf-core.c
new file mode 100644
index 0000000..e70e15e
--- /dev/null
+++ b/drivers/mfd/w83627hf-core.c
@@ -0,0 +1,186 @@
+/*
+ *  w83627hf.c - platform device support
+ *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
+ *
+ *  Based on drivers/hwmon/w83627hf.c
+ *
+ *  Original copyright note:
+ *    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
+ *    Philip Edelbrock <phil@netroedge.com>,
+ *    and Mark Studebaker <mdsxyz123@yahoo.com>
+ *    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
+ *    Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
+ *
+ *    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
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/w83627hf.h>
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+/*
+ * Devices definitions
+ */
+
+static struct platform_device *pdev;
+
+static char *names[] = {
+	"w83627hf",
+	"w83627thf",
+	"w83697hf",
+	"w83637hf",
+	"w83687thf",
+};
+
+static struct mfd_cell cells[] = {
+	{
+		.name		= DRVNAME "_hwmon",
+	},
+};
+
+#define W627_DEVID		0x52
+#define W627THF_DEVID		0x82
+#define W697_DEVID		0x60
+#define W637_DEVID		0x70
+#define W687THF_DEVID		0x85
+
+static int __init w83627hf_find(int sioaddr, struct w83627hf_sio_data *sio_data)
+{
+	int err = -ENODEV;
+	u16 val;
+
+	sio_data->sioaddr = sioaddr;
+
+	superio_enter(sio_data);
+
+	val = force_id ? force_id : superio_inb(sio_data, 0x20);
+	switch (val) {
+	case W627_DEVID:
+		sio_data->type = w83627hf;
+		break;
+	case W627THF_DEVID:
+		sio_data->type = w83627thf;
+		break;
+	case W697_DEVID:
+		sio_data->type = w83697hf;
+		break;
+	case W637_DEVID:
+		sio_data->type = w83637hf;
+		break;
+	case W687THF_DEVID:
+		sio_data->type = w83687thf;
+		break;
+	case 0xff:	/* No device at all */
+		goto exit;
+	default:
+		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
+		goto exit;
+	}
+
+	err = 0;
+	sio_data->name = names[sio_data->type];
+
+	pr_info(DRVNAME ": Found %s chip at %#x\n", sio_data->name, sioaddr);
+
+exit:
+	superio_exit(sio_data);
+
+	return err;
+}
+
+static int __init w83627hf_device_add(const struct w83627hf_sio_data *sio_data)
+{
+	int err;
+
+	pdev = platform_device_alloc(DRVNAME, 0);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct w83627hf_sio_data));
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	err = mfd_add_devices(&pdev->dev, pdev->id, cells, ARRAY_SIZE(cells),
+			0, -1);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Cannot add sub devices (%d)\n",
+			err);
+		goto exit_device_unregister;
+	}
+
+	return 0;
+
+exit_device_unregister:
+	platform_device_unregister(pdev);
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int __init w83627hf_init(void)
+{
+	struct w83627hf_sio_data sio_data;
+	int ret;
+
+	mutex_init(&sio_data.lock);
+
+	ret = w83627hf_find(0x2e, &sio_data);
+	if (ret) {
+		ret = w83627hf_find(0x4e, &sio_data);
+		if (ret)
+			return -ENODEV;
+	}
+
+	/* Sets global pdev as a side effect */
+	return w83627hf_device_add(&sio_data);
+}
+
+static void __exit w83627hf_exit(void)
+{
+	mfd_remove_devices(&pdev->dev);
+	platform_device_unregister(pdev);
+}
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("W83627HF platform devices definitions");
+MODULE_LICENSE("GPL");
+
+module_init(w83627hf_init);
+module_exit(w83627hf_exit);
diff --git a/include/linux/mfd/w83627hf.h b/include/linux/mfd/w83627hf.h
new file mode 100644
index 0000000..5f4200b
--- /dev/null
+++ b/include/linux/mfd/w83627hf.h
@@ -0,0 +1,118 @@
+/*
+ *  w83627hf.h - platform device support, header file
+ *  Copyright (c) 2009 Rodolfo Giometti <giometti@linux.it>
+ *
+ *  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
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#define DRVNAME "w83627hf"
+
+enum chips {
+	w83627hf,
+	w83627thf,
+	w83697hf,
+	w83637hf,
+	w83687thf
+};
+
+struct w83627hf_sio_data {
+	int sioaddr;
+	enum chips type;
+	char *name;
+
+	struct mutex lock;
+};
+
+/* logical device numbers for superio_select (below) */
+#define W83627HF_LD_FDC		0x00
+#define W83627HF_LD_PRT		0x01
+#define W83627HF_LD_UART1	0x02
+#define W83627HF_LD_UART2	0x03
+#define W83627HF_LD_KBC		0x05
+#define W83627HF_LD_CIR		0x06 /* w83627hf only */
+#define W83627HF_LD_GAME	0x07
+#define W83627HF_LD_MIDI	0x07
+#define W83627HF_LD_GPIO1	0x07
+#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
+#define W83627HF_LD_GPIO2	0x08
+#define W83627HF_LD_GPIO3	0x09
+#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
+#define W83627HF_LD_ACPI	0x0a
+#define W83627HF_LD_HWM		0x0b
+
+#define W83627THF_GPIO5_EN	0x30 /* w83627thf only */
+#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
+#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
+
+#define W83687THF_VID_EN	0x29 /* w83687thf only */
+#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
+#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
+
+/*
+ * Common configuration registers access functions.
+ *
+ * These registers are special and they must me accessed by using a well
+ * specified protocol. Client drivers __must__ do as follow in order to
+ * get access correctly to these registers:
+ *
+ *	superio_enter()
+ *
+ *	superio_select()/superio_outb()/superio_inb()
+ *
+ *	superio_exit();
+ *
+ */
+
+static inline void superio_enter(struct w83627hf_sio_data *sio)
+{
+	mutex_lock(&sio->lock);
+
+	outb(0x87, sio->sioaddr);
+	outb(0x87, sio->sioaddr);
+}
+
+static inline void superio_select(struct w83627hf_sio_data *sio, int ld)
+{
+	WARN_ON(!mutex_is_locked(&sio->lock));
+
+	outb(0x07, sio->sioaddr);
+	outb(ld, sio->sioaddr + 1);
+}
+
+static inline void superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
+{
+	WARN_ON(!mutex_is_locked(&sio->lock));
+
+	outb(reg, sio->sioaddr);
+	outb(val, sio->sioaddr + 1);
+}
+
+static inline int superio_inb(struct w83627hf_sio_data *sio, int reg)
+{
+	WARN_ON(!mutex_is_locked(&sio->lock));
+
+	outb(reg, sio->sioaddr);
+	return inb(sio->sioaddr + 1);
+}
+
+static inline void superio_exit(struct w83627hf_sio_data *sio)
+{
+	outb(0xAA, sio->sioaddr);
+
+	mutex_unlock(&sio->lock);
+}
-- 
1.6.3.3


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2011-09-22  9:11 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-09-10 12:30 [lm-sensors] [PATCH] hwmon w83627hf: add mfd support Rodolfo Giometti
2009-09-10 12:56 ` Jean Delvare
2009-09-11  7:42 ` Rodolfo Giometti
2009-09-11 10:58 ` Samuel Ortiz
2009-09-11 15:07 ` Rodolfo Giometti
2009-09-15 11:38 ` Samuel Ortiz
2009-09-17 13:34 ` Jean Delvare
2009-09-17 13:51 ` Rodolfo Giometti
2009-09-17 13:57 ` Jean Delvare
2009-09-17 14:03 ` Rodolfo Giometti
2009-09-17 14:07 ` Jean Delvare
2009-09-17 14:34 ` Samuel Ortiz
2009-09-18  7:42 ` Jean Delvare
2009-09-18  8:01 ` Samuel Ortiz
2009-09-18 11:02 ` Rodolfo Giometti
2009-09-18 12:09 ` Rodolfo Giometti
2009-09-18 14:42 ` Samuel Ortiz
2009-09-18 14:49 ` Jean Delvare
2009-09-18 16:16 ` Jean Delvare
2009-09-20 23:48 ` Samuel Ortiz
2009-09-22  8:22 ` Rodolfo Giometti
2009-09-22  8:26 ` Rodolfo Giometti
2009-09-22  8:33 ` Rodolfo Giometti
2009-10-01 13:23 ` Jean Delvare
2009-10-01 13:53 ` Samuel Ortiz
2009-11-02 13:23 ` Jean Delvare
2009-11-03  8:17 ` Rodolfo Giometti
2010-02-10 12:18 Rodolfo Giometti
2010-02-27 10:58 ` Jean Delvare
2011-09-22  9:11 ` Rodolfo Giometti

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.