X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fhwmon%2Ff71805f.c;h=525a00bd70b1c457c25a831e3017bf8d7b1afba4;hb=b00bc0b237055b4c45816325ee14f0bd83e6f590;hp=7c2973487122cd139b22081225cbcbefefa28bae;hpb=a117dddf6bb27478e6903c9cb242601b6f45b11c;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 7c29734..525a00b 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -10,6 +10,9 @@ * The F71872F/FG is almost the same, with two more voltages monitored, * and 6 VID inputs. * + * The F71806F/FG is essentially the same as the F71872F/FG. It even has + * the same chip ID, so the driver can't differentiate between. + * * 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 @@ -35,7 +38,13 @@ #include #include #include -#include +#include +#include +#include + +static unsigned short force_id; +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); static struct platform_device *pdev; @@ -126,6 +135,13 @@ superio_exit(int base) #define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr)) #define F71805F_REG_TEMP_HYST(nr) (0x55 + 2 * (nr)) #define F71805F_REG_TEMP_MODE 0x01 +/* pwm/fan pwmnr from 0 to 2, auto point apnr from 0 to 2 */ +/* map Fintek numbers to our numbers as follows: 9->0, 5->1, 1->2 */ +#define F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr) \ + (0xA0 + 0x10 * (pwmnr) + (2 - (apnr))) +#define F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr) \ + (0xA4 + 0x10 * (pwmnr) + \ + 2 * (2 - (apnr))) #define F71805F_REG_START 0x00 /* status nr from 0 to 2 */ @@ -143,10 +159,15 @@ superio_exit(int base) * Data structures and manipulation thereof */ +struct f71805f_auto_point { + u8 temp[3]; + u16 fan[3]; +}; + struct f71805f_data { unsigned short addr; const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ @@ -169,6 +190,7 @@ struct f71805f_data { u8 temp_hyst[3]; u8 temp_mode; unsigned long alarms; + struct f71805f_auto_point auto_points[3]; }; struct f71805f_sio_data { @@ -311,7 +333,7 @@ static void f71805f_write16(struct f71805f_data *data, u8 reg, u16 val) static struct f71805f_data *f71805f_update_device(struct device *dev) { struct f71805f_data *data = dev_get_drvdata(dev); - int nr; + int nr, apnr; mutex_lock(&data->update_lock); @@ -341,6 +363,18 @@ static struct f71805f_data *f71805f_update_device(struct device *dev) F71805F_REG_TEMP_HYST(nr)); } data->temp_mode = f71805f_read8(data, F71805F_REG_TEMP_MODE); + for (nr = 0; nr < 3; nr++) { + for (apnr = 0; apnr < 3; apnr++) { + data->auto_points[nr].temp[apnr] = + f71805f_read8(data, + F71805F_REG_PWM_AUTO_POINT_TEMP(nr, + apnr)); + data->auto_points[nr].fan[apnr] = + f71805f_read16(data, + F71805F_REG_PWM_AUTO_POINT_FAN(nr, + apnr)); + } + } data->last_limits = jiffies; } @@ -704,6 +738,70 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute return count; } +static ssize_t show_pwm_auto_point_temp(struct device *dev, + struct device_attribute *devattr, + char* buf) +{ + struct f71805f_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); + int pwmnr = attr->nr; + int apnr = attr->index; + + return sprintf(buf, "%ld\n", + temp_from_reg(data->auto_points[pwmnr].temp[apnr])); +} + +static ssize_t set_pwm_auto_point_temp(struct device *dev, + struct device_attribute *devattr, + const char* buf, size_t count) +{ + struct f71805f_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); + int pwmnr = attr->nr; + int apnr = attr->index; + unsigned long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->auto_points[pwmnr].temp[apnr] = temp_to_reg(val); + f71805f_write8(data, F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr), + data->auto_points[pwmnr].temp[apnr]); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_pwm_auto_point_fan(struct device *dev, + struct device_attribute *devattr, + char* buf) +{ + struct f71805f_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); + int pwmnr = attr->nr; + int apnr = attr->index; + + return sprintf(buf, "%ld\n", + fan_from_reg(data->auto_points[pwmnr].fan[apnr])); +} + +static ssize_t set_pwm_auto_point_fan(struct device *dev, + struct device_attribute *devattr, + const char* buf, size_t count) +{ + struct f71805f_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); + int pwmnr = attr->nr; + int apnr = attr->index; + unsigned long val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->auto_points[pwmnr].fan[apnr] = fan_to_reg(val); + f71805f_write16(data, F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr), + data->auto_points[pwmnr].fan[apnr]); + mutex_unlock(&data->update_lock); + + return count; +} + static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -931,6 +1029,63 @@ static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq, 2); static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR, + show_pwm_auto_point_temp, set_pwm_auto_point_temp, + 0, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_fan, S_IRUGO | S_IWUSR, + show_pwm_auto_point_fan, set_pwm_auto_point_fan, + 0, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR, + show_pwm_auto_point_temp, set_pwm_auto_point_temp, + 0, 1); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_fan, S_IRUGO | S_IWUSR, + show_pwm_auto_point_fan, set_pwm_auto_point_fan, + 0, 1); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR, + show_pwm_auto_point_temp, set_pwm_auto_point_temp, + 0, 2); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_fan, S_IRUGO | S_IWUSR, + show_pwm_auto_point_fan, set_pwm_auto_point_fan, + 0, 2); + +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR, + show_pwm_auto_point_temp, set_pwm_auto_point_temp, + 1, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_fan, S_IRUGO | S_IWUSR, + show_pwm_auto_point_fan, set_pwm_auto_point_fan, + 1, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR, + show_pwm_auto_point_temp, set_pwm_auto_point_temp, + 1, 1); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_fan, S_IRUGO | S_IWUSR, + show_pwm_auto_point_fan, set_pwm_auto_point_fan, + 1, 1); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR, + show_pwm_auto_point_temp, set_pwm_auto_point_temp, + 1, 2); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_fan, S_IRUGO | S_IWUSR, + show_pwm_auto_point_fan, set_pwm_auto_point_fan, + 1, 2); + +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR, + show_pwm_auto_point_temp, set_pwm_auto_point_temp, + 2, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_fan, S_IRUGO | S_IWUSR, + show_pwm_auto_point_fan, set_pwm_auto_point_fan, + 2, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR, + show_pwm_auto_point_temp, set_pwm_auto_point_temp, + 2, 1); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_fan, S_IRUGO | S_IWUSR, + show_pwm_auto_point_fan, set_pwm_auto_point_fan, + 2, 1); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR, + show_pwm_auto_point_temp, set_pwm_auto_point_temp, + 2, 2); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_fan, S_IRUGO | S_IWUSR, + show_pwm_auto_point_fan, set_pwm_auto_point_fan, + 2, 2); + static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); @@ -1013,6 +1168,25 @@ static struct attribute *f71805f_attributes[] = { &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, &sensor_dev_attr_temp3_type.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_fan.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_fan.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_fan.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point1_fan.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_fan.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point3_fan.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point1_fan.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point2_fan.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point3_fan.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, &sensor_dev_attr_in1_alarm.dev_attr.attr, &sensor_dev_attr_in2_alarm.dev_attr.attr, @@ -1140,6 +1314,13 @@ static int __devinit f71805f_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start + ADDR_REG_OFFSET, 2, DRVNAME)) { + err = -EBUSY; + dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n", + (unsigned long)(res->start + ADDR_REG_OFFSET), + (unsigned long)(res->start + ADDR_REG_OFFSET + 1)); + goto exit_free; + } data->addr = res->start; data->name = names[sio_data->kind]; mutex_init(&data->update_lock); @@ -1165,7 +1346,7 @@ static int __devinit f71805f_probe(struct platform_device *pdev) /* Register sysfs interface files */ if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group))) - goto exit_free; + goto exit_release_region; if (data->has_in & (1 << 4)) { /* in4 */ if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group_optin[0]))) @@ -1205,9 +1386,9 @@ static int __devinit f71805f_probe(struct platform_device *pdev) } } - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); dev_err(&pdev->dev, "Class registration failed (%d)\n", err); goto exit_remove_files; } @@ -1219,6 +1400,8 @@ exit_remove_files: for (i = 0; i < 4; i++) sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]); sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); +exit_release_region: + release_region(res->start + ADDR_REG_OFFSET, 2); exit_free: platform_set_drvdata(pdev, NULL); kfree(data); @@ -1229,16 +1412,20 @@ exit: static int __devexit f71805f_remove(struct platform_device *pdev) { struct f71805f_data *data = platform_get_drvdata(pdev); + struct resource *res; int i; - platform_set_drvdata(pdev, NULL); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); for (i = 0; i < 4; i++) sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]); sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); + platform_set_drvdata(pdev, NULL); kfree(data); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(res->start + ADDR_REG_OFFSET, 2); + return 0; } @@ -1269,6 +1456,10 @@ static int __init f71805f_device_add(unsigned short address, } res.name = pdev->name; + 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 " @@ -1276,15 +1467,12 @@ static int __init f71805f_device_add(unsigned short address, goto exit_device_put; } - pdev->dev.platform_data = kmalloc(sizeof(struct f71805f_sio_data), - GFP_KERNEL); - if (!pdev->dev.platform_data) { - err = -ENOMEM; + err = platform_device_add_data(pdev, sio_data, + sizeof(struct f71805f_sio_data)); + if (err) { printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); goto exit_device_put; } - memcpy(pdev->dev.platform_data, sio_data, - sizeof(struct f71805f_sio_data)); err = platform_device_add(pdev); if (err) { @@ -1309,7 +1497,7 @@ static int __init f71805f_find(int sioaddr, unsigned short *address, static const char *names[] = { "F71805F/FG", - "F71872F/FG", + "F71872F/FG or F71806F/FG", }; superio_enter(sioaddr); @@ -1318,7 +1506,7 @@ static int __init f71805f_find(int sioaddr, unsigned short *address, if (devid != SIO_FINTEK_ID) goto exit; - devid = superio_inw(sioaddr, SIO_REG_DEVID); + devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID); switch (devid) { case SIO_F71805F_ID: sio_data->kind = f71805f;