]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/extcon/extcon-axp288.c
Merge tag 'imx-drm-fixes-2017-07-18' of git://git.pengutronix.de/git/pza/linux into...
[karo-tx-linux.git] / drivers / extcon / extcon-axp288.c
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",
        },