]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge tag 'extcon-next-for-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 25 Jan 2017 10:05:04 +0000 (11:05 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 25 Jan 2017 10:05:04 +0000 (11:05 +0100)
Chanwoo writes:

Update extcon for 4.11

Detailed description for this pull request:
1. Add the new extcon driver.
- Intel INT3496 ACPI USB id detection driver detects whether
  EXTCON_USB_HOST is attached or detached. (extcon-intel-int3496.c)

2. Add the new type of external connector.
- EXTCON_CHG_USB_PD (USB Power Delivery) provides the increased
  power more than 7.5W to device with larger power demand.

3. Add the description for EXTCON_CHG_USB_(SDP|ACA|SLOW|FAST)
- EXTCON_CHG_USB_SDP should always appear together with EXTCON_USB
- EXTCON_CHG_USB_ACA would normally appear with EXTCON_USB_HOST.
- EXTCON_CHG_USB_SLOW can provide at least 500mA of current at 5V
- EXTCON_CHG_USB_FAST can provide at least 1A of current at 5V.

4. Modify the connector name of EXTCON_USB_HOST
- "USB_HOST" -> "USB-HOST"

5. Update the extcon core
- Move the private extcon structure into driver/extcon directory.
  The 'struct extcon_dev' should be only handled by extcon core
  to prevent the direct access and to maintain the integrity of it.
- Remove the ambigous operation of extcon_register_notifier()
  in case of the 'extcon_dev' instance is NULL. The user of
  extcon_register_notifier() have to specify the correct instance
  of the provider extcon driver.

6. Update the extcon drivers and fix the minor issues
- Update the extcon-axp288 driver to remove the unncessary code.
- Add pinctrl operation during suspend mode to extcon-usb-gpio driver.
- Clean up the extcon-arizona/adc-jack driver.
- Use the dev_dbg() for debug messsage on extcon-palmas driver.
- Return the error code on failure of extcon_sync()

19 files changed:
Documentation/extcon/intel-int3496.txt [new file with mode: 0644]
drivers/extcon/Kconfig
drivers/extcon/Makefile
drivers/extcon/devres.c
drivers/extcon/extcon-adc-jack.c
drivers/extcon/extcon-arizona.c
drivers/extcon/extcon-axp288.c
drivers/extcon/extcon-intel-int3496.c [new file with mode: 0644]
drivers/extcon/extcon-max14577.c
drivers/extcon/extcon-max77693.c
drivers/extcon/extcon-max77843.c
drivers/extcon/extcon-palmas.c
drivers/extcon/extcon-rt8973a.c
drivers/extcon/extcon-sm5502.c
drivers/extcon/extcon-usb-gpio.c
drivers/extcon/extcon.c
drivers/extcon/extcon.h [new file with mode: 0644]
include/linux/extcon.h
include/linux/extcon/extcon-adc-jack.h

diff --git a/Documentation/extcon/intel-int3496.txt b/Documentation/extcon/intel-int3496.txt
new file mode 100644 (file)
index 0000000..af0b366
--- /dev/null
@@ -0,0 +1,22 @@
+Intel INT3496 ACPI device extcon driver documentation
+-----------------------------------------------------
+
+The Intel INT3496 ACPI device extcon driver is a driver for ACPI
+devices with an acpi-id of INT3496, such as found for example on
+Intel Baytrail and Cherrytrail tablets.
+
+This ACPI device describes how the OS can read the id-pin of the devices'
+USB-otg port, as well as how it optionally can enable Vbus output on the
+otg port and how it can optionally control the muxing of the data pins
+between an USB host and an USB peripheral controller.
+
+The ACPI devices exposes this functionality by returning an array with up
+to 3 gpio descriptors from its ACPI _CRS (Current Resource Settings) call:
+
+Index 0: The input gpio for the id-pin, this is always present and valid
+Index 1: The output gpio for enabling Vbus output from the device to the otg
+         port, write 1 to enable the Vbus output (this gpio descriptor may
+         be absent or invalid)
+Index 2: The output gpio for muxing of the data pins between the USB host and
+         the USB peripheral controller, write 1 to mux to the peripheral
+         controller
index 04788d92ea522a5346e76f6dd6f5d6bf08431c4e..96bbae579c0b01cfdc3798e8fdb03948cb391280 100644 (file)
@@ -42,6 +42,16 @@ config EXTCON_GPIO
          Say Y here to enable GPIO based extcon support. Note that GPIO
          extcon supports single state per extcon instance.
 
+config EXTCON_INTEL_INT3496
+       tristate "Intel INT3496 ACPI device extcon driver"
+       depends on GPIOLIB && ACPI
+       help
+         Say Y here to enable extcon support for USB OTG ports controlled by
+         an Intel INT3496 ACPI device.
+
+         This ACPI device is typically found on Intel Baytrail or Cherrytrail
+         based tablets, or other Baytrail / Cherrytrail devices.
+
 config EXTCON_MAX14577
        tristate "Maxim MAX14577/77836 EXTCON Support"
        depends on MFD_MAX14577
index 31a0a999c4fb0c9b6c3da9680f55caba57e02782..237ac3f953c2bfbfcedc4dff477788af39f1232e 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_EXTCON_ADC_JACK)   += extcon-adc-jack.o
 obj-$(CONFIG_EXTCON_ARIZONA)   += extcon-arizona.o
 obj-$(CONFIG_EXTCON_AXP288)    += extcon-axp288.o
 obj-$(CONFIG_EXTCON_GPIO)      += extcon-gpio.o
+obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o
 obj-$(CONFIG_EXTCON_MAX14577)  += extcon-max14577.o
 obj-$(CONFIG_EXTCON_MAX3355)   += extcon-max3355.o
 obj-$(CONFIG_EXTCON_MAX77693)  += extcon-max77693.o
index e686acd1c459176596d1b20a0e081b9335a13f3f..b40eb18059273715b9ab5e7b30edfaf3ab448743 100644 (file)
@@ -14,7 +14,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/extcon.h>
+#include "extcon.h"
 
 static int devm_extcon_dev_match(struct device *dev, void *res, void *data)
 {
index bc538708c75370a61ac83b9331e0bf1dd6aea810..6f6537ab0a7911e5dbfaaee5e2f2794326588838 100644 (file)
@@ -67,7 +67,7 @@ static void adc_jack_handler(struct work_struct *work)
 
        ret = iio_read_channel_raw(data->chan, &adc_val);
        if (ret < 0) {
-               dev_err(&data->edev->dev, "read channel() error: %d\n", ret);
+               dev_err(data->dev, "read channel() error: %d\n", ret);
                return;
        }
 
index d836d4ce5ee46ab9da23715881d0cdd82ec7fcb5..ed78b7c26627e7df5ebfeeb76841d13bee952246 100644 (file)
@@ -236,12 +236,8 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
 
        mode %= info->micd_num_modes;
 
-       if (arizona->pdata.micd_pol_gpio > 0)
-               gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
-                                       info->micd_modes[mode].gpio);
-       else
-               gpiod_set_value_cansleep(info->micd_pol_gpio,
-                                        info->micd_modes[mode].gpio);
+       gpiod_set_value_cansleep(info->micd_pol_gpio,
+                                info->micd_modes[mode].gpio);
 
        regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1,
                           ARIZONA_MICD_BIAS_SRC_MASK,
@@ -1412,21 +1408,21 @@ static int arizona_extcon_probe(struct platform_device *pdev)
                regmap_update_bits(arizona->regmap, ARIZONA_GP_SWITCH_1,
                                ARIZONA_SW1_MODE_MASK, arizona->pdata.gpsw);
 
-       if (arizona->pdata.micd_pol_gpio > 0) {
+       if (pdata->micd_pol_gpio > 0) {
                if (info->micd_modes[0].gpio)
                        mode = GPIOF_OUT_INIT_HIGH;
                else
                        mode = GPIOF_OUT_INIT_LOW;
 
-               ret = devm_gpio_request_one(&pdev->dev,
-                                           arizona->pdata.micd_pol_gpio,
-                                           mode,
-                                           "MICD polarity");
+               ret = devm_gpio_request_one(&pdev->dev, pdata->micd_pol_gpio,
+                                           mode, "MICD polarity");
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to request GPIO%d: %d\n",
-                               arizona->pdata.micd_pol_gpio, ret);
+                               pdata->micd_pol_gpio, ret);
                        goto err_register;
                }
+
+               info->micd_pol_gpio = gpio_to_desc(pdata->micd_pol_gpio);
        } else {
                if (info->micd_modes[0].gpio)
                        mode = GPIOD_OUT_HIGH;
index 42f41e8082924e229d99ceac264549494449b9d3..f4fd03e58e37292235284506433b3d5efc928b90 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
-#include <linux/usb/phy.h>
 #include <linux/notifier.h>
 #include <linux/extcon.h>
 #include <linux/regmap.h>
 #define DET_STAT_CDP                   2
 #define DET_STAT_DCP                   3
 
-/* IRQ enable-1 register */
-#define PWRSRC_IRQ_CFG_MASK            (BIT(4)|BIT(3)|BIT(2))
-
-/* IRQ enable-6 register */
-#define BC12_IRQ_CFG_MASK              BIT(1)
-
 enum axp288_extcon_reg {
        AXP288_PS_STAT_REG              = 0x00,
        AXP288_PS_BOOT_REASON_REG       = 0x02,
@@ -84,8 +77,6 @@ enum axp288_extcon_reg {
        AXP288_BC_VBUS_CNTL_REG         = 0x2d,
        AXP288_BC_USB_STAT_REG          = 0x2e,
        AXP288_BC_DET_STAT_REG          = 0x2f,
-       AXP288_PWRSRC_IRQ_CFG_REG       = 0x40,
-       AXP288_BC12_IRQ_CFG_REG         = 0x45,
 };
 
 enum axp288_mux_select {
@@ -105,6 +96,7 @@ static const unsigned int axp288_extcon_cables[] = {
        EXTCON_CHG_USB_SDP,
        EXTCON_CHG_USB_CDP,
        EXTCON_CHG_USB_DCP,
+       EXTCON_USB,
        EXTCON_NONE,
 };
 
@@ -112,11 +104,11 @@ struct axp288_extcon_info {
        struct device *dev;
        struct regmap *regmap;
        struct regmap_irq_chip_data *regmap_irqc;
-       struct axp288_extcon_pdata *pdata;
+       struct gpio_desc *gpio_mux_cntl;
        int irq[EXTCON_IRQ_END];
        struct extcon_dev *edev;
        struct notifier_block extcon_nb;
-       struct usb_phy *otg;
+       unsigned int previous_cable;
 };
 
 /* Power up/down reason string array */
@@ -156,10 +148,9 @@ static void axp288_extcon_log_rsi(struct axp288_extcon_info *info)
 
 static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
 {
-       static bool notify_otg, notify_charger;
-       static unsigned int cable;
        int ret, stat, cfg, pwr_stat;
        u8 chrg_type;
+       unsigned int cable = info->previous_cable;
        bool vbus_attach = false;
 
        ret = regmap_read(info->regmap, AXP288_PS_STAT_REG, &pwr_stat);
@@ -168,9 +159,9 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
                return ret;
        }
 
-       vbus_attach = (pwr_stat & PS_STAT_VBUS_PRESENT);
+       vbus_attach = (pwr_stat & PS_STAT_VBUS_VALID);
        if (!vbus_attach)
-               goto notify_otg;
+               goto no_vbus;
 
        /* Check charger detection completion status */
        ret = regmap_read(info->regmap, AXP288_BC_GLOBAL_REG, &cfg);
@@ -190,19 +181,14 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
        switch (chrg_type) {
        case DET_STAT_SDP:
                dev_dbg(info->dev, "sdp cable is connected\n");
-               notify_otg = true;
-               notify_charger = true;
                cable = EXTCON_CHG_USB_SDP;
                break;
        case DET_STAT_CDP:
                dev_dbg(info->dev, "cdp cable is connected\n");
-               notify_otg = true;
-               notify_charger = true;
                cable = EXTCON_CHG_USB_CDP;
                break;
        case DET_STAT_DCP:
                dev_dbg(info->dev, "dcp cable is connected\n");
-               notify_charger = true;
                cable = EXTCON_CHG_USB_DCP;
                break;
        default:
@@ -210,27 +196,28 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
                        "disconnect or unknown or ID event\n");
        }
 
-notify_otg:
-       if (notify_otg) {
-               /*
-                * If VBUS is absent Connect D+/D- lines to PMIC for BC
-                * detection. Else connect them to SOC for USB communication.
-                */
-               if (info->pdata->gpio_mux_cntl)
-                       gpiod_set_value(info->pdata->gpio_mux_cntl,
-                               vbus_attach ? EXTCON_GPIO_MUX_SEL_SOC
-                                               : EXTCON_GPIO_MUX_SEL_PMIC);
-
-               atomic_notifier_call_chain(&info->otg->notifier,
-                       vbus_attach ? USB_EVENT_VBUS : USB_EVENT_NONE, NULL);
-       }
-
-       if (notify_charger)
+no_vbus:
+       /*
+        * If VBUS is absent Connect D+/D- lines to PMIC for BC
+        * detection. Else connect them to SOC for USB communication.
+        */
+       if (info->gpio_mux_cntl)
+               gpiod_set_value(info->gpio_mux_cntl,
+                       vbus_attach ? EXTCON_GPIO_MUX_SEL_SOC
+                                       : EXTCON_GPIO_MUX_SEL_PMIC);
+
+       extcon_set_state_sync(info->edev, info->previous_cable, false);
+       if (info->previous_cable == EXTCON_CHG_USB_SDP)
+               extcon_set_state_sync(info->edev, EXTCON_USB, false);
+
+       if (vbus_attach) {
                extcon_set_state_sync(info->edev, cable, vbus_attach);
+               if (cable == EXTCON_CHG_USB_SDP)
+                       extcon_set_state_sync(info->edev, EXTCON_USB,
+                                               vbus_attach);
 
-       /* Clear the flags on disconnect event */
-       if (!vbus_attach)
-               notify_otg = notify_charger = false;
+               info->previous_cable = cable;
+       }
 
        return 0;
 
@@ -253,15 +240,10 @@ static irqreturn_t axp288_extcon_isr(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static void axp288_extcon_enable_irq(struct axp288_extcon_info *info)
+static void axp288_extcon_enable(struct axp288_extcon_info *info)
 {
-       /* Unmask VBUS interrupt */
-       regmap_write(info->regmap, AXP288_PWRSRC_IRQ_CFG_REG,
-                                               PWRSRC_IRQ_CFG_MASK);
        regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
                                                BC_GLOBAL_RUN, 0);
-       /* Unmask the BC1.2 complete interrupts */
-       regmap_write(info->regmap, AXP288_BC12_IRQ_CFG_REG, BC12_IRQ_CFG_MASK);
        /* Enable the charger detection logic */
        regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
                                        BC_GLOBAL_RUN, BC_GLOBAL_RUN);
@@ -271,6 +253,7 @@ static int axp288_extcon_probe(struct platform_device *pdev)
 {
        struct axp288_extcon_info *info;
        struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+       struct axp288_extcon_pdata *pdata = pdev->dev.platform_data;
        int ret, i, pirq, gpio;
 
        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
@@ -280,15 +263,10 @@ static int axp288_extcon_probe(struct platform_device *pdev)
        info->dev = &pdev->dev;
        info->regmap = axp20x->regmap;
        info->regmap_irqc = axp20x->regmap_irqc;
-       info->pdata = pdev->dev.platform_data;
-
-       if (!info->pdata) {
-               /* Try ACPI provided pdata via device properties */
-               if (!device_property_present(&pdev->dev,
-                                       "axp288_extcon_data\n"))
-                       dev_err(&pdev->dev, "failed to get platform data\n");
-               return -ENODEV;
-       }
+       info->previous_cable = EXTCON_NONE;
+       if (pdata)
+               info->gpio_mux_cntl = pdata->gpio_mux_cntl;
+
        platform_set_drvdata(pdev, info);
 
        axp288_extcon_log_rsi(info);
@@ -308,23 +286,16 @@ static int axp288_extcon_probe(struct platform_device *pdev)
                return ret;
        }
 
-       /* Get otg transceiver phy */
-       info->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
-       if (IS_ERR(info->otg)) {
-               dev_err(&pdev->dev, "failed to get otg transceiver\n");
-               return PTR_ERR(info->otg);
-       }
-
        /* Set up gpio control for USB Mux */
-       if (info->pdata->gpio_mux_cntl) {
-               gpio = desc_to_gpio(info->pdata->gpio_mux_cntl);
+       if (info->gpio_mux_cntl) {
+               gpio = desc_to_gpio(info->gpio_mux_cntl);
                ret = devm_gpio_request(&pdev->dev, gpio, "USB_MUX");
                if (ret < 0) {
                        dev_err(&pdev->dev,
                                "failed to request the gpio=%d\n", gpio);
                        return ret;
                }
-               gpiod_direction_output(info->pdata->gpio_mux_cntl,
+               gpiod_direction_output(info->gpio_mux_cntl,
                                                EXTCON_GPIO_MUX_SEL_PMIC);
        }
 
@@ -349,14 +320,21 @@ static int axp288_extcon_probe(struct platform_device *pdev)
                }
        }
 
-       /* Enable interrupts */
-       axp288_extcon_enable_irq(info);
+       /* Start charger cable type detection */
+       axp288_extcon_enable(info);
 
        return 0;
 }
 
+static const struct platform_device_id axp288_extcon_table[] = {
+       { .name = "axp288_extcon" },
+       {},
+};
+MODULE_DEVICE_TABLE(platform, axp288_extcon_table);
+
 static struct platform_driver axp288_extcon_driver = {
        .probe = axp288_extcon_probe,
+       .id_table = axp288_extcon_table,
        .driver = {
                .name = "axp288_extcon",
        },
diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c
new file mode 100644 (file)
index 0000000..a3131b0
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Intel INT3496 ACPI device extcon driver
+ *
+ * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on android x86 kernel code which is:
+ *
+ * Copyright (c) 2014, Intel Corporation.
+ * Author: David Cohen <david.a.cohen@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/acpi.h>
+#include <linux/extcon.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define INT3496_GPIO_USB_ID    0
+#define INT3496_GPIO_VBUS_EN   1
+#define INT3496_GPIO_USB_MUX   2
+#define DEBOUNCE_TIME          msecs_to_jiffies(50)
+
+struct int3496_data {
+       struct device *dev;
+       struct extcon_dev *edev;
+       struct delayed_work work;
+       struct gpio_desc *gpio_usb_id;
+       struct gpio_desc *gpio_vbus_en;
+       struct gpio_desc *gpio_usb_mux;
+       int usb_id_irq;
+};
+
+static const unsigned int int3496_cable[] = {
+       EXTCON_USB_HOST,
+       EXTCON_NONE,
+};
+
+static void int3496_do_usb_id(struct work_struct *work)
+{
+       struct int3496_data *data =
+               container_of(work, struct int3496_data, work.work);
+       int id = gpiod_get_value_cansleep(data->gpio_usb_id);
+
+       /* id == 1: PERIPHERAL, id == 0: HOST */
+       dev_dbg(data->dev, "Connected %s cable\n", id ? "PERIPHERAL" : "HOST");
+
+       /*
+        * Peripheral: set USB mux to peripheral and disable VBUS
+        * Host: set USB mux to host and enable VBUS
+        */
+       if (!IS_ERR(data->gpio_usb_mux))
+               gpiod_direction_output(data->gpio_usb_mux, id);
+
+       if (!IS_ERR(data->gpio_vbus_en))
+               gpiod_direction_output(data->gpio_vbus_en, !id);
+
+       extcon_set_state_sync(data->edev, EXTCON_USB_HOST, !id);
+}
+
+static irqreturn_t int3496_thread_isr(int irq, void *priv)
+{
+       struct int3496_data *data = priv;
+
+       /* Let the pin settle before processing it */
+       mod_delayed_work(system_wq, &data->work, DEBOUNCE_TIME);
+
+       return IRQ_HANDLED;
+}
+
+static int int3496_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct int3496_data *data;
+       int ret;
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->dev = dev;
+       INIT_DELAYED_WORK(&data->work, int3496_do_usb_id);
+
+       data->gpio_usb_id = devm_gpiod_get_index(dev, "id",
+                                               INT3496_GPIO_USB_ID,
+                                               GPIOD_IN);
+       if (IS_ERR(data->gpio_usb_id)) {
+               ret = PTR_ERR(data->gpio_usb_id);
+               dev_err(dev, "can't request USB ID GPIO: %d\n", ret);
+               return ret;
+       }
+
+       data->usb_id_irq = gpiod_to_irq(data->gpio_usb_id);
+       if (data->usb_id_irq <= 0) {
+               dev_err(dev, "can't get USB ID IRQ: %d\n", data->usb_id_irq);
+               return -EINVAL;
+       }
+
+       data->gpio_vbus_en = devm_gpiod_get_index(dev, "vbus en",
+                                                INT3496_GPIO_VBUS_EN,
+                                                GPIOD_ASIS);
+       if (IS_ERR(data->gpio_vbus_en))
+               dev_info(dev, "can't request VBUS EN GPIO\n");
+
+       data->gpio_usb_mux = devm_gpiod_get_index(dev, "usb mux",
+                                                INT3496_GPIO_USB_MUX,
+                                                GPIOD_ASIS);
+       if (IS_ERR(data->gpio_usb_mux))
+               dev_info(dev, "can't request USB MUX GPIO\n");
+
+       /* register extcon device */
+       data->edev = devm_extcon_dev_allocate(dev, int3496_cable);
+       if (IS_ERR(data->edev))
+               return -ENOMEM;
+
+       ret = devm_extcon_dev_register(dev, data->edev);
+       if (ret < 0) {
+               dev_err(dev, "can't register extcon device: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_request_threaded_irq(dev, data->usb_id_irq,
+                                       NULL, int3496_thread_isr,
+                                       IRQF_SHARED | IRQF_ONESHOT |
+                                       IRQF_TRIGGER_RISING |
+                                       IRQF_TRIGGER_FALLING,
+                                       dev_name(dev), data);
+       if (ret < 0) {
+               dev_err(dev, "can't request IRQ for USB ID GPIO: %d\n", ret);
+               return ret;
+       }
+
+       /* queue initial processing of id-pin */
+       queue_delayed_work(system_wq, &data->work, 0);
+
+       platform_set_drvdata(pdev, data);
+
+       return 0;
+}
+
+static int int3496_remove(struct platform_device *pdev)
+{
+       struct int3496_data *data = platform_get_drvdata(pdev);
+
+       devm_free_irq(&pdev->dev, data->usb_id_irq, data);
+       cancel_delayed_work_sync(&data->work);
+
+       return 0;
+}
+
+static struct acpi_device_id int3496_acpi_match[] = {
+       { "INT3496" },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, int3496_acpi_match);
+
+static struct platform_driver int3496_driver = {
+       .driver = {
+               .name = "intel-int3496",
+               .acpi_match_table = int3496_acpi_match,
+       },
+       .probe = int3496_probe,
+       .remove = int3496_remove,
+};
+
+module_platform_driver(int3496_driver);
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Intel INT3496 ACPI device extcon driver");
+MODULE_LICENSE("GPL");
index 12e26c4e77638cf16041037b040a93371c714bd4..f6414b7fa5bc93fd4d4a6aecdcb63f1401974a8b 100644 (file)
@@ -531,8 +531,10 @@ static int max14577_parse_irq(struct max14577_muic_info *info, int irq_type)
        case MAX14577_IRQ_INT1_ADC:
        case MAX14577_IRQ_INT1_ADCLOW:
        case MAX14577_IRQ_INT1_ADCERR:
-               /* Handle all of accessory except for
-                  type of charger accessory */
+               /*
+                * Handle all of accessory except for
+                * type of charger accessory.
+                */
                info->irq_adc = true;
                return 1;
        case MAX14577_IRQ_INT2_CHGTYP:
index 68dbcb814b2ff78a64bc7a456a380e89227e32f9..62163468f205bd557478247a30130cfd23def9a3 100644 (file)
@@ -188,8 +188,10 @@ enum max77693_muic_acc_type {
        MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE,
        MAX77693_MUIC_ADC_OPEN,
 
-       /* The below accessories have same ADC value so ADCLow and
-          ADC1K bit is used to separate specific accessory */
+       /*
+        * The below accessories have same ADC value so ADCLow and
+        * ADC1K bit is used to separate specific accessory.
+        */
                                                /* ADC|VBVolot|ADCLow|ADC1K| */
        MAX77693_MUIC_GND_USB_HOST = 0x100,     /* 0x0|      0|     0|    0| */
        MAX77693_MUIC_GND_USB_HOST_VB = 0x104,  /* 0x0|      1|     0|    0| */
@@ -970,8 +972,10 @@ static void max77693_muic_irq_work(struct work_struct *work)
        case MAX77693_MUIC_IRQ_INT1_ADC_LOW:
        case MAX77693_MUIC_IRQ_INT1_ADC_ERR:
        case MAX77693_MUIC_IRQ_INT1_ADC1K:
-               /* Handle all of accessory except for
-                  type of charger accessory */
+               /*
+                * Handle all of accessory except for
+                * type of charger accessory.
+                */
                ret = max77693_muic_adc_handler(info);
                break;
        case MAX77693_MUIC_IRQ_INT2_CHGTYP:
index 5d11fdf36e9424b9e03eb484098e4752f147be4c..6e722d552cf101d01986749bab89de68d47898f8 100644 (file)
@@ -97,8 +97,10 @@ enum max77843_muic_accessory_type {
        MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1,
        MAX77843_MUIC_ADC_OPEN,
 
-       /* The blow accessories should check
-          not only ADC value but also ADC1K and VBVolt value. */
+       /*
+        * The below accessories should check
+        * not only ADC value but also ADC1K and VBVolt value.
+        */
                                                /* Offset|ADC1K|VBVolt| */
        MAX77843_MUIC_GND_USB_HOST = 0x100,     /*    0x1|    0|     0| */
        MAX77843_MUIC_GND_USB_HOST_VB = 0x101,  /*    0x1|    0|     1| */
@@ -265,16 +267,20 @@ static int max77843_muic_get_cable_type(struct max77843_muic_info *info,
                /* Check GROUND accessory with charger cable */
                if (adc == MAX77843_MUIC_ADC_GROUND) {
                        if (chg_type == MAX77843_MUIC_CHG_NONE) {
-                               /* The following state when charger cable is
+                               /*
+                                * The following state when charger cable is
                                 * disconnected but the GROUND accessory still
-                                * connected */
+                                * connected.
+                                */
                                *attached = false;
                                cable_type = info->prev_chg_type;
                                info->prev_chg_type = MAX77843_MUIC_CHG_NONE;
                        } else {
 
-                               /* The following state when charger cable is
-                                * connected on the GROUND accessory */
+                               /*
+                                * The following state when charger cable is
+                                * connected on the GROUND accessory.
+                                */
                                *attached = true;
                                cable_type = MAX77843_MUIC_CHG_GND;
                                info->prev_chg_type = MAX77843_MUIC_CHG_GND;
@@ -299,11 +305,13 @@ static int max77843_muic_get_cable_type(struct max77843_muic_info *info,
                } else {
                        *attached = true;
 
-                       /* Offset|ADC1K|VBVolt|
+                       /*
+                        * Offset|ADC1K|VBVolt|
                         *    0x1|    0|     0| USB-HOST
                         *    0x1|    0|     1| USB-HOST with VB
                         *    0x1|    1|     0| MHL
-                        *    0x1|    1|     1| MHL with VB */
+                        *    0x1|    1|     1| MHL with VB
+                        */
                        /* Get ADC1K register bit */
                        gnd_type = (info->status[MAX77843_MUIC_STATUS1] &
                                        MAX77843_MUIC_STATUS1_ADC1K_MASK);
index 634ba70782de9c92f256e9e5cdd535f71dd642f2..ca904e8b32351110335e48c0fd755994c0042d81 100644 (file)
@@ -62,7 +62,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
                if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) {
                        palmas_usb->linkstat = PALMAS_USB_STATE_VBUS;
                        extcon_set_state_sync(edev, EXTCON_USB, true);
-                       dev_info(palmas_usb->dev, "USB cable is attached\n");
+                       dev_dbg(palmas_usb->dev, "USB cable is attached\n");
                } else {
                        dev_dbg(palmas_usb->dev,
                                "Spurious connect event detected\n");
@@ -71,7 +71,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
                if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) {
                        palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
                        extcon_set_state_sync(edev, EXTCON_USB, false);
-                       dev_info(palmas_usb->dev, "USB cable is detached\n");
+                       dev_dbg(palmas_usb->dev, "USB cable is detached\n");
                } else {
                        dev_dbg(palmas_usb->dev,
                                "Spurious disconnect event detected\n");
@@ -99,7 +99,7 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
                        PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
                palmas_usb->linkstat = PALMAS_USB_STATE_ID;
                extcon_set_state_sync(edev, EXTCON_USB_HOST, true);
-               dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
+               dev_dbg(palmas_usb->dev, "USB-HOST cable is attached\n");
        } else if ((set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) &&
                                (id_src & PALMAS_USB_ID_INT_SRC_ID_FLOAT)) {
                palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
@@ -107,17 +107,17 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
                        PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
                palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
                extcon_set_state_sync(edev, EXTCON_USB_HOST, false);
-               dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
+               dev_dbg(palmas_usb->dev, "USB-HOST cable is detached\n");
        } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_ID) &&
                                (!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) {
                palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
                extcon_set_state_sync(edev, EXTCON_USB_HOST, false);
-               dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
+               dev_dbg(palmas_usb->dev, "USB-HOST cable is detached\n");
        } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_DISCONNECT) &&
                                (id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) {
                palmas_usb->linkstat = PALMAS_USB_STATE_ID;
                extcon_set_state_sync(edev, EXTCON_USB_HOST, true);
-               dev_info(palmas_usb->dev, " USB-HOST cable is attached\n");
+               dev_dbg(palmas_usb->dev, " USB-HOST cable is attached\n");
        }
 
        return IRQ_HANDLED;
@@ -138,10 +138,10 @@ static void palmas_gpio_id_detect(struct work_struct *work)
 
        if (id) {
                extcon_set_state_sync(edev, EXTCON_USB_HOST, false);
-               dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
+               dev_dbg(palmas_usb->dev, "USB-HOST cable is detached\n");
        } else {
                extcon_set_state_sync(edev, EXTCON_USB_HOST, true);
-               dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
+               dev_dbg(palmas_usb->dev, "USB-HOST cable is attached\n");
        }
 }
 
@@ -190,6 +190,11 @@ static int palmas_usb_probe(struct platform_device *pdev)
        struct palmas_usb *palmas_usb;
        int status;
 
+       if (!palmas) {
+               dev_err(&pdev->dev, "failed to get valid parent\n");
+               return -EINVAL;
+       }
+
        palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL);
        if (!palmas_usb)
                return -ENOMEM;
index 174c388739ea8da35105a892b61c12741be4638b..3e882aa107e837848a45575fd6b980ba2dfa7fa2 100644 (file)
@@ -142,8 +142,10 @@ enum rt8973a_muic_acc_type {
        RT8973A_MUIC_ADC_UNKNOWN_ACC_5,
        RT8973A_MUIC_ADC_OPEN = 0x1f,
 
-       /* The below accessories has same ADC value (0x1f).
-          So, Device type1 is used to separate specific accessory. */
+       /*
+        * The below accessories has same ADC value (0x1f).
+        * So, Device type1 is used to separate specific accessory.
+        */
                                        /* |---------|--ADC| */
                                        /* |    [7:5]|[4:0]| */
        RT8973A_MUIC_ADC_USB = 0x3f,    /* |      001|11111| */
index b223256885033f01a2af1be8da6fbdb8d5a1ae2c..106ef0297b537b3a768eecef3f8f3af0829c7020 100644 (file)
@@ -135,8 +135,10 @@ enum sm5502_muic_acc_type {
        SM5502_MUIC_ADC_AUDIO_TYPE1,
        SM5502_MUIC_ADC_OPEN = 0x1f,
 
-       /* The below accessories have same ADC value (0x1f or 0x1e).
-          So, Device type1 is used to separate specific accessory. */
+       /*
+        * The below accessories have same ADC value (0x1f or 0x1e).
+        * So, Device type1 is used to separate specific accessory.
+        */
                                                        /* |---------|--ADC| */
                                                        /* |    [7:5]|[4:0]| */
        SM5502_MUIC_ADC_AUDIO_TYPE1_FULL_REMOTE = 0x3e, /* |      001|11110| */
index d589c5feff3d7d082fd8372cf48a0c3d3181b9ff..a5e1882b4ca66e370f4c52c7c024290a1685afd7 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/acpi.h>
+#include <linux/pinctrl/consumer.h>
 
 #define USB_GPIO_DEBOUNCE_MS   20      /* ms */
 
@@ -245,6 +246,9 @@ static int usb_extcon_suspend(struct device *dev)
        if (info->vbus_gpiod)
                disable_irq(info->vbus_irq);
 
+       if (!device_may_wakeup(dev))
+               pinctrl_pm_select_sleep_state(dev);
+
        return ret;
 }
 
@@ -253,6 +257,9 @@ static int usb_extcon_resume(struct device *dev)
        struct usb_extcon_info *info = dev_get_drvdata(dev);
        int ret = 0;
 
+       if (!device_may_wakeup(dev))
+               pinctrl_pm_select_default_state(dev);
+
        if (device_may_wakeup(dev)) {
                if (info->id_gpiod) {
                        ret = disable_irq_wake(info->id_irq);
index 7c1e3a7b14e0c1f540a0bbe7d6b924b124561729..09ac5e70c2f38706909d27a8369d357178d989bd 100644 (file)
 #include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/err.h>
-#include <linux/extcon.h>
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
 
+#include "extcon.h"
+
 #define SUPPORTED_CABLE_MAX    32
 #define CABLE_NAME_MAX         30
 
@@ -59,7 +60,7 @@ struct __extcon_info {
        [EXTCON_USB_HOST] = {
                .type = EXTCON_TYPE_USB,
                .id = EXTCON_USB_HOST,
-               .name = "USB_HOST",
+               .name = "USB-HOST",
        },
 
        /* Charging external connector */
@@ -98,6 +99,11 @@ struct __extcon_info {
                .id = EXTCON_CHG_WPT,
                .name = "WPT",
        },
+       [EXTCON_CHG_USB_PD] = {
+               .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB,
+               .id = EXTCON_CHG_USB_PD,
+               .name = "PD",
+       },
 
        /* Jack external connector */
        [EXTCON_JACK_MICROPHONE] = {
@@ -906,35 +912,16 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
        unsigned long flags;
        int ret, idx = -EINVAL;
 
-       if (!nb)
+       if (!edev || !nb)
                return -EINVAL;
 
-       if (edev) {
-               idx = find_cable_index_by_id(edev, id);
-               if (idx < 0)
-                       return idx;
-
-               spin_lock_irqsave(&edev->lock, flags);
-               ret = raw_notifier_chain_register(&edev->nh[idx], nb);
-               spin_unlock_irqrestore(&edev->lock, flags);
-       } else {
-               struct extcon_dev *extd;
-
-               mutex_lock(&extcon_dev_list_lock);
-               list_for_each_entry(extd, &extcon_dev_list, entry) {
-                       idx = find_cable_index_by_id(extd, id);
-                       if (idx >= 0)
-                               break;
-               }
-               mutex_unlock(&extcon_dev_list_lock);
+       idx = find_cable_index_by_id(edev, id);
+       if (idx < 0)
+               return idx;
 
-               if (idx >= 0) {
-                       edev = extd;
-                       return extcon_register_notifier(extd, id, nb);
-               } else {
-                       ret = -ENODEV;
-               }
-       }
+       spin_lock_irqsave(&edev->lock, flags);
+       ret = raw_notifier_chain_register(&edev->nh[idx], nb);
+       spin_unlock_irqrestore(&edev->lock, flags);
 
        return ret;
 }
diff --git a/drivers/extcon/extcon.h b/drivers/extcon/extcon.h
new file mode 100644 (file)
index 0000000..993ddcc
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef __LINUX_EXTCON_INTERNAL_H__
+#define __LINUX_EXTCON_INTERNAL_H__
+
+#include <linux/extcon.h>
+
+/**
+ * struct extcon_dev - An extcon device represents one external connector.
+ * @name:              The name of this extcon device. Parent device name is
+ *                     used if NULL.
+ * @supported_cable:   Array of supported cable names ending with EXTCON_NONE.
+ *                     If supported_cable is NULL, cable name related APIs
+ *                     are disabled.
+ * @mutually_exclusive:        Array of mutually exclusive set of cables that cannot
+ *                     be attached simultaneously. The array should be
+ *                     ending with NULL or be NULL (no mutually exclusive
+ *                     cables). For example, if it is { 0x7, 0x30, 0}, then,
+ *                     {0, 1}, {0, 1, 2}, {0, 2}, {1, 2}, or {4, 5} cannot
+ *                     be attached simulataneously. {0x7, 0} is equivalent to
+ *                     {0x3, 0x6, 0x5, 0}. If it is {0xFFFFFFFF, 0}, there
+ *                     can be no simultaneous connections.
+ * @dev:               Device of this extcon.
+ * @state:             Attach/detach state of this extcon. Do not provide at
+ *                     register-time.
+ * @nh:                        Notifier for the state change events from this extcon
+ * @entry:             To support list of extcon devices so that users can
+ *                     search for extcon devices based on the extcon name.
+ * @lock:
+ * @max_supported:     Internal value to store the number of cables.
+ * @extcon_dev_type:   Device_type struct to provide attribute_groups
+ *                     customized for each extcon device.
+ * @cables:            Sysfs subdirectories. Each represents one cable.
+ *
+ * In most cases, users only need to provide "User initializing data" of
+ * this struct when registering an extcon. In some exceptional cases,
+ * optional callbacks may be needed. However, the values in "internal data"
+ * are overwritten by register function.
+ */
+struct extcon_dev {
+       /* Optional user initializing data */
+       const char *name;
+       const unsigned int *supported_cable;
+       const u32 *mutually_exclusive;
+
+       /* Internal data. Please do not set. */
+       struct device dev;
+       struct raw_notifier_head *nh;
+       struct list_head entry;
+       int max_supported;
+       spinlock_t lock;        /* could be called by irq handler */
+       u32 state;
+
+       /* /sys/class/extcon/.../cable.n/... */
+       struct device_type extcon_dev_type;
+       struct extcon_cable *cables;
+
+       /* /sys/class/extcon/.../mutually_exclusive/... */
+       struct attribute_group attr_g_muex;
+       struct attribute **attrs_muex;
+       struct device_attribute *d_attrs_muex;
+};
+
+#endif /* __LINUX_EXTCON_INTERNAL_H__ */
index b871c0cb1f02b277df53f835a1d51fe3c99fff28..7010fb01a81a342e20abd9ac917d5c3f7aa3de14 100644 (file)
 #define EXTCON_USB             1
 #define EXTCON_USB_HOST                2
 
-/* Charging external connector */
+/*
+ * Charging external connector
+ *
+ * When one SDP charger connector was reported, we should also report
+ * the USB connector, which means EXTCON_CHG_USB_SDP should always
+ * appear together with EXTCON_USB. The same as ACA charger connector,
+ * EXTCON_CHG_USB_ACA would normally appear with EXTCON_USB_HOST.
+ *
+ * The EXTCON_CHG_USB_SLOW connector can provide at least 500mA of
+ * current at 5V. The EXTCON_CHG_USB_FAST connector can provide at
+ * least 1A of current at 5V.
+ */
 #define EXTCON_CHG_USB_SDP     5       /* Standard Downstream Port */
 #define EXTCON_CHG_USB_DCP     6       /* Dedicated Charging Port */
 #define EXTCON_CHG_USB_CDP     7       /* Charging Downstream Port */
@@ -54,6 +65,7 @@
 #define EXTCON_CHG_USB_FAST    9
 #define EXTCON_CHG_USB_SLOW    10
 #define EXTCON_CHG_WPT         11      /* Wireless Power Transfer */
+#define EXTCON_CHG_USB_PD      12      /* USB Power Delivery */
 
 /* Jack external connector */
 #define EXTCON_JACK_MICROPHONE 20
@@ -160,62 +172,7 @@ union extcon_property_value {
 };
 
 struct extcon_cable;
-
-/**
- * struct extcon_dev - An extcon device represents one external connector.
- * @name:              The name of this extcon device. Parent device name is
- *                     used if NULL.
- * @supported_cable:   Array of supported cable names ending with EXTCON_NONE.
- *                     If supported_cable is NULL, cable name related APIs
- *                     are disabled.
- * @mutually_exclusive:        Array of mutually exclusive set of cables that cannot
- *                     be attached simultaneously. The array should be
- *                     ending with NULL or be NULL (no mutually exclusive
- *                     cables). For example, if it is { 0x7, 0x30, 0}, then,
- *                     {0, 1}, {0, 1, 2}, {0, 2}, {1, 2}, or {4, 5} cannot
- *                     be attached simulataneously. {0x7, 0} is equivalent to
- *                     {0x3, 0x6, 0x5, 0}. If it is {0xFFFFFFFF, 0}, there
- *                     can be no simultaneous connections.
- * @dev:               Device of this extcon.
- * @state:             Attach/detach state of this extcon. Do not provide at
- *                     register-time.
- * @nh:                        Notifier for the state change events from this extcon
- * @entry:             To support list of extcon devices so that users can
- *                     search for extcon devices based on the extcon name.
- * @lock:
- * @max_supported:     Internal value to store the number of cables.
- * @extcon_dev_type:   Device_type struct to provide attribute_groups
- *                     customized for each extcon device.
- * @cables:            Sysfs subdirectories. Each represents one cable.
- *
- * In most cases, users only need to provide "User initializing data" of
- * this struct when registering an extcon. In some exceptional cases,
- * optional callbacks may be needed. However, the values in "internal data"
- * are overwritten by register function.
- */
-struct extcon_dev {
-       /* Optional user initializing data */
-       const char *name;
-       const unsigned int *supported_cable;
-       const u32 *mutually_exclusive;
-
-       /* Internal data. Please do not set. */
-       struct device dev;
-       struct raw_notifier_head *nh;
-       struct list_head entry;
-       int max_supported;
-       spinlock_t lock;        /* could be called by irq handler */
-       u32 state;
-
-       /* /sys/class/extcon/.../cable.n/... */
-       struct device_type extcon_dev_type;
-       struct extcon_cable *cables;
-
-       /* /sys/class/extcon/.../mutually_exclusive/... */
-       struct attribute_group attr_g_muex;
-       struct attribute **attrs_muex;
-       struct device_attribute *d_attrs_muex;
-};
+struct extcon_dev;
 
 #if IS_ENABLED(CONFIG_EXTCON)
 
index a0e03b13b449dbaa721abae03977470e571afc39..2aa32075bca15bc29302d02836057ebc0880512d 100644 (file)
@@ -59,7 +59,7 @@ struct adc_jack_pdata {
        const char *name;
        const char *consumer_channel;
 
-       const enum extcon *cable_names;
+       const unsigned int *cable_names;
 
        /* The last entry's state should be 0 */
        struct adc_jack_cond *adc_conditions;