^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Intel INT3496 ACPI device extcon driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Based on android x86 kernel code which is:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (c) 2014, Intel Corporation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Author: David Cohen <david.a.cohen@linux.intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/extcon-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/gpio/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define INT3496_GPIO_USB_ID 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define INT3496_GPIO_VBUS_EN 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define INT3496_GPIO_USB_MUX 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define DEBOUNCE_TIME msecs_to_jiffies(50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct int3496_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct extcon_dev *edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct delayed_work work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct gpio_desc *gpio_usb_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct gpio_desc *gpio_vbus_en;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct gpio_desc *gpio_usb_mux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) int usb_id_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static const unsigned int int3496_cable[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) EXTCON_USB_HOST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) EXTCON_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static const struct acpi_gpio_params id_gpios = { INT3496_GPIO_USB_ID, 0, false };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static const struct acpi_gpio_params vbus_gpios = { INT3496_GPIO_VBUS_EN, 0, false };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static const struct acpi_gpio_params mux_gpios = { INT3496_GPIO_USB_MUX, 0, false };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static const struct acpi_gpio_mapping acpi_int3496_default_gpios[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * Some platforms have a bug in ACPI GPIO description making IRQ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * GPIO to be output only. Ask the GPIO core to ignore this limit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) { "id-gpios", &id_gpios, 1, ACPI_GPIO_QUIRK_NO_IO_RESTRICTION },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) { "vbus-gpios", &vbus_gpios, 1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) { "mux-gpios", &mux_gpios, 1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static void int3496_do_usb_id(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct int3496_data *data =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) container_of(work, struct int3496_data, work.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) int id = gpiod_get_value_cansleep(data->gpio_usb_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* id == 1: PERIPHERAL, id == 0: HOST */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) dev_dbg(data->dev, "Connected %s cable\n", id ? "PERIPHERAL" : "HOST");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * Peripheral: set USB mux to peripheral and disable VBUS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * Host: set USB mux to host and enable VBUS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (!IS_ERR(data->gpio_usb_mux))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) gpiod_direction_output(data->gpio_usb_mux, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (!IS_ERR(data->gpio_vbus_en))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) gpiod_direction_output(data->gpio_vbus_en, !id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) extcon_set_state_sync(data->edev, EXTCON_USB_HOST, !id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static irqreturn_t int3496_thread_isr(int irq, void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct int3496_data *data = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* Let the pin settle before processing it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) mod_delayed_work(system_wq, &data->work, DEBOUNCE_TIME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static int int3496_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct int3496_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) ret = devm_acpi_dev_add_driver_gpios(dev, acpi_int3496_default_gpios);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) dev_err(dev, "can't add GPIO ACPI mapping\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) data->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) INIT_DELAYED_WORK(&data->work, int3496_do_usb_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) data->gpio_usb_id = devm_gpiod_get(dev, "id", GPIOD_IN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (IS_ERR(data->gpio_usb_id)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) ret = PTR_ERR(data->gpio_usb_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) dev_err(dev, "can't request USB ID GPIO: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return ret;
^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) data->usb_id_irq = gpiod_to_irq(data->gpio_usb_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if (data->usb_id_irq < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) dev_err(dev, "can't get USB ID IRQ: %d\n", data->usb_id_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return data->usb_id_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) data->gpio_vbus_en = devm_gpiod_get(dev, "vbus", GPIOD_ASIS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (IS_ERR(data->gpio_vbus_en))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) dev_info(dev, "can't request VBUS EN GPIO\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) data->gpio_usb_mux = devm_gpiod_get(dev, "mux", GPIOD_ASIS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (IS_ERR(data->gpio_usb_mux))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) dev_info(dev, "can't request USB MUX GPIO\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) /* register extcon device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) data->edev = devm_extcon_dev_allocate(dev, int3496_cable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (IS_ERR(data->edev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) ret = devm_extcon_dev_register(dev, data->edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) dev_err(dev, "can't register extcon device: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ret = devm_request_threaded_irq(dev, data->usb_id_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) NULL, int3496_thread_isr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) IRQF_SHARED | IRQF_ONESHOT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) IRQF_TRIGGER_RISING |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) IRQF_TRIGGER_FALLING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) dev_name(dev), data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) dev_err(dev, "can't request IRQ for USB ID GPIO: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /* process id-pin so that we start with the right status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) queue_delayed_work(system_wq, &data->work, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) flush_delayed_work(&data->work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) platform_set_drvdata(pdev, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static int int3496_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct int3496_data *data = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) devm_free_irq(&pdev->dev, data->usb_id_irq, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) cancel_delayed_work_sync(&data->work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static const struct acpi_device_id int3496_acpi_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) { "INT3496" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) MODULE_DEVICE_TABLE(acpi, int3496_acpi_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static struct platform_driver int3496_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .name = "intel-int3496",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) .acpi_match_table = int3496_acpi_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) .probe = int3496_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .remove = int3496_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) module_platform_driver(int3496_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) MODULE_DESCRIPTION("Intel INT3496 ACPI device extcon driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) MODULE_LICENSE("GPL v2");