cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

extcon-intel-int3496.c (5724B)


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