const: constify remaining dev_pm_ops
[safe/jmp/linux-2.6] / drivers / hwmon / applesmc.c
index 0c16067..c1605b5 100644 (file)
 
 #include <linux/delay.h>
 #include <linux/platform_device.h>
-#include <linux/input.h>
+#include <linux/input-polldev.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/timer.h>
 #include <linux/dmi.h>
 #include <linux/mutex.h>
 #include <linux/hwmon-sysfs.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/leds.h>
 #include <linux/hwmon.h>
 #include <linux/workqueue.h>
@@ -49,6 +49,9 @@
 
 #define APPLESMC_MAX_DATA_LENGTH 32
 
+#define APPLESMC_MIN_WAIT      0x0040
+#define APPLESMC_MAX_WAIT      0x8000
+
 #define APPLESMC_STATUS_MASK   0x0f
 #define APPLESMC_READ_CMD      0x10
 #define APPLESMC_WRITE_CMD     0x11
 
 #define KEY_COUNT_KEY          "#KEY" /* r-o ui32 */
 
-#define LIGHT_SENSOR_LEFT_KEY  "ALV0" /* r-o {alv (6 bytes) */
-#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6 bytes) */
-#define BACKLIGHT_KEY          "LKSB" /* w-o {lkb (2 bytes) */
+#define LIGHT_SENSOR_LEFT_KEY  "ALV0" /* r-o {alv (6-10 bytes) */
+#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6-10 bytes) */
+#define BACKLIGHT_KEY          "LKSB" /* w-o {lkb (2 bytes) */
 
-#define CLAMSHELL_KEY          "MSLD" /* r-o ui8 (unused) */
+#define CLAMSHELL_KEY          "MSLD" /* r-o ui8 (unused) */
 
 #define MOTION_SENSOR_X_KEY    "MO_X" /* r-o sp78 (2 bytes) */
 #define MOTION_SENSOR_Y_KEY    "MO_Y" /* r-o sp78 (2 bytes) */
 
 /*
  * Temperature sensors keys (sp78 - 2 bytes).
- * First set for Macbook(Pro), second for Macmini.
  */
-static const char* temperature_sensors_sets[][13] = {
+static const char *temperature_sensors_sets[][41] = {
+/* Set 0: Macbook Pro */
        { "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
          "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
-       { "TC0D", "TC0P", NULL }
+/* Set 1: Macbook2 set */
+       { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "TTF0", "Th0H",
+         "Th0S", "Th1H", NULL },
+/* Set 2: Macbook set */
+       { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S",
+         "Th1H", "Ts0P", NULL },
+/* Set 3: Macmini set */
+       { "TC0D", "TC0P", NULL },
+/* Set 4: Mac Pro (2 x Quad-Core) */
+       { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
+         "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "THTG", "TH0P",
+         "TH1P", "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S",
+         "TM1P", "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P",
+         "TM9S", "TN0H", "TS0C", NULL },
+/* Set 5: iMac */
+       { "TC0D", "TA0P", "TG0P", "TG0D", "TG0H", "TH0P", "Tm0P", "TO0P",
+         "Tp0C", NULL },
+/* Set 6: Macbook3 set */
+       { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TTF0", "TW0P", "Th0H",
+         "Th0S", "Th1H", NULL },
+/* Set 7: Macbook Air */
+       { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TC0P", "TCFP",
+         "TTF0", "TW0P", "Th0H", "Tp0P", "TpFP", "Ts0P", "Ts0S", NULL },
+/* Set 8: Macbook Pro 4,1 (Penryn) */
+       { "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P", "Th0H",
+         "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
+/* Set 9: Macbook Pro 3,1 (Santa Rosa) */
+       { "TALP", "TB0T", "TC0D", "TC0P", "TG0D", "TG0H", "TTF0", "TW0P",
+         "Th0H", "Th1H", "Th2H", "Tm0P", "Ts0P", NULL },
+/* Set 10: iMac 5,1 */
+       { "TA0P", "TC0D", "TC0P", "TG0D", "TH0P", "TO0P", "Tm0P", NULL },
+/* Set 11: Macbook 5,1 */
+       { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0P", "TN0D", "TN0P",
+         "TTF0", "Th0H", "Th1H", "ThFH", "Ts0P", "Ts0S", NULL },
+/* Set 12: Macbook Pro 5,1 */
+       { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0F", "TC0P", "TG0D",
+         "TG0F", "TG0H", "TG0P", "TG0T", "TG1H", "TN0D", "TN0P", "TTF0",
+         "Th2H", "Tm0P", "Ts0P", "Ts0S", NULL },
+/* Set 13: iMac 8,1 */
+       { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
+         "TL0P", "TO0P", "TW0P", "Tm0P", "Tp0P", NULL },
+/* Set 14: iMac 6,1 */
+       { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P",
+         "TO0P", "Tp0P", NULL },
+/* Set 15: MacBook Air 2,1 */
+       { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TN0D", "TTF0",
+         "TV0P", "TVFP", "TW0P", "Th0P", "Tp0P", "Tp1P", "TpFP", "Ts0P",
+         "Ts0S", NULL },
+/* Set 16: Mac Pro 3,1 (2 x Quad-Core) */
+       { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", "TC0C", "TC0D", "TC0P",
+         "TC1C", "TC1D", "TC2C", "TC2D", "TC3C", "TC3D", "TH0P", "TH1P",
+         "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S", "TM1P",
+         "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P", "TM9S",
+         "TN0C", "TN0D", "TN0H", "TS0C", "Tp0C", "Tp1C", "Tv0S", "Tv1S",
+         NULL },
 };
 
 /* List of keys used to read/write fan speeds */
@@ -99,7 +156,7 @@ static const char* fan_speed_keys[] = {
 #define INIT_TIMEOUT_MSECS     5000    /* wait up to 5s for device init ... */
 #define INIT_WAIT_MSECS                50      /* ... in 50ms increments */
 
-#define APPLESMC_POLL_PERIOD   (HZ/20) /* poll for input every 1/20s */
+#define APPLESMC_POLL_INTERVAL 50      /* msecs */
 #define APPLESMC_INPUT_FUZZ    4       /* input event threshold */
 #define APPLESMC_INPUT_FLAT    4
 
@@ -121,9 +178,10 @@ static const int debug;
 static struct platform_device *pdev;
 static s16 rest_x;
 static s16 rest_y;
-static struct timer_list applesmc_timer;
-static struct input_dev *applesmc_idev;
-static struct class_device *hwmon_class_dev;
+static u8 backlight_state[2];
+
+static struct device *hwmon_dev;
+static struct input_polled_dev *applesmc_idev;
 
 /* Indicates whether this computer has an accelerometer. */
 static unsigned int applesmc_accelerometer;
@@ -134,7 +192,7 @@ static unsigned int applesmc_light;
 /* Indicates which temperature sensors set to use. */
 static unsigned int applesmc_temperature_set;
 
-static struct mutex applesmc_lock;
+static DEFINE_MUTEX(applesmc_lock);
 
 /*
  * Last index written to key_at_index sysfs file, and value to use for all other
@@ -145,25 +203,25 @@ static unsigned int key_at_index;
 static struct workqueue_struct *applesmc_led_wq;
 
 /*
- * __wait_status - Wait up to 2ms for the status port to get a certain value
+ * __wait_status - Wait up to 32ms for the status port to get a certain value
  * (masked with 0x0f), returning zero if the value is obtained.  Callers must
  * hold applesmc_lock.
  */
 static int __wait_status(u8 val)
 {
-       unsigned int i;
+       int us;
 
        val = val & APPLESMC_STATUS_MASK;
 
-       for (i = 0; i < 200; i++) {
+       for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
+               udelay(us);
                if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
                        if (debug)
                                printk(KERN_DEBUG
-                                               "Waited %d us for status %x\n",
-                                               i*10, val);
+                                       "Waited %d us for status %x\n",
+                                       2 * us - APPLESMC_MIN_WAIT, val);
                        return 0;
                }
-               udelay(10);
        }
 
        printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
@@ -173,6 +231,25 @@ static int __wait_status(u8 val)
 }
 
 /*
+ * special treatment of command port - on newer macbooks, it seems necessary
+ * to resend the command byte before polling the status again. Callers must
+ * hold applesmc_lock.
+ */
+static int send_command(u8 cmd)
+{
+       int us;
+       for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
+               outb(cmd, APPLESMC_CMD_PORT);
+               udelay(us);
+               if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c)
+                       return 0;
+       }
+       printk(KERN_WARNING "applesmc: command failed: %x -> %x\n",
+               cmd, inb(APPLESMC_CMD_PORT));
+       return -EIO;
+}
+
+/*
  * applesmc_read_key - reads len bytes from a given key, and put them in buffer.
  * Returns zero on success or a negative error on failure. Callers must
  * hold applesmc_lock.
@@ -187,8 +264,7 @@ static int applesmc_read_key(const char* key, u8* buffer, u8 len)
                return -EINVAL;
        }
 
-       outb(APPLESMC_READ_CMD, APPLESMC_CMD_PORT);
-       if (__wait_status(0x0c))
+       if (send_command(APPLESMC_READ_CMD))
                return -EIO;
 
        for (i = 0; i < 4; i++) {
@@ -231,8 +307,7 @@ static int applesmc_write_key(const char* key, u8* buffer, u8 len)
                return -EINVAL;
        }
 
-       outb(APPLESMC_WRITE_CMD, APPLESMC_CMD_PORT);
-       if (__wait_status(0x0c))
+       if (send_command(APPLESMC_WRITE_CMD))
                return -EIO;
 
        for (i = 0; i < 4; i++) {
@@ -266,8 +341,7 @@ static int applesmc_get_key_at_index(int index, char* key)
        readkey[2] = index >> 8;
        readkey[3] = index;
 
-       outb(APPLESMC_GET_KEY_BY_INDEX_CMD, APPLESMC_CMD_PORT);
-       if (__wait_status(0x0c))
+       if (send_command(APPLESMC_GET_KEY_BY_INDEX_CMD))
                return -EIO;
 
        for (i = 0; i < 4; i++) {
@@ -297,8 +371,7 @@ static int applesmc_get_key_type(char* key, char* type)
 {
        int i;
 
-       outb(APPLESMC_GET_KEY_TYPE_CMD, APPLESMC_CMD_PORT);
-       if (__wait_status(0x0c))
+       if (send_command(APPLESMC_GET_KEY_TYPE_CMD))
                return -EIO;
 
        for (i = 0; i < 4; i++) {
@@ -307,7 +380,7 @@ static int applesmc_get_key_type(char* key, char* type)
                        return -EIO;
        }
 
-       outb(5, APPLESMC_DATA_PORT);
+       outb(6, APPLESMC_DATA_PORT);
 
        for (i = 0; i < 6; i++) {
                if (__wait_status(0x05))
@@ -426,17 +499,36 @@ static int applesmc_probe(struct platform_device *dev)
        return 0;
 }
 
-static int applesmc_resume(struct platform_device *dev)
+/* Synchronize device with memorized backlight state */
+static int applesmc_pm_resume(struct device *dev)
 {
-       return applesmc_device_init();
+       mutex_lock(&applesmc_lock);
+       if (applesmc_light)
+               applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
+       mutex_unlock(&applesmc_lock);
+       return 0;
 }
 
+/* Reinitialize device on resume from hibernation */
+static int applesmc_pm_restore(struct device *dev)
+{
+       int ret = applesmc_device_init();
+       if (ret)
+               return ret;
+       return applesmc_pm_resume(dev);
+}
+
+static const struct dev_pm_ops applesmc_pm_ops = {
+       .resume = applesmc_pm_resume,
+       .restore = applesmc_pm_restore,
+};
+
 static struct platform_driver applesmc_driver = {
        .probe = applesmc_probe,
-       .resume = applesmc_resume,
        .driver = {
                .name = "applesmc",
                .owner = THIS_MODULE,
+               .pm = &applesmc_pm_ops,
        },
 };
 
@@ -451,27 +543,12 @@ static void applesmc_calibrate(void)
        rest_x = -rest_x;
 }
 
-static int applesmc_idev_open(struct input_dev *dev)
-{
-       add_timer(&applesmc_timer);
-
-       return 0;
-}
-
-static void applesmc_idev_close(struct input_dev *dev)
-{
-       del_timer_sync(&applesmc_timer);
-}
-
-static void applesmc_idev_poll(unsigned long unused)
+static void applesmc_idev_poll(struct input_polled_dev *dev)
 {
+       struct input_dev *idev = dev->input;
        s16 x, y;
 
-       /* Cannot sleep.  Try nonblockingly.  If we fail, try again later. */
-       if (!mutex_trylock(&applesmc_lock)) {
-               mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
-               return;
-       }
+       mutex_lock(&applesmc_lock);
 
        if (applesmc_read_motion_sensor(SENSOR_X, &x))
                goto out;
@@ -479,18 +556,22 @@ static void applesmc_idev_poll(unsigned long unused)
                goto out;
 
        x = -x;
-       input_report_abs(applesmc_idev, ABS_X, x - rest_x);
-       input_report_abs(applesmc_idev, ABS_Y, y - rest_y);
-       input_sync(applesmc_idev);
+       input_report_abs(idev, ABS_X, x - rest_x);
+       input_report_abs(idev, ABS_Y, y - rest_y);
+       input_sync(idev);
 
 out:
-       mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
-
        mutex_unlock(&applesmc_lock);
 }
 
 /* Sysfs Files */
 
+static ssize_t applesmc_name_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "applesmc\n");
+}
+
 static ssize_t applesmc_position_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
@@ -520,17 +601,32 @@ out:
 static ssize_t applesmc_light_show(struct device *dev,
                                struct device_attribute *attr, char *sysfsbuf)
 {
+       static int data_length;
        int ret;
        u8 left = 0, right = 0;
-       u8 buffer[6];
+       u8 buffer[10], query[6];
 
        mutex_lock(&applesmc_lock);
 
-       ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, 6);
+       if (!data_length) {
+               ret = applesmc_get_key_type(LIGHT_SENSOR_LEFT_KEY, query);
+               if (ret)
+                       goto out;
+               data_length = clamp_val(query[0], 0, 10);
+               printk(KERN_INFO "applesmc: light sensor data length set to "
+                       "%d\n", data_length);
+       }
+
+       ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
+       /* newer macbooks report a single 10-bit bigendian value */
+       if (data_length == 10) {
+               left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2;
+               goto out;
+       }
        left = buffer[2];
        if (ret)
                goto out;
-       ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, 6);
+       ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, data_length);
        right = buffer[2];
 
 out:
@@ -729,17 +825,10 @@ static ssize_t applesmc_calibrate_store(struct device *dev,
        return count;
 }
 
-/* Store the next backlight value to be written by the work */
-static unsigned int backlight_value;
-
 static void applesmc_backlight_set(struct work_struct *work)
 {
-       u8 buffer[2];
-
        mutex_lock(&applesmc_lock);
-       buffer[0] = backlight_value;
-       buffer[1] = 0x00;
-       applesmc_write_key(BACKLIGHT_KEY, buffer, 2);
+       applesmc_write_key(BACKLIGHT_KEY, backlight_state, 2);
        mutex_unlock(&applesmc_lock);
 }
 static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
@@ -749,7 +838,7 @@ static void applesmc_brightness_set(struct led_classdev *led_cdev,
 {
        int ret;
 
-       backlight_value = value;
+       backlight_state[0] = value;
        ret = queue_work(applesmc_led_wq, &backlight_work);
 
        if (debug && (!ret))
@@ -811,8 +900,7 @@ static ssize_t applesmc_key_at_index_read_show(struct device *dev,
 
        if (!ret) {
                return info[0];
-       }
-       else {
+       } else {
                return ret;
        }
 }
@@ -908,11 +996,13 @@ static ssize_t applesmc_key_at_index_store(struct device *dev,
 }
 
 static struct led_classdev applesmc_backlight = {
-       .name                   = "smc:kbd_backlight",
+       .name                   = "smc::kbd_backlight",
        .default_trigger        = "nand-disk",
        .brightness_set         = applesmc_brightness_set,
 };
 
+static DEVICE_ATTR(name, 0444, applesmc_name_show, NULL);
+
 static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
 static DEVICE_ATTR(calibrate, 0644,
                        applesmc_calibrate_show, applesmc_calibrate_store);
@@ -997,14 +1087,18 @@ static struct attribute *fan##offset##_attributes[] = { \
 
 /*
  * Create the needed functions for each fan using the macro defined above
- * (2 fans are supported)
+ * (4 fans are supported)
  */
 sysfs_fan_speeds_offset(1);
 sysfs_fan_speeds_offset(2);
+sysfs_fan_speeds_offset(3);
+sysfs_fan_speeds_offset(4);
 
 static const struct attribute_group fan_attribute_groups[] = {
        { .attrs = fan1_attributes },
-       { .attrs = fan2_attributes }
+       { .attrs = fan2_attributes },
+       { .attrs = fan3_attributes },
+       { .attrs = fan4_attributes },
 };
 
 /*
@@ -1034,6 +1128,62 @@ static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
                                        applesmc_show_temperature, NULL, 10);
 static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
                                        applesmc_show_temperature, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp13_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp14_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp15_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp16_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 15);
+static SENSOR_DEVICE_ATTR(temp17_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 16);
+static SENSOR_DEVICE_ATTR(temp18_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp19_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 18);
+static SENSOR_DEVICE_ATTR(temp20_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 19);
+static SENSOR_DEVICE_ATTR(temp21_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 20);
+static SENSOR_DEVICE_ATTR(temp22_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 21);
+static SENSOR_DEVICE_ATTR(temp23_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 22);
+static SENSOR_DEVICE_ATTR(temp24_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 23);
+static SENSOR_DEVICE_ATTR(temp25_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 24);
+static SENSOR_DEVICE_ATTR(temp26_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 25);
+static SENSOR_DEVICE_ATTR(temp27_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 26);
+static SENSOR_DEVICE_ATTR(temp28_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 27);
+static SENSOR_DEVICE_ATTR(temp29_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 28);
+static SENSOR_DEVICE_ATTR(temp30_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 29);
+static SENSOR_DEVICE_ATTR(temp31_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 30);
+static SENSOR_DEVICE_ATTR(temp32_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 31);
+static SENSOR_DEVICE_ATTR(temp33_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 32);
+static SENSOR_DEVICE_ATTR(temp34_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 33);
+static SENSOR_DEVICE_ATTR(temp35_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 34);
+static SENSOR_DEVICE_ATTR(temp36_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 35);
+static SENSOR_DEVICE_ATTR(temp37_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 36);
+static SENSOR_DEVICE_ATTR(temp38_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 37);
+static SENSOR_DEVICE_ATTR(temp39_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 38);
+static SENSOR_DEVICE_ATTR(temp40_input, S_IRUGO,
+                                       applesmc_show_temperature, NULL, 39);
 
 static struct attribute *temperature_attributes[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
@@ -1048,6 +1198,34 @@ static struct attribute *temperature_attributes[] = {
        &sensor_dev_attr_temp10_input.dev_attr.attr,
        &sensor_dev_attr_temp11_input.dev_attr.attr,
        &sensor_dev_attr_temp12_input.dev_attr.attr,
+       &sensor_dev_attr_temp13_input.dev_attr.attr,
+       &sensor_dev_attr_temp14_input.dev_attr.attr,
+       &sensor_dev_attr_temp15_input.dev_attr.attr,
+       &sensor_dev_attr_temp16_input.dev_attr.attr,
+       &sensor_dev_attr_temp17_input.dev_attr.attr,
+       &sensor_dev_attr_temp18_input.dev_attr.attr,
+       &sensor_dev_attr_temp19_input.dev_attr.attr,
+       &sensor_dev_attr_temp20_input.dev_attr.attr,
+       &sensor_dev_attr_temp21_input.dev_attr.attr,
+       &sensor_dev_attr_temp22_input.dev_attr.attr,
+       &sensor_dev_attr_temp23_input.dev_attr.attr,
+       &sensor_dev_attr_temp24_input.dev_attr.attr,
+       &sensor_dev_attr_temp25_input.dev_attr.attr,
+       &sensor_dev_attr_temp26_input.dev_attr.attr,
+       &sensor_dev_attr_temp27_input.dev_attr.attr,
+       &sensor_dev_attr_temp28_input.dev_attr.attr,
+       &sensor_dev_attr_temp29_input.dev_attr.attr,
+       &sensor_dev_attr_temp30_input.dev_attr.attr,
+       &sensor_dev_attr_temp31_input.dev_attr.attr,
+       &sensor_dev_attr_temp32_input.dev_attr.attr,
+       &sensor_dev_attr_temp33_input.dev_attr.attr,
+       &sensor_dev_attr_temp34_input.dev_attr.attr,
+       &sensor_dev_attr_temp35_input.dev_attr.attr,
+       &sensor_dev_attr_temp36_input.dev_attr.attr,
+       &sensor_dev_attr_temp37_input.dev_attr.attr,
+       &sensor_dev_attr_temp38_input.dev_attr.attr,
+       &sensor_dev_attr_temp39_input.dev_attr.attr,
+       &sensor_dev_attr_temp40_input.dev_attr.attr,
        NULL
 };
 
@@ -1059,7 +1237,7 @@ static const struct attribute_group temperature_attributes_group =
 /*
  * applesmc_dmi_match - found a match.  return one, short-circuiting the hunt.
  */
-static int applesmc_dmi_match(struct dmi_system_id *id)
+static int applesmc_dmi_match(const struct dmi_system_id *id)
 {
        int i = 0;
        struct dmi_match_data* dmi_data = id->driver_data;
@@ -1081,6 +1259,7 @@ static int applesmc_dmi_match(struct dmi_system_id *id)
 /* Create accelerometer ressources */
 static int applesmc_create_accelerometer(void)
 {
+       struct input_dev *idev;
        int ret;
 
        ret = sysfs_create_group(&pdev->dev.kobj,
@@ -1088,40 +1267,37 @@ static int applesmc_create_accelerometer(void)
        if (ret)
                goto out;
 
-       applesmc_idev = input_allocate_device();
+       applesmc_idev = input_allocate_polled_device();
        if (!applesmc_idev) {
                ret = -ENOMEM;
                goto out_sysfs;
        }
 
+       applesmc_idev->poll = applesmc_idev_poll;
+       applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
+
        /* initial calibrate for the input device */
        applesmc_calibrate();
 
-       /* initialize the input class */
-       applesmc_idev->name = "applesmc";
-       applesmc_idev->id.bustype = BUS_HOST;
-       applesmc_idev->dev.parent = &pdev->dev;
-       applesmc_idev->evbit[0] = BIT(EV_ABS);
-       applesmc_idev->open = applesmc_idev_open;
-       applesmc_idev->close = applesmc_idev_close;
-       input_set_abs_params(applesmc_idev, ABS_X,
+       /* initialize the input device */
+       idev = applesmc_idev->input;
+       idev->name = "applesmc";
+       idev->id.bustype = BUS_HOST;
+       idev->dev.parent = &pdev->dev;
+       idev->evbit[0] = BIT_MASK(EV_ABS);
+       input_set_abs_params(idev, ABS_X,
                        -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
-       input_set_abs_params(applesmc_idev, ABS_Y,
+       input_set_abs_params(idev, ABS_Y,
                        -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
 
-       ret = input_register_device(applesmc_idev);
+       ret = input_register_polled_device(applesmc_idev);
        if (ret)
                goto out_idev;
 
-       /* start up our timer for the input device */
-       init_timer(&applesmc_timer);
-       applesmc_timer.function = applesmc_idev_poll;
-       applesmc_timer.expires = jiffies + APPLESMC_POLL_PERIOD;
-
        return 0;
 
 out_idev:
-       input_free_device(applesmc_idev);
+       input_free_polled_device(applesmc_idev);
 
 out_sysfs:
        sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
@@ -1134,35 +1310,127 @@ out:
 /* Release all ressources used by the accelerometer */
 static void applesmc_release_accelerometer(void)
 {
-       del_timer_sync(&applesmc_timer);
-       input_unregister_device(applesmc_idev);
+       input_unregister_polled_device(applesmc_idev);
+       input_free_polled_device(applesmc_idev);
        sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
 }
 
 static __initdata struct dmi_match_data applesmc_dmi_data[] = {
 /* MacBook Pro: accelerometer, backlight and temperature set 0 */
        { .accelerometer = 1, .light = 1, .temperature_set = 0 },
-/* MacBook: accelerometer and temperature set 0 */
-       { .accelerometer = 1, .light = 0, .temperature_set = 0 },
-/* MacBook: temperature set 1 */
-       { .accelerometer = 0, .light = 0, .temperature_set = 1 }
+/* MacBook2: accelerometer and temperature set 1 */
+       { .accelerometer = 1, .light = 0, .temperature_set = 1 },
+/* MacBook: accelerometer and temperature set 2 */
+       { .accelerometer = 1, .light = 0, .temperature_set = 2 },
+/* MacMini: temperature set 3 */
+       { .accelerometer = 0, .light = 0, .temperature_set = 3 },
+/* MacPro: temperature set 4 */
+       { .accelerometer = 0, .light = 0, .temperature_set = 4 },
+/* iMac: temperature set 5 */
+       { .accelerometer = 0, .light = 0, .temperature_set = 5 },
+/* MacBook3, MacBook4: accelerometer and temperature set 6 */
+       { .accelerometer = 1, .light = 0, .temperature_set = 6 },
+/* MacBook Air: accelerometer, backlight and temperature set 7 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 7 },
+/* MacBook Pro 4: accelerometer, backlight and temperature set 8 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 8 },
+/* MacBook Pro 3: accelerometer, backlight and temperature set 9 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 9 },
+/* iMac 5: light sensor only, temperature set 10 */
+       { .accelerometer = 0, .light = 0, .temperature_set = 10 },
+/* MacBook 5: accelerometer, backlight and temperature set 11 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 11 },
+/* MacBook Pro 5: accelerometer, backlight and temperature set 12 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 12 },
+/* iMac 8: light sensor only, temperature set 13 */
+       { .accelerometer = 0, .light = 0, .temperature_set = 13 },
+/* iMac 6: light sensor only, temperature set 14 */
+       { .accelerometer = 0, .light = 0, .temperature_set = 14 },
+/* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */
+       { .accelerometer = 1, .light = 1, .temperature_set = 15 },
+/* MacPro3,1: temperature set 16 */
+       { .accelerometer = 0, .light = 0, .temperature_set = 16 },
 };
 
 /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
  * So we need to put "Apple MacBook Pro" before "Apple MacBook". */
 static __initdata struct dmi_system_id applesmc_whitelist[] = {
+       { applesmc_dmi_match, "Apple MacBook Air 2", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") },
+               &applesmc_dmi_data[15]},
+       { applesmc_dmi_match, "Apple MacBook Air", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") },
+               &applesmc_dmi_data[7]},
+       { applesmc_dmi_match, "Apple MacBook Pro 5", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5") },
+               &applesmc_dmi_data[12]},
+       { applesmc_dmi_match, "Apple MacBook Pro 4", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4") },
+               &applesmc_dmi_data[8]},
+       { applesmc_dmi_match, "Apple MacBook Pro 3", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") },
+               &applesmc_dmi_data[9]},
        { applesmc_dmi_match, "Apple MacBook Pro", {
          DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
-               (void*)&applesmc_dmi_data[0]},
+               &applesmc_dmi_data[0]},
+       { applesmc_dmi_match, "Apple MacBook (v2)", {
+         DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") },
+               &applesmc_dmi_data[1]},
+       { applesmc_dmi_match, "Apple MacBook (v3)", {
+         DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") },
+               &applesmc_dmi_data[6]},
+       { applesmc_dmi_match, "Apple MacBook 4", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4") },
+               &applesmc_dmi_data[6]},
+       { applesmc_dmi_match, "Apple MacBook 5", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5") },
+               &applesmc_dmi_data[11]},
        { applesmc_dmi_match, "Apple MacBook", {
          DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
-               (void*)&applesmc_dmi_data[1]},
+               &applesmc_dmi_data[2]},
        { applesmc_dmi_match, "Apple Macmini", {
          DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
          DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
-               (void*)&applesmc_dmi_data[2]},
+               &applesmc_dmi_data[3]},
+       { applesmc_dmi_match, "Apple MacPro2", {
+         DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
+               &applesmc_dmi_data[4]},
+       { applesmc_dmi_match, "Apple MacPro3", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacPro3") },
+               &applesmc_dmi_data[16]},
+       { applesmc_dmi_match, "Apple MacPro", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
+               &applesmc_dmi_data[4]},
+       { applesmc_dmi_match, "Apple iMac 8", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "iMac8") },
+               &applesmc_dmi_data[13]},
+       { applesmc_dmi_match, "Apple iMac 6", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "iMac6") },
+               &applesmc_dmi_data[14]},
+       { applesmc_dmi_match, "Apple iMac 5", {
+         DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME, "iMac5") },
+               &applesmc_dmi_data[10]},
+       { applesmc_dmi_match, "Apple iMac", {
+         DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
+         DMI_MATCH(DMI_PRODUCT_NAME,"iMac") },
+               &applesmc_dmi_data[5]},
        { .ident = NULL }
 };
 
@@ -1172,8 +1440,6 @@ static int __init applesmc_init(void)
        int count;
        int i;
 
-       mutex_init(&applesmc_lock);
-
        if (!dmi_check_system(applesmc_whitelist)) {
                printk(KERN_WARNING "applesmc: supported laptop not found!\n");
                ret = -ENODEV;
@@ -1197,10 +1463,14 @@ static int __init applesmc_init(void)
                goto out_driver;
        }
 
+       ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_name.attr);
+       if (ret)
+               goto out_device;
+
        /* Create key enumeration sysfs files */
        ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
        if (ret)
-               goto out_device;
+               goto out_name;
 
        /* create fan files */
        count = applesmc_get_fan_count();
@@ -1211,9 +1481,19 @@ static int __init applesmc_init(void)
 
                switch (count) {
                default:
-                       printk(KERN_WARNING "applesmc: More than 2 fans found,"
-                                       " but at most 2 fans are supported"
+                       printk(KERN_WARNING "applesmc: More than 4 fans found,"
+                                       " but at most 4 fans are supported"
                                                " by the driver.\n");
+               case 4:
+                       ret = sysfs_create_group(&pdev->dev.kobj,
+                                                &fan_attribute_groups[3]);
+                       if (ret)
+                               goto out_key_enumeration;
+               case 3:
+                       ret = sysfs_create_group(&pdev->dev.kobj,
+                                                &fan_attribute_groups[2]);
+                       if (ret)
+                               goto out_key_enumeration;
                case 2:
                        ret = sysfs_create_group(&pdev->dev.kobj,
                                                 &fan_attribute_groups[1]);
@@ -1271,9 +1551,9 @@ static int __init applesmc_init(void)
                        goto out_light_wq;
        }
 
-       hwmon_class_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(hwmon_class_dev)) {
-               ret = PTR_ERR(hwmon_class_dev);
+       hwmon_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(hwmon_dev)) {
+               ret = PTR_ERR(hwmon_dev);
                goto out_light_ledclass;
        }
 
@@ -1300,6 +1580,8 @@ out_fan_1:
        sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
 out_key_enumeration:
        sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
+out_name:
+       sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
 out_device:
        platform_device_unregister(pdev);
 out_driver:
@@ -1313,7 +1595,7 @@ out:
 
 static void __exit applesmc_exit(void)
 {
-       hwmon_device_unregister(hwmon_class_dev);
+       hwmon_device_unregister(hwmon_dev);
        if (applesmc_light) {
                led_classdev_unregister(&applesmc_backlight);
                destroy_workqueue(applesmc_led_wq);
@@ -1325,6 +1607,7 @@ static void __exit applesmc_exit(void)
        sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
        sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
        sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
+       sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
        platform_device_unregister(pdev);
        platform_driver_unregister(&applesmc_driver);
        release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
@@ -1338,3 +1621,4 @@ module_exit(applesmc_exit);
 MODULE_AUTHOR("Nicolas Boichat");
 MODULE_DESCRIPTION("Apple SMC");
 MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(dmi, applesmc_whitelist);