diff options
Diffstat (limited to 'drivers/extcon')
-rw-r--r-- | drivers/extcon/extcon-axp288.c | 36 | ||||
-rw-r--r-- | drivers/extcon/extcon-gpio.c | 103 | ||||
-rw-r--r-- | drivers/extcon/extcon-intel-cht-wc.c | 11 | ||||
-rw-r--r-- | drivers/extcon/extcon-intel-int3496.c | 12 |
4 files changed, 63 insertions, 99 deletions
diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c index 0a44d43802fe..3ec4c715e240 100644 --- a/drivers/extcon/extcon-axp288.c +++ b/drivers/extcon/extcon-axp288.c @@ -1,7 +1,6 @@ /* * extcon-axp288.c - X-Power AXP288 PMIC extcon cable detection driver * - * Copyright (C) 2016-2017 Hans de Goede <hdegoede@redhat.com> * Copyright (C) 2015 Intel Corporation * Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com> * @@ -98,15 +97,13 @@ struct axp288_extcon_info { struct device *dev; struct regmap *regmap; struct regmap_irq_chip_data *regmap_irqc; - struct delayed_work det_work; int irq[EXTCON_IRQ_END]; struct extcon_dev *edev; unsigned int previous_cable; - bool first_detect_done; }; /* Power up/down reason string array */ -static char *axp288_pwr_up_down_info[] = { +static const char * const axp288_pwr_up_down_info[] = { "Last wake caused by user pressing the power button", "Last wake caused by a charger insertion", "Last wake caused by a battery insertion", @@ -124,7 +121,7 @@ static char *axp288_pwr_up_down_info[] = { */ static void axp288_extcon_log_rsi(struct axp288_extcon_info *info) { - char **rsi; + const char * const *rsi; unsigned int val, i, clear_mask = 0; int ret; @@ -140,25 +137,6 @@ static void axp288_extcon_log_rsi(struct axp288_extcon_info *info) regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask); } -static void axp288_chrg_detect_complete(struct axp288_extcon_info *info) -{ - /* - * We depend on other drivers to do things like mux the data lines, - * enable/disable vbus based on the id-pin, etc. Sometimes the BIOS has - * not set these things up correctly resulting in the initial charger - * cable type detection giving a wrong result and we end up not charging - * or charging at only 0.5A. - * - * So we schedule a second cable type detection after 2 seconds to - * give the other drivers time to load and do their thing. - */ - if (!info->first_detect_done) { - queue_delayed_work(system_wq, &info->det_work, - msecs_to_jiffies(2000)); - info->first_detect_done = true; - } -} - static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) { int ret, stat, cfg, pwr_stat; @@ -223,8 +201,6 @@ no_vbus: info->previous_cable = cable; } - axp288_chrg_detect_complete(info); - return 0; dev_det_ret: @@ -246,11 +222,8 @@ static irqreturn_t axp288_extcon_isr(int irq, void *data) return IRQ_HANDLED; } -static void axp288_extcon_det_work(struct work_struct *work) +static void axp288_extcon_enable(struct axp288_extcon_info *info) { - struct axp288_extcon_info *info = - container_of(work, struct axp288_extcon_info, det_work.work); - regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, BC_GLOBAL_RUN, 0); /* Enable the charger detection logic */ @@ -272,7 +245,6 @@ static int axp288_extcon_probe(struct platform_device *pdev) info->regmap = axp20x->regmap; info->regmap_irqc = axp20x->regmap_irqc; info->previous_cable = EXTCON_NONE; - INIT_DELAYED_WORK(&info->det_work, axp288_extcon_det_work); platform_set_drvdata(pdev, info); @@ -318,7 +290,7 @@ static int axp288_extcon_probe(struct platform_device *pdev) } /* Start charger cable type detection */ - queue_delayed_work(system_wq, &info->det_work, 0); + axp288_extcon_enable(info); return 0; } diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index ab770adcca7e..13ba3a6e81d5 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -18,8 +18,6 @@ */ #include <linux/extcon-provider.h> -#include <linux/extcon/extcon-gpio.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -29,14 +27,30 @@ #include <linux/slab.h> #include <linux/workqueue.h> +/** + * struct gpio_extcon_data - A simple GPIO-controlled extcon device state container. + * @edev: Extcon device. + * @irq: Interrupt line for the external connector. + * @work: Work fired by the interrupt. + * @debounce_jiffies: Number of jiffies to wait for the GPIO to stabilize, from the debounce + * value. + * @gpiod: GPIO descriptor for this external connector. + * @extcon_id: The unique id of specific external connector. + * @debounce: Debounce time for GPIO IRQ in ms. + * @irq_flags: IRQ Flags (e.g., IRQF_TRIGGER_LOW). + * @check_on_resume: Boolean describing whether to check the state of gpio + * while resuming from sleep. + */ struct gpio_extcon_data { struct extcon_dev *edev; int irq; struct delayed_work work; unsigned long debounce_jiffies; - - struct gpio_desc *id_gpiod; - struct gpio_extcon_pdata *pdata; + struct gpio_desc *gpiod; + unsigned int extcon_id; + unsigned long debounce; + unsigned long irq_flags; + bool check_on_resume; }; static void gpio_extcon_work(struct work_struct *work) @@ -46,11 +60,8 @@ static void gpio_extcon_work(struct work_struct *work) container_of(to_delayed_work(work), struct gpio_extcon_data, work); - state = gpiod_get_value_cansleep(data->id_gpiod); - if (data->pdata->gpio_active_low) - state = !state; - - extcon_set_state_sync(data->edev, data->pdata->extcon_id, state); + state = gpiod_get_value_cansleep(data->gpiod); + extcon_set_state_sync(data->edev, data->extcon_id, state); } static irqreturn_t gpio_irq_handler(int irq, void *dev_id) @@ -62,65 +73,41 @@ static irqreturn_t gpio_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int gpio_extcon_init(struct device *dev, struct gpio_extcon_data *data) -{ - struct gpio_extcon_pdata *pdata = data->pdata; - int ret; - - ret = devm_gpio_request_one(dev, pdata->gpio, GPIOF_DIR_IN, - dev_name(dev)); - if (ret < 0) - return ret; - - data->id_gpiod = gpio_to_desc(pdata->gpio); - if (!data->id_gpiod) - return -EINVAL; - - if (pdata->debounce) { - ret = gpiod_set_debounce(data->id_gpiod, - pdata->debounce * 1000); - if (ret < 0) - data->debounce_jiffies = - msecs_to_jiffies(pdata->debounce); - } - - data->irq = gpiod_to_irq(data->id_gpiod); - if (data->irq < 0) - return data->irq; - - return 0; -} - static int gpio_extcon_probe(struct platform_device *pdev) { - struct gpio_extcon_pdata *pdata = dev_get_platdata(&pdev->dev); struct gpio_extcon_data *data; + struct device *dev = &pdev->dev; int ret; - if (!pdata) - return -EBUSY; - if (!pdata->irq_flags || pdata->extcon_id > EXTCON_NONE) - return -EINVAL; - - data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data), - GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct gpio_extcon_data), GFP_KERNEL); if (!data) return -ENOMEM; - data->pdata = pdata; - /* Initialize the gpio */ - ret = gpio_extcon_init(&pdev->dev, data); - if (ret < 0) - return ret; + /* + * FIXME: extcon_id represents the unique identifier of external + * connectors such as EXTCON_USB, EXTCON_DISP_HDMI and so on. extcon_id + * is necessary to register the extcon device. But, it's not yet + * developed to get the extcon id from device-tree or others. + * On later, it have to be solved. + */ + if (!data->irq_flags || data->extcon_id > EXTCON_NONE) + return -EINVAL; + + data->gpiod = devm_gpiod_get(dev, "extcon", GPIOD_IN); + if (IS_ERR(data->gpiod)) + return PTR_ERR(data->gpiod); + data->irq = gpiod_to_irq(data->gpiod); + if (data->irq <= 0) + return data->irq; /* Allocate the memory of extcon devie and register extcon device */ - data->edev = devm_extcon_dev_allocate(&pdev->dev, &pdata->extcon_id); + data->edev = devm_extcon_dev_allocate(dev, &data->extcon_id); if (IS_ERR(data->edev)) { - dev_err(&pdev->dev, "failed to allocate extcon device\n"); + dev_err(dev, "failed to allocate extcon device\n"); return -ENOMEM; } - ret = devm_extcon_dev_register(&pdev->dev, data->edev); + ret = devm_extcon_dev_register(dev, data->edev); if (ret < 0) return ret; @@ -130,8 +117,8 @@ static int gpio_extcon_probe(struct platform_device *pdev) * Request the interrupt of gpio to detect whether external connector * is attached or detached. */ - ret = devm_request_any_context_irq(&pdev->dev, data->irq, - gpio_irq_handler, pdata->irq_flags, + ret = devm_request_any_context_irq(dev, data->irq, + gpio_irq_handler, data->irq_flags, pdev->name, data); if (ret < 0) return ret; @@ -158,7 +145,7 @@ static int gpio_extcon_resume(struct device *dev) struct gpio_extcon_data *data; data = dev_get_drvdata(dev); - if (data->pdata->check_on_resume) + if (data->check_on_resume) queue_delayed_work(system_power_efficient_wq, &data->work, data->debounce_jiffies); diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index 7c4bc8c44c3f..b7e9ea377d70 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -66,6 +66,8 @@ #define CHT_WC_VBUS_GPIO_CTLO 0x6e2d #define CHT_WC_VBUS_GPIO_CTLO_OUTPUT BIT(0) +#define CHT_WC_VBUS_GPIO_CTLO_DRV_OD BIT(4) +#define CHT_WC_VBUS_GPIO_CTLO_DIR_OUT BIT(5) enum cht_wc_usb_id { USB_ID_OTG, @@ -183,14 +185,15 @@ static void cht_wc_extcon_set_5v_boost(struct cht_wc_extcon_data *ext, { int ret, val; - val = enable ? CHT_WC_VBUS_GPIO_CTLO_OUTPUT : 0; - /* * The 5V boost converter is enabled through a gpio on the PMIC, since * there currently is no gpio driver we access the gpio reg directly. */ - ret = regmap_update_bits(ext->regmap, CHT_WC_VBUS_GPIO_CTLO, - CHT_WC_VBUS_GPIO_CTLO_OUTPUT, val); + val = CHT_WC_VBUS_GPIO_CTLO_DRV_OD | CHT_WC_VBUS_GPIO_CTLO_DIR_OUT; + if (enable) + val |= CHT_WC_VBUS_GPIO_CTLO_OUTPUT; + + ret = regmap_write(ext->regmap, CHT_WC_VBUS_GPIO_CTLO, val); if (ret) dev_err(ext->dev, "Error writing Vbus GPIO CTLO: %d\n", ret); } diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c index c8691b5a9cb0..acaccb128fc4 100644 --- a/drivers/extcon/extcon-intel-int3496.c +++ b/drivers/extcon/extcon-intel-int3496.c @@ -50,7 +50,11 @@ static const struct acpi_gpio_params vbus_gpios = { INT3496_GPIO_VBUS_EN, 0, fal static const struct acpi_gpio_params mux_gpios = { INT3496_GPIO_USB_MUX, 0, false }; static const struct acpi_gpio_mapping acpi_int3496_default_gpios[] = { - { "id-gpios", &id_gpios, 1 }, + /* + * Some platforms have a bug in ACPI GPIO description making IRQ + * GPIO to be output only. Ask the GPIO core to ignore this limit. + */ + { "id-gpios", &id_gpios, 1, ACPI_GPIO_QUIRK_NO_IO_RESTRICTION }, { "vbus-gpios", &vbus_gpios, 1 }, { "mux-gpios", &mux_gpios, 1 }, { }, @@ -112,9 +116,6 @@ static int int3496_probe(struct platform_device *pdev) ret = PTR_ERR(data->gpio_usb_id); dev_err(dev, "can't request USB ID GPIO: %d\n", ret); return ret; - } else if (gpiod_get_direction(data->gpio_usb_id) != GPIOF_DIR_IN) { - dev_warn(dev, FW_BUG "USB ID GPIO not in input mode, fixing\n"); - gpiod_direction_input(data->gpio_usb_id); } data->usb_id_irq = gpiod_to_irq(data->gpio_usb_id); @@ -153,8 +154,9 @@ static int int3496_probe(struct platform_device *pdev) return ret; } - /* queue initial processing of id-pin */ + /* process id-pin so that we start with the right status */ queue_delayed_work(system_wq, &data->work, 0); + flush_delayed_work(&data->work); platform_set_drvdata(pdev, data); |