1*06ffe5b2SHans de Goede // SPDX-License-Identifier: GPL-2.0 2*06ffe5b2SHans de Goede /* 3*06ffe5b2SHans de Goede * Platform driver for Lenovo Yoga Book YB1-X90F/L tablets (Android model) 4*06ffe5b2SHans de Goede * WMI driver for Lenovo Yoga Book YB1-X91F/L tablets (Windows model) 5*06ffe5b2SHans de Goede * 6*06ffe5b2SHans de Goede * The keyboard half of the YB1 models can function as both a capacitive 7*06ffe5b2SHans de Goede * touch keyboard or as a Wacom digitizer, but not at the same time. 8*06ffe5b2SHans de Goede * 9*06ffe5b2SHans de Goede * This driver takes care of switching between the 2 functions. 10*06ffe5b2SHans de Goede * 11*06ffe5b2SHans de Goede * Copyright 2023 Hans de Goede <hansg@kernel.org> 12*06ffe5b2SHans de Goede */ 13*06ffe5b2SHans de Goede 14*06ffe5b2SHans de Goede #include <linux/acpi.h> 15*06ffe5b2SHans de Goede #include <linux/gpio/consumer.h> 16*06ffe5b2SHans de Goede #include <linux/gpio/machine.h> 17*06ffe5b2SHans de Goede #include <linux/i2c.h> 18*06ffe5b2SHans de Goede #include <linux/interrupt.h> 19*06ffe5b2SHans de Goede #include <linux/leds.h> 20*06ffe5b2SHans de Goede #include <linux/module.h> 21*06ffe5b2SHans de Goede #include <linux/platform_device.h> 22*06ffe5b2SHans de Goede #include <linux/pwm.h> 23*06ffe5b2SHans de Goede #include <linux/wmi.h> 24*06ffe5b2SHans de Goede #include <linux/workqueue.h> 25*06ffe5b2SHans de Goede 26*06ffe5b2SHans de Goede #define YB_MBTN_EVENT_GUID "243FEC1D-1963-41C1-8100-06A9D82A94B4" 27*06ffe5b2SHans de Goede 28*06ffe5b2SHans de Goede #define YB_KBD_BL_DEFAULT 128 29*06ffe5b2SHans de Goede #define YB_KBD_BL_MAX 255 30*06ffe5b2SHans de Goede #define YB_KBD_BL_PWM_PERIOD 13333 31*06ffe5b2SHans de Goede 32*06ffe5b2SHans de Goede #define YB_PDEV_NAME "yogabook-touch-kbd-digitizer-switch" 33*06ffe5b2SHans de Goede 34*06ffe5b2SHans de Goede /* flags */ 35*06ffe5b2SHans de Goede enum { 36*06ffe5b2SHans de Goede YB_KBD_IS_ON, 37*06ffe5b2SHans de Goede YB_DIGITIZER_IS_ON, 38*06ffe5b2SHans de Goede YB_DIGITIZER_MODE, 39*06ffe5b2SHans de Goede YB_TABLET_MODE, 40*06ffe5b2SHans de Goede YB_SUSPENDED, 41*06ffe5b2SHans de Goede }; 42*06ffe5b2SHans de Goede 43*06ffe5b2SHans de Goede struct yogabook_data { 44*06ffe5b2SHans de Goede struct device *dev; 45*06ffe5b2SHans de Goede struct acpi_device *kbd_adev; 46*06ffe5b2SHans de Goede struct acpi_device *dig_adev; 47*06ffe5b2SHans de Goede struct device *kbd_dev; 48*06ffe5b2SHans de Goede struct device *dig_dev; 49*06ffe5b2SHans de Goede struct led_classdev *pen_led; 50*06ffe5b2SHans de Goede struct gpio_desc *pen_touch_event; 51*06ffe5b2SHans de Goede struct gpio_desc *kbd_bl_led_enable; 52*06ffe5b2SHans de Goede struct gpio_desc *backside_hall_gpio; 53*06ffe5b2SHans de Goede struct pwm_device *kbd_bl_pwm; 54*06ffe5b2SHans de Goede int (*set_kbd_backlight)(struct yogabook_data *data, uint8_t level); 55*06ffe5b2SHans de Goede int pen_touch_irq; 56*06ffe5b2SHans de Goede int backside_hall_irq; 57*06ffe5b2SHans de Goede struct work_struct work; 58*06ffe5b2SHans de Goede struct led_classdev kbd_bl_led; 59*06ffe5b2SHans de Goede unsigned long flags; 60*06ffe5b2SHans de Goede uint8_t brightness; 61*06ffe5b2SHans de Goede }; 62*06ffe5b2SHans de Goede 63*06ffe5b2SHans de Goede static void yogabook_work(struct work_struct *work) 64*06ffe5b2SHans de Goede { 65*06ffe5b2SHans de Goede struct yogabook_data *data = container_of(work, struct yogabook_data, work); 66*06ffe5b2SHans de Goede bool kbd_on, digitizer_on; 67*06ffe5b2SHans de Goede int r; 68*06ffe5b2SHans de Goede 69*06ffe5b2SHans de Goede if (test_bit(YB_SUSPENDED, &data->flags)) 70*06ffe5b2SHans de Goede return; 71*06ffe5b2SHans de Goede 72*06ffe5b2SHans de Goede if (test_bit(YB_TABLET_MODE, &data->flags)) { 73*06ffe5b2SHans de Goede kbd_on = false; 74*06ffe5b2SHans de Goede digitizer_on = false; 75*06ffe5b2SHans de Goede } else if (test_bit(YB_DIGITIZER_MODE, &data->flags)) { 76*06ffe5b2SHans de Goede digitizer_on = true; 77*06ffe5b2SHans de Goede kbd_on = false; 78*06ffe5b2SHans de Goede } else { 79*06ffe5b2SHans de Goede kbd_on = true; 80*06ffe5b2SHans de Goede digitizer_on = false; 81*06ffe5b2SHans de Goede } 82*06ffe5b2SHans de Goede 83*06ffe5b2SHans de Goede if (!kbd_on && test_bit(YB_KBD_IS_ON, &data->flags)) { 84*06ffe5b2SHans de Goede /* 85*06ffe5b2SHans de Goede * Must be done before releasing the keyboard touchscreen driver, 86*06ffe5b2SHans de Goede * so that the keyboard touchscreen dev is still in D0. 87*06ffe5b2SHans de Goede */ 88*06ffe5b2SHans de Goede data->set_kbd_backlight(data, 0); 89*06ffe5b2SHans de Goede device_release_driver(data->kbd_dev); 90*06ffe5b2SHans de Goede clear_bit(YB_KBD_IS_ON, &data->flags); 91*06ffe5b2SHans de Goede } 92*06ffe5b2SHans de Goede 93*06ffe5b2SHans de Goede if (!digitizer_on && test_bit(YB_DIGITIZER_IS_ON, &data->flags)) { 94*06ffe5b2SHans de Goede led_set_brightness(data->pen_led, LED_OFF); 95*06ffe5b2SHans de Goede device_release_driver(data->dig_dev); 96*06ffe5b2SHans de Goede clear_bit(YB_DIGITIZER_IS_ON, &data->flags); 97*06ffe5b2SHans de Goede } 98*06ffe5b2SHans de Goede 99*06ffe5b2SHans de Goede if (kbd_on && !test_bit(YB_KBD_IS_ON, &data->flags)) { 100*06ffe5b2SHans de Goede r = device_reprobe(data->kbd_dev); 101*06ffe5b2SHans de Goede if (r) 102*06ffe5b2SHans de Goede dev_warn(data->dev, "Reprobe of keyboard touchscreen failed: %d\n", r); 103*06ffe5b2SHans de Goede 104*06ffe5b2SHans de Goede data->set_kbd_backlight(data, data->brightness); 105*06ffe5b2SHans de Goede set_bit(YB_KBD_IS_ON, &data->flags); 106*06ffe5b2SHans de Goede } 107*06ffe5b2SHans de Goede 108*06ffe5b2SHans de Goede if (digitizer_on && !test_bit(YB_DIGITIZER_IS_ON, &data->flags)) { 109*06ffe5b2SHans de Goede r = device_reprobe(data->dig_dev); 110*06ffe5b2SHans de Goede if (r) 111*06ffe5b2SHans de Goede dev_warn(data->dev, "Reprobe of digitizer failed: %d\n", r); 112*06ffe5b2SHans de Goede 113*06ffe5b2SHans de Goede led_set_brightness(data->pen_led, LED_FULL); 114*06ffe5b2SHans de Goede set_bit(YB_DIGITIZER_IS_ON, &data->flags); 115*06ffe5b2SHans de Goede } 116*06ffe5b2SHans de Goede } 117*06ffe5b2SHans de Goede 118*06ffe5b2SHans de Goede static void yogabook_toggle_digitizer_mode(struct yogabook_data *data) 119*06ffe5b2SHans de Goede { 120*06ffe5b2SHans de Goede if (test_bit(YB_SUSPENDED, &data->flags)) 121*06ffe5b2SHans de Goede return; 122*06ffe5b2SHans de Goede 123*06ffe5b2SHans de Goede if (test_bit(YB_DIGITIZER_MODE, &data->flags)) 124*06ffe5b2SHans de Goede clear_bit(YB_DIGITIZER_MODE, &data->flags); 125*06ffe5b2SHans de Goede else 126*06ffe5b2SHans de Goede set_bit(YB_DIGITIZER_MODE, &data->flags); 127*06ffe5b2SHans de Goede 128*06ffe5b2SHans de Goede /* 129*06ffe5b2SHans de Goede * We are called from the ACPI core and the driver [un]binding which is 130*06ffe5b2SHans de Goede * done also needs ACPI functions, use a workqueue to avoid deadlocking. 131*06ffe5b2SHans de Goede */ 132*06ffe5b2SHans de Goede schedule_work(&data->work); 133*06ffe5b2SHans de Goede } 134*06ffe5b2SHans de Goede 135*06ffe5b2SHans de Goede static irqreturn_t yogabook_backside_hall_irq(int irq, void *_data) 136*06ffe5b2SHans de Goede { 137*06ffe5b2SHans de Goede struct yogabook_data *data = _data; 138*06ffe5b2SHans de Goede 139*06ffe5b2SHans de Goede if (gpiod_get_value(data->backside_hall_gpio)) 140*06ffe5b2SHans de Goede set_bit(YB_TABLET_MODE, &data->flags); 141*06ffe5b2SHans de Goede else 142*06ffe5b2SHans de Goede clear_bit(YB_TABLET_MODE, &data->flags); 143*06ffe5b2SHans de Goede 144*06ffe5b2SHans de Goede schedule_work(&data->work); 145*06ffe5b2SHans de Goede 146*06ffe5b2SHans de Goede return IRQ_HANDLED; 147*06ffe5b2SHans de Goede } 148*06ffe5b2SHans de Goede 149*06ffe5b2SHans de Goede #define kbd_led_to_yogabook(cdev) container_of(cdev, struct yogabook_data, kbd_bl_led) 150*06ffe5b2SHans de Goede 151*06ffe5b2SHans de Goede static enum led_brightness kbd_brightness_get(struct led_classdev *cdev) 152*06ffe5b2SHans de Goede { 153*06ffe5b2SHans de Goede struct yogabook_data *data = kbd_led_to_yogabook(cdev); 154*06ffe5b2SHans de Goede 155*06ffe5b2SHans de Goede return data->brightness; 156*06ffe5b2SHans de Goede } 157*06ffe5b2SHans de Goede 158*06ffe5b2SHans de Goede static int kbd_brightness_set(struct led_classdev *cdev, 159*06ffe5b2SHans de Goede enum led_brightness value) 160*06ffe5b2SHans de Goede { 161*06ffe5b2SHans de Goede struct yogabook_data *data = kbd_led_to_yogabook(cdev); 162*06ffe5b2SHans de Goede 163*06ffe5b2SHans de Goede if ((value < 0) || (value > YB_KBD_BL_MAX)) 164*06ffe5b2SHans de Goede return -EINVAL; 165*06ffe5b2SHans de Goede 166*06ffe5b2SHans de Goede data->brightness = value; 167*06ffe5b2SHans de Goede 168*06ffe5b2SHans de Goede if (!test_bit(YB_KBD_IS_ON, &data->flags)) 169*06ffe5b2SHans de Goede return 0; 170*06ffe5b2SHans de Goede 171*06ffe5b2SHans de Goede return data->set_kbd_backlight(data, data->brightness); 172*06ffe5b2SHans de Goede } 173*06ffe5b2SHans de Goede 174*06ffe5b2SHans de Goede static struct gpiod_lookup_table yogabook_gpios = { 175*06ffe5b2SHans de Goede .table = { 176*06ffe5b2SHans de Goede GPIO_LOOKUP("INT33FF:02", 18, "backside_hall_sw", GPIO_ACTIVE_LOW), 177*06ffe5b2SHans de Goede {} 178*06ffe5b2SHans de Goede }, 179*06ffe5b2SHans de Goede }; 180*06ffe5b2SHans de Goede 181*06ffe5b2SHans de Goede static struct led_lookup_data yogabook_pen_led = { 182*06ffe5b2SHans de Goede .provider = "platform::indicator", 183*06ffe5b2SHans de Goede .con_id = "pen-icon-led", 184*06ffe5b2SHans de Goede }; 185*06ffe5b2SHans de Goede 186*06ffe5b2SHans de Goede static int yogabook_probe(struct device *dev, struct yogabook_data *data, 187*06ffe5b2SHans de Goede const char *kbd_bl_led_name) 188*06ffe5b2SHans de Goede { 189*06ffe5b2SHans de Goede int r; 190*06ffe5b2SHans de Goede 191*06ffe5b2SHans de Goede data->dev = dev; 192*06ffe5b2SHans de Goede data->brightness = YB_KBD_BL_DEFAULT; 193*06ffe5b2SHans de Goede set_bit(YB_KBD_IS_ON, &data->flags); 194*06ffe5b2SHans de Goede set_bit(YB_DIGITIZER_IS_ON, &data->flags); 195*06ffe5b2SHans de Goede INIT_WORK(&data->work, yogabook_work); 196*06ffe5b2SHans de Goede 197*06ffe5b2SHans de Goede yogabook_pen_led.dev_id = dev_name(dev); 198*06ffe5b2SHans de Goede led_add_lookup(&yogabook_pen_led); 199*06ffe5b2SHans de Goede data->pen_led = devm_led_get(dev, "pen-icon-led"); 200*06ffe5b2SHans de Goede led_remove_lookup(&yogabook_pen_led); 201*06ffe5b2SHans de Goede 202*06ffe5b2SHans de Goede if (IS_ERR(data->pen_led)) 203*06ffe5b2SHans de Goede return dev_err_probe(dev, PTR_ERR(data->pen_led), "Getting pen icon LED\n"); 204*06ffe5b2SHans de Goede 205*06ffe5b2SHans de Goede yogabook_gpios.dev_id = dev_name(dev); 206*06ffe5b2SHans de Goede gpiod_add_lookup_table(&yogabook_gpios); 207*06ffe5b2SHans de Goede data->backside_hall_gpio = devm_gpiod_get(dev, "backside_hall_sw", GPIOD_IN); 208*06ffe5b2SHans de Goede gpiod_remove_lookup_table(&yogabook_gpios); 209*06ffe5b2SHans de Goede 210*06ffe5b2SHans de Goede if (IS_ERR(data->backside_hall_gpio)) 211*06ffe5b2SHans de Goede return dev_err_probe(dev, PTR_ERR(data->backside_hall_gpio), 212*06ffe5b2SHans de Goede "Getting backside_hall_sw GPIO\n"); 213*06ffe5b2SHans de Goede 214*06ffe5b2SHans de Goede r = gpiod_to_irq(data->backside_hall_gpio); 215*06ffe5b2SHans de Goede if (r < 0) 216*06ffe5b2SHans de Goede return dev_err_probe(dev, r, "Getting backside_hall_sw IRQ\n"); 217*06ffe5b2SHans de Goede 218*06ffe5b2SHans de Goede data->backside_hall_irq = r; 219*06ffe5b2SHans de Goede 220*06ffe5b2SHans de Goede /* Set default brightness before enabling the IRQ */ 221*06ffe5b2SHans de Goede data->set_kbd_backlight(data, YB_KBD_BL_DEFAULT); 222*06ffe5b2SHans de Goede 223*06ffe5b2SHans de Goede r = request_irq(data->backside_hall_irq, yogabook_backside_hall_irq, 224*06ffe5b2SHans de Goede IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 225*06ffe5b2SHans de Goede "backside_hall_sw", data); 226*06ffe5b2SHans de Goede if (r) 227*06ffe5b2SHans de Goede return dev_err_probe(dev, r, "Requesting backside_hall_sw IRQ\n"); 228*06ffe5b2SHans de Goede 229*06ffe5b2SHans de Goede schedule_work(&data->work); 230*06ffe5b2SHans de Goede 231*06ffe5b2SHans de Goede data->kbd_bl_led.name = kbd_bl_led_name; 232*06ffe5b2SHans de Goede data->kbd_bl_led.brightness_set_blocking = kbd_brightness_set; 233*06ffe5b2SHans de Goede data->kbd_bl_led.brightness_get = kbd_brightness_get; 234*06ffe5b2SHans de Goede data->kbd_bl_led.max_brightness = YB_KBD_BL_MAX; 235*06ffe5b2SHans de Goede 236*06ffe5b2SHans de Goede r = devm_led_classdev_register(dev, &data->kbd_bl_led); 237*06ffe5b2SHans de Goede if (r < 0) { 238*06ffe5b2SHans de Goede dev_err_probe(dev, r, "Registering backlight LED device\n"); 239*06ffe5b2SHans de Goede goto error_free_irq; 240*06ffe5b2SHans de Goede } 241*06ffe5b2SHans de Goede 242*06ffe5b2SHans de Goede dev_set_drvdata(dev, data); 243*06ffe5b2SHans de Goede return 0; 244*06ffe5b2SHans de Goede 245*06ffe5b2SHans de Goede error_free_irq: 246*06ffe5b2SHans de Goede free_irq(data->backside_hall_irq, data); 247*06ffe5b2SHans de Goede cancel_work_sync(&data->work); 248*06ffe5b2SHans de Goede return r; 249*06ffe5b2SHans de Goede } 250*06ffe5b2SHans de Goede 251*06ffe5b2SHans de Goede static void yogabook_remove(struct yogabook_data *data) 252*06ffe5b2SHans de Goede { 253*06ffe5b2SHans de Goede int r = 0; 254*06ffe5b2SHans de Goede 255*06ffe5b2SHans de Goede free_irq(data->backside_hall_irq, data); 256*06ffe5b2SHans de Goede cancel_work_sync(&data->work); 257*06ffe5b2SHans de Goede 258*06ffe5b2SHans de Goede if (!test_bit(YB_KBD_IS_ON, &data->flags)) 259*06ffe5b2SHans de Goede r |= device_reprobe(data->kbd_dev); 260*06ffe5b2SHans de Goede 261*06ffe5b2SHans de Goede if (!test_bit(YB_DIGITIZER_IS_ON, &data->flags)) 262*06ffe5b2SHans de Goede r |= device_reprobe(data->dig_dev); 263*06ffe5b2SHans de Goede 264*06ffe5b2SHans de Goede if (r) 265*06ffe5b2SHans de Goede dev_warn(data->dev, "Reprobe of devices failed\n"); 266*06ffe5b2SHans de Goede } 267*06ffe5b2SHans de Goede 268*06ffe5b2SHans de Goede static int yogabook_suspend(struct device *dev) 269*06ffe5b2SHans de Goede { 270*06ffe5b2SHans de Goede struct yogabook_data *data = dev_get_drvdata(dev); 271*06ffe5b2SHans de Goede 272*06ffe5b2SHans de Goede set_bit(YB_SUSPENDED, &data->flags); 273*06ffe5b2SHans de Goede flush_work(&data->work); 274*06ffe5b2SHans de Goede 275*06ffe5b2SHans de Goede if (test_bit(YB_KBD_IS_ON, &data->flags)) 276*06ffe5b2SHans de Goede data->set_kbd_backlight(data, 0); 277*06ffe5b2SHans de Goede 278*06ffe5b2SHans de Goede return 0; 279*06ffe5b2SHans de Goede } 280*06ffe5b2SHans de Goede 281*06ffe5b2SHans de Goede static int yogabook_resume(struct device *dev) 282*06ffe5b2SHans de Goede { 283*06ffe5b2SHans de Goede struct yogabook_data *data = dev_get_drvdata(dev); 284*06ffe5b2SHans de Goede 285*06ffe5b2SHans de Goede if (test_bit(YB_KBD_IS_ON, &data->flags)) 286*06ffe5b2SHans de Goede data->set_kbd_backlight(data, data->brightness); 287*06ffe5b2SHans de Goede 288*06ffe5b2SHans de Goede clear_bit(YB_SUSPENDED, &data->flags); 289*06ffe5b2SHans de Goede 290*06ffe5b2SHans de Goede /* Check for YB_TABLET_MODE changes made during suspend */ 291*06ffe5b2SHans de Goede schedule_work(&data->work); 292*06ffe5b2SHans de Goede 293*06ffe5b2SHans de Goede return 0; 294*06ffe5b2SHans de Goede } 295*06ffe5b2SHans de Goede 296*06ffe5b2SHans de Goede static DEFINE_SIMPLE_DEV_PM_OPS(yogabook_pm_ops, yogabook_suspend, yogabook_resume); 297*06ffe5b2SHans de Goede 298*06ffe5b2SHans de Goede /********** WMI driver code **********/ 299*06ffe5b2SHans de Goede 300*06ffe5b2SHans de Goede /* 301*06ffe5b2SHans de Goede * To control keyboard backlight, call the method KBLC() of the TCS1 ACPI 302*06ffe5b2SHans de Goede * device (Goodix touchpad acts as virtual sensor keyboard). 303*06ffe5b2SHans de Goede */ 304*06ffe5b2SHans de Goede static int yogabook_wmi_set_kbd_backlight(struct yogabook_data *data, 305*06ffe5b2SHans de Goede uint8_t level) 306*06ffe5b2SHans de Goede { 307*06ffe5b2SHans de Goede struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 308*06ffe5b2SHans de Goede struct acpi_object_list input; 309*06ffe5b2SHans de Goede union acpi_object param; 310*06ffe5b2SHans de Goede acpi_status status; 311*06ffe5b2SHans de Goede 312*06ffe5b2SHans de Goede dev_dbg(data->dev, "Set KBLC level to %u\n", level); 313*06ffe5b2SHans de Goede 314*06ffe5b2SHans de Goede /* Ensure keyboard touchpad is on before we call KBLC() */ 315*06ffe5b2SHans de Goede acpi_device_set_power(data->kbd_adev, ACPI_STATE_D0); 316*06ffe5b2SHans de Goede 317*06ffe5b2SHans de Goede input.count = 1; 318*06ffe5b2SHans de Goede input.pointer = ¶m; 319*06ffe5b2SHans de Goede 320*06ffe5b2SHans de Goede param.type = ACPI_TYPE_INTEGER; 321*06ffe5b2SHans de Goede param.integer.value = YB_KBD_BL_MAX - level; 322*06ffe5b2SHans de Goede 323*06ffe5b2SHans de Goede status = acpi_evaluate_object(acpi_device_handle(data->kbd_adev), "KBLC", 324*06ffe5b2SHans de Goede &input, &output); 325*06ffe5b2SHans de Goede if (ACPI_FAILURE(status)) { 326*06ffe5b2SHans de Goede dev_err(data->dev, "Failed to call KBLC method: 0x%x\n", status); 327*06ffe5b2SHans de Goede return status; 328*06ffe5b2SHans de Goede } 329*06ffe5b2SHans de Goede 330*06ffe5b2SHans de Goede kfree(output.pointer); 331*06ffe5b2SHans de Goede return 0; 332*06ffe5b2SHans de Goede } 333*06ffe5b2SHans de Goede 334*06ffe5b2SHans de Goede static int yogabook_wmi_probe(struct wmi_device *wdev, const void *context) 335*06ffe5b2SHans de Goede { 336*06ffe5b2SHans de Goede struct device *dev = &wdev->dev; 337*06ffe5b2SHans de Goede struct yogabook_data *data; 338*06ffe5b2SHans de Goede int r; 339*06ffe5b2SHans de Goede 340*06ffe5b2SHans de Goede data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 341*06ffe5b2SHans de Goede if (data == NULL) 342*06ffe5b2SHans de Goede return -ENOMEM; 343*06ffe5b2SHans de Goede 344*06ffe5b2SHans de Goede data->kbd_adev = acpi_dev_get_first_match_dev("GDIX1001", NULL, -1); 345*06ffe5b2SHans de Goede if (!data->kbd_adev) 346*06ffe5b2SHans de Goede return dev_err_probe(dev, -ENODEV, "Cannot find the touchpad device in ACPI tables\n"); 347*06ffe5b2SHans de Goede 348*06ffe5b2SHans de Goede data->dig_adev = acpi_dev_get_first_match_dev("WCOM0019", NULL, -1); 349*06ffe5b2SHans de Goede if (!data->dig_adev) { 350*06ffe5b2SHans de Goede r = dev_err_probe(dev, -ENODEV, "Cannot find the digitizer device in ACPI tables\n"); 351*06ffe5b2SHans de Goede goto error_put_devs; 352*06ffe5b2SHans de Goede } 353*06ffe5b2SHans de Goede 354*06ffe5b2SHans de Goede data->kbd_dev = get_device(acpi_get_first_physical_node(data->kbd_adev)); 355*06ffe5b2SHans de Goede if (!data->kbd_dev || !data->kbd_dev->driver) { 356*06ffe5b2SHans de Goede r = -EPROBE_DEFER; 357*06ffe5b2SHans de Goede goto error_put_devs; 358*06ffe5b2SHans de Goede } 359*06ffe5b2SHans de Goede 360*06ffe5b2SHans de Goede data->dig_dev = get_device(acpi_get_first_physical_node(data->dig_adev)); 361*06ffe5b2SHans de Goede if (!data->dig_dev || !data->dig_dev->driver) { 362*06ffe5b2SHans de Goede r = -EPROBE_DEFER; 363*06ffe5b2SHans de Goede goto error_put_devs; 364*06ffe5b2SHans de Goede } 365*06ffe5b2SHans de Goede 366*06ffe5b2SHans de Goede data->set_kbd_backlight = yogabook_wmi_set_kbd_backlight; 367*06ffe5b2SHans de Goede 368*06ffe5b2SHans de Goede r = yogabook_probe(dev, data, "ybwmi::kbd_backlight"); 369*06ffe5b2SHans de Goede if (r) 370*06ffe5b2SHans de Goede goto error_put_devs; 371*06ffe5b2SHans de Goede 372*06ffe5b2SHans de Goede return 0; 373*06ffe5b2SHans de Goede 374*06ffe5b2SHans de Goede error_put_devs: 375*06ffe5b2SHans de Goede put_device(data->dig_dev); 376*06ffe5b2SHans de Goede put_device(data->kbd_dev); 377*06ffe5b2SHans de Goede acpi_dev_put(data->dig_adev); 378*06ffe5b2SHans de Goede acpi_dev_put(data->kbd_adev); 379*06ffe5b2SHans de Goede return r; 380*06ffe5b2SHans de Goede } 381*06ffe5b2SHans de Goede 382*06ffe5b2SHans de Goede static void yogabook_wmi_remove(struct wmi_device *wdev) 383*06ffe5b2SHans de Goede { 384*06ffe5b2SHans de Goede struct yogabook_data *data = dev_get_drvdata(&wdev->dev); 385*06ffe5b2SHans de Goede 386*06ffe5b2SHans de Goede yogabook_remove(data); 387*06ffe5b2SHans de Goede 388*06ffe5b2SHans de Goede put_device(data->dig_dev); 389*06ffe5b2SHans de Goede put_device(data->kbd_dev); 390*06ffe5b2SHans de Goede acpi_dev_put(data->dig_adev); 391*06ffe5b2SHans de Goede acpi_dev_put(data->kbd_adev); 392*06ffe5b2SHans de Goede } 393*06ffe5b2SHans de Goede 394*06ffe5b2SHans de Goede static void yogabook_wmi_notify(struct wmi_device *wdev, union acpi_object *dummy) 395*06ffe5b2SHans de Goede { 396*06ffe5b2SHans de Goede yogabook_toggle_digitizer_mode(dev_get_drvdata(&wdev->dev)); 397*06ffe5b2SHans de Goede } 398*06ffe5b2SHans de Goede 399*06ffe5b2SHans de Goede static const struct wmi_device_id yogabook_wmi_id_table[] = { 400*06ffe5b2SHans de Goede { 401*06ffe5b2SHans de Goede .guid_string = YB_MBTN_EVENT_GUID, 402*06ffe5b2SHans de Goede }, 403*06ffe5b2SHans de Goede { } /* Terminating entry */ 404*06ffe5b2SHans de Goede }; 405*06ffe5b2SHans de Goede MODULE_DEVICE_TABLE(wmi, yogabook_wmi_id_table); 406*06ffe5b2SHans de Goede 407*06ffe5b2SHans de Goede static struct wmi_driver yogabook_wmi_driver = { 408*06ffe5b2SHans de Goede .driver = { 409*06ffe5b2SHans de Goede .name = "yogabook-wmi", 410*06ffe5b2SHans de Goede .pm = pm_sleep_ptr(&yogabook_pm_ops), 411*06ffe5b2SHans de Goede }, 412*06ffe5b2SHans de Goede .no_notify_data = true, 413*06ffe5b2SHans de Goede .id_table = yogabook_wmi_id_table, 414*06ffe5b2SHans de Goede .probe = yogabook_wmi_probe, 415*06ffe5b2SHans de Goede .remove = yogabook_wmi_remove, 416*06ffe5b2SHans de Goede .notify = yogabook_wmi_notify, 417*06ffe5b2SHans de Goede }; 418*06ffe5b2SHans de Goede 419*06ffe5b2SHans de Goede /********** platform driver code **********/ 420*06ffe5b2SHans de Goede 421*06ffe5b2SHans de Goede static struct gpiod_lookup_table yogabook_pdev_gpios = { 422*06ffe5b2SHans de Goede .dev_id = YB_PDEV_NAME, 423*06ffe5b2SHans de Goede .table = { 424*06ffe5b2SHans de Goede GPIO_LOOKUP("INT33FF:00", 95, "pen_touch_event", GPIO_ACTIVE_HIGH), 425*06ffe5b2SHans de Goede GPIO_LOOKUP("INT33FF:03", 52, "enable_keyboard_led", GPIO_ACTIVE_HIGH), 426*06ffe5b2SHans de Goede {} 427*06ffe5b2SHans de Goede }, 428*06ffe5b2SHans de Goede }; 429*06ffe5b2SHans de Goede 430*06ffe5b2SHans de Goede static int yogabook_pdev_set_kbd_backlight(struct yogabook_data *data, u8 level) 431*06ffe5b2SHans de Goede { 432*06ffe5b2SHans de Goede struct pwm_state state = { 433*06ffe5b2SHans de Goede .period = YB_KBD_BL_PWM_PERIOD, 434*06ffe5b2SHans de Goede .duty_cycle = YB_KBD_BL_PWM_PERIOD * level / YB_KBD_BL_MAX, 435*06ffe5b2SHans de Goede .enabled = level, 436*06ffe5b2SHans de Goede }; 437*06ffe5b2SHans de Goede 438*06ffe5b2SHans de Goede pwm_apply_state(data->kbd_bl_pwm, &state); 439*06ffe5b2SHans de Goede gpiod_set_value(data->kbd_bl_led_enable, level ? 1 : 0); 440*06ffe5b2SHans de Goede return 0; 441*06ffe5b2SHans de Goede } 442*06ffe5b2SHans de Goede 443*06ffe5b2SHans de Goede static irqreturn_t yogabook_pen_touch_irq(int irq, void *data) 444*06ffe5b2SHans de Goede { 445*06ffe5b2SHans de Goede yogabook_toggle_digitizer_mode(data); 446*06ffe5b2SHans de Goede return IRQ_HANDLED; 447*06ffe5b2SHans de Goede } 448*06ffe5b2SHans de Goede 449*06ffe5b2SHans de Goede static int yogabook_pdev_probe(struct platform_device *pdev) 450*06ffe5b2SHans de Goede { 451*06ffe5b2SHans de Goede struct device *dev = &pdev->dev; 452*06ffe5b2SHans de Goede struct yogabook_data *data; 453*06ffe5b2SHans de Goede int r; 454*06ffe5b2SHans de Goede 455*06ffe5b2SHans de Goede data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 456*06ffe5b2SHans de Goede if (data == NULL) 457*06ffe5b2SHans de Goede return -ENOMEM; 458*06ffe5b2SHans de Goede 459*06ffe5b2SHans de Goede data->kbd_dev = bus_find_device_by_name(&i2c_bus_type, NULL, "i2c-goodix_ts"); 460*06ffe5b2SHans de Goede if (!data->kbd_dev || !data->kbd_dev->driver) { 461*06ffe5b2SHans de Goede r = -EPROBE_DEFER; 462*06ffe5b2SHans de Goede goto error_put_devs; 463*06ffe5b2SHans de Goede } 464*06ffe5b2SHans de Goede 465*06ffe5b2SHans de Goede data->dig_dev = bus_find_device_by_name(&i2c_bus_type, NULL, "i2c-wacom"); 466*06ffe5b2SHans de Goede if (!data->dig_dev || !data->dig_dev->driver) { 467*06ffe5b2SHans de Goede r = -EPROBE_DEFER; 468*06ffe5b2SHans de Goede goto error_put_devs; 469*06ffe5b2SHans de Goede } 470*06ffe5b2SHans de Goede 471*06ffe5b2SHans de Goede gpiod_add_lookup_table(&yogabook_pdev_gpios); 472*06ffe5b2SHans de Goede data->pen_touch_event = devm_gpiod_get(dev, "pen_touch_event", GPIOD_IN); 473*06ffe5b2SHans de Goede data->kbd_bl_led_enable = devm_gpiod_get(dev, "enable_keyboard_led", GPIOD_OUT_HIGH); 474*06ffe5b2SHans de Goede gpiod_remove_lookup_table(&yogabook_pdev_gpios); 475*06ffe5b2SHans de Goede 476*06ffe5b2SHans de Goede if (IS_ERR(data->pen_touch_event)) { 477*06ffe5b2SHans de Goede r = dev_err_probe(dev, PTR_ERR(data->pen_touch_event), 478*06ffe5b2SHans de Goede "Getting pen_touch_event GPIO\n"); 479*06ffe5b2SHans de Goede goto error_put_devs; 480*06ffe5b2SHans de Goede } 481*06ffe5b2SHans de Goede 482*06ffe5b2SHans de Goede if (IS_ERR(data->kbd_bl_led_enable)) { 483*06ffe5b2SHans de Goede r = dev_err_probe(dev, PTR_ERR(data->kbd_bl_led_enable), 484*06ffe5b2SHans de Goede "Getting enable_keyboard_led GPIO\n"); 485*06ffe5b2SHans de Goede goto error_put_devs; 486*06ffe5b2SHans de Goede } 487*06ffe5b2SHans de Goede 488*06ffe5b2SHans de Goede data->kbd_bl_pwm = devm_pwm_get(dev, "pwm_soc_lpss_2"); 489*06ffe5b2SHans de Goede if (IS_ERR(data->kbd_bl_pwm)) { 490*06ffe5b2SHans de Goede r = dev_err_probe(dev, PTR_ERR(data->kbd_bl_pwm), 491*06ffe5b2SHans de Goede "Getting keyboard backlight PWM\n"); 492*06ffe5b2SHans de Goede goto error_put_devs; 493*06ffe5b2SHans de Goede } 494*06ffe5b2SHans de Goede 495*06ffe5b2SHans de Goede r = gpiod_to_irq(data->pen_touch_event); 496*06ffe5b2SHans de Goede if (r < 0) { 497*06ffe5b2SHans de Goede dev_err_probe(dev, r, "Getting pen_touch_event IRQ\n"); 498*06ffe5b2SHans de Goede goto error_put_devs; 499*06ffe5b2SHans de Goede } 500*06ffe5b2SHans de Goede data->pen_touch_irq = r; 501*06ffe5b2SHans de Goede 502*06ffe5b2SHans de Goede r = request_irq(data->pen_touch_irq, yogabook_pen_touch_irq, IRQF_TRIGGER_FALLING, 503*06ffe5b2SHans de Goede "pen_touch_event", data); 504*06ffe5b2SHans de Goede if (r) { 505*06ffe5b2SHans de Goede dev_err_probe(dev, r, "Requesting pen_touch_event IRQ\n"); 506*06ffe5b2SHans de Goede goto error_put_devs; 507*06ffe5b2SHans de Goede } 508*06ffe5b2SHans de Goede 509*06ffe5b2SHans de Goede data->set_kbd_backlight = yogabook_pdev_set_kbd_backlight; 510*06ffe5b2SHans de Goede 511*06ffe5b2SHans de Goede r = yogabook_probe(dev, data, "yogabook::kbd_backlight"); 512*06ffe5b2SHans de Goede if (r) 513*06ffe5b2SHans de Goede goto error_free_irq; 514*06ffe5b2SHans de Goede 515*06ffe5b2SHans de Goede return 0; 516*06ffe5b2SHans de Goede 517*06ffe5b2SHans de Goede error_free_irq: 518*06ffe5b2SHans de Goede free_irq(data->pen_touch_irq, data); 519*06ffe5b2SHans de Goede cancel_work_sync(&data->work); 520*06ffe5b2SHans de Goede error_put_devs: 521*06ffe5b2SHans de Goede put_device(data->dig_dev); 522*06ffe5b2SHans de Goede put_device(data->kbd_dev); 523*06ffe5b2SHans de Goede return r; 524*06ffe5b2SHans de Goede } 525*06ffe5b2SHans de Goede 526*06ffe5b2SHans de Goede static void yogabook_pdev_remove(struct platform_device *pdev) 527*06ffe5b2SHans de Goede { 528*06ffe5b2SHans de Goede struct yogabook_data *data = platform_get_drvdata(pdev); 529*06ffe5b2SHans de Goede 530*06ffe5b2SHans de Goede yogabook_remove(data); 531*06ffe5b2SHans de Goede free_irq(data->pen_touch_irq, data); 532*06ffe5b2SHans de Goede cancel_work_sync(&data->work); 533*06ffe5b2SHans de Goede put_device(data->dig_dev); 534*06ffe5b2SHans de Goede put_device(data->kbd_dev); 535*06ffe5b2SHans de Goede } 536*06ffe5b2SHans de Goede 537*06ffe5b2SHans de Goede static struct platform_driver yogabook_pdev_driver = { 538*06ffe5b2SHans de Goede .probe = yogabook_pdev_probe, 539*06ffe5b2SHans de Goede .remove_new = yogabook_pdev_remove, 540*06ffe5b2SHans de Goede .driver = { 541*06ffe5b2SHans de Goede .name = YB_PDEV_NAME, 542*06ffe5b2SHans de Goede .pm = pm_sleep_ptr(&yogabook_pm_ops), 543*06ffe5b2SHans de Goede }, 544*06ffe5b2SHans de Goede }; 545*06ffe5b2SHans de Goede 546*06ffe5b2SHans de Goede static int __init yogabook_module_init(void) 547*06ffe5b2SHans de Goede { 548*06ffe5b2SHans de Goede int r; 549*06ffe5b2SHans de Goede 550*06ffe5b2SHans de Goede r = wmi_driver_register(&yogabook_wmi_driver); 551*06ffe5b2SHans de Goede if (r) 552*06ffe5b2SHans de Goede return r; 553*06ffe5b2SHans de Goede 554*06ffe5b2SHans de Goede r = platform_driver_register(&yogabook_pdev_driver); 555*06ffe5b2SHans de Goede if (r) 556*06ffe5b2SHans de Goede wmi_driver_unregister(&yogabook_wmi_driver); 557*06ffe5b2SHans de Goede 558*06ffe5b2SHans de Goede return r; 559*06ffe5b2SHans de Goede } 560*06ffe5b2SHans de Goede 561*06ffe5b2SHans de Goede static void __exit yogabook_module_exit(void) 562*06ffe5b2SHans de Goede { 563*06ffe5b2SHans de Goede platform_driver_unregister(&yogabook_pdev_driver); 564*06ffe5b2SHans de Goede wmi_driver_unregister(&yogabook_wmi_driver); 565*06ffe5b2SHans de Goede } 566*06ffe5b2SHans de Goede 567*06ffe5b2SHans de Goede module_init(yogabook_module_init); 568*06ffe5b2SHans de Goede module_exit(yogabook_module_exit); 569*06ffe5b2SHans de Goede 570*06ffe5b2SHans de Goede MODULE_ALIAS("platform:" YB_PDEV_NAME); 571*06ffe5b2SHans de Goede MODULE_AUTHOR("Yauhen Kharuzhy"); 572*06ffe5b2SHans de Goede MODULE_DESCRIPTION("Lenovo Yoga Book driver"); 573*06ffe5b2SHans de Goede MODULE_LICENSE("GPL v2"); 574