diff options
| author | Zhiqiang Tu <ztu@codeaurora.org> | 2017-04-27 10:51:03 +0800 |
|---|---|---|
| committer | Zhiqiang Tu <ztu@codeaurora.org> | 2017-05-02 08:59:16 +0800 |
| commit | b15484bc067e8c01e7cc2b186227f994547cf709 (patch) | |
| tree | 88d900f03484d25dc8b5ad72b3706069adf1aa88 /drivers/platform | |
| parent | b1980b6bfedd0ac23e3b0320a8ed9bf7959e88bb (diff) | |
| parent | 35ae76d2731e009ff57ccb33c766cb3086b65a51 (diff) | |
Merge remote-tracking branch 'remotes/quic/dev/msm-4.4-8996au' into msm-4.4
Conflicts:
arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
drivers/gpu/drm/msm/Makefile
Change-Id: Ief80c28ff1422fd71a0c3d2041531e2ab078ee7a
Signed-off-by: Zhiqiang Tu <ztu@codeaurora.org>
Diffstat (limited to 'drivers/platform')
| -rw-r--r-- | drivers/platform/msm/gpio-usbdetect.c | 142 |
1 files changed, 104 insertions, 38 deletions
diff --git a/drivers/platform/msm/gpio-usbdetect.c b/drivers/platform/msm/gpio-usbdetect.c index 80e16573e0aa..dc05d7108135 100644 --- a/drivers/platform/msm/gpio-usbdetect.c +++ b/drivers/platform/msm/gpio-usbdetect.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015,2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -20,57 +20,101 @@ #include <linux/interrupt.h> #include <linux/of_gpio.h> #include <linux/gpio.h> -#include <linux/power_supply.h> +#include <linux/extcon.h> #include <linux/regulator/consumer.h> struct gpio_usbdetect { struct platform_device *pdev; struct regulator *vin; - struct power_supply *usb_psy; 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[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_USB_CC, + EXTCON_USB_SPEED, + EXTCON_NONE, }; static irqreturn_t gpio_usbdetect_vbus_irq(int irq, void *data) { struct gpio_usbdetect *usb = data; - int vbus; - union power_supply_propval pval = {0,}; - vbus = gpio_get_value(usb->gpio); - if (vbus) - pval.intval = POWER_SUPPLY_TYPE_USB; - else - pval.intval = POWER_SUPPLY_TYPE_UNKNOWN; + usb->vbus_state = gpio_get_value(usb->gpio); + if (usb->vbus_state) { + dev_dbg(&usb->pdev->dev, "setting vbus notification\n"); + extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 1); + } else { + dev_dbg(&usb->pdev->dev, "setting vbus removed notification\n"); + extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 0); + } + + 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; + } - power_supply_set_property(usb->usb_psy, - POWER_SUPPLY_PROP_TYPE, &pval); + return IRQ_WAKE_THREAD; +} - pval.intval = vbus; - power_supply_set_property(usb->usb_psy, POWER_SUPPLY_PROP_PRESENT, - &pval); +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) { struct gpio_usbdetect *usb; - struct power_supply *usb_psy; int rc; - unsigned long flags; - - usb_psy = power_supply_get_by_name("usb"); - if (!usb_psy) { - dev_dbg(&pdev->dev, "USB power_supply not found, deferring probe\n"); - return -EPROBE_DEFER; - } usb = devm_kzalloc(&pdev->dev, sizeof(*usb), GFP_KERNEL); if (!usb) return -ENOMEM; usb->pdev = pdev; - usb->usb_psy = usb_psy; + + usb->extcon_dev = devm_extcon_dev_allocate(&pdev->dev, + gpio_usb_extcon_table); + if (IS_ERR(usb->extcon_dev)) { + dev_err(&pdev->dev, "failed to allocate a extcon device\n"); + return PTR_ERR(usb->extcon_dev); + } + + usb->extcon_dev->mutually_exclusive = gpio_usb_extcon_exclusive; + rc = devm_extcon_dev_register(&pdev->dev, usb->extcon_dev); + if (rc) { + dev_err(&pdev->dev, "failed to register extcon device\n"); + return rc; + } if (of_get_property(pdev->dev.of_node, "vin-supply", NULL)) { usb->vin = devm_regulator_get(&pdev->dev, "vin"); @@ -94,43 +138,63 @@ static int gpio_usbdetect_probe(struct platform_device *pdev) "qcom,vbus-det-gpio", 0); if (usb->gpio < 0) { dev_err(&pdev->dev, "Failed to get gpio: %d\n", usb->gpio); - return usb->gpio; + rc = usb->gpio; + goto error; } rc = gpio_request(usb->gpio, "vbus-det-gpio"); if (rc < 0) { dev_err(&pdev->dev, "Failed to request gpio: %d\n", rc); - return rc; + goto error; } usb->vbus_det_irq = gpio_to_irq(usb->gpio); if (usb->vbus_det_irq < 0) { - if (usb->vin) - regulator_disable(usb->vin); - return usb->vbus_det_irq; + dev_err(&pdev->dev, "get vbus_det_irq failed\n"); + rc = usb->vbus_det_irq; + goto error; } - rc = devm_request_irq(&pdev->dev, usb->vbus_det_irq, - gpio_usbdetect_vbus_irq, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "vbus_det_irq", usb); + rc = devm_request_threaded_irq(&pdev->dev, usb->vbus_det_irq, + NULL, gpio_usbdetect_vbus_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, "vbus_det_irq", usb); if (rc) { dev_err(&pdev->dev, "request for vbus_det_irq failed: %d\n", rc); - if (usb->vin) - regulator_disable(usb->vin); - return rc; + 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 */ - local_irq_save(flags); gpio_usbdetect_vbus_irq(usb->vbus_det_irq, usb); - local_irq_restore(flags); return 0; + +error: + if (usb->vin) + regulator_disable(usb->vin); + return rc; } static int gpio_usbdetect_remove(struct platform_device *pdev) @@ -139,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); |
