X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fhwmon%2Fw83627ehf.c;h=feae743ba99163c2475b0f51663c89fc7e7f1375;hb=9f5bc7f1908665d7cf379f698c7bdc53bc10da85;hp=e615b8378fc3313a7f4f79a8121ee6e12d07b2e5;hpb=475ef85512900dcb87435e13656c1f5e724de379;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index e615b83..feae743 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -45,8 +45,10 @@ #include #include #include +#include #include #include +#include #include #include "lm75.h" @@ -58,6 +60,10 @@ static const char * w83627ehf_device_names[] = { "w83627dhg", }; +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + #define DRVNAME "w83627ehf" /* @@ -68,8 +74,11 @@ static const char * w83627ehf_device_names[] = { #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 0x8850 #define SIO_W83627EHG_ID 0x8860 @@ -219,7 +228,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; @@ -252,7 +261,7 @@ struct w83627ehf_data { int addr; /* IO base of hw monitor block */ const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; struct mutex update_lock; @@ -268,6 +277,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; @@ -285,6 +295,9 @@ struct w83627ehf_data { u8 fan_min_output[4]; /* minimum fan speed */ u8 fan_stop_time[4]; + + u8 vid; + u8 vrm; }; struct w83627ehf_sio_data { @@ -301,18 +314,16 @@ 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). */ +/* Registers 0x50-0x5f are banked */ static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg) { - if (reg & 0xff00) { + if ((reg & 0x00f0) == 0x50) { outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET); outb_p(reg >> 8, data->addr + DATA_REG_OFFSET); } } +/* Not strictly necessary, but play it safe for now */ static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg) { if (reg & 0xff00) { @@ -413,6 +424,31 @@ static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr) } } +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 w83627ehf_data *data = dev_get_drvdata(dev); @@ -421,28 +457,10 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) 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(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; - } + w83627ehf_update_fan_div(data); /* Measured voltages and limits */ for (i = 0; i < data->in_num; i++) { @@ -485,7 +503,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) } 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(data, W83627EHF_REG_PWM_ENABLE[i]); @@ -727,6 +745,8 @@ store_fan_min(struct device *dev, struct device_attribute *attr, div_from_reg(new_div)); data->fan_div[nr] = new_div; w83627ehf_write_fan_div(data, nr); + /* Give the chip time to sample a new speed value */ + data->last_updated = jiffies; } w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr], data->fan_min[nr]); @@ -790,7 +810,7 @@ store_temp1_##reg(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ struct w83627ehf_data *data = dev_get_drvdata(dev); \ - u32 val = simple_strtoul(buf, NULL, 10); \ + long val = simple_strtol(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \ @@ -825,7 +845,7 @@ store_##reg(struct device *dev, struct device_attribute *attr, \ 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); \ @@ -837,6 +857,15 @@ store_##reg(struct device *dev, struct device_attribute *attr, \ store_temp_reg(OVER, temp_max); store_temp_reg(HYST, temp_max_hyst); +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[] = { SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0), SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0), @@ -856,6 +885,9 @@ static struct sensor_device_attribute sda_temp[] = { 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), + 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) \ @@ -1125,6 +1157,14 @@ static struct sensor_device_attribute sda_sf3_arrays[] = { store_fan_min_output, 2), }; +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 device management */ @@ -1163,13 +1203,14 @@ static void w83627ehf_device_remove_files(struct device *dev) device_remove_file(dev, &sda_temp[i].dev_attr); device_remove_file(dev, &dev_attr_name); + device_remove_file(dev, &dev_attr_cpu0_vid); } /* 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(data, W83627EHF_REG_CONFIG); @@ -1186,6 +1227,20 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *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 __devinit w83627ehf_probe(struct platform_device *pdev) @@ -1194,7 +1249,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) struct w83627ehf_sio_data *sio_data = dev->platform_data; struct w83627ehf_data *data; struct resource *res; - u8 fan4pin, fan5pin; + u8 fan4pin, fan5pin, en_vrm10; int i, err = 0; res = platform_get_resource(pdev, IORESOURCE_IO, 0); @@ -1223,14 +1278,45 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) /* Initialize the chip */ w83627ehf_init_device(data); - /* A few vars need to be filled upon startup */ - for (i = 0; i < 5; i++) - data->fan_min[i] = w83627ehf_read_value(data, - W83627EHF_REG_FAN_MIN[i]); + data->vrm = vid_which_vrm(); + superio_enter(sio_data->sioreg); + /* Read VID value */ + superio_select(sio_data->sioreg, W83627EHF_LD_HWM); + if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) { + /* Set VID input sensibility if needed. In theory the BIOS + should have set it, but in practice it's not always the + case. We only do it for the W83627EHF/EHG because the + W83627DHG is more complex in this respect. */ + if (sio_data->kind == w83627ehf) { + en_vrm10 = superio_inb(sio_data->sioreg, + SIO_REG_EN_VRM10); + if ((en_vrm10 & 0x08) && data->vrm == 90) { + dev_warn(dev, "Setting VID input voltage to " + "TTL\n"); + superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10, + en_vrm10 & ~0x08); + } else if (!(en_vrm10 & 0x08) && data->vrm == 100) { + dev_warn(dev, "Setting VID input voltage to " + "VRM10\n"); + superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10, + en_vrm10 | 0x08); + } + } + + data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA); + if (sio_data->kind == w83627ehf) /* 6 VID pins only */ + data->vid &= 0x3f; + + 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(sio_data->sioreg); fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2; fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6; superio_exit(sio_data->sioreg); @@ -1248,6 +1334,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) 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, @@ -1306,9 +1395,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) 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; } @@ -1328,7 +1417,7 @@ static int __devexit w83627ehf_remove(struct platform_device *pdev) { struct w83627ehf_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); w83627ehf_device_remove_files(&pdev->dev); release_region(data->addr, IOREGION_LENGTH); platform_set_drvdata(pdev, NULL); @@ -1359,8 +1448,11 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, superio_enter(sioaddr); - val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) - | superio_inb(sioaddr, SIO_REG_DEVID + 1); + 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; @@ -1375,8 +1467,9 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, sio_name = sio_name_W83627DHG; break; default: - pr_info(DRVNAME ": unsupported chip ID: 0x%04x\n", - val); + if (val != 0xffff) + pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n", + val); superio_exit(sioaddr); return -ENODEV; } @@ -1452,6 +1545,11 @@ static int __init sensors_w83627ehf_init(void) 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 "