X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fhwmon%2Fabituguru.c;h=4dbdb81ea3b1bfffce5d016746409ef7a3fe7f1d;hb=26dcce0fabbef75ae426461edf21b5030bad60f3;hp=cc15c4f2e9ecd28595e5f80c4bc5712e46d7f817;hpb=0d10e47f9635ecafe5a9dc6e10cb056a87a4daa2;p=linux-2.6 diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index cc15c4f2e9..4dbdb81ea3 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -16,19 +16,22 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* - This driver supports the sensor part of the custom Abit uGuru chip found - on Abit uGuru motherboards. Note: because of lack of specs the CPU / RAM / - etc voltage & frequency control is not supported! + This driver supports the sensor part of the first and second revision of + the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because + of lack of specs the CPU/RAM voltage & frequency control is not supported! */ #include +#include #include #include #include #include #include +#include #include #include #include +#include #include /* Banks */ @@ -64,17 +67,17 @@ #define ABIT_UGURU_IN_SENSOR 0 #define ABIT_UGURU_TEMP_SENSOR 1 #define ABIT_UGURU_NC 2 -/* Timeouts / Retries, if these turn out to need a lot of fiddling we could - convert them to params. */ -/* 250 was determined by trial and error, 200 works most of the time, but not - always. I assume this is cpu-speed independent, since the ISA-bus and not - the CPU should be the bottleneck. Note that 250 sometimes is still not - enough (only reported on AN7 mb) this is handled by a higher layer. */ -#define ABIT_UGURU_WAIT_TIMEOUT 250 +/* In many cases we need to wait for the uGuru to reach a certain status, most + of the time it will reach this status within 30 - 90 ISA reads, and thus we + can best busy wait. This define gives the total amount of reads to try. */ +#define ABIT_UGURU_WAIT_TIMEOUT 125 +/* However sometimes older versions of the uGuru seem to be distracted and they + do not respond for a long time. To handle this we sleep before each of the + last ABIT_UGURU_WAIT_TIMEOUT_SLEEP tries. */ +#define ABIT_UGURU_WAIT_TIMEOUT_SLEEP 5 /* Normally all expected status in abituguru_ready, are reported after the - first read, but sometimes not and we need to poll, 5 polls was not enough - 50 sofar is. */ -#define ABIT_UGURU_READY_TIMEOUT 50 + first read, but sometimes not and we need to poll. */ +#define ABIT_UGURU_READY_TIMEOUT 5 /* Maximum 3 retries on timedout reads/writes, delay 200 ms before retrying */ #define ABIT_UGURU_MAX_RETRIES 3 #define ABIT_UGURU_RETRY_DELAY (HZ/5) @@ -173,7 +176,7 @@ MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n" The structure is dynamically allocated, at the same time when a new abituguru device is allocated. */ struct abituguru_data { - struct class_device *class_dev; /* hwmon registered device */ + struct device *hwmon_dev; /* hwmon registered device */ struct mutex update_lock; /* protect access to data and uGuru */ unsigned long last_updated; /* In jiffies */ unsigned short addr; /* uguru base address */ @@ -226,6 +229,10 @@ static int abituguru_wait(struct abituguru_data *data, u8 state) timeout--; if (timeout == 0) return -EBUSY; + /* sleep a bit before our last few tries, see the comment on + this where ABIT_UGURU_WAIT_TIMEOUT_SLEEP is defined. */ + if (timeout <= ABIT_UGURU_WAIT_TIMEOUT_SLEEP) + msleep(0); } return 0; } @@ -256,6 +263,7 @@ static int abituguru_ready(struct abituguru_data *data) "CMD reg does not hold 0xAC after ready command\n"); return -EIO; } + msleep(0); } /* After this the ABIT_UGURU_DATA port should contain @@ -268,6 +276,7 @@ static int abituguru_ready(struct abituguru_data *data) "state != more input after ready command\n"); return -EIO; } + msleep(0); } data->uguru_ready = 1; @@ -331,7 +340,8 @@ static int abituguru_read(struct abituguru_data *data, /* And read the data */ for (i = 0; i < count; i++) { if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) { - ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for " + ABIT_UGURU_DEBUG(retries ? 1 : 3, + "timeout exceeded waiting for " "read state (bank: %d, sensor: %d)\n", (int)bank_addr, (int)sensor_addr); break; @@ -350,7 +360,9 @@ static int abituguru_read(struct abituguru_data *data, static int abituguru_write(struct abituguru_data *data, u8 bank_addr, u8 sensor_addr, u8 *buf, int count) { - int i; + /* We use the ready timeout as we have to wait for 0xAC just like the + ready function */ + int i, timeout = ABIT_UGURU_READY_TIMEOUT; /* Send the address */ i = abituguru_send_address(data, bank_addr, sensor_addr, @@ -370,7 +382,8 @@ static int abituguru_write(struct abituguru_data *data, } /* Now we need to wait till the chip is ready to be read again, - don't ask why */ + so that we can read 0xAC as confirmation that our write has + succeeded. */ if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) { ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for read state " "after write (bank: %d, sensor: %d)\n", (int)bank_addr, @@ -379,11 +392,15 @@ static int abituguru_write(struct abituguru_data *data, } /* Cmd port MUST be read now and should contain 0xAC */ - if (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) { - ABIT_UGURU_DEBUG(1, "CMD reg does not hold 0xAC after write " - "(bank: %d, sensor: %d)\n", (int)bank_addr, - (int)sensor_addr); - return -EIO; + while (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) { + timeout--; + if (timeout == 0) { + ABIT_UGURU_DEBUG(1, "CMD reg does not hold 0xAC after " + "write (bank: %d, sensor: %d)\n", + (int)bank_addr, (int)sensor_addr); + return -EIO; + } + msleep(0); } /* Last put the chip back in ready state */ @@ -402,8 +419,8 @@ static int __devinit abituguru_detect_bank1_sensor_type(struct abituguru_data *data, u8 sensor_addr) { - u8 val, buf[3]; - int ret = ABIT_UGURU_NC; + u8 val, test_flag, buf[3]; + int i, ret = -ENODEV; /* error is the most common used retval :| */ /* If overriden by the user return the user selected type */ if (bank1_types[sensor_addr] >= ABIT_UGURU_IN_SENSOR && @@ -420,7 +437,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, return -ENODEV; /* Test val is sane / usable for sensor type detection. */ - if ((val < 10u) || (val > 240u)) { + if ((val < 10u) || (val > 250u)) { printk(KERN_WARNING ABIT_UGURU_NAME ": bank1-sensor: %d reading (%d) too close to limits, " "unable to determine sensor type, skipping sensor\n", @@ -433,13 +450,23 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr); /* Volt sensor test, enable volt low alarm, set min value ridicously - high. If its a volt sensor this should always give us an alarm. */ - buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE; - buf[1] = 245; - buf[2] = 250; + high, or vica versa if the reading is very high. If its a volt + sensor this should always give us an alarm. */ + if (val <= 240u) { + buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE; + buf[1] = 245; + buf[2] = 250; + test_flag = ABIT_UGURU_VOLT_LOW_ALARM_FLAG; + } else { + buf[0] = ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE; + buf[1] = 5; + buf[2] = 10; + test_flag = ABIT_UGURU_VOLT_HIGH_ALARM_FLAG; + } + if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, buf, 3) != 3) - return -ENODEV; + goto abituguru_detect_bank1_sensor_type_exit; /* Now we need 20 ms to give the uguru time to read the sensors and raise a voltage alarm */ set_current_state(TASK_UNINTERRUPTIBLE); @@ -447,24 +474,19 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, /* Check for alarm and check the alarm is a volt low alarm. */ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3, ABIT_UGURU_MAX_RETRIES) != 3) - return -ENODEV; + goto abituguru_detect_bank1_sensor_type_exit; if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) { if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1, sensor_addr, buf, 3, ABIT_UGURU_MAX_RETRIES) != 3) - return -ENODEV; - if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) { - /* Restore original settings */ - if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, - sensor_addr, - data->bank1_settings[sensor_addr], - 3) != 3) - return -ENODEV; + goto abituguru_detect_bank1_sensor_type_exit; + if (buf[0] & test_flag) { ABIT_UGURU_DEBUG(2, " found volt sensor\n"); - return ABIT_UGURU_IN_SENSOR; + ret = ABIT_UGURU_IN_SENSOR; + goto abituguru_detect_bank1_sensor_type_exit; } else ABIT_UGURU_DEBUG(2, " alarm raised during volt " - "sensor test, but volt low flag not set\n"); + "sensor test, but volt range flag not set\n"); } else ABIT_UGURU_DEBUG(2, " alarm not raised during volt sensor " "test\n"); @@ -477,7 +499,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, buf[2] = 10; if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, buf, 3) != 3) - return -ENODEV; + goto abituguru_detect_bank1_sensor_type_exit; /* Now we need 50 ms to give the uguru time to read the sensors and raise a temp alarm */ set_current_state(TASK_UNINTERRUPTIBLE); @@ -485,15 +507,16 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, /* Check for alarm and check the alarm is a temp high alarm. */ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3, ABIT_UGURU_MAX_RETRIES) != 3) - return -ENODEV; + goto abituguru_detect_bank1_sensor_type_exit; if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) { if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1, sensor_addr, buf, 3, ABIT_UGURU_MAX_RETRIES) != 3) - return -ENODEV; + goto abituguru_detect_bank1_sensor_type_exit; if (buf[0] & ABIT_UGURU_TEMP_HIGH_ALARM_FLAG) { - ret = ABIT_UGURU_TEMP_SENSOR; ABIT_UGURU_DEBUG(2, " found temp sensor\n"); + ret = ABIT_UGURU_TEMP_SENSOR; + goto abituguru_detect_bank1_sensor_type_exit; } else ABIT_UGURU_DEBUG(2, " alarm raised during temp " "sensor test, but temp high flag not set\n"); @@ -501,11 +524,23 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, ABIT_UGURU_DEBUG(2, " alarm not raised during temp sensor " "test\n"); - /* Restore original settings */ - if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, - data->bank1_settings[sensor_addr], 3) != 3) + ret = ABIT_UGURU_NC; +abituguru_detect_bank1_sensor_type_exit: + /* Restore original settings, failing here is really BAD, it has been + reported that some BIOS-es hang when entering the uGuru menu with + invalid settings present in the uGuru, so we try this 3 times. */ + for (i = 0; i < 3; i++) + if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, + sensor_addr, data->bank1_settings[sensor_addr], + 3) == 3) + break; + if (i == 3) { + printk(KERN_ERR ABIT_UGURU_NAME + ": Fatal error could not restore original settings. " + "This should never happen please report this to the " + "abituguru maintainer (see MAINTAINERS)\n"); return -ENODEV; - + } return ret; } @@ -1243,30 +1278,43 @@ static int __devinit abituguru_probe(struct platform_device *pdev) printk(KERN_INFO ABIT_UGURU_NAME ": found Abit uGuru\n"); /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - res = PTR_ERR(data->class_dev); - goto abituguru_probe_error; - } for (i = 0; i < sysfs_attr_i; i++) - device_create_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); + if (device_create_file(&pdev->dev, + &data->sysfs_attr[i].dev_attr)) + goto abituguru_probe_error; for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) - device_create_file(&pdev->dev, - &abituguru_sysfs_attr[i].dev_attr); + if (device_create_file(&pdev->dev, + &abituguru_sysfs_attr[i].dev_attr)) + goto abituguru_probe_error; - return 0; + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (!IS_ERR(data->hwmon_dev)) + return 0; /* success */ + res = PTR_ERR(data->hwmon_dev); abituguru_probe_error: + for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++) + device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); + for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) + device_remove_file(&pdev->dev, + &abituguru_sysfs_attr[i].dev_attr); + platform_set_drvdata(pdev, NULL); kfree(data); return res; } static int __devexit abituguru_remove(struct platform_device *pdev) { + int i; struct abituguru_data *data = platform_get_drvdata(pdev); + hwmon_device_unregister(data->hwmon_dev); + for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++) + device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); + for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) + device_remove_file(&pdev->dev, + &abituguru_sysfs_attr[i].dev_attr); platform_set_drvdata(pdev, NULL); - hwmon_device_unregister(data->class_dev); kfree(data); return 0; @@ -1305,7 +1353,7 @@ static struct abituguru_data *abituguru_update_device(struct device *dev) data->update_timeouts = 0; LEAVE_UPDATE: /* handle timeout condition */ - if (err == -EBUSY) { + if (!success && (err == -EBUSY || err >= 0)) { /* No overflow please */ if (data->update_timeouts < 255u) data->update_timeouts++; @@ -1331,13 +1379,39 @@ LEAVE_UPDATE: return NULL; } +#ifdef CONFIG_PM +static int abituguru_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct abituguru_data *data = platform_get_drvdata(pdev); + /* make sure all communications with the uguru are done and no new + ones are started */ + mutex_lock(&data->update_lock); + return 0; +} + +static int abituguru_resume(struct platform_device *pdev) +{ + struct abituguru_data *data = platform_get_drvdata(pdev); + /* See if the uGuru is still ready */ + if (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT) + data->uguru_ready = 0; + mutex_unlock(&data->update_lock); + return 0; +} +#else +#define abituguru_suspend NULL +#define abituguru_resume NULL +#endif /* CONFIG_PM */ + static struct platform_driver abituguru_driver = { .driver = { .owner = THIS_MODULE, .name = ABIT_UGURU_NAME, }, - .probe = abituguru_probe, - .remove = __devexit_p(abituguru_remove), + .probe = abituguru_probe, + .remove = __devexit_p(abituguru_remove), + .suspend = abituguru_suspend, + .resume = abituguru_resume, }; static int __init abituguru_detect(void) @@ -1374,6 +1448,15 @@ static int __init abituguru_init(void) int address, err; struct resource res = { .flags = IORESOURCE_IO }; +#ifdef CONFIG_DMI + const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); + + /* safety check, refuse to load on non Abit motherboards */ + if (!force && (!board_vendor || + strcmp(board_vendor, "http://www.abit.com.tw/"))) + return -ENODEV; +#endif + address = abituguru_detect(); if (address < 0) return address;