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 <linux/module.h>
#include <linux/sched.h>
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/dmi.h>
#include <asm/io.h>
/* Banks */
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 */
abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
u8 sensor_addr)
{
- u8 val, buf[3];
+ 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 */
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",
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)
goto abituguru_detect_bank1_sensor_type_exit;
sensor_addr, buf, 3,
ABIT_UGURU_MAX_RETRIES) != 3)
goto abituguru_detect_bank1_sensor_type_exit;
- if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) {
+ if (buf[0] & test_flag) {
ABIT_UGURU_DEBUG(2, " found volt sensor\n");
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");
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;
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;