Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-backlight
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 26 Sep 2009 17:49:42 +0000 (10:49 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 26 Sep 2009 17:49:42 +0000 (10:49 -0700)
* 'for-linus' of git://git.o-hand.com/linux-rpurdie-backlight:
  backlight: new driver for ADP5520/ADP5501 MFD PMICs
  backlight: extend event support to also support poll()
  backlight/eeepc-laptop: Update the backlight state when we change brightness
  backlight/acpi: Update the backlight state when we change brightness
  backlight: Allow drivers to update the core, and generate events on changes
  backlight: switch to da903x driver to dev_pm_ops
  backlight: Add support for the Avionic Design Xanthos backlight device.
  backlight: spi driver for LMS283GF05 LCD
  backlight: move hp680-bl's probe function to .devinit.text
  backlight: Add support for new Apple machines.
  backlight: mbp_nvidia_bl: add support for MacBookAir 1,1
  backlight: Add WM831x backlight driver

Trivial conflicts due to '#ifdef CONFIG_PM' differences in
drivers/video/backlight/da903x_bl.c

1  2 
drivers/acpi/video.c
drivers/platform/x86/eeepc-laptop.c
drivers/video/backlight/Kconfig

diff --combined drivers/acpi/video.c
index 94b1a4c5abab26978503835e4b5a9bf965776c6d,5845398479fa522704736f2750f6a7c496cd1f66..a4fddb24476fdba0bc1ebbafd510aaa3544595d1
  #include <linux/pci.h>
  #include <linux/pci_ids.h>
  #include <asm/uaccess.h>
 -
 +#include <linux/dmi.h>
  #include <acpi/acpi_bus.h>
  #include <acpi/acpi_drivers.h>
  
 +#define PREFIX "ACPI: "
 +
  #define ACPI_VIDEO_CLASS              "video"
  #define ACPI_VIDEO_BUS_NAME           "Video Bus"
  #define ACPI_VIDEO_DEVICE_NAME                "Video Device"
@@@ -200,7 -198,7 +200,7 @@@ struct acpi_video_device 
        struct acpi_device *dev;
        struct acpi_video_device_brightness *brightness;
        struct backlight_device *backlight;
 -      struct thermal_cooling_device *cdev;
 +      struct thermal_cooling_device *cooling_dev;
        struct output_device *output_dev;
  };
  
@@@ -389,20 -387,20 +389,20 @@@ static struct output_properties acpi_ou
  
  
  /* thermal cooling device callbacks */
 -static int video_get_max_state(struct thermal_cooling_device *cdev, unsigned
 +static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned
                               long *state)
  {
 -      struct acpi_device *device = cdev->devdata;
 +      struct acpi_device *device = cooling_dev->devdata;
        struct acpi_video_device *video = acpi_driver_data(device);
  
        *state = video->brightness->count - 3;
        return 0;
  }
  
 -static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned
 +static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsigned
                               long *state)
  {
 -      struct acpi_device *device = cdev->devdata;
 +      struct acpi_device *device = cooling_dev->devdata;
        struct acpi_video_device *video = acpi_driver_data(device);
        unsigned long long level;
        int offset;
  }
  
  static int
 -video_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
 +video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long state)
  {
 -      struct acpi_device *device = cdev->devdata;
 +      struct acpi_device *device = cooling_dev->devdata;
        struct acpi_video_device *video = acpi_driver_data(device);
        int level;
  
@@@ -605,7 -603,6 +605,7 @@@ acpi_video_device_lcd_get_level_current
                                        unsigned long long *level)
  {
        acpi_status status = AE_OK;
 +      int i;
  
        if (device->cap._BQC || device->cap._BCQ) {
                char *buf = device->cap._BQC ? "_BQC" : "_BCQ";
  
                        }
                        *level += bqc_offset_aml_bug_workaround;
 -                      device->brightness->curr = *level;
 -                      return 0;
 +                      for (i = 2; i < device->brightness->count; i++)
 +                              if (device->brightness->levels[i] == *level) {
 +                                      device->brightness->curr = *level;
 +                                      return 0;
 +                      }
 +                      /* BQC returned an invalid level. Stop using it.  */
 +                      ACPI_WARNING((AE_INFO, "%s returned an invalid level",
 +                                              buf));
 +                      device->cap._BQC = device->cap._BCQ = 0;
                } else {
                        /* Fixme:
                         * should we return an error or ignore this failure?
@@@ -880,7 -870,7 +880,7 @@@ acpi_video_init_brightness(struct acpi_
        br->flags._BCM_use_index = br->flags._BCL_use_index;
  
        /* _BQC uses INDEX while _BCL uses VALUE in some laptops */
 -      br->curr = level_old = max_level;
 +      br->curr = level = max_level;
  
        if (!device->cap._BQC)
                goto set_level;
  
        br->flags._BQC_use_index = (level == max_level ? 0 : 1);
  
 -      if (!br->flags._BQC_use_index)
 +      if (!br->flags._BQC_use_index) {
 +              /*
 +               * Set the backlight to the initial state.
 +               * On some buggy laptops, _BQC returns an uninitialized value
 +               * when invoked for the first time, i.e. level_old is invalid.
 +               * set the backlight to max_level in this case
 +               */
 +              for (i = 2; i < br->count; i++)
 +                      if (level_old == br->levels[i])
 +                              level = level_old;
                goto set_level;
 +      }
  
        if (br->flags._BCL_reversed)
                level_old = (br->count - 1) - level_old;
 -      level_old = br->levels[level_old];
 +      level = br->levels[level_old];
  
  set_level:
 -      result = acpi_video_device_lcd_set_level(device, level_old);
 +      result = acpi_video_device_lcd_set_level(device, level);
        if (result)
                goto out_free_levels;
  
@@@ -954,6 -934,9 +954,6 @@@ static void acpi_video_device_find_cap(
  {
        acpi_handle h_dummy1;
  
 -
 -      memset(&device->cap, 0, sizeof(device->cap));
 -
        if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) {
                device->cap._ADR = 1;
        }
                if (result)
                        printk(KERN_ERR PREFIX "Create sysfs link\n");
  
 -              device->cdev = thermal_cooling_device_register("LCD",
 +              device->cooling_dev = thermal_cooling_device_register("LCD",
                                        device->dev, &video_cooling_ops);
 -              if (IS_ERR(device->cdev))
 +              if (IS_ERR(device->cooling_dev)) {
 +                      /*
 +                       * Set cooling_dev to NULL so we don't crash trying to
 +                       * free it.
 +                       * Also, why the hell we are returning early and
 +                       * not attempt to register video output if cooling
 +                       * device registration failed?
 +                       * -- dtor
 +                       */
 +                      device->cooling_dev = NULL;
                        return;
 +              }
  
                dev_info(&device->dev->dev, "registered as cooling_device%d\n",
 -                       device->cdev->id);
 +                       device->cooling_dev->id);
                result = sysfs_create_link(&device->dev->dev.kobj,
 -                              &device->cdev->device.kobj,
 +                              &device->cooling_dev->device.kobj,
                                "thermal_cooling");
                if (result)
                        printk(KERN_ERR PREFIX "Create sysfs link\n");
 -              result = sysfs_create_link(&device->cdev->device.kobj,
 +              result = sysfs_create_link(&device->cooling_dev->device.kobj,
                                &device->dev->dev.kobj, "device");
                if (result)
                        printk(KERN_ERR PREFIX "Create sysfs link\n");
@@@ -1066,6 -1039,7 +1066,6 @@@ static void acpi_video_bus_find_cap(str
  {
        acpi_handle h_dummy1;
  
 -      memset(&video->cap, 0, sizeof(video->cap));
        if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) {
                video->cap._DOS = 1;
        }
@@@ -1986,6 -1960,10 +1986,10 @@@ acpi_video_switch_brightness(struct acp
  
        result = acpi_video_device_lcd_set_level(device, level_next);
  
+       if (!result)
+               backlight_force_update(device->backlight,
+                                      BACKLIGHT_UPDATE_HOTKEY);
  out:
        if (result)
                printk(KERN_ERR PREFIX "Failed to switch the brightness\n");
@@@ -2035,13 -2013,13 +2039,13 @@@ static int acpi_video_bus_put_one_devic
                backlight_device_unregister(device->backlight);
                device->backlight = NULL;
        }
 -      if (device->cdev) {
 +      if (device->cooling_dev) {
                sysfs_remove_link(&device->dev->dev.kobj,
                                  "thermal_cooling");
 -              sysfs_remove_link(&device->cdev->device.kobj,
 +              sysfs_remove_link(&device->cooling_dev->device.kobj,
                                  "device");
 -              thermal_cooling_device_unregister(device->cdev);
 -              device->cdev = NULL;
 +              thermal_cooling_device_unregister(device->cooling_dev);
 +              device->cooling_dev = NULL;
        }
        video_output_unregister(device->output_dev);
  
index da3c08b3dcc1d719918e26718986a75817b76203,7b5ee494cdf75510855219e39c9acafc219de293..749e2102b2be7519b8f0835979d7b0e9320356de
@@@ -142,28 -142,18 +142,28 @@@ struct eeepc_hotk 
        struct rfkill *wlan_rfkill;
        struct rfkill *bluetooth_rfkill;
        struct rfkill *wwan3g_rfkill;
 +      struct rfkill *wimax_rfkill;
        struct hotplug_slot *hotplug_slot;
 -      struct work_struct hotplug_work;
 +      struct mutex hotplug_lock;
  };
  
  /* The actual device the driver binds to */
  static struct eeepc_hotk *ehotk;
  
  /* Platform device/driver */
 +static int eeepc_hotk_thaw(struct device *device);
 +static int eeepc_hotk_restore(struct device *device);
 +
 +static struct dev_pm_ops eeepc_pm_ops = {
 +      .thaw = eeepc_hotk_thaw,
 +      .restore = eeepc_hotk_restore,
 +};
 +
  static struct platform_driver platform_driver = {
        .driver = {
                .name = EEEPC_HOTK_FILE,
                .owner = THIS_MODULE,
 +              .pm = &eeepc_pm_ops,
        }
  };
  
@@@ -202,6 -192,7 +202,6 @@@ static struct key_entry eeepc_keymap[] 
   */
  static int eeepc_hotk_add(struct acpi_device *device);
  static int eeepc_hotk_remove(struct acpi_device *device, int type);
 -static int eeepc_hotk_resume(struct acpi_device *device);
  static void eeepc_hotk_notify(struct acpi_device *device, u32 event);
  
  static const struct acpi_device_id eeepc_device_ids[] = {
@@@ -218,6 -209,7 +218,6 @@@ static struct acpi_driver eeepc_hotk_dr
        .ops = {
                .add = eeepc_hotk_add,
                .remove = eeepc_hotk_remove,
 -              .resume = eeepc_hotk_resume,
                .notify = eeepc_hotk_notify,
        },
  };
@@@ -587,6 -579,7 +587,6 @@@ static void cmsg_quirks(void
  
  static int eeepc_hotk_check(void)
  {
 -      const struct key_entry *key;
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        int result;
  
                        pr_info("Get control methods supported: 0x%x\n",
                                ehotk->cm_supported);
                }
 -              ehotk->inputdev = input_allocate_device();
 -              if (!ehotk->inputdev) {
 -                      pr_info("Unable to allocate input device\n");
 -                      return 0;
 -              }
 -              ehotk->inputdev->name = "Asus EeePC extra buttons";
 -              ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
 -              ehotk->inputdev->id.bustype = BUS_HOST;
 -              ehotk->inputdev->getkeycode = eeepc_getkeycode;
 -              ehotk->inputdev->setkeycode = eeepc_setkeycode;
 -
 -              for (key = eeepc_keymap; key->type != KE_END; key++) {
 -                      switch (key->type) {
 -                      case KE_KEY:
 -                              set_bit(EV_KEY, ehotk->inputdev->evbit);
 -                              set_bit(key->keycode, ehotk->inputdev->keybit);
 -                              break;
 -                      }
 -              }
 -              result = input_register_device(ehotk->inputdev);
 -              if (result) {
 -                      pr_info("Unable to register input device\n");
 -                      input_free_device(ehotk->inputdev);
 -                      return 0;
 -              }
        } else {
                pr_err("Hotkey device not present, aborting\n");
                return -EINVAL;
@@@ -624,7 -642,7 +624,7 @@@ static int notify_brn(void
        struct backlight_device *bd = eeepc_backlight_device;
        if (bd) {
                int old = bd->props.brightness;
-               bd->props.brightness = read_brightness(bd);
+               backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
                return old;
        }
        return -1;
@@@ -643,48 -661,40 +643,48 @@@ static int eeepc_get_adapter_status(str
        return 0;
  }
  
 -static void eeepc_hotplug_work(struct work_struct *work)
 +static void eeepc_rfkill_hotplug(void)
  {
        struct pci_dev *dev;
 -      struct pci_bus *bus = pci_find_bus(0, 1);
 -      bool blocked;
 +      struct pci_bus *bus;
 +      bool blocked = eeepc_wlan_rfkill_blocked();
  
 -      if (!bus) {
 -              pr_warning("Unable to find PCI bus 1?\n");
 -              return;
 -      }
 +      if (ehotk->wlan_rfkill)
 +              rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
  
 -      blocked = eeepc_wlan_rfkill_blocked();
 -      if (!blocked) {
 -              dev = pci_get_slot(bus, 0);
 -              if (dev) {
 -                      /* Device already present */
 -                      pci_dev_put(dev);
 -                      return;
 -              }
 -              dev = pci_scan_single_device(bus, 0);
 -              if (dev) {
 -                      pci_bus_assign_resources(bus);
 -                      if (pci_bus_add_device(dev))
 -                              pr_err("Unable to hotplug wifi\n");
 +      mutex_lock(&ehotk->hotplug_lock);
 +
 +      if (ehotk->hotplug_slot) {
 +              bus = pci_find_bus(0, 1);
 +              if (!bus) {
 +                      pr_warning("Unable to find PCI bus 1?\n");
 +                      goto out_unlock;
                }
 -      } else {
 -              dev = pci_get_slot(bus, 0);
 -              if (dev) {
 -                      pci_remove_bus_device(dev);
 -                      pci_dev_put(dev);
 +
 +              if (!blocked) {
 +                      dev = pci_get_slot(bus, 0);
 +                      if (dev) {
 +                              /* Device already present */
 +                              pci_dev_put(dev);
 +                              goto out_unlock;
 +                      }
 +                      dev = pci_scan_single_device(bus, 0);
 +                      if (dev) {
 +                              pci_bus_assign_resources(bus);
 +                              if (pci_bus_add_device(dev))
 +                                      pr_err("Unable to hotplug wifi\n");
 +                      }
 +              } else {
 +                      dev = pci_get_slot(bus, 0);
 +                      if (dev) {
 +                              pci_remove_bus_device(dev);
 +                              pci_dev_put(dev);
 +                      }
                }
        }
  
 -      rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
 +out_unlock:
 +      mutex_unlock(&ehotk->hotplug_lock);
  }
  
  static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
        if (event != ACPI_NOTIFY_BUS_CHECK)
                return;
  
 -      schedule_work(&ehotk->hotplug_work);
 +      eeepc_rfkill_hotplug();
  }
  
  static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
@@@ -829,38 -839,66 +829,38 @@@ error_slot
        return ret;
  }
  
 -static int eeepc_hotk_add(struct acpi_device *device)
 -{
 -      int result;
 -
 -      if (!device)
 -               return -EINVAL;
 -      pr_notice(EEEPC_HOTK_NAME "\n");
 -      ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
 -      if (!ehotk)
 -              return -ENOMEM;
 -      ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
 -      ehotk->handle = device->handle;
 -      strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
 -      strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
 -      device->driver_data = ehotk;
 -      ehotk->device = device;
 -      result = eeepc_hotk_check();
 -      if (result)
 -              goto ehotk_fail;
 -
 -      return 0;
 -
 - ehotk_fail:
 -      kfree(ehotk);
 -      ehotk = NULL;
 -
 -      return result;
 -}
 -
 -static int eeepc_hotk_remove(struct acpi_device *device, int type)
 -{
 -      if (!device || !acpi_driver_data(device))
 -               return -EINVAL;
 -
 -      kfree(ehotk);
 -      return 0;
 -}
 -
 -static int eeepc_hotk_resume(struct acpi_device *device)
 +static int eeepc_hotk_thaw(struct device *device)
  {
        if (ehotk->wlan_rfkill) {
                bool wlan;
  
 -              /* Workaround - it seems that _PTS disables the wireless
 -                 without notification or changing the value read by WLAN.
 -                 Normally this is fine because the correct value is restored
 -                 from the non-volatile storage on resume, but we need to do
 -                 it ourself if case suspend is aborted, or we lose wireless.
 +              /*
 +               * Work around bios bug - acpi _PTS turns off the wireless led
 +               * during suspend.  Normally it restores it on resume, but
 +               * we should kick it ourselves in case hibernation is aborted.
                 */
                wlan = get_acpi(CM_ASL_WLAN);
                set_acpi(CM_ASL_WLAN, wlan);
 +      }
  
 -              rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1);
 +      return 0;
 +}
  
 -              schedule_work(&ehotk->hotplug_work);
 -      }
 +static int eeepc_hotk_restore(struct device *device)
 +{
 +      /* Refresh both wlan rfkill state and pci hotplug */
 +      if (ehotk->wlan_rfkill)
 +              eeepc_rfkill_hotplug();
  
        if (ehotk->bluetooth_rfkill)
                rfkill_set_sw_state(ehotk->bluetooth_rfkill,
                                    get_acpi(CM_ASL_BLUETOOTH) != 1);
 +      if (ehotk->wwan3g_rfkill)
 +              rfkill_set_sw_state(ehotk->wwan3g_rfkill,
 +                                  get_acpi(CM_ASL_3G) != 1);
 +      if (ehotk->wimax_rfkill)
 +              rfkill_set_sw_state(ehotk->wimax_rfkill,
 +                                  get_acpi(CM_ASL_WIMAX) != 1);
  
        return 0;
  }
@@@ -981,37 -1019,16 +981,37 @@@ static void eeepc_backlight_exit(void
  
  static void eeepc_rfkill_exit(void)
  {
 +      eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P5");
        eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
        eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
 -      if (ehotk->wlan_rfkill)
 +      if (ehotk->wlan_rfkill) {
                rfkill_unregister(ehotk->wlan_rfkill);
 -      if (ehotk->bluetooth_rfkill)
 -              rfkill_unregister(ehotk->bluetooth_rfkill);
 -      if (ehotk->wwan3g_rfkill)
 -              rfkill_unregister(ehotk->wwan3g_rfkill);
 +              rfkill_destroy(ehotk->wlan_rfkill);
 +              ehotk->wlan_rfkill = NULL;
 +      }
 +      /*
 +       * Refresh pci hotplug in case the rfkill state was changed after
 +       * eeepc_unregister_rfkill_notifier()
 +       */
 +      eeepc_rfkill_hotplug();
        if (ehotk->hotplug_slot)
                pci_hp_deregister(ehotk->hotplug_slot);
 +
 +      if (ehotk->bluetooth_rfkill) {
 +              rfkill_unregister(ehotk->bluetooth_rfkill);
 +              rfkill_destroy(ehotk->bluetooth_rfkill);
 +              ehotk->bluetooth_rfkill = NULL;
 +      }
 +      if (ehotk->wwan3g_rfkill) {
 +              rfkill_unregister(ehotk->wwan3g_rfkill);
 +              rfkill_destroy(ehotk->wwan3g_rfkill);
 +              ehotk->wwan3g_rfkill = NULL;
 +      }
 +      if (ehotk->wimax_rfkill) {
 +              rfkill_unregister(ehotk->wimax_rfkill);
 +              rfkill_destroy(ehotk->wimax_rfkill);
 +              ehotk->wimax_rfkill = NULL;
 +      }
  }
  
  static void eeepc_input_exit(void)
@@@ -1033,6 -1050,19 +1033,6 @@@ static void eeepc_hwmon_exit(void
        eeepc_hwmon_device = NULL;
  }
  
 -static void __exit eeepc_laptop_exit(void)
 -{
 -      eeepc_backlight_exit();
 -      eeepc_rfkill_exit();
 -      eeepc_input_exit();
 -      eeepc_hwmon_exit();
 -      acpi_bus_unregister_driver(&eeepc_hotk_driver);
 -      sysfs_remove_group(&platform_device->dev.kobj,
 -                         &platform_attribute_group);
 -      platform_device_unregister(platform_device);
 -      platform_driver_unregister(&platform_driver);
 -}
 -
  static int eeepc_new_rfkill(struct rfkill **rfkill,
                            const char *name, struct device *dev,
                            enum rfkill_type type, int cm)
@@@ -1064,7 -1094,10 +1064,7 @@@ static int eeepc_rfkill_init(struct dev
  {
        int result = 0;
  
 -      INIT_WORK(&ehotk->hotplug_work, eeepc_hotplug_work);
 -
 -      eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
 -      eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
 +      mutex_init(&ehotk->hotplug_lock);
  
        result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
                                  "eeepc-wlan", dev,
        if (result && result != -ENODEV)
                goto exit;
  
 +      result = eeepc_new_rfkill(&ehotk->wimax_rfkill,
 +                                "eeepc-wimax", dev,
 +                                RFKILL_TYPE_WIMAX, CM_ASL_WIMAX);
 +
 +      if (result && result != -ENODEV)
 +              goto exit;
 +
        result = eeepc_setup_pci_hotplug();
        /*
         * If we get -EBUSY then something else is handling the PCI hotplug -
        if (result == -EBUSY)
                result = 0;
  
 +      eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P5");
 +      eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
 +      eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
 +      /*
 +       * Refresh pci hotplug in case the rfkill state was changed during
 +       * setup.
 +       */
 +      eeepc_rfkill_hotplug();
 +
  exit:
        if (result && result != -ENODEV)
                eeepc_rfkill_exit();
@@@ -1155,61 -1172,21 +1155,61 @@@ static int eeepc_hwmon_init(struct devi
        return result;
  }
  
 -static int __init eeepc_laptop_init(void)
 +static int eeepc_input_init(struct device *dev)
  {
 -      struct device *dev;
 +      const struct key_entry *key;
        int result;
  
 -      if (acpi_disabled)
 -              return -ENODEV;
 -      result = acpi_bus_register_driver(&eeepc_hotk_driver);
 -      if (result < 0)
 +      ehotk->inputdev = input_allocate_device();
 +      if (!ehotk->inputdev) {
 +              pr_info("Unable to allocate input device\n");
 +              return -ENOMEM;
 +      }
 +      ehotk->inputdev->name = "Asus EeePC extra buttons";
 +      ehotk->inputdev->dev.parent = dev;
 +      ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
 +      ehotk->inputdev->id.bustype = BUS_HOST;
 +      ehotk->inputdev->getkeycode = eeepc_getkeycode;
 +      ehotk->inputdev->setkeycode = eeepc_setkeycode;
 +
 +      for (key = eeepc_keymap; key->type != KE_END; key++) {
 +              switch (key->type) {
 +              case KE_KEY:
 +                      set_bit(EV_KEY, ehotk->inputdev->evbit);
 +                      set_bit(key->keycode, ehotk->inputdev->keybit);
 +                      break;
 +              }
 +      }
 +      result = input_register_device(ehotk->inputdev);
 +      if (result) {
 +              pr_info("Unable to register input device\n");
 +              input_free_device(ehotk->inputdev);
                return result;
 -      if (!ehotk) {
 -              acpi_bus_unregister_driver(&eeepc_hotk_driver);
 -              return -ENODEV;
        }
 +      return 0;
 +}
 +
 +static int eeepc_hotk_add(struct acpi_device *device)
 +{
 +      struct device *dev;
 +      int result;
  
 +      if (!device)
 +              return -EINVAL;
 +      pr_notice(EEEPC_HOTK_NAME "\n");
 +      ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
 +      if (!ehotk)
 +              return -ENOMEM;
 +      ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
 +      ehotk->handle = device->handle;
 +      strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
 +      strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
 +      device->driver_data = ehotk;
 +      ehotk->device = device;
 +
 +      result = eeepc_hotk_check();
 +      if (result)
 +              goto fail_platform_driver;
        eeepc_enable_camera();
  
        /* Register platform stuff */
                pr_info("Backlight controlled by ACPI video "
                        "driver\n");
  
 +      result = eeepc_input_init(dev);
 +      if (result)
 +              goto fail_input;
 +
        result = eeepc_hwmon_init(dev);
        if (result)
                goto fail_hwmon;
                goto fail_rfkill;
  
        return 0;
 +
  fail_rfkill:
        eeepc_hwmon_exit();
  fail_hwmon:
 +      eeepc_input_exit();
 +fail_input:
        eeepc_backlight_exit();
  fail_backlight:
        sysfs_remove_group(&platform_device->dev.kobj,
@@@ -1269,49 -1239,9 +1269,49 @@@ fail_platform_device2
  fail_platform_device1:
        platform_driver_unregister(&platform_driver);
  fail_platform_driver:
 -      eeepc_input_exit();
 +      kfree(ehotk);
 +
        return result;
  }
  
 +static int eeepc_hotk_remove(struct acpi_device *device, int type)
 +{
 +      if (!device || !acpi_driver_data(device))
 +              return -EINVAL;
 +
 +      eeepc_backlight_exit();
 +      eeepc_rfkill_exit();
 +      eeepc_input_exit();
 +      eeepc_hwmon_exit();
 +      sysfs_remove_group(&platform_device->dev.kobj,
 +                         &platform_attribute_group);
 +      platform_device_unregister(platform_device);
 +      platform_driver_unregister(&platform_driver);
 +
 +      kfree(ehotk);
 +      return 0;
 +}
 +
 +static int __init eeepc_laptop_init(void)
 +{
 +      int result;
 +
 +      if (acpi_disabled)
 +              return -ENODEV;
 +      result = acpi_bus_register_driver(&eeepc_hotk_driver);
 +      if (result < 0)
 +              return result;
 +      if (!ehotk) {
 +              acpi_bus_unregister_driver(&eeepc_hotk_driver);
 +              return -ENODEV;
 +      }
 +      return 0;
 +}
 +
 +static void __exit eeepc_laptop_exit(void)
 +{
 +      acpi_bus_unregister_driver(&eeepc_hotk_driver);
 +}
 +
  module_init(eeepc_laptop_init);
  module_exit(eeepc_laptop_exit);
index 90861cd93165124461a2bcc18c57e603b86155df,8b3bc71ddb0473e4803cc094b9fdfad1756be274..09bfa9662e4d9fd8cf032e0f30d2cca19cc20b2b
@@@ -31,6 -31,13 +31,13 @@@ config LCD_CORG
          Say y here to support the LCD panels usually found on SHARP
          corgi (C7x0) and spitz (Cxx00) models.
  
+ config LCD_LMS283GF05
+       tristate "Samsung LMS283GF05 LCD"
+       depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO
+       help
+         SPI driver for Samsung LMS283GF05. This provides basic support
+         for powering the LCD up/down through a sysfs interface.
  config LCD_LTV350QV
        tristate "Samsung LTV350QV LCD Panel"
        depends on LCD_CLASS_DEVICE && SPI_MASTER
@@@ -110,7 -117,7 +117,7 @@@ config BACKLIGHT_CLASS_DEVIC
  config BACKLIGHT_ATMEL_LCDC
        bool "Atmel LCDC Contrast-as-Backlight control"
        depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL
 -      default y if MACH_SAM9261EK || MACH_SAM9263EK
 +      default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK
        help
          This provides a backlight control internal to the Atmel LCDC
          driver.  If the LCD "contrast control" on your board is wired
@@@ -229,3 -236,29 +236,29 @@@ config BACKLIGHT_SAHAR
        help
          If you have a Tabletkiosk Sahara Touch-iT, say y to enable the
          backlight driver.
+ config BACKLIGHT_WM831X
+       tristate "WM831x PMIC Backlight Driver"
+       depends on BACKLIGHT_CLASS_DEVICE && MFD_WM831X
+       help
+         If you have a backlight driven by the ISINK and DCDC of a
+         WM831x PMIC say y to enable the backlight driver for it.
+ config BACKLIGHT_ADX
+       tristate "Avionic Design Xanthos Backlight Driver"
+       depends on BACKLIGHT_CLASS_DEVICE && ARCH_PXA_ADX
+       default y
+       help
+         Say Y to enable the backlight driver on Avionic Design Xanthos-based
+         boards.
+ config BACKLIGHT_ADP5520
+       tristate "Backlight Driver for ADP5520/ADP5501 using WLED"
+       depends on BACKLIGHT_CLASS_DEVICE && PMIC_ADP5520
+       help
+         If you have a LCD backlight connected to the BST/BL_SNK output of
+         ADP5520 or ADP5501, say Y here to enable this driver.
+         To compile this driver as a module, choose M here: the module will
+         be called adp5520_bl.