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@xxxxxxxx> > --- > 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@xxxxxx>, > Philip Edelbrock <phil@xxxxxxxxxxxxx>, > and Mark Studebaker <mdsxyz123@xxxxxxxxx> > @@ -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@xxxxxx>, " > "Philip Edelbrock <phil@xxxxxxxxxxxxx>, " > "and Mark Studebaker <mdsxyz123@xxxxxxxxx>"); > -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@xxxxxxxx> > + * > + * Based on drivers/hwmon/w83627hf.c > + * > + * Original copyright note: > + * Copyright (c) 1998 - 2003 Frodo Looijaard <frodol@xxxxxx>, > + * Philip Edelbrock <phil@xxxxxxxxxxxxx>, > + * and Mark Studebaker <mdsxyz123@xxxxxxxxx> > + * Ported to 2.6 by Bernhard C. Schrenk <clemy@xxxxxxxxx> > + * Copyright (c) 2007 Jean Delvare <khali@xxxxxxxxxxxx> > + * > + * 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@xxxxxxxx>"); > +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@xxxxxxxxxxxxxx http://lists.lm-sensors.org/mailman/listinfo/lm-sensors