From: George Cherian <george.cherian@ti.com>
To: balbi@ti.com, myungjoo.ham@samsung.com, cw00.choi@samsung.com
Cc: linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
devicetree@vger.kernel.org, grant.likely@linaro.org,
rob@landley.net, ian.campbell@citrix.com, swarren@wwwdotorg.org,
mark.rutland@arm.com, pawel.moll@arm.com,
rob.herring@calxeda.com, linux-omap@vger.kernel.org,
linux-usb@vger.kernel.org, bcousson@baylibre.com,
davidb@codeaurora.org, arnd@arndb.de, swarren@nvidia.com,
popcornmix@gmail.com, George Cherian <george.cherian@ti.com>
Subject: [PATCH v3 1/3] extcon: extcon-gpio-usbvid: Generic USB VBUS/ID detection via GPIO
Date: Wed, 28 Aug 2013 23:03:03 +0530 [thread overview]
Message-ID: <1377711185-31238-2-git-send-email-george.cherian@ti.com> (raw)
In-Reply-To: <1377711185-31238-1-git-send-email-george.cherian@ti.com>
Add a generic USB VBUS/ID detection EXTCON driver. This driver expects
the ID/VBUS pin are connected via GPIOs. This driver is tested on
DRA7x board were the ID pin is routed via GPIOs. The driver supports
both VBUS and ID pin configuration and ID pin only configuration.
Signed-off-by: George Cherian <george.cherian@ti.com>
---
.../bindings/extcon/extcon-gpio-usbvid.txt | 20 ++
drivers/extcon/Kconfig | 6 +
drivers/extcon/Makefile | 1 +
drivers/extcon/extcon-gpio-usbvid.c | 286 +++++++++++++++++++++
4 files changed, 313 insertions(+)
create mode 100644 Documentation/devicetree/bindings/extcon/extcon-gpio-usbvid.txt
create mode 100644 drivers/extcon/extcon-gpio-usbvid.c
diff --git a/Documentation/devicetree/bindings/extcon/extcon-gpio-usbvid.txt b/Documentation/devicetree/bindings/extcon/extcon-gpio-usbvid.txt
new file mode 100644
index 0000000..eea0741
--- /dev/null
+++ b/Documentation/devicetree/bindings/extcon/extcon-gpio-usbvid.txt
@@ -0,0 +1,20 @@
+EXTCON FOR USB VIA GPIO
+
+Required Properties:
+ - compatible : Should be "ti,gpio-usb-vid" for USB VBUS-ID detector
+ using gpios or "ti,gpio-usb-id" for USB ID pin detector
+ - gpios : phandle and args ID pin gpio and VBUS gpio.
+ The first gpio used for ID pin detection
+ and the second used for VBUS detection.
+ ID pin gpio is mandatory and VBUS is optional
+ depending on implementation.
+
+Please refer to ../gpio/gpio.txt for details of the common GPIO bindings
+
+Example:
+
+ gpio_usbvid_extcon1 {
+ compatible = "ti,gpio-usb-vid";
+ gpios = <&gpio1 1 0>,
+ <&gpio2 2 0>;
+ };
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index f1d54a3..8097398 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -64,4 +64,10 @@ config EXTCON_PALMAS
Say Y here to enable support for USB peripheral and USB host
detection by palmas usb.
+config EXTCON_GPIO_USBVID
+ tristate "Generic USB VBUS/ID detection using GPIO EXTCON support"
+ help
+ Say Y here to enable support for USB VBUS/ID deetction by GPIO.
+
+
endif # MULTISTATE_SWITCH
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index e4fa8ba..0451f698 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
obj-$(CONFIG_EXTCON_PALMAS) += extcon-palmas.o
+obj-$(CONFIG_EXTCON_GPIO_USBVID) += extcon-gpio-usbvid.o
diff --git a/drivers/extcon/extcon-gpio-usbvid.c b/drivers/extcon/extcon-gpio-usbvid.c
new file mode 100644
index 0000000..e9bc2a97
--- /dev/null
+++ b/drivers/extcon/extcon-gpio-usbvid.c
@@ -0,0 +1,286 @@
+/*
+ * Generic USB VBUS-ID pin detection driver
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Author: George Cherian <george.cherian@ti.com>
+ *
+ * Based on extcon-palmas.c
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * 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/module.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/platform_device.h>
+#include <linux/extcon.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+
+struct gpio_usbvid {
+ struct device *dev;
+
+ struct extcon_dev edev;
+
+ /*GPIO pin */
+ int id_gpio;
+ int vbus_gpio;
+
+ int id_irq;
+ int vbus_irq;
+ int type;
+};
+
+static const char *dra7xx_extcon_cable[] = {
+ [0] = "USB",
+ [1] = "USB-HOST",
+ NULL,
+};
+
+static const int mutually_exclusive[] = {0x3, 0x0};
+
+/* Two types of support are provided.
+ * Systems which has
+ * 1) VBUS and ID pin connected via GPIO
+ * 2) only ID pin connected via GPIO
+ * For Case 1 both the gpios should be provided via DT
+ * Always the first GPIO in dt is considered ID pin GPIO
+ */
+
+enum {
+ UNKNOWN = 0,
+ ID_DETECT,
+ VBUS_ID_DETECT,
+};
+
+#define ID_GND 0
+#define ID_FLOAT 1
+#define VBUS_OFF 0
+#define VBUS_ON 1
+
+
+static irqreturn_t id_irq_handler(int irq, void *data)
+{
+ struct gpio_usbvid *gpio_usbvid = (struct gpio_usbvid *) data;
+ int id_current;
+
+ id_current = gpio_get_value_cansleep(gpio_usbvid->id_gpio);
+ if (id_current == ID_GND) {
+ if (gpio_usbvid->type == ID_DETECT)
+ extcon_set_cable_state(&gpio_usbvid->edev,
+ "USB", false);
+ extcon_set_cable_state(&gpio_usbvid->edev, "USB-HOST", true);
+ } else {
+ extcon_set_cable_state(&gpio_usbvid->edev, "USB-HOST", false);
+ if (gpio_usbvid->type == ID_DETECT)
+ extcon_set_cable_state(&gpio_usbvid->edev,
+ "USB", true);
+ }
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t vbus_irq_handler(int irq, void *data)
+{
+ struct gpio_usbvid *gpio_usbvid = (struct gpio_usbvid *) data;
+ int vbus_current;
+
+ vbus_current = gpio_get_value_cansleep(gpio_usbvid->vbus_gpio);
+ if (vbus_current == VBUS_OFF)
+ extcon_set_cable_state(&gpio_usbvid->edev, "USB", false);
+ else
+ extcon_set_cable_state(&gpio_usbvid->edev, "USB", true);
+
+ return IRQ_HANDLED;
+}
+
+
+static void gpio_usbvid_set_initial_state(struct gpio_usbvid *gpio_usbvid)
+{
+ int id_current;
+ int vbus_current;
+
+ switch (gpio_usbvid->type) {
+ case ID_DETECT:
+ id_current = gpio_get_value_cansleep(gpio_usbvid->id_gpio);
+ if (!!id_current == ID_FLOAT) {
+ extcon_set_cable_state(&gpio_usbvid->edev,
+ "USB-HOST", false);
+ extcon_set_cable_state(&gpio_usbvid->edev,
+ "USB", true);
+ } else {
+ extcon_set_cable_state(&gpio_usbvid->edev,
+ "USB", false);
+ extcon_set_cable_state(&gpio_usbvid->edev,
+ "USB-HOST", true);
+ }
+ break;
+
+ case VBUS_ID_DETECT:
+ id_current = gpio_get_value_cansleep(gpio_usbvid->id_gpio);
+ if (!!id_current == ID_FLOAT)
+ extcon_set_cable_state(&gpio_usbvid->edev,
+ "USB-HOST", false);
+ else
+ extcon_set_cable_state(&gpio_usbvid->edev,
+ "USB-HOST", true);
+
+ vbus_current = gpio_get_value_cansleep(gpio_usbvid->vbus_gpio);
+ if (!!vbus_current == VBUS_ON)
+ extcon_set_cable_state(&gpio_usbvid->edev,
+ "USB", true);
+ else
+ extcon_set_cable_state(&gpio_usbvid->edev,
+ "USB", false);
+ break;
+
+ default:
+ dev_err(gpio_usbvid->dev, "Unknown VBUS-ID type\n");
+ }
+}
+
+static int gpio_usbvid_request_irq(struct gpio_usbvid *gpio_usbvid)
+{
+ int ret;
+ ret = devm_request_threaded_irq(gpio_usbvid->dev, gpio_usbvid->id_irq,
+ NULL, id_irq_handler,
+ IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
+ dev_name(gpio_usbvid->dev),
+ (void *) gpio_usbvid);
+ if (ret) {
+ dev_err(gpio_usbvid->dev, "failed to request id irq #%d\n",
+ gpio_usbvid->id_irq);
+ return ret;
+ }
+ if (gpio_usbvid->type == VBUS_ID_DETECT) {
+ ret = devm_request_threaded_irq(gpio_usbvid->dev,
+ gpio_usbvid->vbus_irq, NULL,
+ vbus_irq_handler,
+ IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
+ dev_name(gpio_usbvid->dev),
+ (void *) gpio_usbvid);
+ if (ret)
+ dev_err(gpio_usbvid->dev, "failed to request vbus irq #%d\n",
+ gpio_usbvid->vbus_irq);
+ }
+ return ret;
+}
+
+static int gpio_usbvid_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct gpio_usbvid *gpio_usbvid;
+ int ret;
+ int gpio;
+
+ gpio_usbvid = devm_kzalloc(&pdev->dev, sizeof(*gpio_usbvid),
+ GFP_KERNEL);
+ if (!gpio_usbvid)
+ return -ENOMEM;
+
+
+ gpio_usbvid->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, gpio_usbvid);
+
+ gpio_usbvid->edev.name = dev_name(&pdev->dev);
+ gpio_usbvid->edev.supported_cable = dra7xx_extcon_cable;
+ gpio_usbvid->edev.mutually_exclusive = mutually_exclusive;
+
+ if (of_device_is_compatible(node, "ti,gpio-usb-id"))
+ gpio_usbvid->type = ID_DETECT;
+
+ gpio = of_get_gpio(node, 0);
+ if (gpio_is_valid(gpio)) {
+ gpio_usbvid->id_gpio = gpio;
+ ret = devm_gpio_request(&pdev->dev, gpio_usbvid->id_gpio,
+ "id_gpio");
+ if (ret)
+ return ret;
+ gpio_usbvid->id_irq = gpio_to_irq(gpio_usbvid->id_gpio);
+ } else {
+ dev_err(&pdev->dev, "failed to get id gpio\n");
+ return -ENODEV;
+ }
+
+ if (of_device_is_compatible(node, "ti,gpio-usb-vid")) {
+ gpio_usbvid->type = VBUS_ID_DETECT;
+ gpio = of_get_gpio(node, 1);
+ if (gpio_is_valid(gpio)) {
+ gpio_usbvid->vbus_gpio = gpio;
+ ret = devm_gpio_request(&pdev->dev,
+ gpio_usbvid->vbus_gpio,
+ "vbus_gpio");
+ if (ret)
+ return ret;
+ gpio_usbvid->vbus_irq =
+ gpio_to_irq(gpio_usbvid->vbus_gpio);
+ } else {
+ dev_err(&pdev->dev, "failed to get vbus gpio\n");
+ return -ENODEV;
+ }
+ }
+
+ ret = extcon_dev_register(&gpio_usbvid->edev, gpio_usbvid->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register extcon device\n");
+ return ret;
+ }
+
+ gpio_usbvid_set_initial_state(gpio_usbvid);
+ ret = gpio_usbvid_request_irq(gpio_usbvid);
+ if (ret)
+ goto err0;
+
+ return 0;
+
+err0:
+ extcon_dev_unregister(&gpio_usbvid->edev);
+
+ return ret;
+}
+
+static int gpio_usbvid_remove(struct platform_device *pdev)
+{
+ struct gpio_usbvid *gpio_usbvid = platform_get_drvdata(pdev);
+
+ extcon_dev_unregister(&gpio_usbvid->edev);
+ return 0;
+}
+
+static struct of_device_id of_gpio_usbvid_match_tbl[] = {
+ { .compatible = "ti,gpio-usb-vid", },
+ { .compatible = "ti,gpio-usb-id", },
+ { /* end */ }
+};
+
+static struct platform_driver gpio_usbvid_driver = {
+ .probe = gpio_usbvid_probe,
+ .remove = gpio_usbvid_remove,
+ .driver = {
+ .name = "gpio-usbvid",
+ .of_match_table = of_gpio_usbvid_match_tbl,
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(gpio_usbvid_driver);
+
+MODULE_ALIAS("platform:gpio-usbvid");
+MODULE_AUTHOR("George Cherian <george.cherian@ti.com>");
+MODULE_DESCRIPTION("GPIO based USB Connector driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, of_gpio_usbvid_match_tbl);
--
1.8.1.4
next prev parent reply other threads:[~2013-08-28 17:33 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-08-28 17:33 [PATCH v3 0/3] Add Generic USB VBUS/ID detection via GPIO using extcon George Cherian
2013-08-28 17:33 ` George Cherian [this message]
2013-08-29 1:35 ` [PATCH v3 1/3] extcon: extcon-gpio-usbvid: Generic USB VBUS/ID detection via GPIO Chanwoo Choi
2013-08-29 2:21 ` George Cherian
2013-08-29 6:23 ` Chanwoo Choi
2013-08-29 7:30 ` George Cherian
2013-08-29 10:37 ` Chanwoo Choi
2013-08-29 11:48 ` George Cherian
2013-08-29 12:12 ` Chanwoo Choi
2013-08-29 13:45 ` George Cherian
2013-08-30 0:11 ` Chanwoo Choi
2013-08-30 6:15 ` George Cherian
2013-08-30 6:53 ` Chanwoo Choi
2013-09-02 1:58 ` George Cherian
2013-08-30 7:14 ` Chanwoo Choi
2013-09-02 2:01 ` George Cherian
2013-08-29 19:11 ` Stephen Warren
2013-08-29 19:19 ` Stephen Warren
[not found] ` <1377711185-31238-1-git-send-email-george.cherian-l0cyMroinI0@public.gmane.org>
2013-08-28 17:33 ` [PATCH v3 2/3] drivers: Makefile: Extcon is a framework so bump it up George Cherian
2013-08-28 17:33 ` [PATCH v3 3/3] ARM: dts: dra7-evm: Add extcon nodes for USB ID pin detection George Cherian
2013-08-28 17:54 ` Sergei Shtylyov
2013-08-29 2:53 ` George Cherian
2013-08-29 19:21 ` Stephen Warren
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1377711185-31238-2-git-send-email-george.cherian@ti.com \
--to=george.cherian@ti.com \
--cc=arnd@arndb.de \
--cc=balbi@ti.com \
--cc=bcousson@baylibre.com \
--cc=cw00.choi@samsung.com \
--cc=davidb@codeaurora.org \
--cc=devicetree@vger.kernel.org \
--cc=grant.likely@linaro.org \
--cc=ian.campbell@citrix.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-omap@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=myungjoo.ham@samsung.com \
--cc=pawel.moll@arm.com \
--cc=popcornmix@gmail.com \
--cc=rob.herring@calxeda.com \
--cc=rob@landley.net \
--cc=swarren@nvidia.com \
--cc=swarren@wwwdotorg.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).