From a2552776b9dfbb61c6979d4d6e3b4de33cf01065 Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Tue, 21 Mar 2017 18:46:16 +0530 Subject: [PATCH] platform: msm: Support ID detection using extcon framework Support ID detection for dual role USB port on 8996 automotive kernel v4.4 using extcon framework. Change-Id: I3f523f9a52dc8e2e8458c661ff11c93156e1c232 Signed-off-by: Sriharsha Allenki --- drivers/platform/msm/gpio-usbdetect.c | 53 +++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/platform/msm/gpio-usbdetect.c b/drivers/platform/msm/gpio-usbdetect.c index a622bf962fb9..789b14dcfeca 100644 --- a/drivers/platform/msm/gpio-usbdetect.c +++ b/drivers/platform/msm/gpio-usbdetect.c @@ -27,9 +27,11 @@ struct gpio_usbdetect { struct platform_device *pdev; struct regulator *vin; int vbus_det_irq; + int id_det_irq; int gpio; struct extcon_dev *extcon_dev; int vbus_state; + bool id_state; }; static const unsigned int gpio_usb_extcon_table[] = { @@ -56,6 +58,37 @@ static irqreturn_t gpio_usbdetect_vbus_irq(int irq, void *data) return IRQ_HANDLED; } +static irqreturn_t gpio_usbdetect_id_irq(int irq, void *data) +{ + struct gpio_usbdetect *usb = data; + int ret; + + ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL, + &usb->id_state); + if (ret < 0) { + dev_err(&usb->pdev->dev, "unable to read ID IRQ LINE\n"); + return IRQ_HANDLED; + } + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t gpio_usbdetect_id_irq_thread(int irq, void *data) +{ + struct gpio_usbdetect *usb = data; + + if (usb->id_state) { + dev_dbg(&usb->pdev->dev, "stopping usb host\n"); + extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 0); + enable_irq(usb->vbus_det_irq); + } else { + dev_dbg(&usb->pdev->dev, "starting usb HOST\n"); + disable_irq(usb->vbus_det_irq); + extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 1); + } + return IRQ_HANDLED; +} + static const u32 gpio_usb_extcon_exclusive[] = {0x3, 0}; static int gpio_usbdetect_probe(struct platform_device *pdev) @@ -132,7 +165,25 @@ static int gpio_usbdetect_probe(struct platform_device *pdev) goto error; } + usb->id_det_irq = platform_get_irq_byname(pdev, "pmic_id_irq"); + if (usb->id_det_irq < 0) { + dev_err(&pdev->dev, "get id_det_irq failed\n"); + rc = usb->id_det_irq; + goto error; + } + + rc = devm_request_threaded_irq(&pdev->dev, usb->id_det_irq, + gpio_usbdetect_id_irq, + gpio_usbdetect_id_irq_thread, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, "id_det_irq", usb); + if (rc) { + dev_err(&pdev->dev, "request for id_det_irq failed: %d\n", rc); + goto error; + } + enable_irq_wake(usb->vbus_det_irq); + enable_irq_wake(usb->id_det_irq); dev_set_drvdata(&pdev->dev, usb); /* Read and report initial VBUS state */ @@ -152,6 +203,8 @@ static int gpio_usbdetect_remove(struct platform_device *pdev) disable_irq_wake(usb->vbus_det_irq); disable_irq(usb->vbus_det_irq); + disable_irq_wake(usb->id_det_irq); + disable_irq(usb->id_det_irq); if (usb->vin) regulator_disable(usb->vin);