174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
23faa1ffbSHans de Goede /*
3562fca2fSGuenter Roeck * abituguru3.c
4562fca2fSGuenter Roeck *
5562fca2fSGuenter Roeck * Copyright (c) 2006-2008 Hans de Goede <hdegoede@redhat.com>
6562fca2fSGuenter Roeck * Copyright (c) 2008 Alistair John Strachan <alistair@devzero.co.uk>
73faa1ffbSHans de Goede */
83faa1ffbSHans de Goede /*
9562fca2fSGuenter Roeck * This driver supports the sensor part of revision 3 of the custom Abit uGuru
10562fca2fSGuenter Roeck * chip found on newer Abit uGuru motherboards. Note: because of lack of specs
11562fca2fSGuenter Roeck * only reading the sensors and their settings is supported.
123faa1ffbSHans de Goede */
13fe826749SJoe Perches
14fe826749SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15fe826749SJoe Perches
163faa1ffbSHans de Goede #include <linux/module.h>
173faa1ffbSHans de Goede #include <linux/init.h>
183faa1ffbSHans de Goede #include <linux/slab.h>
193faa1ffbSHans de Goede #include <linux/jiffies.h>
203faa1ffbSHans de Goede #include <linux/mutex.h>
213faa1ffbSHans de Goede #include <linux/err.h>
223faa1ffbSHans de Goede #include <linux/delay.h>
233faa1ffbSHans de Goede #include <linux/platform_device.h>
243faa1ffbSHans de Goede #include <linux/hwmon.h>
253faa1ffbSHans de Goede #include <linux/hwmon-sysfs.h>
26b3aeab0cSHans de Goede #include <linux/dmi.h>
276055fae8SH Hartley Sweeten #include <linux/io.h>
283faa1ffbSHans de Goede
293faa1ffbSHans de Goede /* uGuru3 bank addresses */
303faa1ffbSHans de Goede #define ABIT_UGURU3_SETTINGS_BANK 0x01
313faa1ffbSHans de Goede #define ABIT_UGURU3_SENSORS_BANK 0x08
323faa1ffbSHans de Goede #define ABIT_UGURU3_MISC_BANK 0x09
333faa1ffbSHans de Goede #define ABIT_UGURU3_ALARMS_START 0x1E
343faa1ffbSHans de Goede #define ABIT_UGURU3_SETTINGS_START 0x24
353faa1ffbSHans de Goede #define ABIT_UGURU3_VALUES_START 0x80
363faa1ffbSHans de Goede #define ABIT_UGURU3_BOARD_ID 0x0A
373faa1ffbSHans de Goede /* uGuru3 sensor bank flags */ /* Alarm if: */
383faa1ffbSHans de Goede #define ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE 0x01 /* temp over warn */
393faa1ffbSHans de Goede #define ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE 0x02 /* volt over max */
403faa1ffbSHans de Goede #define ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE 0x04 /* volt under min */
413faa1ffbSHans de Goede #define ABIT_UGURU3_TEMP_HIGH_ALARM_FLAG 0x10 /* temp is over warn */
423faa1ffbSHans de Goede #define ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG 0x20 /* volt is over max */
433faa1ffbSHans de Goede #define ABIT_UGURU3_VOLT_LOW_ALARM_FLAG 0x40 /* volt is under min */
443faa1ffbSHans de Goede #define ABIT_UGURU3_FAN_LOW_ALARM_ENABLE 0x01 /* fan under min */
453faa1ffbSHans de Goede #define ABIT_UGURU3_BEEP_ENABLE 0x08 /* beep if alarm */
463faa1ffbSHans de Goede #define ABIT_UGURU3_SHUTDOWN_ENABLE 0x80 /* shutdown if alarm */
473faa1ffbSHans de Goede /* sensor types */
483faa1ffbSHans de Goede #define ABIT_UGURU3_IN_SENSOR 0
493faa1ffbSHans de Goede #define ABIT_UGURU3_TEMP_SENSOR 1
503faa1ffbSHans de Goede #define ABIT_UGURU3_FAN_SENSOR 2
513faa1ffbSHans de Goede
52562fca2fSGuenter Roeck /*
53562fca2fSGuenter Roeck * Timeouts / Retries, if these turn out to need a lot of fiddling we could
54562fca2fSGuenter Roeck * convert them to params. Determined by trial and error. I assume this is
55562fca2fSGuenter Roeck * cpu-speed independent, since the ISA-bus and not the CPU should be the
56562fca2fSGuenter Roeck * bottleneck.
57562fca2fSGuenter Roeck */
583faa1ffbSHans de Goede #define ABIT_UGURU3_WAIT_TIMEOUT 250
59562fca2fSGuenter Roeck /*
60562fca2fSGuenter Roeck * Normally the 0xAC at the end of synchronize() is reported after the
61562fca2fSGuenter Roeck * first read, but sometimes not and we need to poll
62562fca2fSGuenter Roeck */
633faa1ffbSHans de Goede #define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT 5
643faa1ffbSHans de Goede /* utility macros */
653faa1ffbSHans de Goede #define ABIT_UGURU3_NAME "abituguru3"
663faa1ffbSHans de Goede #define ABIT_UGURU3_DEBUG(format, arg...) \
6724f9c539SGuenter Roeck do { \
683faa1ffbSHans de Goede if (verbose) \
6924f9c539SGuenter Roeck pr_debug(format , ## arg); \
7024f9c539SGuenter Roeck } while (0)
713faa1ffbSHans de Goede
723faa1ffbSHans de Goede /* Macros to help calculate the sysfs_names array length */
733faa1ffbSHans de Goede #define ABIT_UGURU3_MAX_NO_SENSORS 26
74562fca2fSGuenter Roeck /*
75562fca2fSGuenter Roeck * sum of strlen +1 of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
76562fca2fSGuenter Roeck * in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0, in??_label\0
77562fca2fSGuenter Roeck */
7879738416SGuenter Roeck #define ABIT_UGURU3_IN_NAMES_LENGTH \
7979738416SGuenter Roeck (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14 + 11)
80562fca2fSGuenter Roeck /*
81562fca2fSGuenter Roeck * sum of strlen +1 of: temp??_input\0, temp??_max\0, temp??_crit\0,
82562fca2fSGuenter Roeck * temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0,
83562fca2fSGuenter Roeck * temp??_label\0
84562fca2fSGuenter Roeck */
853faa1ffbSHans de Goede #define ABIT_UGURU3_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16 + 13)
86562fca2fSGuenter Roeck /*
87562fca2fSGuenter Roeck * sum of strlen +1 of: fan??_input\0, fan??_min\0, fan??_alarm\0,
88562fca2fSGuenter Roeck * fan??_alarm_enable\0, fan??_beep\0, fan??_shutdown\0, fan??_label\0
89562fca2fSGuenter Roeck */
903faa1ffbSHans de Goede #define ABIT_UGURU3_FAN_NAMES_LENGTH (12 + 10 + 12 + 19 + 11 + 15 + 12)
91562fca2fSGuenter Roeck /*
92562fca2fSGuenter Roeck * Worst case scenario 16 in sensors (longest names_length) and the rest
93562fca2fSGuenter Roeck * temp sensors (second longest names_length).
94562fca2fSGuenter Roeck */
953faa1ffbSHans de Goede #define ABIT_UGURU3_SYSFS_NAMES_LENGTH (16 * ABIT_UGURU3_IN_NAMES_LENGTH + \
963faa1ffbSHans de Goede (ABIT_UGURU3_MAX_NO_SENSORS - 16) * ABIT_UGURU3_TEMP_NAMES_LENGTH)
973faa1ffbSHans de Goede
98562fca2fSGuenter Roeck /*
99562fca2fSGuenter Roeck * All the macros below are named identical to the openguru2 program
100562fca2fSGuenter Roeck * reverse engineered by Louis Kruger, hence the names might not be 100%
101562fca2fSGuenter Roeck * logical. I could come up with better names, but I prefer keeping the names
102562fca2fSGuenter Roeck * identical so that this driver can be compared with his work more easily.
103562fca2fSGuenter Roeck */
1043faa1ffbSHans de Goede /* Two i/o-ports are used by uGuru */
1053faa1ffbSHans de Goede #define ABIT_UGURU3_BASE 0x00E0
1063faa1ffbSHans de Goede #define ABIT_UGURU3_CMD 0x00
1073faa1ffbSHans de Goede #define ABIT_UGURU3_DATA 0x04
1083faa1ffbSHans de Goede #define ABIT_UGURU3_REGION_LENGTH 5
109562fca2fSGuenter Roeck /*
110562fca2fSGuenter Roeck * The wait_xxx functions return this on success and the last contents
111562fca2fSGuenter Roeck * of the DATA register (0-255) on failure.
112562fca2fSGuenter Roeck */
1133faa1ffbSHans de Goede #define ABIT_UGURU3_SUCCESS -1
1143faa1ffbSHans de Goede /* uGuru status flags */
1153faa1ffbSHans de Goede #define ABIT_UGURU3_STATUS_READY_FOR_READ 0x01
1163faa1ffbSHans de Goede #define ABIT_UGURU3_STATUS_BUSY 0x02
1173faa1ffbSHans de Goede
1183faa1ffbSHans de Goede
1193faa1ffbSHans de Goede /* Structures */
1203faa1ffbSHans de Goede struct abituguru3_sensor_info {
1213faa1ffbSHans de Goede const char *name;
1223faa1ffbSHans de Goede int port;
1233faa1ffbSHans de Goede int type;
1243faa1ffbSHans de Goede int multiplier;
1253faa1ffbSHans de Goede int divisor;
1263faa1ffbSHans de Goede int offset;
1273faa1ffbSHans de Goede };
1283faa1ffbSHans de Goede
129bbe5939aSAlistair John Strachan /* Avoid use of flexible array members */
130bbe5939aSAlistair John Strachan #define ABIT_UGURU3_MAX_DMI_NAMES 2
131bbe5939aSAlistair John Strachan
1323faa1ffbSHans de Goede struct abituguru3_motherboard_info {
1333faa1ffbSHans de Goede u16 id;
134bbe5939aSAlistair John Strachan const char *dmi_name[ABIT_UGURU3_MAX_DMI_NAMES + 1];
1353faa1ffbSHans de Goede /* + 1 -> end of sensors indicated by a sensor with name == NULL */
1363faa1ffbSHans de Goede struct abituguru3_sensor_info sensors[ABIT_UGURU3_MAX_NO_SENSORS + 1];
1373faa1ffbSHans de Goede };
1383faa1ffbSHans de Goede
139562fca2fSGuenter Roeck /*
140562fca2fSGuenter Roeck * For the Abit uGuru, we need to keep some data in memory.
141562fca2fSGuenter Roeck * The structure is dynamically allocated, at the same time when a new
142562fca2fSGuenter Roeck * abituguru3 device is allocated.
143562fca2fSGuenter Roeck */
1443faa1ffbSHans de Goede struct abituguru3_data {
1451beeffe4STony Jones struct device *hwmon_dev; /* hwmon registered device */
1463faa1ffbSHans de Goede struct mutex update_lock; /* protect access to data and uGuru */
1473faa1ffbSHans de Goede unsigned short addr; /* uguru base address */
148952a11caSPaul Fertser bool valid; /* true if following fields are valid */
1493faa1ffbSHans de Goede unsigned long last_updated; /* In jiffies */
1503faa1ffbSHans de Goede
151562fca2fSGuenter Roeck /*
152562fca2fSGuenter Roeck * For convenience the sysfs attr and their names are generated
153562fca2fSGuenter Roeck * automatically. We have max 10 entries per sensor (for in sensors)
154562fca2fSGuenter Roeck */
1553faa1ffbSHans de Goede struct sensor_device_attribute_2 sysfs_attr[ABIT_UGURU3_MAX_NO_SENSORS
1563faa1ffbSHans de Goede * 10];
1573faa1ffbSHans de Goede
1583faa1ffbSHans de Goede /* Buffer to store the dynamically generated sysfs names */
1593faa1ffbSHans de Goede char sysfs_names[ABIT_UGURU3_SYSFS_NAMES_LENGTH];
1603faa1ffbSHans de Goede
1613faa1ffbSHans de Goede /* Pointer to the sensors info for the detected motherboard */
1623faa1ffbSHans de Goede const struct abituguru3_sensor_info *sensors;
1633faa1ffbSHans de Goede
164562fca2fSGuenter Roeck /*
165562fca2fSGuenter Roeck * The abituguru3 supports up to 48 sensors, and thus has registers
16684fb029fSLABBE Corentin * sets for 48 sensors, for convenience reasons / simplicity of the
167562fca2fSGuenter Roeck * code we always read and store all registers for all 48 sensors
168562fca2fSGuenter Roeck */
1693faa1ffbSHans de Goede
1703faa1ffbSHans de Goede /* Alarms for all 48 sensors (1 bit per sensor) */
1713faa1ffbSHans de Goede u8 alarms[48/8];
1723faa1ffbSHans de Goede
1733faa1ffbSHans de Goede /* Value of all 48 sensors */
1743faa1ffbSHans de Goede u8 value[48];
1753faa1ffbSHans de Goede
176562fca2fSGuenter Roeck /*
177562fca2fSGuenter Roeck * Settings of all 48 sensors, note in and temp sensors (the first 32
178562fca2fSGuenter Roeck * sensors) have 3 bytes of settings, while fans only have 2 bytes,
179562fca2fSGuenter Roeck * for convenience we use 3 bytes for all sensors
180562fca2fSGuenter Roeck */
1813faa1ffbSHans de Goede u8 settings[48][3];
1823faa1ffbSHans de Goede };
1833faa1ffbSHans de Goede
1843faa1ffbSHans de Goede
1853faa1ffbSHans de Goede /* Constants */
1863faa1ffbSHans de Goede static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
187bbe5939aSAlistair John Strachan { 0x000C, { NULL } /* Unknown, need DMI string */, {
1883faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
1893faa1ffbSHans de Goede { "DDR", 1, 0, 10, 1, 0 },
1903faa1ffbSHans de Goede { "DDR VTT", 2, 0, 10, 1, 0 },
1913faa1ffbSHans de Goede { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
1923faa1ffbSHans de Goede { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
1933faa1ffbSHans de Goede { "MCH 2.5V", 5, 0, 20, 1, 0 },
1943faa1ffbSHans de Goede { "ICH 1.05V", 6, 0, 10, 1, 0 },
1953faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
1963faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
1973faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
1983faa1ffbSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
1993faa1ffbSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
2003faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
2013faa1ffbSHans de Goede { "System", 25, 1, 1, 1, 0 },
2023faa1ffbSHans de Goede { "PWM", 26, 1, 1, 1, 0 },
2033faa1ffbSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
2043faa1ffbSHans de Goede { "NB Fan", 33, 2, 60, 1, 0 },
2053faa1ffbSHans de Goede { "SYS FAN", 34, 2, 60, 1, 0 },
2063faa1ffbSHans de Goede { "AUX1 Fan", 35, 2, 60, 1, 0 },
2073faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
2083faa1ffbSHans de Goede },
209bbe5939aSAlistair John Strachan { 0x000D, { NULL } /* Abit AW8, need DMI string */, {
2103faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
2113faa1ffbSHans de Goede { "DDR", 1, 0, 10, 1, 0 },
2123faa1ffbSHans de Goede { "DDR VTT", 2, 0, 10, 1, 0 },
2133faa1ffbSHans de Goede { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
2143faa1ffbSHans de Goede { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
2153faa1ffbSHans de Goede { "MCH 2.5V", 5, 0, 20, 1, 0 },
2163faa1ffbSHans de Goede { "ICH 1.05V", 6, 0, 10, 1, 0 },
2173faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
2183faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
2193faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
2203faa1ffbSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
2213faa1ffbSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
2223faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
2233faa1ffbSHans de Goede { "System", 25, 1, 1, 1, 0 },
2243faa1ffbSHans de Goede { "PWM1", 26, 1, 1, 1, 0 },
2253faa1ffbSHans de Goede { "PWM2", 27, 1, 1, 1, 0 },
2263faa1ffbSHans de Goede { "PWM3", 28, 1, 1, 1, 0 },
2273faa1ffbSHans de Goede { "PWM4", 29, 1, 1, 1, 0 },
2283faa1ffbSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
2293faa1ffbSHans de Goede { "NB Fan", 33, 2, 60, 1, 0 },
2303faa1ffbSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
2313faa1ffbSHans de Goede { "AUX1 Fan", 35, 2, 60, 1, 0 },
2323faa1ffbSHans de Goede { "AUX2 Fan", 36, 2, 60, 1, 0 },
2333faa1ffbSHans de Goede { "AUX3 Fan", 37, 2, 60, 1, 0 },
2343faa1ffbSHans de Goede { "AUX4 Fan", 38, 2, 60, 1, 0 },
2353faa1ffbSHans de Goede { "AUX5 Fan", 39, 2, 60, 1, 0 },
2363faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
2373faa1ffbSHans de Goede },
238bbe5939aSAlistair John Strachan { 0x000E, { NULL } /* AL-8, need DMI string */, {
2393faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
2403faa1ffbSHans de Goede { "DDR", 1, 0, 10, 1, 0 },
2413faa1ffbSHans de Goede { "DDR VTT", 2, 0, 10, 1, 0 },
2423faa1ffbSHans de Goede { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
2433faa1ffbSHans de Goede { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
2443faa1ffbSHans de Goede { "MCH 2.5V", 5, 0, 20, 1, 0 },
2453faa1ffbSHans de Goede { "ICH 1.05V", 6, 0, 10, 1, 0 },
2463faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
2473faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
2483faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
2493faa1ffbSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
2503faa1ffbSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
2513faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
2523faa1ffbSHans de Goede { "System", 25, 1, 1, 1, 0 },
2533faa1ffbSHans de Goede { "PWM", 26, 1, 1, 1, 0 },
2543faa1ffbSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
2553faa1ffbSHans de Goede { "NB Fan", 33, 2, 60, 1, 0 },
2563faa1ffbSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
2573faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
2583faa1ffbSHans de Goede },
259bbe5939aSAlistair John Strachan { 0x000F, { NULL } /* Unknown, need DMI string */, {
260bbe5939aSAlistair John Strachan
2613faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
2623faa1ffbSHans de Goede { "DDR", 1, 0, 10, 1, 0 },
2633faa1ffbSHans de Goede { "DDR VTT", 2, 0, 10, 1, 0 },
2643faa1ffbSHans de Goede { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
2653faa1ffbSHans de Goede { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
2663faa1ffbSHans de Goede { "MCH 2.5V", 5, 0, 20, 1, 0 },
2673faa1ffbSHans de Goede { "ICH 1.05V", 6, 0, 10, 1, 0 },
2683faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
2693faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
2703faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
2713faa1ffbSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
2723faa1ffbSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
2733faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
2743faa1ffbSHans de Goede { "System", 25, 1, 1, 1, 0 },
2753faa1ffbSHans de Goede { "PWM", 26, 1, 1, 1, 0 },
2763faa1ffbSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
2773faa1ffbSHans de Goede { "NB Fan", 33, 2, 60, 1, 0 },
2783faa1ffbSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
2793faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
2803faa1ffbSHans de Goede },
281bbe5939aSAlistair John Strachan { 0x0010, { NULL } /* Abit NI8 SLI GR, need DMI string */, {
2823faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
2833faa1ffbSHans de Goede { "DDR", 1, 0, 10, 1, 0 },
2843faa1ffbSHans de Goede { "DDR VTT", 2, 0, 10, 1, 0 },
2853faa1ffbSHans de Goede { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
2863faa1ffbSHans de Goede { "NB 1.4V", 4, 0, 10, 1, 0 },
2873faa1ffbSHans de Goede { "SB 1.5V", 6, 0, 10, 1, 0 },
2883faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
2893faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
2903faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
2913faa1ffbSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
2923faa1ffbSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
2933faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
2943faa1ffbSHans de Goede { "SYS", 25, 1, 1, 1, 0 },
2953faa1ffbSHans de Goede { "PWM", 26, 1, 1, 1, 0 },
2963faa1ffbSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
2973faa1ffbSHans de Goede { "NB Fan", 33, 2, 60, 1, 0 },
2983faa1ffbSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
2993faa1ffbSHans de Goede { "AUX1 Fan", 35, 2, 60, 1, 0 },
3003faa1ffbSHans de Goede { "OTES1 Fan", 36, 2, 60, 1, 0 },
3013faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
3023faa1ffbSHans de Goede },
303bbe5939aSAlistair John Strachan { 0x0011, { "AT8 32X", NULL }, {
3043faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
3053faa1ffbSHans de Goede { "DDR", 1, 0, 20, 1, 0 },
3063faa1ffbSHans de Goede { "DDR VTT", 2, 0, 10, 1, 0 },
3073faa1ffbSHans de Goede { "CPU VDDA 2.5V", 6, 0, 20, 1, 0 },
3083faa1ffbSHans de Goede { "NB 1.8V", 4, 0, 10, 1, 0 },
3093faa1ffbSHans de Goede { "NB 1.8V Dual", 5, 0, 10, 1, 0 },
3103faa1ffbSHans de Goede { "HTV 1.2", 3, 0, 10, 1, 0 },
3113faa1ffbSHans de Goede { "PCIE 1.2V", 12, 0, 10, 1, 0 },
3123faa1ffbSHans de Goede { "NB 1.2V", 13, 0, 10, 1, 0 },
3133faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
3143faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
3153faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
3163faa1ffbSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
3173faa1ffbSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
3183faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
3193faa1ffbSHans de Goede { "NB", 25, 1, 1, 1, 0 },
3203faa1ffbSHans de Goede { "System", 26, 1, 1, 1, 0 },
3213faa1ffbSHans de Goede { "PWM", 27, 1, 1, 1, 0 },
3223faa1ffbSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
3233faa1ffbSHans de Goede { "NB Fan", 33, 2, 60, 1, 0 },
3243faa1ffbSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
3253faa1ffbSHans de Goede { "AUX1 Fan", 35, 2, 60, 1, 0 },
3263faa1ffbSHans de Goede { "AUX2 Fan", 36, 2, 60, 1, 0 },
3278748a71eSAlistair John Strachan { "AUX3 Fan", 37, 2, 60, 1, 0 },
3283faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
3293faa1ffbSHans de Goede },
330bbe5939aSAlistair John Strachan { 0x0012, { NULL } /* Abit AN8 32X, need DMI string */, {
3313faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
3323faa1ffbSHans de Goede { "DDR", 1, 0, 20, 1, 0 },
3333faa1ffbSHans de Goede { "DDR VTT", 2, 0, 10, 1, 0 },
3343faa1ffbSHans de Goede { "HyperTransport", 3, 0, 10, 1, 0 },
3353faa1ffbSHans de Goede { "CPU VDDA 2.5V", 5, 0, 20, 1, 0 },
3363faa1ffbSHans de Goede { "NB", 4, 0, 10, 1, 0 },
3373faa1ffbSHans de Goede { "SB", 6, 0, 10, 1, 0 },
3383faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
3393faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
3403faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
3413faa1ffbSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
3423faa1ffbSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
3433faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
3443faa1ffbSHans de Goede { "SYS", 25, 1, 1, 1, 0 },
3453faa1ffbSHans de Goede { "PWM", 26, 1, 1, 1, 0 },
3463faa1ffbSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
3473faa1ffbSHans de Goede { "NB Fan", 33, 2, 60, 1, 0 },
3483faa1ffbSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
3493faa1ffbSHans de Goede { "AUX1 Fan", 36, 2, 60, 1, 0 },
3503faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
3513faa1ffbSHans de Goede },
352bbe5939aSAlistair John Strachan { 0x0013, { NULL } /* Abit AW8D, need DMI string */, {
3533faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
3543faa1ffbSHans de Goede { "DDR", 1, 0, 10, 1, 0 },
3553faa1ffbSHans de Goede { "DDR VTT", 2, 0, 10, 1, 0 },
3563faa1ffbSHans de Goede { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
3573faa1ffbSHans de Goede { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
3583faa1ffbSHans de Goede { "MCH 2.5V", 5, 0, 20, 1, 0 },
3593faa1ffbSHans de Goede { "ICH 1.05V", 6, 0, 10, 1, 0 },
3603faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
3613faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
3623faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
3633faa1ffbSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
3643faa1ffbSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
3653faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
3663faa1ffbSHans de Goede { "System", 25, 1, 1, 1, 0 },
3673faa1ffbSHans de Goede { "PWM1", 26, 1, 1, 1, 0 },
3683faa1ffbSHans de Goede { "PWM2", 27, 1, 1, 1, 0 },
3693faa1ffbSHans de Goede { "PWM3", 28, 1, 1, 1, 0 },
3703faa1ffbSHans de Goede { "PWM4", 29, 1, 1, 1, 0 },
3713faa1ffbSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
3723faa1ffbSHans de Goede { "NB Fan", 33, 2, 60, 1, 0 },
3733faa1ffbSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
3743faa1ffbSHans de Goede { "AUX1 Fan", 35, 2, 60, 1, 0 },
3753faa1ffbSHans de Goede { "AUX2 Fan", 36, 2, 60, 1, 0 },
3763faa1ffbSHans de Goede { "AUX3 Fan", 37, 2, 60, 1, 0 },
3773faa1ffbSHans de Goede { "AUX4 Fan", 38, 2, 60, 1, 0 },
3781604e78bSHans de Goede { "AUX5 Fan", 39, 2, 60, 1, 0 },
3793faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
3803faa1ffbSHans de Goede },
381bbe5939aSAlistair John Strachan { 0x0014, { "AB9", "AB9 Pro", NULL }, {
3823faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
3833faa1ffbSHans de Goede { "DDR", 1, 0, 10, 1, 0 },
3843faa1ffbSHans de Goede { "DDR VTT", 2, 0, 10, 1, 0 },
3853faa1ffbSHans de Goede { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
3863faa1ffbSHans de Goede { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
3873faa1ffbSHans de Goede { "MCH 2.5V", 5, 0, 20, 1, 0 },
3883faa1ffbSHans de Goede { "ICH 1.05V", 6, 0, 10, 1, 0 },
3893faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
3903faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
3913faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
3923faa1ffbSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
3933faa1ffbSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
3943faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
3953faa1ffbSHans de Goede { "System", 25, 1, 1, 1, 0 },
3963faa1ffbSHans de Goede { "PWM", 26, 1, 1, 1, 0 },
3973faa1ffbSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
3983faa1ffbSHans de Goede { "NB Fan", 33, 2, 60, 1, 0 },
3993faa1ffbSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
4003faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
4013faa1ffbSHans de Goede },
402bbe5939aSAlistair John Strachan { 0x0015, { NULL } /* Unknown, need DMI string */, {
4033faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
4043faa1ffbSHans de Goede { "DDR", 1, 0, 20, 1, 0 },
4053faa1ffbSHans de Goede { "DDR VTT", 2, 0, 10, 1, 0 },
4063faa1ffbSHans de Goede { "HyperTransport", 3, 0, 10, 1, 0 },
4073faa1ffbSHans de Goede { "CPU VDDA 2.5V", 5, 0, 20, 1, 0 },
4083faa1ffbSHans de Goede { "NB", 4, 0, 10, 1, 0 },
4093faa1ffbSHans de Goede { "SB", 6, 0, 10, 1, 0 },
4103faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
4113faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
4123faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
4133faa1ffbSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
4143faa1ffbSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
4153faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
4163faa1ffbSHans de Goede { "SYS", 25, 1, 1, 1, 0 },
4173faa1ffbSHans de Goede { "PWM", 26, 1, 1, 1, 0 },
4183faa1ffbSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
4193faa1ffbSHans de Goede { "NB Fan", 33, 2, 60, 1, 0 },
4203faa1ffbSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
4213faa1ffbSHans de Goede { "AUX1 Fan", 33, 2, 60, 1, 0 },
4223faa1ffbSHans de Goede { "AUX2 Fan", 35, 2, 60, 1, 0 },
4233faa1ffbSHans de Goede { "AUX3 Fan", 36, 2, 60, 1, 0 },
4243faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
4253faa1ffbSHans de Goede },
426bbe5939aSAlistair John Strachan { 0x0016, { "AW9D-MAX", NULL }, {
4273faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
4283faa1ffbSHans de Goede { "DDR2", 1, 0, 20, 1, 0 },
4293faa1ffbSHans de Goede { "DDR2 VTT", 2, 0, 10, 1, 0 },
4303faa1ffbSHans de Goede { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
4313faa1ffbSHans de Goede { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
4323faa1ffbSHans de Goede { "MCH 2.5V", 5, 0, 20, 1, 0 },
4333faa1ffbSHans de Goede { "ICH 1.05V", 6, 0, 10, 1, 0 },
4343faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
4353faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
4363faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
4373faa1ffbSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
4383faa1ffbSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
4393faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
4403faa1ffbSHans de Goede { "System", 25, 1, 1, 1, 0 },
4413faa1ffbSHans de Goede { "PWM1", 26, 1, 1, 1, 0 },
4423faa1ffbSHans de Goede { "PWM2", 27, 1, 1, 1, 0 },
4433faa1ffbSHans de Goede { "PWM3", 28, 1, 1, 1, 0 },
4443faa1ffbSHans de Goede { "PWM4", 29, 1, 1, 1, 0 },
4453faa1ffbSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
4463faa1ffbSHans de Goede { "NB Fan", 33, 2, 60, 1, 0 },
4473faa1ffbSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
4483faa1ffbSHans de Goede { "AUX1 Fan", 35, 2, 60, 1, 0 },
4493faa1ffbSHans de Goede { "AUX2 Fan", 36, 2, 60, 1, 0 },
4503faa1ffbSHans de Goede { "AUX3 Fan", 37, 2, 60, 1, 0 },
4513faa1ffbSHans de Goede { "OTES1 Fan", 38, 2, 60, 1, 0 },
4523faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
4533faa1ffbSHans de Goede },
454bbe5939aSAlistair John Strachan { 0x0017, { NULL } /* Unknown, need DMI string */, {
4553faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
4563faa1ffbSHans de Goede { "DDR2", 1, 0, 20, 1, 0 },
4573faa1ffbSHans de Goede { "DDR2 VTT", 2, 0, 10, 1, 0 },
4583faa1ffbSHans de Goede { "HyperTransport", 3, 0, 10, 1, 0 },
4593faa1ffbSHans de Goede { "CPU VDDA 2.5V", 6, 0, 20, 1, 0 },
4603faa1ffbSHans de Goede { "NB 1.8V", 4, 0, 10, 1, 0 },
4613faa1ffbSHans de Goede { "NB 1.2V ", 13, 0, 10, 1, 0 },
4623faa1ffbSHans de Goede { "SB 1.2V", 5, 0, 10, 1, 0 },
4633faa1ffbSHans de Goede { "PCIE 1.2V", 12, 0, 10, 1, 0 },
4643faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
4653faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
4663faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
4673faa1ffbSHans de Goede { "ATX +3.3V", 10, 0, 20, 1, 0 },
4683faa1ffbSHans de Goede { "ATX 5VSB", 11, 0, 30, 1, 0 },
4693faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
4703faa1ffbSHans de Goede { "System", 26, 1, 1, 1, 0 },
4713faa1ffbSHans de Goede { "PWM", 27, 1, 1, 1, 0 },
4723faa1ffbSHans de Goede { "CPU FAN", 32, 2, 60, 1, 0 },
4733faa1ffbSHans de Goede { "SYS FAN", 34, 2, 60, 1, 0 },
4743faa1ffbSHans de Goede { "AUX1 FAN", 35, 2, 60, 1, 0 },
4753faa1ffbSHans de Goede { "AUX2 FAN", 36, 2, 60, 1, 0 },
4763faa1ffbSHans de Goede { "AUX3 FAN", 37, 2, 60, 1, 0 },
4773faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
4783faa1ffbSHans de Goede },
479bbe5939aSAlistair John Strachan { 0x0018, { "AB9 QuadGT", NULL }, {
4803faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
4813faa1ffbSHans de Goede { "DDR2", 1, 0, 20, 1, 0 },
4823faa1ffbSHans de Goede { "DDR2 VTT", 2, 0, 10, 1, 0 },
4833faa1ffbSHans de Goede { "CPU VTT", 3, 0, 10, 1, 0 },
4843faa1ffbSHans de Goede { "MCH 1.25V", 4, 0, 10, 1, 0 },
4853faa1ffbSHans de Goede { "ICHIO 1.5V", 5, 0, 10, 1, 0 },
4863faa1ffbSHans de Goede { "ICH 1.05V", 6, 0, 10, 1, 0 },
4873faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
4883faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
4893faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
4903faa1ffbSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
4913faa1ffbSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
4923faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
4933faa1ffbSHans de Goede { "System", 25, 1, 1, 1, 0 },
4943faa1ffbSHans de Goede { "PWM Phase1", 26, 1, 1, 1, 0 },
4953faa1ffbSHans de Goede { "PWM Phase2", 27, 1, 1, 1, 0 },
4963faa1ffbSHans de Goede { "PWM Phase3", 28, 1, 1, 1, 0 },
4973faa1ffbSHans de Goede { "PWM Phase4", 29, 1, 1, 1, 0 },
4983faa1ffbSHans de Goede { "PWM Phase5", 30, 1, 1, 1, 0 },
4993faa1ffbSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
5003faa1ffbSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
5013faa1ffbSHans de Goede { "AUX1 Fan", 33, 2, 60, 1, 0 },
5023faa1ffbSHans de Goede { "AUX2 Fan", 35, 2, 60, 1, 0 },
5033faa1ffbSHans de Goede { "AUX3 Fan", 36, 2, 60, 1, 0 },
5043faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
5053faa1ffbSHans de Goede },
506bbe5939aSAlistair John Strachan { 0x0019, { "IN9 32X MAX", NULL }, {
5073faa1ffbSHans de Goede { "CPU Core", 7, 0, 10, 1, 0 },
5083faa1ffbSHans de Goede { "DDR2", 13, 0, 20, 1, 0 },
5093faa1ffbSHans de Goede { "DDR2 VTT", 14, 0, 10, 1, 0 },
5103faa1ffbSHans de Goede { "CPU VTT", 3, 0, 20, 1, 0 },
5113faa1ffbSHans de Goede { "NB 1.2V", 4, 0, 10, 1, 0 },
5123faa1ffbSHans de Goede { "SB 1.5V", 6, 0, 10, 1, 0 },
5133faa1ffbSHans de Goede { "HyperTransport", 5, 0, 10, 1, 0 },
5143faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 12, 0, 60, 1, 0 },
5153faa1ffbSHans de Goede { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
5163faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
5173faa1ffbSHans de Goede { "ATX +3.3V", 10, 0, 20, 1, 0 },
5183faa1ffbSHans de Goede { "ATX 5VSB", 11, 0, 30, 1, 0 },
5193faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
5203faa1ffbSHans de Goede { "System", 25, 1, 1, 1, 0 },
5213faa1ffbSHans de Goede { "PWM Phase1", 26, 1, 1, 1, 0 },
5223faa1ffbSHans de Goede { "PWM Phase2", 27, 1, 1, 1, 0 },
5233faa1ffbSHans de Goede { "PWM Phase3", 28, 1, 1, 1, 0 },
5243faa1ffbSHans de Goede { "PWM Phase4", 29, 1, 1, 1, 0 },
5253faa1ffbSHans de Goede { "PWM Phase5", 30, 1, 1, 1, 0 },
5263faa1ffbSHans de Goede { "CPU FAN", 32, 2, 60, 1, 0 },
5273faa1ffbSHans de Goede { "SYS FAN", 34, 2, 60, 1, 0 },
5283faa1ffbSHans de Goede { "AUX1 FAN", 33, 2, 60, 1, 0 },
5293faa1ffbSHans de Goede { "AUX2 FAN", 35, 2, 60, 1, 0 },
5303faa1ffbSHans de Goede { "AUX3 FAN", 36, 2, 60, 1, 0 },
5313faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
5323faa1ffbSHans de Goede },
533bbe5939aSAlistair John Strachan { 0x001A, { "IP35 Pro", "IP35 Pro XE", NULL }, {
5343faa1ffbSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
5353faa1ffbSHans de Goede { "DDR2", 1, 0, 20, 1, 0 },
5363faa1ffbSHans de Goede { "DDR2 VTT", 2, 0, 10, 1, 0 },
5373faa1ffbSHans de Goede { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
5383faa1ffbSHans de Goede { "MCH 1.25V", 4, 0, 10, 1, 0 },
5393faa1ffbSHans de Goede { "ICHIO 1.5V", 5, 0, 10, 1, 0 },
5403faa1ffbSHans de Goede { "ICH 1.05V", 6, 0, 10, 1, 0 },
5413faa1ffbSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
5423faa1ffbSHans de Goede { "ATX +12V (8-pin)", 8, 0, 60, 1, 0 },
5433faa1ffbSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
5443faa1ffbSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
5453faa1ffbSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
5463faa1ffbSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
5473faa1ffbSHans de Goede { "System", 25, 1, 1, 1, 0 },
5483faa1ffbSHans de Goede { "PWM", 26, 1, 1, 1, 0 },
5493faa1ffbSHans de Goede { "PWM Phase2", 27, 1, 1, 1, 0 },
5503faa1ffbSHans de Goede { "PWM Phase3", 28, 1, 1, 1, 0 },
5513faa1ffbSHans de Goede { "PWM Phase4", 29, 1, 1, 1, 0 },
5523faa1ffbSHans de Goede { "PWM Phase5", 30, 1, 1, 1, 0 },
5533faa1ffbSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
5543faa1ffbSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
5553faa1ffbSHans de Goede { "AUX1 Fan", 33, 2, 60, 1, 0 },
5563faa1ffbSHans de Goede { "AUX2 Fan", 35, 2, 60, 1, 0 },
5573faa1ffbSHans de Goede { "AUX3 Fan", 36, 2, 60, 1, 0 },
558cb96b8caSSergey Vlasov { "AUX4 Fan", 37, 2, 60, 1, 0 },
5593faa1ffbSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
5603faa1ffbSHans de Goede },
561bbe5939aSAlistair John Strachan { 0x001B, { NULL } /* Unknown, need DMI string */, {
562ff8966acSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
563ff8966acSHans de Goede { "DDR3", 1, 0, 20, 1, 0 },
564ff8966acSHans de Goede { "DDR3 VTT", 2, 0, 10, 1, 0 },
565ff8966acSHans de Goede { "CPU VTT", 3, 0, 10, 1, 0 },
566ff8966acSHans de Goede { "MCH 1.25V", 4, 0, 10, 1, 0 },
567ff8966acSHans de Goede { "ICHIO 1.5V", 5, 0, 10, 1, 0 },
568ff8966acSHans de Goede { "ICH 1.05V", 6, 0, 10, 1, 0 },
569ff8966acSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
570ff8966acSHans de Goede { "ATX +12V (8-pin)", 8, 0, 60, 1, 0 },
571ff8966acSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
572ff8966acSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
573ff8966acSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
574ff8966acSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
575ff8966acSHans de Goede { "System", 25, 1, 1, 1, 0 },
576ff8966acSHans de Goede { "PWM Phase1", 26, 1, 1, 1, 0 },
577ff8966acSHans de Goede { "PWM Phase2", 27, 1, 1, 1, 0 },
578ff8966acSHans de Goede { "PWM Phase3", 28, 1, 1, 1, 0 },
579ff8966acSHans de Goede { "PWM Phase4", 29, 1, 1, 1, 0 },
580ff8966acSHans de Goede { "PWM Phase5", 30, 1, 1, 1, 0 },
581ff8966acSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
582ff8966acSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
583ff8966acSHans de Goede { "AUX1 Fan", 33, 2, 60, 1, 0 },
584ff8966acSHans de Goede { "AUX2 Fan", 35, 2, 60, 1, 0 },
585ff8966acSHans de Goede { "AUX3 Fan", 36, 2, 60, 1, 0 },
586ff8966acSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
587ff8966acSHans de Goede },
588bbe5939aSAlistair John Strachan { 0x001C, { "IX38 QuadGT", NULL }, {
589ff8966acSHans de Goede { "CPU Core", 0, 0, 10, 1, 0 },
590ff8966acSHans de Goede { "DDR2", 1, 0, 20, 1, 0 },
591ff8966acSHans de Goede { "DDR2 VTT", 2, 0, 10, 1, 0 },
592ff8966acSHans de Goede { "CPU VTT", 3, 0, 10, 1, 0 },
593ff8966acSHans de Goede { "MCH 1.25V", 4, 0, 10, 1, 0 },
594ff8966acSHans de Goede { "ICHIO 1.5V", 5, 0, 10, 1, 0 },
595ff8966acSHans de Goede { "ICH 1.05V", 6, 0, 10, 1, 0 },
596ff8966acSHans de Goede { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
597ff8966acSHans de Goede { "ATX +12V (8-pin)", 8, 0, 60, 1, 0 },
598ff8966acSHans de Goede { "ATX +5V", 9, 0, 30, 1, 0 },
599ff8966acSHans de Goede { "+3.3V", 10, 0, 20, 1, 0 },
600ff8966acSHans de Goede { "5VSB", 11, 0, 30, 1, 0 },
601ff8966acSHans de Goede { "CPU", 24, 1, 1, 1, 0 },
602ff8966acSHans de Goede { "System", 25, 1, 1, 1, 0 },
603ff8966acSHans de Goede { "PWM Phase1", 26, 1, 1, 1, 0 },
604ff8966acSHans de Goede { "PWM Phase2", 27, 1, 1, 1, 0 },
605ff8966acSHans de Goede { "PWM Phase3", 28, 1, 1, 1, 0 },
606ff8966acSHans de Goede { "PWM Phase4", 29, 1, 1, 1, 0 },
607ff8966acSHans de Goede { "PWM Phase5", 30, 1, 1, 1, 0 },
608ff8966acSHans de Goede { "CPU Fan", 32, 2, 60, 1, 0 },
609ff8966acSHans de Goede { "SYS Fan", 34, 2, 60, 1, 0 },
610ff8966acSHans de Goede { "AUX1 Fan", 33, 2, 60, 1, 0 },
611ff8966acSHans de Goede { "AUX2 Fan", 35, 2, 60, 1, 0 },
612ff8966acSHans de Goede { "AUX3 Fan", 36, 2, 60, 1, 0 },
613ff8966acSHans de Goede { NULL, 0, 0, 0, 0, 0 } }
614ff8966acSHans de Goede },
615bbe5939aSAlistair John Strachan { 0x0000, { NULL }, { { NULL, 0, 0, 0, 0, 0 } } }
6163faa1ffbSHans de Goede };
6173faa1ffbSHans de Goede
6183faa1ffbSHans de Goede
6193faa1ffbSHans de Goede /* Insmod parameters */
62090ab5ee9SRusty Russell static bool force;
6213faa1ffbSHans de Goede module_param(force, bool, 0);
6223faa1ffbSHans de Goede MODULE_PARM_DESC(force, "Set to one to force detection.");
6233faa1ffbSHans de Goede /* Default verbose is 1, since this driver is still in the testing phase */
62490ab5ee9SRusty Russell static bool verbose = 1;
6253faa1ffbSHans de Goede module_param(verbose, bool, 0644);
6263faa1ffbSHans de Goede MODULE_PARM_DESC(verbose, "Enable/disable verbose error reporting");
6273faa1ffbSHans de Goede
628fe826749SJoe Perches static const char *never_happen = "This should never happen.";
629fe826749SJoe Perches static const char *report_this =
630fe826749SJoe Perches "Please report this to the abituguru3 maintainer (see MAINTAINERS)";
6313faa1ffbSHans de Goede
6323faa1ffbSHans de Goede /* wait while the uguru is busy (usually after a write) */
abituguru3_wait_while_busy(struct abituguru3_data * data)6333faa1ffbSHans de Goede static int abituguru3_wait_while_busy(struct abituguru3_data *data)
6343faa1ffbSHans de Goede {
6353faa1ffbSHans de Goede u8 x;
6363faa1ffbSHans de Goede int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
6373faa1ffbSHans de Goede
6383faa1ffbSHans de Goede while ((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
6393faa1ffbSHans de Goede ABIT_UGURU3_STATUS_BUSY) {
6403faa1ffbSHans de Goede timeout--;
6413faa1ffbSHans de Goede if (timeout == 0)
6423faa1ffbSHans de Goede return x;
643562fca2fSGuenter Roeck /*
644562fca2fSGuenter Roeck * sleep a bit before our last try, to give the uGuru3 one
645562fca2fSGuenter Roeck * last chance to respond.
646562fca2fSGuenter Roeck */
6473faa1ffbSHans de Goede if (timeout == 1)
6483faa1ffbSHans de Goede msleep(1);
6493faa1ffbSHans de Goede }
6503faa1ffbSHans de Goede return ABIT_UGURU3_SUCCESS;
6513faa1ffbSHans de Goede }
6523faa1ffbSHans de Goede
6533faa1ffbSHans de Goede /* wait till uguru is ready to be read */
abituguru3_wait_for_read(struct abituguru3_data * data)6543faa1ffbSHans de Goede static int abituguru3_wait_for_read(struct abituguru3_data *data)
6553faa1ffbSHans de Goede {
6563faa1ffbSHans de Goede u8 x;
6573faa1ffbSHans de Goede int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
6583faa1ffbSHans de Goede
6593faa1ffbSHans de Goede while (!((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
6603faa1ffbSHans de Goede ABIT_UGURU3_STATUS_READY_FOR_READ)) {
6613faa1ffbSHans de Goede timeout--;
6623faa1ffbSHans de Goede if (timeout == 0)
6633faa1ffbSHans de Goede return x;
664562fca2fSGuenter Roeck /*
665562fca2fSGuenter Roeck * sleep a bit before our last try, to give the uGuru3 one
666562fca2fSGuenter Roeck * last chance to respond.
667562fca2fSGuenter Roeck */
6683faa1ffbSHans de Goede if (timeout == 1)
6693faa1ffbSHans de Goede msleep(1);
6703faa1ffbSHans de Goede }
6713faa1ffbSHans de Goede return ABIT_UGURU3_SUCCESS;
6723faa1ffbSHans de Goede }
6733faa1ffbSHans de Goede
674562fca2fSGuenter Roeck /*
675562fca2fSGuenter Roeck * This synchronizes us with the uGuru3's protocol state machine, this
676562fca2fSGuenter Roeck * must be done before each command.
677562fca2fSGuenter Roeck */
abituguru3_synchronize(struct abituguru3_data * data)6783faa1ffbSHans de Goede static int abituguru3_synchronize(struct abituguru3_data *data)
6793faa1ffbSHans de Goede {
6803faa1ffbSHans de Goede int x, timeout = ABIT_UGURU3_SYNCHRONIZE_TIMEOUT;
6813faa1ffbSHans de Goede
68279738416SGuenter Roeck x = abituguru3_wait_while_busy(data);
68379738416SGuenter Roeck if (x != ABIT_UGURU3_SUCCESS) {
6843faa1ffbSHans de Goede ABIT_UGURU3_DEBUG("synchronize timeout during initial busy "
6853faa1ffbSHans de Goede "wait, status: 0x%02x\n", x);
6863faa1ffbSHans de Goede return -EIO;
6873faa1ffbSHans de Goede }
6883faa1ffbSHans de Goede
6893faa1ffbSHans de Goede outb(0x20, data->addr + ABIT_UGURU3_DATA);
69079738416SGuenter Roeck x = abituguru3_wait_while_busy(data);
69179738416SGuenter Roeck if (x != ABIT_UGURU3_SUCCESS) {
6923faa1ffbSHans de Goede ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x20, "
6933faa1ffbSHans de Goede "status: 0x%02x\n", x);
6943faa1ffbSHans de Goede return -EIO;
6953faa1ffbSHans de Goede }
6963faa1ffbSHans de Goede
6973faa1ffbSHans de Goede outb(0x10, data->addr + ABIT_UGURU3_CMD);
69879738416SGuenter Roeck x = abituguru3_wait_while_busy(data);
69979738416SGuenter Roeck if (x != ABIT_UGURU3_SUCCESS) {
7003faa1ffbSHans de Goede ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x10, "
7013faa1ffbSHans de Goede "status: 0x%02x\n", x);
7023faa1ffbSHans de Goede return -EIO;
7033faa1ffbSHans de Goede }
7043faa1ffbSHans de Goede
7053faa1ffbSHans de Goede outb(0x00, data->addr + ABIT_UGURU3_CMD);
70679738416SGuenter Roeck x = abituguru3_wait_while_busy(data);
70779738416SGuenter Roeck if (x != ABIT_UGURU3_SUCCESS) {
7083faa1ffbSHans de Goede ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x00, "
7093faa1ffbSHans de Goede "status: 0x%02x\n", x);
7103faa1ffbSHans de Goede return -EIO;
7113faa1ffbSHans de Goede }
7123faa1ffbSHans de Goede
71379738416SGuenter Roeck x = abituguru3_wait_for_read(data);
71479738416SGuenter Roeck if (x != ABIT_UGURU3_SUCCESS) {
7153faa1ffbSHans de Goede ABIT_UGURU3_DEBUG("synchronize timeout waiting for read, "
7163faa1ffbSHans de Goede "status: 0x%02x\n", x);
7173faa1ffbSHans de Goede return -EIO;
7183faa1ffbSHans de Goede }
7193faa1ffbSHans de Goede
7203faa1ffbSHans de Goede while ((x = inb(data->addr + ABIT_UGURU3_CMD)) != 0xAC) {
7213faa1ffbSHans de Goede timeout--;
7223faa1ffbSHans de Goede if (timeout == 0) {
7233faa1ffbSHans de Goede ABIT_UGURU3_DEBUG("synchronize timeout cmd does not "
7243faa1ffbSHans de Goede "hold 0xAC after synchronize, cmd: 0x%02x\n",
7253faa1ffbSHans de Goede x);
7263faa1ffbSHans de Goede return -EIO;
7273faa1ffbSHans de Goede }
7283faa1ffbSHans de Goede msleep(1);
7293faa1ffbSHans de Goede }
7303faa1ffbSHans de Goede return 0;
7313faa1ffbSHans de Goede }
7323faa1ffbSHans de Goede
733562fca2fSGuenter Roeck /*
734562fca2fSGuenter Roeck * Read count bytes from sensor sensor_addr in bank bank_addr and store the
735562fca2fSGuenter Roeck * result in buf
736562fca2fSGuenter Roeck */
abituguru3_read(struct abituguru3_data * data,u8 bank,u8 offset,u8 count,u8 * buf)7373faa1ffbSHans de Goede static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset,
7383faa1ffbSHans de Goede u8 count, u8 *buf)
7393faa1ffbSHans de Goede {
7403faa1ffbSHans de Goede int i, x;
7413faa1ffbSHans de Goede
74279738416SGuenter Roeck x = abituguru3_synchronize(data);
74379738416SGuenter Roeck if (x)
7443faa1ffbSHans de Goede return x;
7453faa1ffbSHans de Goede
7463faa1ffbSHans de Goede outb(0x1A, data->addr + ABIT_UGURU3_DATA);
74779738416SGuenter Roeck x = abituguru3_wait_while_busy(data);
74879738416SGuenter Roeck if (x != ABIT_UGURU3_SUCCESS) {
7493faa1ffbSHans de Goede ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
7503faa1ffbSHans de Goede "sending 0x1A, status: 0x%02x\n", (unsigned int)bank,
7513faa1ffbSHans de Goede (unsigned int)offset, x);
7523faa1ffbSHans de Goede return -EIO;
7533faa1ffbSHans de Goede }
7543faa1ffbSHans de Goede
7553faa1ffbSHans de Goede outb(bank, data->addr + ABIT_UGURU3_CMD);
75679738416SGuenter Roeck x = abituguru3_wait_while_busy(data);
75779738416SGuenter Roeck if (x != ABIT_UGURU3_SUCCESS) {
7583faa1ffbSHans de Goede ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
7593faa1ffbSHans de Goede "sending the bank, status: 0x%02x\n",
7603faa1ffbSHans de Goede (unsigned int)bank, (unsigned int)offset, x);
7613faa1ffbSHans de Goede return -EIO;
7623faa1ffbSHans de Goede }
7633faa1ffbSHans de Goede
7643faa1ffbSHans de Goede outb(offset, data->addr + ABIT_UGURU3_CMD);
76579738416SGuenter Roeck x = abituguru3_wait_while_busy(data);
76679738416SGuenter Roeck if (x != ABIT_UGURU3_SUCCESS) {
7673faa1ffbSHans de Goede ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
7683faa1ffbSHans de Goede "sending the offset, status: 0x%02x\n",
7693faa1ffbSHans de Goede (unsigned int)bank, (unsigned int)offset, x);
7703faa1ffbSHans de Goede return -EIO;
7713faa1ffbSHans de Goede }
7723faa1ffbSHans de Goede
7733faa1ffbSHans de Goede outb(count, data->addr + ABIT_UGURU3_CMD);
77479738416SGuenter Roeck x = abituguru3_wait_while_busy(data);
77579738416SGuenter Roeck if (x != ABIT_UGURU3_SUCCESS) {
7763faa1ffbSHans de Goede ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
7773faa1ffbSHans de Goede "sending the count, status: 0x%02x\n",
7783faa1ffbSHans de Goede (unsigned int)bank, (unsigned int)offset, x);
7793faa1ffbSHans de Goede return -EIO;
7803faa1ffbSHans de Goede }
7813faa1ffbSHans de Goede
7823faa1ffbSHans de Goede for (i = 0; i < count; i++) {
78379738416SGuenter Roeck x = abituguru3_wait_for_read(data);
78479738416SGuenter Roeck if (x != ABIT_UGURU3_SUCCESS) {
7853faa1ffbSHans de Goede ABIT_UGURU3_DEBUG("timeout reading byte %d from "
7863faa1ffbSHans de Goede "0x%02x:0x%02x, status: 0x%02x\n", i,
7873faa1ffbSHans de Goede (unsigned int)bank, (unsigned int)offset, x);
7883faa1ffbSHans de Goede break;
7893faa1ffbSHans de Goede }
7903faa1ffbSHans de Goede buf[i] = inb(data->addr + ABIT_UGURU3_CMD);
7913faa1ffbSHans de Goede }
7923faa1ffbSHans de Goede return i;
7933faa1ffbSHans de Goede }
7943faa1ffbSHans de Goede
795562fca2fSGuenter Roeck /*
796562fca2fSGuenter Roeck * Sensor settings are stored 1 byte per offset with the bytes
797562fca2fSGuenter Roeck * placed add consecutive offsets.
798562fca2fSGuenter Roeck */
abituguru3_read_increment_offset(struct abituguru3_data * data,u8 bank,u8 offset,u8 count,u8 * buf,int offset_count)7994688902dSAdrian Bunk static int abituguru3_read_increment_offset(struct abituguru3_data *data,
8004688902dSAdrian Bunk u8 bank, u8 offset, u8 count,
8014688902dSAdrian Bunk u8 *buf, int offset_count)
8023faa1ffbSHans de Goede {
8033faa1ffbSHans de Goede int i, x;
8043faa1ffbSHans de Goede
80579738416SGuenter Roeck for (i = 0; i < offset_count; i++) {
80679738416SGuenter Roeck x = abituguru3_read(data, bank, offset + i, count,
80779738416SGuenter Roeck buf + i * count);
80879738416SGuenter Roeck if (x != count) {
8093bb9db79SJean Delvare if (x < 0)
8103bb9db79SJean Delvare return x;
8113bb9db79SJean Delvare return i * count + x;
8123bb9db79SJean Delvare }
81379738416SGuenter Roeck }
8143faa1ffbSHans de Goede
8153faa1ffbSHans de Goede return i * count;
8163faa1ffbSHans de Goede }
8173faa1ffbSHans de Goede
818562fca2fSGuenter Roeck /*
819562fca2fSGuenter Roeck * Following are the sysfs callback functions. These functions expect:
820562fca2fSGuenter Roeck * sensor_device_attribute_2->index: index into the data->sensors array
821562fca2fSGuenter Roeck * sensor_device_attribute_2->nr: register offset, bitmask or NA.
822562fca2fSGuenter Roeck */
8233faa1ffbSHans de Goede static struct abituguru3_data *abituguru3_update_device(struct device *dev);
8243faa1ffbSHans de Goede
show_value(struct device * dev,struct device_attribute * devattr,char * buf)8253faa1ffbSHans de Goede static ssize_t show_value(struct device *dev,
8263faa1ffbSHans de Goede struct device_attribute *devattr, char *buf)
8273faa1ffbSHans de Goede {
8283faa1ffbSHans de Goede int value;
8293faa1ffbSHans de Goede struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
8303faa1ffbSHans de Goede struct abituguru3_data *data = abituguru3_update_device(dev);
8313faa1ffbSHans de Goede const struct abituguru3_sensor_info *sensor;
8323faa1ffbSHans de Goede
8333faa1ffbSHans de Goede if (!data)
8343faa1ffbSHans de Goede return -EIO;
8353faa1ffbSHans de Goede
8363faa1ffbSHans de Goede sensor = &data->sensors[attr->index];
8373faa1ffbSHans de Goede
8383faa1ffbSHans de Goede /* are we reading a setting, or is this a normal read? */
8393faa1ffbSHans de Goede if (attr->nr)
8403faa1ffbSHans de Goede value = data->settings[sensor->port][attr->nr];
8413faa1ffbSHans de Goede else
8423faa1ffbSHans de Goede value = data->value[sensor->port];
8433faa1ffbSHans de Goede
8443faa1ffbSHans de Goede /* convert the value */
8453faa1ffbSHans de Goede value = (value * sensor->multiplier) / sensor->divisor +
8463faa1ffbSHans de Goede sensor->offset;
8473faa1ffbSHans de Goede
848562fca2fSGuenter Roeck /*
849562fca2fSGuenter Roeck * alternatively we could update the sensors settings struct for this,
850562fca2fSGuenter Roeck * but then its contents would differ from the windows sw ini files
851562fca2fSGuenter Roeck */
8523faa1ffbSHans de Goede if (sensor->type == ABIT_UGURU3_TEMP_SENSOR)
8533faa1ffbSHans de Goede value *= 1000;
8543faa1ffbSHans de Goede
8553faa1ffbSHans de Goede return sprintf(buf, "%d\n", value);
8563faa1ffbSHans de Goede }
8573faa1ffbSHans de Goede
show_alarm(struct device * dev,struct device_attribute * devattr,char * buf)8583faa1ffbSHans de Goede static ssize_t show_alarm(struct device *dev,
8593faa1ffbSHans de Goede struct device_attribute *devattr, char *buf)
8603faa1ffbSHans de Goede {
8613faa1ffbSHans de Goede int port;
8623faa1ffbSHans de Goede struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
8633faa1ffbSHans de Goede struct abituguru3_data *data = abituguru3_update_device(dev);
8643faa1ffbSHans de Goede
8653faa1ffbSHans de Goede if (!data)
8663faa1ffbSHans de Goede return -EIO;
8673faa1ffbSHans de Goede
8683faa1ffbSHans de Goede port = data->sensors[attr->index].port;
8693faa1ffbSHans de Goede
870562fca2fSGuenter Roeck /*
871562fca2fSGuenter Roeck * See if the alarm bit for this sensor is set and if a bitmask is
872562fca2fSGuenter Roeck * given in attr->nr also check if the alarm matches the type of alarm
873562fca2fSGuenter Roeck * we're looking for (for volt it can be either low or high). The type
874562fca2fSGuenter Roeck * is stored in a few readonly bits in the settings of the sensor.
875562fca2fSGuenter Roeck */
8763faa1ffbSHans de Goede if ((data->alarms[port / 8] & (0x01 << (port % 8))) &&
8773faa1ffbSHans de Goede (!attr->nr || (data->settings[port][0] & attr->nr)))
8783faa1ffbSHans de Goede return sprintf(buf, "1\n");
8793faa1ffbSHans de Goede else
8803faa1ffbSHans de Goede return sprintf(buf, "0\n");
8813faa1ffbSHans de Goede }
8823faa1ffbSHans de Goede
show_mask(struct device * dev,struct device_attribute * devattr,char * buf)8833faa1ffbSHans de Goede static ssize_t show_mask(struct device *dev,
8843faa1ffbSHans de Goede struct device_attribute *devattr, char *buf)
8853faa1ffbSHans de Goede {
8863faa1ffbSHans de Goede struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
8873faa1ffbSHans de Goede struct abituguru3_data *data = dev_get_drvdata(dev);
8883faa1ffbSHans de Goede
8893faa1ffbSHans de Goede if (data->settings[data->sensors[attr->index].port][0] & attr->nr)
8903faa1ffbSHans de Goede return sprintf(buf, "1\n");
8913faa1ffbSHans de Goede else
8923faa1ffbSHans de Goede return sprintf(buf, "0\n");
8933faa1ffbSHans de Goede }
8943faa1ffbSHans de Goede
show_label(struct device * dev,struct device_attribute * devattr,char * buf)8953faa1ffbSHans de Goede static ssize_t show_label(struct device *dev,
8963faa1ffbSHans de Goede struct device_attribute *devattr, char *buf)
8973faa1ffbSHans de Goede {
8983faa1ffbSHans de Goede struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
8993faa1ffbSHans de Goede struct abituguru3_data *data = dev_get_drvdata(dev);
9003faa1ffbSHans de Goede
9013faa1ffbSHans de Goede return sprintf(buf, "%s\n", data->sensors[attr->index].name);
9023faa1ffbSHans de Goede }
9033faa1ffbSHans de Goede
show_name(struct device * dev,struct device_attribute * devattr,char * buf)9043faa1ffbSHans de Goede static ssize_t show_name(struct device *dev,
9053faa1ffbSHans de Goede struct device_attribute *devattr, char *buf)
9063faa1ffbSHans de Goede {
9073faa1ffbSHans de Goede return sprintf(buf, "%s\n", ABIT_UGURU3_NAME);
9083faa1ffbSHans de Goede }
9093faa1ffbSHans de Goede
9103faa1ffbSHans de Goede /* Sysfs attr templates, the real entries are generated automatically. */
9113faa1ffbSHans de Goede static const
9123faa1ffbSHans de Goede struct sensor_device_attribute_2 abituguru3_sysfs_templ[3][10] = { {
9133faa1ffbSHans de Goede SENSOR_ATTR_2(in%d_input, 0444, show_value, NULL, 0, 0),
9143faa1ffbSHans de Goede SENSOR_ATTR_2(in%d_min, 0444, show_value, NULL, 1, 0),
9153faa1ffbSHans de Goede SENSOR_ATTR_2(in%d_max, 0444, show_value, NULL, 2, 0),
9163faa1ffbSHans de Goede SENSOR_ATTR_2(in%d_min_alarm, 0444, show_alarm, NULL,
9173faa1ffbSHans de Goede ABIT_UGURU3_VOLT_LOW_ALARM_FLAG, 0),
9183faa1ffbSHans de Goede SENSOR_ATTR_2(in%d_max_alarm, 0444, show_alarm, NULL,
9193faa1ffbSHans de Goede ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG, 0),
9203faa1ffbSHans de Goede SENSOR_ATTR_2(in%d_beep, 0444, show_mask, NULL,
9213faa1ffbSHans de Goede ABIT_UGURU3_BEEP_ENABLE, 0),
9223faa1ffbSHans de Goede SENSOR_ATTR_2(in%d_shutdown, 0444, show_mask, NULL,
9233faa1ffbSHans de Goede ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
9243faa1ffbSHans de Goede SENSOR_ATTR_2(in%d_min_alarm_enable, 0444, show_mask, NULL,
9253faa1ffbSHans de Goede ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE, 0),
9263faa1ffbSHans de Goede SENSOR_ATTR_2(in%d_max_alarm_enable, 0444, show_mask, NULL,
9273faa1ffbSHans de Goede ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE, 0),
9283faa1ffbSHans de Goede SENSOR_ATTR_2(in%d_label, 0444, show_label, NULL, 0, 0)
9293faa1ffbSHans de Goede }, {
9303faa1ffbSHans de Goede SENSOR_ATTR_2(temp%d_input, 0444, show_value, NULL, 0, 0),
9313faa1ffbSHans de Goede SENSOR_ATTR_2(temp%d_max, 0444, show_value, NULL, 1, 0),
9323faa1ffbSHans de Goede SENSOR_ATTR_2(temp%d_crit, 0444, show_value, NULL, 2, 0),
9333faa1ffbSHans de Goede SENSOR_ATTR_2(temp%d_alarm, 0444, show_alarm, NULL, 0, 0),
9343faa1ffbSHans de Goede SENSOR_ATTR_2(temp%d_beep, 0444, show_mask, NULL,
9353faa1ffbSHans de Goede ABIT_UGURU3_BEEP_ENABLE, 0),
9363faa1ffbSHans de Goede SENSOR_ATTR_2(temp%d_shutdown, 0444, show_mask, NULL,
9373faa1ffbSHans de Goede ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
9383faa1ffbSHans de Goede SENSOR_ATTR_2(temp%d_alarm_enable, 0444, show_mask, NULL,
9393faa1ffbSHans de Goede ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE, 0),
9403faa1ffbSHans de Goede SENSOR_ATTR_2(temp%d_label, 0444, show_label, NULL, 0, 0)
9413faa1ffbSHans de Goede }, {
9423faa1ffbSHans de Goede SENSOR_ATTR_2(fan%d_input, 0444, show_value, NULL, 0, 0),
9433faa1ffbSHans de Goede SENSOR_ATTR_2(fan%d_min, 0444, show_value, NULL, 1, 0),
9443faa1ffbSHans de Goede SENSOR_ATTR_2(fan%d_alarm, 0444, show_alarm, NULL, 0, 0),
9453faa1ffbSHans de Goede SENSOR_ATTR_2(fan%d_beep, 0444, show_mask, NULL,
9463faa1ffbSHans de Goede ABIT_UGURU3_BEEP_ENABLE, 0),
9473faa1ffbSHans de Goede SENSOR_ATTR_2(fan%d_shutdown, 0444, show_mask, NULL,
9483faa1ffbSHans de Goede ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
9493faa1ffbSHans de Goede SENSOR_ATTR_2(fan%d_alarm_enable, 0444, show_mask, NULL,
9503faa1ffbSHans de Goede ABIT_UGURU3_FAN_LOW_ALARM_ENABLE, 0),
9513faa1ffbSHans de Goede SENSOR_ATTR_2(fan%d_label, 0444, show_label, NULL, 0, 0)
9523faa1ffbSHans de Goede } };
9533faa1ffbSHans de Goede
9543faa1ffbSHans de Goede static struct sensor_device_attribute_2 abituguru3_sysfs_attr[] = {
9553faa1ffbSHans de Goede SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0),
9563faa1ffbSHans de Goede };
9573faa1ffbSHans de Goede
abituguru3_probe(struct platform_device * pdev)9586c931ae1SBill Pemberton static int abituguru3_probe(struct platform_device *pdev)
9593faa1ffbSHans de Goede {
9603faa1ffbSHans de Goede const int no_sysfs_attr[3] = { 10, 8, 7 };
9613faa1ffbSHans de Goede int sensor_index[3] = { 0, 1, 1 };
9623faa1ffbSHans de Goede struct abituguru3_data *data;
9633faa1ffbSHans de Goede int i, j, type, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV;
9643faa1ffbSHans de Goede char *sysfs_filename;
9653faa1ffbSHans de Goede u8 buf[2];
9663faa1ffbSHans de Goede u16 id;
9673faa1ffbSHans de Goede
968a34c26d8SGuenter Roeck data = devm_kzalloc(&pdev->dev, sizeof(struct abituguru3_data),
969a34c26d8SGuenter Roeck GFP_KERNEL);
97079738416SGuenter Roeck if (!data)
9713faa1ffbSHans de Goede return -ENOMEM;
9723faa1ffbSHans de Goede
9733faa1ffbSHans de Goede data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
9743faa1ffbSHans de Goede mutex_init(&data->update_lock);
9753faa1ffbSHans de Goede platform_set_drvdata(pdev, data);
9763faa1ffbSHans de Goede
9773faa1ffbSHans de Goede /* Read the motherboard ID */
97879738416SGuenter Roeck i = abituguru3_read(data, ABIT_UGURU3_MISC_BANK, ABIT_UGURU3_BOARD_ID,
97979738416SGuenter Roeck 2, buf);
98079738416SGuenter Roeck if (i != 2)
9813faa1ffbSHans de Goede goto abituguru3_probe_error;
9823faa1ffbSHans de Goede
9833faa1ffbSHans de Goede /* Completely read the uGuru to see if one really is there */
9843faa1ffbSHans de Goede if (!abituguru3_update_device(&pdev->dev))
9853faa1ffbSHans de Goede goto abituguru3_probe_error;
9863faa1ffbSHans de Goede
9873faa1ffbSHans de Goede /* lookup the ID in our motherboard table */
9883faa1ffbSHans de Goede id = ((u16)buf[0] << 8) | (u16)buf[1];
9893faa1ffbSHans de Goede for (i = 0; abituguru3_motherboards[i].id; i++)
9903faa1ffbSHans de Goede if (abituguru3_motherboards[i].id == id)
9913faa1ffbSHans de Goede break;
9923faa1ffbSHans de Goede if (!abituguru3_motherboards[i].id) {
993fe826749SJoe Perches pr_err("error unknown motherboard ID: %04X. %s\n",
994fe826749SJoe Perches (unsigned int)id, report_this);
9953faa1ffbSHans de Goede goto abituguru3_probe_error;
9963faa1ffbSHans de Goede }
9973faa1ffbSHans de Goede data->sensors = abituguru3_motherboards[i].sensors;
9984ef664b5SAlistair John Strachan
999fe826749SJoe Perches pr_info("found Abit uGuru3, motherboard ID: %04X\n", (unsigned int)id);
10004ef664b5SAlistair John Strachan
10013faa1ffbSHans de Goede /* Fill the sysfs attr array */
10023faa1ffbSHans de Goede sysfs_attr_i = 0;
10033faa1ffbSHans de Goede sysfs_filename = data->sysfs_names;
10043faa1ffbSHans de Goede sysfs_names_free = ABIT_UGURU3_SYSFS_NAMES_LENGTH;
10053faa1ffbSHans de Goede for (i = 0; data->sensors[i].name; i++) {
10063faa1ffbSHans de Goede /* Fail safe check, this should never happen! */
10073faa1ffbSHans de Goede if (i >= ABIT_UGURU3_MAX_NO_SENSORS) {
1008fe826749SJoe Perches pr_err("Fatal error motherboard has more sensors then ABIT_UGURU3_MAX_NO_SENSORS. %s %s\n",
1009fe826749SJoe Perches never_happen, report_this);
10103faa1ffbSHans de Goede res = -ENAMETOOLONG;
10113faa1ffbSHans de Goede goto abituguru3_probe_error;
10123faa1ffbSHans de Goede }
10133faa1ffbSHans de Goede type = data->sensors[i].type;
10143faa1ffbSHans de Goede for (j = 0; j < no_sysfs_attr[type]; j++) {
10153faa1ffbSHans de Goede used = snprintf(sysfs_filename, sysfs_names_free,
10163faa1ffbSHans de Goede abituguru3_sysfs_templ[type][j].dev_attr.attr.
10173faa1ffbSHans de Goede name, sensor_index[type]) + 1;
10183faa1ffbSHans de Goede data->sysfs_attr[sysfs_attr_i] =
10193faa1ffbSHans de Goede abituguru3_sysfs_templ[type][j];
10203faa1ffbSHans de Goede data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
10213faa1ffbSHans de Goede sysfs_filename;
10223faa1ffbSHans de Goede data->sysfs_attr[sysfs_attr_i].index = i;
10233faa1ffbSHans de Goede sysfs_filename += used;
10243faa1ffbSHans de Goede sysfs_names_free -= used;
10253faa1ffbSHans de Goede sysfs_attr_i++;
10263faa1ffbSHans de Goede }
10273faa1ffbSHans de Goede sensor_index[type]++;
10283faa1ffbSHans de Goede }
10293faa1ffbSHans de Goede /* Fail safe check, this should never happen! */
10303faa1ffbSHans de Goede if (sysfs_names_free < 0) {
1031fe826749SJoe Perches pr_err("Fatal error ran out of space for sysfs attr names. %s %s\n",
1032fe826749SJoe Perches never_happen, report_this);
10333faa1ffbSHans de Goede res = -ENAMETOOLONG;
10343faa1ffbSHans de Goede goto abituguru3_probe_error;
10353faa1ffbSHans de Goede }
10363faa1ffbSHans de Goede
10373faa1ffbSHans de Goede /* Register sysfs hooks */
10383faa1ffbSHans de Goede for (i = 0; i < sysfs_attr_i; i++)
10393faa1ffbSHans de Goede if (device_create_file(&pdev->dev,
10403faa1ffbSHans de Goede &data->sysfs_attr[i].dev_attr))
10413faa1ffbSHans de Goede goto abituguru3_probe_error;
10423faa1ffbSHans de Goede for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
10433faa1ffbSHans de Goede if (device_create_file(&pdev->dev,
10443faa1ffbSHans de Goede &abituguru3_sysfs_attr[i].dev_attr))
10453faa1ffbSHans de Goede goto abituguru3_probe_error;
10463faa1ffbSHans de Goede
10471beeffe4STony Jones data->hwmon_dev = hwmon_device_register(&pdev->dev);
10481beeffe4STony Jones if (IS_ERR(data->hwmon_dev)) {
10491beeffe4STony Jones res = PTR_ERR(data->hwmon_dev);
10503faa1ffbSHans de Goede goto abituguru3_probe_error;
10513faa1ffbSHans de Goede }
10523faa1ffbSHans de Goede
10533faa1ffbSHans de Goede return 0; /* success */
10543faa1ffbSHans de Goede
10553faa1ffbSHans de Goede abituguru3_probe_error:
10563faa1ffbSHans de Goede for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
10573faa1ffbSHans de Goede device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
10583faa1ffbSHans de Goede for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
10593faa1ffbSHans de Goede device_remove_file(&pdev->dev,
10603faa1ffbSHans de Goede &abituguru3_sysfs_attr[i].dev_attr);
10613faa1ffbSHans de Goede return res;
10623faa1ffbSHans de Goede }
10633faa1ffbSHans de Goede
abituguru3_remove(struct platform_device * pdev)1064281dfd0bSBill Pemberton static int abituguru3_remove(struct platform_device *pdev)
10653faa1ffbSHans de Goede {
10663faa1ffbSHans de Goede int i;
10673faa1ffbSHans de Goede struct abituguru3_data *data = platform_get_drvdata(pdev);
10683faa1ffbSHans de Goede
10691beeffe4STony Jones hwmon_device_unregister(data->hwmon_dev);
10703faa1ffbSHans de Goede for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
10713faa1ffbSHans de Goede device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
10723faa1ffbSHans de Goede for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
10733faa1ffbSHans de Goede device_remove_file(&pdev->dev,
10743faa1ffbSHans de Goede &abituguru3_sysfs_attr[i].dev_attr);
10753faa1ffbSHans de Goede return 0;
10763faa1ffbSHans de Goede }
10773faa1ffbSHans de Goede
abituguru3_update_device(struct device * dev)10783faa1ffbSHans de Goede static struct abituguru3_data *abituguru3_update_device(struct device *dev)
10793faa1ffbSHans de Goede {
10803faa1ffbSHans de Goede int i;
10813faa1ffbSHans de Goede struct abituguru3_data *data = dev_get_drvdata(dev);
10823faa1ffbSHans de Goede
10833faa1ffbSHans de Goede mutex_lock(&data->update_lock);
10843faa1ffbSHans de Goede if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
10853faa1ffbSHans de Goede /* Clear data->valid while updating */
1086952a11caSPaul Fertser data->valid = false;
10873faa1ffbSHans de Goede /* Read alarms */
10883faa1ffbSHans de Goede if (abituguru3_read_increment_offset(data,
10893faa1ffbSHans de Goede ABIT_UGURU3_SETTINGS_BANK,
10903faa1ffbSHans de Goede ABIT_UGURU3_ALARMS_START,
10913faa1ffbSHans de Goede 1, data->alarms, 48/8) != (48/8))
10923faa1ffbSHans de Goede goto LEAVE_UPDATE;
10933faa1ffbSHans de Goede /* Read in and temp sensors (3 byte settings / sensor) */
10943faa1ffbSHans de Goede for (i = 0; i < 32; i++) {
10953faa1ffbSHans de Goede if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
10963faa1ffbSHans de Goede ABIT_UGURU3_VALUES_START + i,
10973faa1ffbSHans de Goede 1, &data->value[i]) != 1)
10983faa1ffbSHans de Goede goto LEAVE_UPDATE;
10993faa1ffbSHans de Goede if (abituguru3_read_increment_offset(data,
11003faa1ffbSHans de Goede ABIT_UGURU3_SETTINGS_BANK,
11013faa1ffbSHans de Goede ABIT_UGURU3_SETTINGS_START + i * 3,
11023faa1ffbSHans de Goede 1,
11033faa1ffbSHans de Goede data->settings[i], 3) != 3)
11043faa1ffbSHans de Goede goto LEAVE_UPDATE;
11053faa1ffbSHans de Goede }
11063faa1ffbSHans de Goede /* Read temp sensors (2 byte settings / sensor) */
11073faa1ffbSHans de Goede for (i = 0; i < 16; i++) {
11083faa1ffbSHans de Goede if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
11093faa1ffbSHans de Goede ABIT_UGURU3_VALUES_START + 32 + i,
11103faa1ffbSHans de Goede 1, &data->value[32 + i]) != 1)
11113faa1ffbSHans de Goede goto LEAVE_UPDATE;
11123faa1ffbSHans de Goede if (abituguru3_read_increment_offset(data,
11133faa1ffbSHans de Goede ABIT_UGURU3_SETTINGS_BANK,
11143faa1ffbSHans de Goede ABIT_UGURU3_SETTINGS_START + 32 * 3 +
11153faa1ffbSHans de Goede i * 2, 1,
11163faa1ffbSHans de Goede data->settings[32 + i], 2) != 2)
11173faa1ffbSHans de Goede goto LEAVE_UPDATE;
11183faa1ffbSHans de Goede }
11193faa1ffbSHans de Goede data->last_updated = jiffies;
1120952a11caSPaul Fertser data->valid = true;
11213faa1ffbSHans de Goede }
11223faa1ffbSHans de Goede LEAVE_UPDATE:
11233faa1ffbSHans de Goede mutex_unlock(&data->update_lock);
11243faa1ffbSHans de Goede if (data->valid)
11253faa1ffbSHans de Goede return data;
11263faa1ffbSHans de Goede else
11273faa1ffbSHans de Goede return NULL;
11283faa1ffbSHans de Goede }
11293faa1ffbSHans de Goede
abituguru3_suspend(struct device * dev)1130c248f24cSRafael J. Wysocki static int abituguru3_suspend(struct device *dev)
11313faa1ffbSHans de Goede {
1132c248f24cSRafael J. Wysocki struct abituguru3_data *data = dev_get_drvdata(dev);
1133562fca2fSGuenter Roeck /*
1134562fca2fSGuenter Roeck * make sure all communications with the uguru3 are done and no new
1135562fca2fSGuenter Roeck * ones are started
1136562fca2fSGuenter Roeck */
11373faa1ffbSHans de Goede mutex_lock(&data->update_lock);
11383faa1ffbSHans de Goede return 0;
11393faa1ffbSHans de Goede }
11403faa1ffbSHans de Goede
abituguru3_resume(struct device * dev)1141c248f24cSRafael J. Wysocki static int abituguru3_resume(struct device *dev)
11423faa1ffbSHans de Goede {
1143c248f24cSRafael J. Wysocki struct abituguru3_data *data = dev_get_drvdata(dev);
11443faa1ffbSHans de Goede mutex_unlock(&data->update_lock);
11453faa1ffbSHans de Goede return 0;
11463faa1ffbSHans de Goede }
1147c248f24cSRafael J. Wysocki
1148*e7045a14SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(abituguru3_pm, abituguru3_suspend, abituguru3_resume);
11493faa1ffbSHans de Goede
11503faa1ffbSHans de Goede static struct platform_driver abituguru3_driver = {
11513faa1ffbSHans de Goede .driver = {
11523faa1ffbSHans de Goede .name = ABIT_UGURU3_NAME,
1153*e7045a14SJonathan Cameron .pm = pm_sleep_ptr(&abituguru3_pm),
11543faa1ffbSHans de Goede },
11553faa1ffbSHans de Goede .probe = abituguru3_probe,
11569e5e9b7aSBill Pemberton .remove = abituguru3_remove,
11573faa1ffbSHans de Goede };
11583faa1ffbSHans de Goede
abituguru3_dmi_detect(void)11594ef664b5SAlistair John Strachan static int __init abituguru3_dmi_detect(void)
11604ef664b5SAlistair John Strachan {
11614ef664b5SAlistair John Strachan const char *board_vendor, *board_name;
11624ef664b5SAlistair John Strachan int i, err = (force) ? 1 : -ENODEV;
1163bbe5939aSAlistair John Strachan const char *const *dmi_name;
1164058943ddSAlistair John Strachan size_t sublen;
11654ef664b5SAlistair John Strachan
11664ef664b5SAlistair John Strachan board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
11674ef664b5SAlistair John Strachan if (!board_vendor || strcmp(board_vendor, "http://www.abit.com.tw/"))
11684ef664b5SAlistair John Strachan return err;
11694ef664b5SAlistair John Strachan
11704ef664b5SAlistair John Strachan board_name = dmi_get_system_info(DMI_BOARD_NAME);
11714ef664b5SAlistair John Strachan if (!board_name)
11724ef664b5SAlistair John Strachan return err;
11734ef664b5SAlistair John Strachan
1174562fca2fSGuenter Roeck /*
1175562fca2fSGuenter Roeck * At the moment, we don't care about the part of the vendor
1176058943ddSAlistair John Strachan * DMI string contained in brackets. Truncate the string at
1177058943ddSAlistair John Strachan * the first occurrence of a bracket. Trim any trailing space
1178058943ddSAlistair John Strachan * from the substring.
1179058943ddSAlistair John Strachan */
1180058943ddSAlistair John Strachan sublen = strcspn(board_name, "(");
1181058943ddSAlistair John Strachan while (sublen > 0 && board_name[sublen - 1] == ' ')
1182058943ddSAlistair John Strachan sublen--;
1183058943ddSAlistair John Strachan
11844ef664b5SAlistair John Strachan for (i = 0; abituguru3_motherboards[i].id; i++) {
1185bbe5939aSAlistair John Strachan dmi_name = abituguru3_motherboards[i].dmi_name;
1186bbe5939aSAlistair John Strachan for ( ; *dmi_name; dmi_name++) {
1187bbe5939aSAlistair John Strachan if (strlen(*dmi_name) != sublen)
1188058943ddSAlistair John Strachan continue;
1189bbe5939aSAlistair John Strachan if (!strncasecmp(board_name, *dmi_name, sublen))
1190bbe5939aSAlistair John Strachan return 0;
1191bbe5939aSAlistair John Strachan }
11924ef664b5SAlistair John Strachan }
11934ef664b5SAlistair John Strachan
1194bbe5939aSAlistair John Strachan /* No match found */
11954ef664b5SAlistair John Strachan return 1;
11964ef664b5SAlistair John Strachan }
11974ef664b5SAlistair John Strachan
1198562fca2fSGuenter Roeck /*
1199562fca2fSGuenter Roeck * FIXME: Manual detection should die eventually; we need to collect stable
12004ef664b5SAlistair John Strachan * DMI model names first before we can rely entirely on CONFIG_DMI.
12014ef664b5SAlistair John Strachan */
12024ef664b5SAlistair John Strachan
abituguru3_detect(void)12033faa1ffbSHans de Goede static int __init abituguru3_detect(void)
12043faa1ffbSHans de Goede {
1205562fca2fSGuenter Roeck /*
1206562fca2fSGuenter Roeck * See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or
1207562fca2fSGuenter Roeck * 0x08 at DATA and 0xAC at CMD. Sometimes the uGuru3 will hold 0x05
1208562fca2fSGuenter Roeck * or 0x55 at CMD instead, why is unknown.
1209562fca2fSGuenter Roeck */
12103faa1ffbSHans de Goede u8 data_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_DATA);
12113faa1ffbSHans de Goede u8 cmd_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_CMD);
12129c2e14afSHans de Goede if (((data_val == 0x00) || (data_val == 0x08)) &&
1213b3aeab0cSHans de Goede ((cmd_val == 0xAC) || (cmd_val == 0x05) ||
1214b3aeab0cSHans de Goede (cmd_val == 0x55)))
12154ef664b5SAlistair John Strachan return 0;
12163faa1ffbSHans de Goede
12173faa1ffbSHans de Goede ABIT_UGURU3_DEBUG("no Abit uGuru3 found, data = 0x%02X, cmd = "
12183faa1ffbSHans de Goede "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
12193faa1ffbSHans de Goede
12203faa1ffbSHans de Goede if (force) {
1221fe826749SJoe Perches pr_info("Assuming Abit uGuru3 is present because of \"force\" parameter\n");
12224ef664b5SAlistair John Strachan return 0;
12233faa1ffbSHans de Goede }
12243faa1ffbSHans de Goede
12253faa1ffbSHans de Goede /* No uGuru3 found */
12263faa1ffbSHans de Goede return -ENODEV;
12273faa1ffbSHans de Goede }
12283faa1ffbSHans de Goede
12293faa1ffbSHans de Goede static struct platform_device *abituguru3_pdev;
12303faa1ffbSHans de Goede
abituguru3_init(void)12313faa1ffbSHans de Goede static int __init abituguru3_init(void)
12323faa1ffbSHans de Goede {
12333faa1ffbSHans de Goede struct resource res = { .flags = IORESOURCE_IO };
12344ef664b5SAlistair John Strachan int err;
12353faa1ffbSHans de Goede
12364ef664b5SAlistair John Strachan /* Attempt DMI detection first */
12374ef664b5SAlistair John Strachan err = abituguru3_dmi_detect();
12384ef664b5SAlistair John Strachan if (err < 0)
12394ef664b5SAlistair John Strachan return err;
1240b3aeab0cSHans de Goede
1241562fca2fSGuenter Roeck /*
1242562fca2fSGuenter Roeck * Fall back to manual detection if there was no exact
12434ef664b5SAlistair John Strachan * board name match, or force was specified.
12444ef664b5SAlistair John Strachan */
12454ef664b5SAlistair John Strachan if (err > 0) {
12464ef664b5SAlistair John Strachan err = abituguru3_detect();
12474ef664b5SAlistair John Strachan if (err)
12484ef664b5SAlistair John Strachan return err;
1249bbe5939aSAlistair John Strachan
1250fe826749SJoe Perches pr_warn("this motherboard was not detected using DMI. "
1251fe826749SJoe Perches "Please send the output of \"dmidecode\" to the abituguru3 maintainer (see MAINTAINERS)\n");
12524ef664b5SAlistair John Strachan }
12533faa1ffbSHans de Goede
12543faa1ffbSHans de Goede err = platform_driver_register(&abituguru3_driver);
12553faa1ffbSHans de Goede if (err)
12563faa1ffbSHans de Goede goto exit;
12573faa1ffbSHans de Goede
12584ef664b5SAlistair John Strachan abituguru3_pdev = platform_device_alloc(ABIT_UGURU3_NAME,
12594ef664b5SAlistair John Strachan ABIT_UGURU3_BASE);
12603faa1ffbSHans de Goede if (!abituguru3_pdev) {
1261fe826749SJoe Perches pr_err("Device allocation failed\n");
12623faa1ffbSHans de Goede err = -ENOMEM;
12633faa1ffbSHans de Goede goto exit_driver_unregister;
12643faa1ffbSHans de Goede }
12653faa1ffbSHans de Goede
12664ef664b5SAlistair John Strachan res.start = ABIT_UGURU3_BASE;
12674ef664b5SAlistair John Strachan res.end = ABIT_UGURU3_BASE + ABIT_UGURU3_REGION_LENGTH - 1;
12683faa1ffbSHans de Goede res.name = ABIT_UGURU3_NAME;
12693faa1ffbSHans de Goede
12703faa1ffbSHans de Goede err = platform_device_add_resources(abituguru3_pdev, &res, 1);
12713faa1ffbSHans de Goede if (err) {
1272fe826749SJoe Perches pr_err("Device resource addition failed (%d)\n", err);
12733faa1ffbSHans de Goede goto exit_device_put;
12743faa1ffbSHans de Goede }
12753faa1ffbSHans de Goede
12763faa1ffbSHans de Goede err = platform_device_add(abituguru3_pdev);
12773faa1ffbSHans de Goede if (err) {
1278fe826749SJoe Perches pr_err("Device addition failed (%d)\n", err);
12793faa1ffbSHans de Goede goto exit_device_put;
12803faa1ffbSHans de Goede }
12813faa1ffbSHans de Goede
12823faa1ffbSHans de Goede return 0;
12833faa1ffbSHans de Goede
12843faa1ffbSHans de Goede exit_device_put:
12853faa1ffbSHans de Goede platform_device_put(abituguru3_pdev);
12863faa1ffbSHans de Goede exit_driver_unregister:
12873faa1ffbSHans de Goede platform_driver_unregister(&abituguru3_driver);
12883faa1ffbSHans de Goede exit:
12893faa1ffbSHans de Goede return err;
12903faa1ffbSHans de Goede }
12913faa1ffbSHans de Goede
abituguru3_exit(void)12923faa1ffbSHans de Goede static void __exit abituguru3_exit(void)
12933faa1ffbSHans de Goede {
12943faa1ffbSHans de Goede platform_device_unregister(abituguru3_pdev);
12953faa1ffbSHans de Goede platform_driver_unregister(&abituguru3_driver);
12963faa1ffbSHans de Goede }
12973faa1ffbSHans de Goede
129893d0cc58SHans de Goede MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
12993faa1ffbSHans de Goede MODULE_DESCRIPTION("Abit uGuru3 Sensor device");
13003faa1ffbSHans de Goede MODULE_LICENSE("GPL");
13013faa1ffbSHans de Goede
13023faa1ffbSHans de Goede module_init(abituguru3_init);
13033faa1ffbSHans de Goede module_exit(abituguru3_exit);
1304