static int acpi_button_add(struct acpi_device *device);
 static void acpi_button_remove(struct acpi_device *device);
-static void acpi_button_notify(struct acpi_device *device, u32 event);
 
 #ifdef CONFIG_PM_SLEEP
 static int acpi_button_suspend(struct device *dev);
        .ops = {
                .add = acpi_button_add,
                .remove = acpi_button_remove,
-               .notify = acpi_button_notify,
        },
        .drv.pm = &acpi_button_pm,
 };
        button->lid_state_initialized = true;
 }
 
-static void acpi_button_notify(struct acpi_device *device, u32 event)
+static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
 {
-       struct acpi_button *button = acpi_driver_data(device);
+       struct acpi_device *device = data;
+       struct acpi_button *button;
        struct input_dev *input;
+       int keycode;
 
-       switch (event) {
-       case ACPI_FIXED_HARDWARE_EVENT:
-               event = ACPI_BUTTON_NOTIFY_STATUS;
-               fallthrough;
-       case ACPI_BUTTON_NOTIFY_STATUS:
-               input = button->input;
-               if (button->type == ACPI_BUTTON_TYPE_LID) {
-                       if (button->lid_state_initialized)
-                               acpi_lid_update_state(device, true);
-               } else {
-                       int keycode;
-
-                       acpi_pm_wakeup_event(&device->dev);
-                       if (button->suspended)
-                               break;
-
-                       keycode = test_bit(KEY_SLEEP, input->keybit) ?
-                                               KEY_SLEEP : KEY_POWER;
-                       input_report_key(input, keycode, 1);
-                       input_sync(input);
-                       input_report_key(input, keycode, 0);
-                       input_sync(input);
-
-                       acpi_bus_generate_netlink_event(
-                                       device->pnp.device_class,
-                                       dev_name(&device->dev),
-                                       event, ++button->pushed);
-               }
-               break;
-       default:
+       if (event != ACPI_BUTTON_NOTIFY_STATUS) {
                acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n",
                                  event);
-               break;
+               return;
        }
+
+       button = acpi_driver_data(device);
+
+       if (button->type == ACPI_BUTTON_TYPE_LID) {
+               if (button->lid_state_initialized)
+                       acpi_lid_update_state(device, true);
+
+               return;
+       }
+
+       acpi_pm_wakeup_event(&device->dev);
+
+       if (button->suspended)
+               return;
+
+       input = button->input;
+       keycode = test_bit(KEY_SLEEP, input->keybit) ? KEY_SLEEP : KEY_POWER;
+
+       input_report_key(input, keycode, 1);
+       input_sync(input);
+       input_report_key(input, keycode, 0);
+       input_sync(input);
+
+       acpi_bus_generate_netlink_event(device->pnp.device_class,
+                                       dev_name(&device->dev),
+                                       event, ++button->pushed);
+}
+
+static void acpi_button_notify_run(void *data)
+{
+       acpi_button_notify(NULL, ACPI_BUTTON_NOTIFY_STATUS, data);
+}
+
+static u32 acpi_button_event(void *data)
+{
+       acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_button_notify_run, data);
+       return ACPI_INTERRUPT_HANDLED;
 }
 
 #ifdef CONFIG_PM_SLEEP
        struct acpi_button *button;
        struct input_dev *input;
        const char *hid = acpi_device_hid(device);
+       acpi_status status;
        char *name, *class;
-       int error;
+       int error = 0;
 
        if (!strcmp(hid, ACPI_BUTTON_HID_LID) &&
             lid_init_state == ACPI_BUTTON_LID_INIT_DISABLED)
        } else {
                pr_info("Unsupported hid [%s]\n", hid);
                error = -ENODEV;
-               goto err_free_input;
        }
 
-       error = acpi_button_add_fs(device);
-       if (error)
-               goto err_free_input;
+       if (!error)
+               error = acpi_button_add_fs(device);
+
+       if (error) {
+               input_free_device(input);
+               goto err_free_button;
+       }
 
        snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
 
        error = input_register_device(input);
        if (error)
                goto err_remove_fs;
+
+       switch (device->device_type) {
+       case ACPI_BUS_TYPE_POWER_BUTTON:
+               status = acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+                                                         acpi_button_event,
+                                                         device);
+               break;
+       case ACPI_BUS_TYPE_SLEEP_BUTTON:
+               status = acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+                                                         acpi_button_event,
+                                                         device);
+               break;
+       default:
+               status = acpi_install_notify_handler(device->handle,
+                                                    ACPI_DEVICE_NOTIFY,
+                                                    acpi_button_notify,
+                                                    device);
+               break;
+       }
+       if (ACPI_FAILURE(status)) {
+               error = -ENODEV;
+               goto err_input_unregister;
+       }
+
        if (button->type == ACPI_BUTTON_TYPE_LID) {
                /*
                 * This assumes there's only one lid device, or if there are
        pr_info("%s [%s]\n", name, acpi_device_bid(device));
        return 0;
 
- err_remove_fs:
+err_input_unregister:
+       input_unregister_device(input);
+err_remove_fs:
        acpi_button_remove_fs(device);
- err_free_input:
-       input_free_device(input);
- err_free_button:
+err_free_button:
        kfree(button);
        return error;
 }
 {
        struct acpi_button *button = acpi_driver_data(device);
 
+       switch (device->device_type) {
+       case ACPI_BUS_TYPE_POWER_BUTTON:
+               acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+                                               acpi_button_event);
+               break;
+       case ACPI_BUS_TYPE_SLEEP_BUTTON:
+               acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+                                               acpi_button_event);
+               break;
+       default:
+               acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+                                          acpi_button_notify);
+               break;
+       }
+       acpi_os_wait_events_complete();
+
        acpi_button_remove_fs(device);
        input_unregister_device(button->input);
        kfree(button);