X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fhwmon%2Fw83627ehf.c;h=0dcaba9b7189c26cd242a2acfb72804e083a7f70;hb=0abbb609ac511fc226b8b1082613193c8ecf8324;hp=833faa275ffaed22b8eb5caa57172a965595ca7a;hpb=3379ceeefde923a05c2c77ed2d84ba26c2fe9e81;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 833faa2..0dcaba9 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -3,8 +3,9 @@ the Winbond W83627EHF Super-I/O chip Copyright (C) 2005 Jean Delvare Copyright (C) 2006 Yuan Mu (Winbond), - Rudolf Marek + Rudolf Marek David Hubbard + Daniel J Blueman Shamelessly ripped from the w83627hf driver Copyright (C) 2003 Mark Studebaker @@ -32,91 +33,119 @@ Supports the following chips: - Chip #vin #fan #pwm #temp chip_id man_id - w83627ehf 10 5 4 3 0x88,0xa1 0x5ca3 + Chip #vin #fan #pwm #temp chip IDs man ID + w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 + 0x8860 0xa1 + w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 + w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3 + w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 */ #include #include #include -#include -#include +#include +#include #include #include +#include #include #include -#include +#include +#include #include "lm75.h" -/* The actual ISA address is read from Super-I/O configuration space */ -static unsigned short address; +enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg }; + +/* used to set data->name = w83627ehf_device_names[data->sio_kind] */ +static const char * w83627ehf_device_names[] = { + "w83627ehf", + "w83627dhg", + "w83627dhg", + "w83667hg", +}; + +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + +#define DRVNAME "w83627ehf" /* * Super-I/O constants and functions */ -static int REG; /* The register to read/write */ -static int VAL; /* The value to read/write */ - #define W83627EHF_LD_HWM 0x0b +#define W83667HG_LD_VID 0x0d #define SIO_REG_LDSEL 0x07 /* Logical device select */ #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ +#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */ #define SIO_REG_ENABLE 0x30 /* Logical device enable */ #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ +#define SIO_REG_VID_CTRL 0xF0 /* VID control */ +#define SIO_REG_VID_DATA 0xF1 /* VID data */ -#define SIO_W83627EHF_ID 0x8840 -#define SIO_ID_MASK 0xFFC0 +#define SIO_W83627EHF_ID 0x8850 +#define SIO_W83627EHG_ID 0x8860 +#define SIO_W83627DHG_ID 0xa020 +#define SIO_W83627DHG_P_ID 0xb070 +#define SIO_W83667HG_ID 0xa510 +#define SIO_ID_MASK 0xFFF0 static inline void -superio_outb(int reg, int val) +superio_outb(int ioreg, int reg, int val) { - outb(reg, REG); - outb(val, VAL); + outb(reg, ioreg); + outb(val, ioreg + 1); } static inline int -superio_inb(int reg) +superio_inb(int ioreg, int reg) { - outb(reg, REG); - return inb(VAL); + outb(reg, ioreg); + return inb(ioreg + 1); } static inline void -superio_select(int ld) +superio_select(int ioreg, int ld) { - outb(SIO_REG_LDSEL, REG); - outb(ld, VAL); + outb(SIO_REG_LDSEL, ioreg); + outb(ld, ioreg + 1); } static inline void -superio_enter(void) +superio_enter(int ioreg) { - outb(0x87, REG); - outb(0x87, REG); + outb(0x87, ioreg); + outb(0x87, ioreg); } static inline void -superio_exit(void) +superio_exit(int ioreg) { - outb(0x02, REG); - outb(0x02, VAL); + outb(0x02, ioreg); + outb(0x02, ioreg + 1); } /* * ISA constants */ -#define REGION_ALIGNMENT ~7 -#define REGION_OFFSET 5 -#define REGION_LENGTH 2 -#define ADDR_REG_OFFSET 5 -#define DATA_REG_OFFSET 6 +#define IOREGION_ALIGNMENT ~7 +#define IOREGION_OFFSET 5 +#define IOREGION_LENGTH 2 +#define ADDR_REG_OFFSET 0 +#define DATA_REG_OFFSET 1 #define W83627EHF_REG_BANK 0x4E #define W83627EHF_REG_CONFIG 0x40 -#define W83627EHF_REG_CHIP_ID 0x49 -#define W83627EHF_REG_MAN_ID 0x4F + +/* Not currently used: + * REG_MAN_ID has the value 0x5ca3 for all supported chips. + * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model. + * REG_MAN_ID is at port 0x4f + * REG_CHIP_ID is at port 0x58 */ static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; @@ -149,12 +178,15 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 }; #define W83627EHF_REG_ALARM3 0x45B /* SmartFan registers */ +#define W83627EHF_REG_FAN_STEPUP_TIME 0x0f +#define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e + /* DC or PWM output fan configuration */ static const u8 W83627EHF_REG_PWM_ENABLE[] = { 0x04, /* SYS FAN0 output mode and PWM mode */ 0x04, /* CPU FAN0 output mode and PWM mode */ 0x12, /* AUX FAN mode */ - 0x62, /* CPU fan1 mode */ + 0x62, /* CPU FAN1 mode */ }; static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 }; @@ -165,10 +197,12 @@ static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 }; static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 }; static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 }; - /* Advanced Fan control, some values are common for all fans */ -static const u8 W83627EHF_REG_FAN_MIN_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 }; -static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0C, 0x0D, 0x17, 0x66 }; +static const u8 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 }; +static const u8 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 }; +static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 }; +static const u8 W83627EHF_REG_FAN_MAX_OUTPUT[] = { 0xff, 0x67, 0xff, 0x69 }; +static const u8 W83627EHF_REG_FAN_STEP_OUTPUT[] = { 0xff, 0x68, 0xff, 0x6a }; /* * Conversions @@ -207,7 +241,7 @@ temp1_from_reg(s8 reg) } static inline s8 -temp1_to_reg(int temp, int min, int max) +temp1_to_reg(long temp, int min, int max) { if (temp <= min) return min / 1000; @@ -237,8 +271,10 @@ static inline u8 in_to_reg(u32 val, u8 nr) */ struct w83627ehf_data { - struct i2c_client client; - struct class_device *class_dev; + int addr; /* IO base of hw monitor block */ + const char *name; + + struct device *hwmon_dev; struct mutex lock; struct mutex update_lock; @@ -246,6 +282,7 @@ struct w83627ehf_data { unsigned long last_updated; /* In jiffies */ /* Register values */ + u8 in_num; /* number of in inputs we have */ u8 in[10]; /* Register value */ u8 in_max[10]; /* Register value */ u8 in_min[10]; /* Register value */ @@ -253,6 +290,7 @@ struct w83627ehf_data { u8 fan_min[5]; u8 fan_div[5]; u8 has_fan; /* some fan inputs can be disabled */ + u8 temp_type[3]; s8 temp1; s8 temp1_max; s8 temp1_max_hyst; @@ -263,13 +301,30 @@ struct w83627ehf_data { u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ u8 pwm_enable[4]; /* 1->manual - 2->thermal cruise (also called SmartFan I) */ + 2->thermal cruise mode (also called SmartFan I) + 3->fan speed cruise mode + 4->variable thermal cruise (also called SmartFan III) */ + u8 pwm_num; /* number of pwm */ u8 pwm[4]; u8 target_temp[4]; u8 tolerance[4]; - u8 fan_min_output[4]; /* minimum fan speed */ - u8 fan_stop_time[4]; + u8 fan_start_output[4]; /* minimum fan speed when spinning up */ + u8 fan_stop_output[4]; /* minimum fan speed when spinning down */ + u8 fan_stop_time[4]; /* time at minimum before disabling fan */ + u8 fan_max_output[4]; /* maximum fan speed */ + u8 fan_step_output[4]; /* rate of change output value */ + + u8 vid; + u8 vrm; + + u8 temp3_disable; + u8 in6_skip; +}; + +struct w83627ehf_sio_data { + int sioreg; + enum kinds kind; }; static inline int is_word_sized(u16 reg) @@ -281,156 +336,161 @@ static inline int is_word_sized(u16 reg) || (reg & 0x00ff) == 0x55)); } -/* We assume that the default bank is 0, thus the following two functions do - nothing for registers which live in bank 0. For others, they respectively - set the bank register to the correct value (before the register is - accessed), and back to 0 (afterwards). */ -static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg) +/* Registers 0x50-0x5f are banked */ +static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg) { - if (reg & 0xff00) { - outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); - outb_p(reg >> 8, client->addr + DATA_REG_OFFSET); + if ((reg & 0x00f0) == 0x50) { + outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET); + outb_p(reg >> 8, data->addr + DATA_REG_OFFSET); } } -static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg) +/* Not strictly necessary, but play it safe for now */ +static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg) { if (reg & 0xff00) { - outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); - outb_p(0, client->addr + DATA_REG_OFFSET); + outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET); + outb_p(0, data->addr + DATA_REG_OFFSET); } } -static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg) +static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg) { - struct w83627ehf_data *data = i2c_get_clientdata(client); int res, word_sized = is_word_sized(reg); mutex_lock(&data->lock); - w83627ehf_set_bank(client, reg); - outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); - res = inb_p(client->addr + DATA_REG_OFFSET); + w83627ehf_set_bank(data, reg); + outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET); + res = inb_p(data->addr + DATA_REG_OFFSET); if (word_sized) { outb_p((reg & 0xff) + 1, - client->addr + ADDR_REG_OFFSET); - res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET); + data->addr + ADDR_REG_OFFSET); + res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET); } - w83627ehf_reset_bank(client, reg); + w83627ehf_reset_bank(data, reg); mutex_unlock(&data->lock); return res; } -static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value) +static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value) { - struct w83627ehf_data *data = i2c_get_clientdata(client); int word_sized = is_word_sized(reg); mutex_lock(&data->lock); - w83627ehf_set_bank(client, reg); - outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); + w83627ehf_set_bank(data, reg); + outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET); if (word_sized) { - outb_p(value >> 8, client->addr + DATA_REG_OFFSET); + outb_p(value >> 8, data->addr + DATA_REG_OFFSET); outb_p((reg & 0xff) + 1, - client->addr + ADDR_REG_OFFSET); + data->addr + ADDR_REG_OFFSET); } - outb_p(value & 0xff, client->addr + DATA_REG_OFFSET); - w83627ehf_reset_bank(client, reg); + outb_p(value & 0xff, data->addr + DATA_REG_OFFSET); + w83627ehf_reset_bank(data, reg); mutex_unlock(&data->lock); return 0; } /* This function assumes that the caller holds data->update_lock */ -static void w83627ehf_write_fan_div(struct i2c_client *client, int nr) +static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr) { - struct w83627ehf_data *data = i2c_get_clientdata(client); u8 reg; switch (nr) { case 0: - reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf) + reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf) | ((data->fan_div[0] & 0x03) << 4); - w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); - reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf) + /* fan5 input control bit is write only, compute the value */ + reg |= (data->has_fan & (1 << 4)) ? 1 : 0; + w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg); + reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf) | ((data->fan_div[0] & 0x04) << 3); - w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg); break; case 1: - reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f) + reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f) | ((data->fan_div[1] & 0x03) << 6); - w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); - reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf) + /* fan5 input control bit is write only, compute the value */ + reg |= (data->has_fan & (1 << 4)) ? 1 : 0; + w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg); + reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf) | ((data->fan_div[1] & 0x04) << 4); - w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg); break; case 2: - reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f) + reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f) | ((data->fan_div[2] & 0x03) << 6); - w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg); - reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f) + w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg); + reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f) | ((data->fan_div[2] & 0x04) << 5); - w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg); break; case 3: - reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc) + reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc) | (data->fan_div[3] & 0x03); - w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); - reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f) + w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg); + reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f) | ((data->fan_div[3] & 0x04) << 5); - w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg); + w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg); break; case 4: - reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73) - | ((data->fan_div[4] & 0x03) << 3) + reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73) + | ((data->fan_div[4] & 0x03) << 2) | ((data->fan_div[4] & 0x04) << 5); - w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); + w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg); break; } } +static void w83627ehf_update_fan_div(struct w83627ehf_data *data) +{ + int i; + + i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2); + data->fan_div[2] = (i >> 6) & 0x03; + i = w83627ehf_read_value(data, W83627EHF_REG_VBAT); + data->fan_div[0] |= (i >> 3) & 0x04; + data->fan_div[1] |= (i >> 4) & 0x04; + data->fan_div[2] |= (i >> 5) & 0x04; + if (data->has_fan & ((1 << 3) | (1 << 4))) { + i = w83627ehf_read_value(data, W83627EHF_REG_DIODE); + data->fan_div[3] = i & 0x03; + data->fan_div[4] = ((i >> 2) & 0x03) + | ((i >> 5) & 0x04); + } + if (data->has_fan & (1 << 3)) { + i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT); + data->fan_div[3] |= (i >> 5) & 0x04; + } +} + static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627ehf_data *data = i2c_get_clientdata(client); + struct w83627ehf_data *data = dev_get_drvdata(dev); int pwmcfg = 0, tolerance = 0; /* shut up the compiler */ int i; mutex_lock(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ) + if (time_after(jiffies, data->last_updated + HZ + HZ/2) || !data->valid) { /* Fan clock dividers */ - i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2); - data->fan_div[2] = (i >> 6) & 0x03; - i = w83627ehf_read_value(client, W83627EHF_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - data->fan_div[2] |= (i >> 5) & 0x04; - if (data->has_fan & ((1 << 3) | (1 << 4))) { - i = w83627ehf_read_value(client, W83627EHF_REG_DIODE); - data->fan_div[3] = i & 0x03; - data->fan_div[4] = ((i >> 2) & 0x03) - | ((i >> 5) & 0x04); - } - if (data->has_fan & (1 << 3)) { - i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT); - data->fan_div[3] |= (i >> 5) & 0x04; - } + w83627ehf_update_fan_div(data); /* Measured voltages and limits */ - for (i = 0; i < 10; i++) { - data->in[i] = w83627ehf_read_value(client, + for (i = 0; i < data->in_num; i++) { + data->in[i] = w83627ehf_read_value(data, W83627EHF_REG_IN(i)); - data->in_min[i] = w83627ehf_read_value(client, + data->in_min[i] = w83627ehf_read_value(data, W83627EHF_REG_IN_MIN(i)); - data->in_max[i] = w83627ehf_read_value(client, + data->in_max[i] = w83627ehf_read_value(data, W83627EHF_REG_IN_MAX(i)); } @@ -439,9 +499,9 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) if (!(data->has_fan & (1 << i))) continue; - data->fan[i] = w83627ehf_read_value(client, + data->fan[i] = w83627ehf_read_value(data, W83627EHF_REG_FAN[i]); - data->fan_min[i] = w83627ehf_read_value(client, + data->fan_min[i] = w83627ehf_read_value(data, W83627EHF_REG_FAN_MIN[i]); /* If we failed to measure the fan speed and clock @@ -449,27 +509,27 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) time */ if (data->fan[i] == 0xff && data->fan_div[i] < 0x07) { - dev_dbg(&client->dev, "Increasing fan %d " + dev_dbg(dev, "Increasing fan%d " "clock divider from %u to %u\n", - i, div_from_reg(data->fan_div[i]), + i + 1, div_from_reg(data->fan_div[i]), div_from_reg(data->fan_div[i] + 1)); data->fan_div[i]++; - w83627ehf_write_fan_div(client, i); + w83627ehf_write_fan_div(data, i); /* Preserve min limit if possible */ if (data->fan_min[i] >= 2 && data->fan_min[i] != 255) - w83627ehf_write_value(client, + w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[i], (data->fan_min[i] /= 2)); } } for (i = 0; i < 4; i++) { - /* pwmcfg, tolarance mapped for i=0, i=1 to same reg */ + /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */ if (i != 1) { - pwmcfg = w83627ehf_read_value(client, + pwmcfg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[i]); - tolerance = w83627ehf_read_value(client, + tolerance = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[i]); } data->pwm_mode[i] = @@ -478,14 +538,16 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) data->pwm_enable[i] = ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i]) & 3) + 1; - data->pwm[i] = w83627ehf_read_value(client, + data->pwm[i] = w83627ehf_read_value(data, W83627EHF_REG_PWM[i]); - data->fan_min_output[i] = w83627ehf_read_value(client, - W83627EHF_REG_FAN_MIN_OUTPUT[i]); - data->fan_stop_time[i] = w83627ehf_read_value(client, + data->fan_start_output[i] = w83627ehf_read_value(data, + W83627EHF_REG_FAN_START_OUTPUT[i]); + data->fan_stop_output[i] = w83627ehf_read_value(data, + W83627EHF_REG_FAN_STOP_OUTPUT[i]); + data->fan_stop_time[i] = w83627ehf_read_value(data, W83627EHF_REG_FAN_STOP_TIME[i]); data->target_temp[i] = - w83627ehf_read_value(client, + w83627ehf_read_value(data, W83627EHF_REG_TARGET[i]) & (data->pwm_mode[i] == 1 ? 0x7f : 0xff); data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) @@ -493,26 +555,26 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) } /* Measured temperatures and limits */ - data->temp1 = w83627ehf_read_value(client, + data->temp1 = w83627ehf_read_value(data, W83627EHF_REG_TEMP1); - data->temp1_max = w83627ehf_read_value(client, + data->temp1_max = w83627ehf_read_value(data, W83627EHF_REG_TEMP1_OVER); - data->temp1_max_hyst = w83627ehf_read_value(client, + data->temp1_max_hyst = w83627ehf_read_value(data, W83627EHF_REG_TEMP1_HYST); for (i = 0; i < 2; i++) { - data->temp[i] = w83627ehf_read_value(client, + data->temp[i] = w83627ehf_read_value(data, W83627EHF_REG_TEMP[i]); - data->temp_max[i] = w83627ehf_read_value(client, + data->temp_max[i] = w83627ehf_read_value(data, W83627EHF_REG_TEMP_OVER[i]); - data->temp_max_hyst[i] = w83627ehf_read_value(client, + data->temp_max_hyst[i] = w83627ehf_read_value(data, W83627EHF_REG_TEMP_HYST[i]); } - data->alarms = w83627ehf_read_value(client, + data->alarms = w83627ehf_read_value(data, W83627EHF_REG_ALARM1) | - (w83627ehf_read_value(client, + (w83627ehf_read_value(data, W83627EHF_REG_ALARM2) << 8) | - (w83627ehf_read_value(client, + (w83627ehf_read_value(data, W83627EHF_REG_ALARM3) << 16); data->last_updated = jiffies; @@ -545,15 +607,14 @@ static ssize_t \ store_in_##reg (struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627ehf_data *data = i2c_get_clientdata(client); \ + struct w83627ehf_data *data = dev_get_drvdata(dev); \ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ int nr = sensor_attr->index; \ u32 val = simple_strtoul(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ data->in_##reg[nr] = in_to_reg(val, nr); \ - w83627ehf_write_value(client, W83627EHF_REG_IN_##REG(nr), \ + w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \ data->in_##reg[nr]); \ mutex_unlock(&data->update_lock); \ return count; \ @@ -651,8 +712,7 @@ static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627ehf_data *data = i2c_get_clientdata(client); + struct w83627ehf_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; unsigned int val = simple_strtoul(buf, NULL, 10); @@ -694,18 +754,25 @@ store_fan_min(struct device *dev, struct device_attribute *attr, /* Write both the fan clock divider (if it changed) and the new fan min (unconditionally) */ if (new_div != data->fan_div[nr]) { - if (new_div > data->fan_div[nr]) - data->fan[nr] >>= (data->fan_div[nr] - new_div); - else - data->fan[nr] <<= (new_div - data->fan_div[nr]); + /* Preserve the fan speed reading */ + if (data->fan[nr] != 0xff) { + if (new_div > data->fan_div[nr]) + data->fan[nr] >>= new_div - data->fan_div[nr]; + else if (data->fan[nr] & 0x80) + data->fan[nr] = 0xff; + else + data->fan[nr] <<= data->fan_div[nr] - new_div; + } dev_dbg(dev, "fan%u clock divider changed from %u to %u\n", nr + 1, div_from_reg(data->fan_div[nr]), div_from_reg(new_div)); data->fan_div[nr] = new_div; - w83627ehf_write_fan_div(client, nr); + w83627ehf_write_fan_div(data, nr); + /* Give the chip time to sample a new speed value */ + data->last_updated = jiffies; } - w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr], + w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr], data->fan_min[nr]); mutex_unlock(&data->update_lock); @@ -766,13 +833,12 @@ static ssize_t \ store_temp1_##reg(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627ehf_data *data = i2c_get_clientdata(client); \ - u32 val = simple_strtoul(buf, NULL, 10); \ + struct w83627ehf_data *data = dev_get_drvdata(dev); \ + long val = simple_strtol(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \ - w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \ + w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \ data->temp1_##reg); \ mutex_unlock(&data->update_lock); \ return count; \ @@ -800,15 +866,14 @@ static ssize_t \ store_##reg(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627ehf_data *data = i2c_get_clientdata(client); \ + struct w83627ehf_data *data = dev_get_drvdata(dev); \ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ int nr = sensor_attr->index; \ - u32 val = simple_strtoul(buf, NULL, 10); \ + long val = simple_strtol(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ data->reg[nr] = LM75_TEMP_TO_REG(val); \ - w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \ + w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \ data->reg[nr]); \ mutex_unlock(&data->update_lock); \ return count; \ @@ -816,27 +881,51 @@ store_##reg(struct device *dev, struct device_attribute *attr, \ store_temp_reg(OVER, temp_max); store_temp_reg(HYST, temp_max_hyst); -static struct sensor_device_attribute sda_temp[] = { +static ssize_t +show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627ehf_data *data = w83627ehf_update_device(dev); + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + return sprintf(buf, "%d\n", (int)data->temp_type[nr]); +} + +static struct sensor_device_attribute sda_temp_input[] = { SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0), SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0), SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1), +}; + +static struct sensor_device_attribute sda_temp_max[] = { SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max, store_temp1_max, 0), SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max, store_temp_max, 0), SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max, store_temp_max, 1), +}; + +static struct sensor_device_attribute sda_temp_max_hyst[] = { SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst, store_temp1_max_hyst, 0), SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, store_temp_max_hyst, 0), SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, store_temp_max_hyst, 1), +}; + +static struct sensor_device_attribute sda_temp_alarm[] = { SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4), SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5), SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), }; +static struct sensor_device_attribute sda_temp_type[] = { + SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0), + SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1), + SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2), +}; + #define show_pwm_reg(reg) \ static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \ char *buf) \ @@ -855,8 +944,7 @@ static ssize_t store_pwm_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627ehf_data *data = i2c_get_clientdata(client); + struct w83627ehf_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; u32 val = simple_strtoul(buf, NULL, 10); @@ -865,12 +953,12 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, if (val > 1) return -EINVAL; mutex_lock(&data->update_lock); - reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]); + reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]); data->pwm_mode[nr] = val; reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]); if (!val) reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr]; - w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg); + w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg); mutex_unlock(&data->update_lock); return count; } @@ -879,15 +967,14 @@ static ssize_t store_pwm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627ehf_data *data = i2c_get_clientdata(client); + struct w83627ehf_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255); mutex_lock(&data->update_lock); data->pwm[nr] = val; - w83627ehf_write_value(client, W83627EHF_REG_PWM[nr], val); + w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val); mutex_unlock(&data->update_lock); return count; } @@ -896,21 +983,20 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627ehf_data *data = i2c_get_clientdata(client); + struct w83627ehf_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; u32 val = simple_strtoul(buf, NULL, 10); u16 reg; - if (!val || (val > 2)) /* only modes 1 and 2 are supported */ + if (!val || (val > 4)) return -EINVAL; mutex_lock(&data->update_lock); - reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]); + reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]); data->pwm_enable[nr] = val; reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]); reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr]; - w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg); + w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg); mutex_unlock(&data->update_lock); return count; } @@ -933,15 +1019,14 @@ static ssize_t store_target_temp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627ehf_data *data = i2c_get_clientdata(client); + struct w83627ehf_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000); mutex_lock(&data->update_lock); data->target_temp[nr] = val; - w83627ehf_write_value(client, W83627EHF_REG_TARGET[nr], val); + w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val); mutex_unlock(&data->update_lock); return count; } @@ -950,8 +1035,7 @@ static ssize_t store_tolerance(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct w83627ehf_data *data = i2c_get_clientdata(client); + struct w83627ehf_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; u16 reg; @@ -959,13 +1043,13 @@ store_tolerance(struct device *dev, struct device_attribute *attr, u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000); mutex_lock(&data->update_lock); - reg = w83627ehf_read_value(client, W83627EHF_REG_TOLERANCE[nr]); + reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]); data->tolerance[nr] = val; if (nr == 1) reg = (reg & 0x0f) | (val << 4); else reg = (reg & 0xf0) | val; - w83627ehf_write_value(client, W83627EHF_REG_TOLERANCE[nr], reg); + w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg); mutex_unlock(&data->update_lock); return count; } @@ -1036,19 +1120,21 @@ static ssize_t \ store_##reg(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ {\ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627ehf_data *data = i2c_get_clientdata(client); \ + struct w83627ehf_data *data = dev_get_drvdata(dev); \ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ int nr = sensor_attr->index; \ u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \ mutex_lock(&data->update_lock); \ data->reg[nr] = val; \ - w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \ + w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \ mutex_unlock(&data->update_lock); \ return count; \ } -fan_functions(fan_min_output, FAN_MIN_OUTPUT) +fan_functions(fan_start_output, FAN_START_OUTPUT) +fan_functions(fan_stop_output, FAN_STOP_OUTPUT) +fan_functions(fan_max_output, FAN_MAX_OUTPUT) +fan_functions(fan_step_output, FAN_STEP_OUTPUT) #define fan_time_functions(reg, REG) \ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ @@ -1065,27 +1151,40 @@ static ssize_t \ store_##reg(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627ehf_data *data = i2c_get_clientdata(client); \ + struct w83627ehf_data *data = dev_get_drvdata(dev); \ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ int nr = sensor_attr->index; \ u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \ data->pwm_mode[nr]); \ mutex_lock(&data->update_lock); \ data->reg[nr] = val; \ - w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \ + w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \ mutex_unlock(&data->update_lock); \ return count; \ } \ fan_time_functions(fan_stop_time, FAN_STOP_TIME) +static ssize_t show_name(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct w83627ehf_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", data->name); +} +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); static struct sensor_device_attribute sda_sf3_arrays_fan4[] = { SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, store_fan_stop_time, 3), - SENSOR_ATTR(pwm4_min_output, S_IWUSR | S_IRUGO, show_fan_min_output, - store_fan_min_output, 3), + SENSOR_ATTR(pwm4_start_output, S_IWUSR | S_IRUGO, show_fan_start_output, + store_fan_start_output, 3), + SENSOR_ATTR(pwm4_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output, + store_fan_stop_output, 3), + SENSOR_ATTR(pwm4_max_output, S_IWUSR | S_IRUGO, show_fan_max_output, + store_fan_max_output, 3), + SENSOR_ATTR(pwm4_step_output, S_IWUSR | S_IRUGO, show_fan_step_output, + store_fan_step_output, 3), }; static struct sensor_device_attribute sda_sf3_arrays[] = { @@ -1095,16 +1194,36 @@ static struct sensor_device_attribute sda_sf3_arrays[] = { store_fan_stop_time, 1), SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, store_fan_stop_time, 2), - SENSOR_ATTR(pwm1_min_output, S_IWUSR | S_IRUGO, show_fan_min_output, - store_fan_min_output, 0), - SENSOR_ATTR(pwm2_min_output, S_IWUSR | S_IRUGO, show_fan_min_output, - store_fan_min_output, 1), - SENSOR_ATTR(pwm3_min_output, S_IWUSR | S_IRUGO, show_fan_min_output, - store_fan_min_output, 2), + SENSOR_ATTR(pwm1_start_output, S_IWUSR | S_IRUGO, show_fan_start_output, + store_fan_start_output, 0), + SENSOR_ATTR(pwm2_start_output, S_IWUSR | S_IRUGO, show_fan_start_output, + store_fan_start_output, 1), + SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output, + store_fan_start_output, 2), + SENSOR_ATTR(pwm1_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output, + store_fan_stop_output, 0), + SENSOR_ATTR(pwm2_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output, + store_fan_stop_output, 1), + SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output, + store_fan_stop_output, 2), + + /* pwm1 and pwm3 don't support max and step settings */ + SENSOR_ATTR(pwm2_max_output, S_IWUSR | S_IRUGO, show_fan_max_output, + store_fan_max_output, 1), + SENSOR_ATTR(pwm2_step_output, S_IWUSR | S_IRUGO, show_fan_step_output, + store_fan_step_output, 1), }; +static ssize_t +show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627ehf_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + /* - * Driver and client management + * Driver and device management */ static void w83627ehf_device_remove_files(struct device *dev) @@ -1112,12 +1231,15 @@ static void w83627ehf_device_remove_files(struct device *dev) /* some entries in the following arrays may not have been used in * device_create_file(), but device_remove_file() will ignore them */ int i; + struct w83627ehf_data *data = dev_get_drvdata(dev); for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) device_remove_file(dev, &sda_sf3_arrays[i].dev_attr); for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr); - for (i = 0; i < 10; i++) { + for (i = 0; i < data->in_num; i++) { + if ((i == 6) && data->in6_skip) + continue; device_remove_file(dev, &sda_in_input[i].dev_attr); device_remove_file(dev, &sda_in_alarm[i].dev_attr); device_remove_file(dev, &sda_in_min[i].dev_attr); @@ -1129,52 +1251,81 @@ static void w83627ehf_device_remove_files(struct device *dev) device_remove_file(dev, &sda_fan_div[i].dev_attr); device_remove_file(dev, &sda_fan_min[i].dev_attr); } - for (i = 0; i < 4; i++) { + for (i = 0; i < data->pwm_num; i++) { device_remove_file(dev, &sda_pwm[i].dev_attr); device_remove_file(dev, &sda_pwm_mode[i].dev_attr); device_remove_file(dev, &sda_pwm_enable[i].dev_attr); device_remove_file(dev, &sda_target_temp[i].dev_attr); device_remove_file(dev, &sda_tolerance[i].dev_attr); } - for (i = 0; i < ARRAY_SIZE(sda_temp); i++) - device_remove_file(dev, &sda_temp[i].dev_attr); -} + for (i = 0; i < 3; i++) { + if ((i == 2) && data->temp3_disable) + continue; + device_remove_file(dev, &sda_temp_input[i].dev_attr); + device_remove_file(dev, &sda_temp_max[i].dev_attr); + device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr); + device_remove_file(dev, &sda_temp_alarm[i].dev_attr); + device_remove_file(dev, &sda_temp_type[i].dev_attr); + } -static struct i2c_driver w83627ehf_driver; + device_remove_file(dev, &dev_attr_name); + device_remove_file(dev, &dev_attr_cpu0_vid); +} -static void w83627ehf_init_client(struct i2c_client *client) +/* Get the monitoring functions started */ +static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data) { int i; - u8 tmp; + u8 tmp, diode; /* Start monitoring is needed */ - tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG); + tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG); if (!(tmp & 0x01)) - w83627ehf_write_value(client, W83627EHF_REG_CONFIG, + w83627ehf_write_value(data, W83627EHF_REG_CONFIG, tmp | 0x01); /* Enable temp2 and temp3 if needed */ for (i = 0; i < 2; i++) { - tmp = w83627ehf_read_value(client, + tmp = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[i]); + if ((i == 1) && data->temp3_disable) + continue; if (tmp & 0x01) - w83627ehf_write_value(client, + w83627ehf_write_value(data, W83627EHF_REG_TEMP_CONFIG[i], tmp & 0xfe); } + + /* Enable VBAT monitoring if needed */ + tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT); + if (!(tmp & 0x01)) + w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01); + + /* Get thermal sensor types */ + diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE); + for (i = 0; i < 3; i++) { + if ((tmp & (0x02 << i))) + data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2; + else + data->temp_type[i] = 4; /* thermistor */ + } } -static int w83627ehf_detect(struct i2c_adapter *adapter) +static int __devinit w83627ehf_probe(struct platform_device *pdev) { - struct i2c_client *client; + struct device *dev = &pdev->dev; + struct w83627ehf_sio_data *sio_data = dev->platform_data; struct w83627ehf_data *data; - struct device *dev; - u8 fan4pin, fan5pin; + struct resource *res; + u8 fan4pin, fan5pin, en_vrm10; int i, err = 0; - if (!request_region(address + REGION_OFFSET, REGION_LENGTH, - w83627ehf_driver.driver.name)) { + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) { err = -EBUSY; + dev_err(dev, "Failed to request region 0x%lx-0x%lx\n", + (unsigned long)res->start, + (unsigned long)res->start + IOREGION_LENGTH - 1); goto exit; } @@ -1183,48 +1334,106 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) goto exit_release; } - client = &data->client; - i2c_set_clientdata(client, data); - client->addr = address; + data->addr = res->start; mutex_init(&data->lock); - client->adapter = adapter; - client->driver = &w83627ehf_driver; - client->flags = 0; - dev = &client->dev; - - strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE); - data->valid = 0; mutex_init(&data->update_lock); - - /* Tell the i2c layer a new client has arrived */ - if ((err = i2c_attach_client(client))) - goto exit_free; + data->name = w83627ehf_device_names[sio_data->kind]; + platform_set_drvdata(pdev, data); + + /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */ + data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9; + /* 667HG has 3 pwms */ + data->pwm_num = (sio_data->kind == w83667hg) ? 3 : 4; + + /* Check temp3 configuration bit for 667HG */ + if (sio_data->kind == w83667hg) { + data->temp3_disable = w83627ehf_read_value(data, + W83627EHF_REG_TEMP_CONFIG[1]) & 0x01; + data->in6_skip = !data->temp3_disable; + } /* Initialize the chip */ - w83627ehf_init_client(client); + w83627ehf_init_device(data); + + data->vrm = vid_which_vrm(); + superio_enter(sio_data->sioreg); + /* Read VID value */ + if (sio_data->kind == w83667hg) { + /* W83667HG has different pins for VID input and output, so + we can get the VID input values directly at logical device D + 0xe3. */ + superio_select(sio_data->sioreg, W83667HG_LD_VID); + data->vid = superio_inb(sio_data->sioreg, 0xe3); + err = device_create_file(dev, &dev_attr_cpu0_vid); + if (err) + goto exit_release; + } else { + superio_select(sio_data->sioreg, W83627EHF_LD_HWM); + if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) { + /* Set VID input sensibility if needed. In theory the + BIOS should have set it, but in practice it's not + always the case. We only do it for the W83627EHF/EHG + because the W83627DHG is more complex in this + respect. */ + if (sio_data->kind == w83627ehf) { + en_vrm10 = superio_inb(sio_data->sioreg, + SIO_REG_EN_VRM10); + if ((en_vrm10 & 0x08) && data->vrm == 90) { + dev_warn(dev, "Setting VID input " + "voltage to TTL\n"); + superio_outb(sio_data->sioreg, + SIO_REG_EN_VRM10, + en_vrm10 & ~0x08); + } else if (!(en_vrm10 & 0x08) + && data->vrm == 100) { + dev_warn(dev, "Setting VID input " + "voltage to VRM10\n"); + superio_outb(sio_data->sioreg, + SIO_REG_EN_VRM10, + en_vrm10 | 0x08); + } + } - /* A few vars need to be filled upon startup */ - for (i = 0; i < 5; i++) - data->fan_min[i] = w83627ehf_read_value(client, - W83627EHF_REG_FAN_MIN[i]); + data->vid = superio_inb(sio_data->sioreg, + SIO_REG_VID_DATA); + if (sio_data->kind == w83627ehf) /* 6 VID pins only */ + data->vid &= 0x3f; + + err = device_create_file(dev, &dev_attr_cpu0_vid); + if (err) + goto exit_release; + } else { + dev_info(dev, "VID pins in output mode, CPU VID not " + "available\n"); + } + } /* fan4 and fan5 share some pins with the GPIO and serial flash */ - - superio_enter(); - fan5pin = superio_inb(0x24) & 0x2; - fan4pin = superio_inb(0x29) & 0x6; - superio_exit(); + if (sio_data->kind == w83667hg) { + fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20; + fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40; + } else { + fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02); + fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06); + } + superio_exit(sio_data->sioreg); /* It looks like fan4 and fan5 pins can be alternatively used - as fan on/off switches */ + as fan on/off switches, but fan5 control is write only :/ + We assume that if the serial interface is disabled, designers + connected fan5 as input unless they are emitting log 1, which + is not the default. */ data->has_fan = 0x07; /* fan1, fan2 and fan3 */ - i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); - if ((i & (1 << 2)) && (!fan4pin)) + i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); + if ((i & (1 << 2)) && fan4pin) data->has_fan |= (1 << 3); - if ((i & (1 << 0)) && (!fan5pin)) + if (!(i & (1 << 1)) && fan5pin) data->has_fan |= (1 << 4); + /* Read fan clock dividers immediately */ + w83627ehf_update_fan_div(data); + /* Register sysfs hooks */ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) if ((err = device_create_file(dev, @@ -1232,14 +1441,16 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) goto exit_remove; /* if fan4 is enabled create the sf3 files for it */ - if (data->has_fan & (1 << 3)) + if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4) for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) { if ((err = device_create_file(dev, &sda_sf3_arrays_fan4[i].dev_attr))) goto exit_remove; } - for (i = 0; i < 10; i++) + for (i = 0; i < data->in_num; i++) { + if ((i == 6) && data->in6_skip) + continue; if ((err = device_create_file(dev, &sda_in_input[i].dev_attr)) || (err = device_create_file(dev, &sda_in_alarm[i].dev_attr)) @@ -1248,6 +1459,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) || (err = device_create_file(dev, &sda_in_max[i].dev_attr))) goto exit_remove; + } for (i = 0; i < 5; i++) { if (data->has_fan & (1 << i)) { @@ -1260,7 +1472,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) || (err = device_create_file(dev, &sda_fan_min[i].dev_attr))) goto exit_remove; - if (i < 4 && /* w83627ehf only has 4 pwm */ + if (i < data->pwm_num && ((err = device_create_file(dev, &sda_pwm[i].dev_attr)) || (err = device_create_file(dev, @@ -1275,13 +1487,29 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) } } - for (i = 0; i < ARRAY_SIZE(sda_temp); i++) - if ((err = device_create_file(dev, &sda_temp[i].dev_attr))) + for (i = 0; i < 3; i++) { + if ((i == 2) && data->temp3_disable) + continue; + if ((err = device_create_file(dev, + &sda_temp_input[i].dev_attr)) + || (err = device_create_file(dev, + &sda_temp_max[i].dev_attr)) + || (err = device_create_file(dev, + &sda_temp_max_hyst[i].dev_attr)) + || (err = device_create_file(dev, + &sda_temp_alarm[i].dev_attr)) + || (err = device_create_file(dev, + &sda_temp_type[i].dev_attr))) goto exit_remove; + } + + err = device_create_file(dev, &dev_attr_name); + if (err) + goto exit_remove; - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -1289,85 +1517,190 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) exit_remove: w83627ehf_device_remove_files(dev); - i2c_detach_client(client); -exit_free: kfree(data); + platform_set_drvdata(pdev, NULL); exit_release: - release_region(address + REGION_OFFSET, REGION_LENGTH); + release_region(res->start, IOREGION_LENGTH); exit: return err; } -static int w83627ehf_detach_client(struct i2c_client *client) +static int __devexit w83627ehf_remove(struct platform_device *pdev) { - struct w83627ehf_data *data = i2c_get_clientdata(client); - int err; - - hwmon_device_unregister(data->class_dev); - w83627ehf_device_remove_files(&client->dev); + struct w83627ehf_data *data = platform_get_drvdata(pdev); - if ((err = i2c_detach_client(client))) - return err; - release_region(client->addr + REGION_OFFSET, REGION_LENGTH); + hwmon_device_unregister(data->hwmon_dev); + w83627ehf_device_remove_files(&pdev->dev); + release_region(data->addr, IOREGION_LENGTH); + platform_set_drvdata(pdev, NULL); kfree(data); return 0; } -static struct i2c_driver w83627ehf_driver = { +static struct platform_driver w83627ehf_driver = { .driver = { .owner = THIS_MODULE, - .name = "w83627ehf", + .name = DRVNAME, }, - .attach_adapter = w83627ehf_detect, - .detach_client = w83627ehf_detach_client, + .probe = w83627ehf_probe, + .remove = __devexit_p(w83627ehf_remove), }; -static int __init w83627ehf_find(int sioaddr, unsigned short *addr) +/* w83627ehf_find() looks for a '627 in the Super-I/O config space */ +static int __init w83627ehf_find(int sioaddr, unsigned short *addr, + struct w83627ehf_sio_data *sio_data) { + static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; + static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; + static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; + static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P"; + static const char __initdata sio_name_W83667HG[] = "W83667HG"; + u16 val; + const char *sio_name; - REG = sioaddr; - VAL = sioaddr + 1; - superio_enter(); + superio_enter(sioaddr); - val = (superio_inb(SIO_REG_DEVID) << 8) - | superio_inb(SIO_REG_DEVID + 1); - if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) { - superio_exit(); + if (force_id) + val = force_id; + else + val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) + | superio_inb(sioaddr, SIO_REG_DEVID + 1); + switch (val & SIO_ID_MASK) { + case SIO_W83627EHF_ID: + sio_data->kind = w83627ehf; + sio_name = sio_name_W83627EHF; + break; + case SIO_W83627EHG_ID: + sio_data->kind = w83627ehf; + sio_name = sio_name_W83627EHG; + break; + case SIO_W83627DHG_ID: + sio_data->kind = w83627dhg; + sio_name = sio_name_W83627DHG; + break; + case SIO_W83627DHG_P_ID: + sio_data->kind = w83627dhg_p; + sio_name = sio_name_W83627DHG_P; + break; + case SIO_W83667HG_ID: + sio_data->kind = w83667hg; + sio_name = sio_name_W83667HG; + break; + default: + if (val != 0xffff) + pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n", + val); + superio_exit(sioaddr); return -ENODEV; } - superio_select(W83627EHF_LD_HWM); - val = (superio_inb(SIO_REG_ADDR) << 8) - | superio_inb(SIO_REG_ADDR + 1); - *addr = val & REGION_ALIGNMENT; + /* We have a known chip, find the HWM I/O address */ + superio_select(sioaddr, W83627EHF_LD_HWM); + val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8) + | superio_inb(sioaddr, SIO_REG_ADDR + 1); + *addr = val & IOREGION_ALIGNMENT; if (*addr == 0) { - superio_exit(); + printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O " + "device with a base I/O port 0.\n"); + superio_exit(sioaddr); return -ENODEV; } /* Activate logical device if needed */ - val = superio_inb(SIO_REG_ENABLE); - if (!(val & 0x01)) - superio_outb(SIO_REG_ENABLE, val | 0x01); + val = superio_inb(sioaddr, SIO_REG_ENABLE); + if (!(val & 0x01)) { + printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. " + "Sensor is probably unusable.\n"); + superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01); + } + + superio_exit(sioaddr); + pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr); + sio_data->sioreg = sioaddr; - superio_exit(); return 0; } +/* when Super-I/O functions move to a separate file, the Super-I/O + * bus will manage the lifetime of the device and this module will only keep + * track of the w83627ehf driver. But since we platform_device_alloc(), we + * must keep track of the device */ +static struct platform_device *pdev; + static int __init sensors_w83627ehf_init(void) { - if (w83627ehf_find(0x2e, &address) - && w83627ehf_find(0x4e, &address)) + int err; + unsigned short address; + struct resource res; + struct w83627ehf_sio_data sio_data; + + /* initialize sio_data->kind and sio_data->sioreg. + * + * when Super-I/O functions move to a separate file, the Super-I/O + * driver will probe 0x2e and 0x4e and auto-detect the presence of a + * w83627ehf hardware monitor, and call probe() */ + if (w83627ehf_find(0x2e, &address, &sio_data) && + w83627ehf_find(0x4e, &address, &sio_data)) return -ENODEV; - return i2c_isa_add_driver(&w83627ehf_driver); + err = platform_driver_register(&w83627ehf_driver); + if (err) + goto exit; + + if (!(pdev = platform_device_alloc(DRVNAME, address))) { + err = -ENOMEM; + printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + goto exit_unregister; + } + + err = platform_device_add_data(pdev, &sio_data, + sizeof(struct w83627ehf_sio_data)); + if (err) { + printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); + goto exit_device_put; + } + + memset(&res, 0, sizeof(res)); + res.name = DRVNAME; + res.start = address + IOREGION_OFFSET; + res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1; + res.flags = IORESOURCE_IO; + + err = acpi_check_resource_conflict(&res); + if (err) + goto exit_device_put; + + 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; + } + + /* platform_device_add calls probe() */ + 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_unregister: + platform_driver_unregister(&w83627ehf_driver); +exit: + return err; } static void __exit sensors_w83627ehf_exit(void) { - i2c_isa_del_driver(&w83627ehf_driver); + platform_device_unregister(pdev); + platform_driver_unregister(&w83627ehf_driver); } MODULE_AUTHOR("Jean Delvare ");