^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * OLPC XO-1.5 ebook switch driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * (based on generic ACPI button driver)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2009 Paul Fox <pgf@laptop.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2010 One Laptop per Child
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define MODULE_NAME "xo15-ebook"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define XO15_EBOOK_CLASS MODULE_NAME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define XO15_EBOOK_TYPE_UNKNOWN 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define XO15_EBOOK_NOTIFY_STATUS 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define XO15_EBOOK_SUBCLASS "ebook"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define XO15_EBOOK_HID "XO15EBK"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define XO15_EBOOK_DEVICE_NAME "EBook Switch"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) ACPI_MODULE_NAME(MODULE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) MODULE_DESCRIPTION("OLPC XO-1.5 ebook switch driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static const struct acpi_device_id ebook_device_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) { XO15_EBOOK_HID, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) { "", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) MODULE_DEVICE_TABLE(acpi, ebook_device_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct ebook_switch {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) char phys[32]; /* for input device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static int ebook_send_state(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct ebook_switch *button = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) unsigned long long state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) status = acpi_evaluate_integer(device->handle, "EBK", NULL, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /* input layer checks if event is redundant */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) input_report_switch(button->input, SW_TABLET_MODE, !state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) input_sync(button->input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static void ebook_switch_notify(struct acpi_device *device, u32 event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) case ACPI_FIXED_HARDWARE_EVENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) case XO15_EBOOK_NOTIFY_STATUS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) ebook_send_state(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) ACPI_DEBUG_PRINT((ACPI_DB_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) "Unsupported event [0x%x]\n", event));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static int ebook_switch_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return ebook_send_state(to_acpi_device(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static SIMPLE_DEV_PM_OPS(ebook_switch_pm, NULL, ebook_switch_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static int ebook_switch_add(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct ebook_switch *button;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) const char *hid = acpi_device_hid(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) char *name, *class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) button = kzalloc(sizeof(struct ebook_switch), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (!button)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) device->driver_data = button;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) button->input = input = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (!input) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) error = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) goto err_free_button;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) name = acpi_device_name(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) class = acpi_device_class(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (strcmp(hid, XO15_EBOOK_HID)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) pr_err("Unsupported hid [%s]\n", hid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) error = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) goto err_free_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) strcpy(name, XO15_EBOOK_DEVICE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) input->name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) input->phys = button->phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) input->id.bustype = BUS_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) input->dev.parent = &device->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) input->evbit[0] = BIT_MASK(EV_SW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) set_bit(SW_TABLET_MODE, input->swbit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) error = input_register_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) goto err_free_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) ebook_send_state(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (device->wakeup.flags.valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) /* Button's GPE is run-wake GPE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) acpi_enable_gpe(device->wakeup.gpe_device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) device->wakeup.gpe_number);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) device_set_wakeup_enable(&device->dev, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) err_free_input:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) input_free_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) err_free_button:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) kfree(button);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static int ebook_switch_remove(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) struct ebook_switch *button = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) input_unregister_device(button->input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) kfree(button);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) static struct acpi_driver xo15_ebook_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) .name = MODULE_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .class = XO15_EBOOK_CLASS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .ids = ebook_device_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) .add = ebook_switch_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .remove = ebook_switch_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .notify = ebook_switch_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) .drv.pm = &ebook_switch_pm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) module_acpi_driver(xo15_ebook_driver);