All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kishon Vijay Abraham I <kishon-l0cyMroinI0@public.gmane.org>
To: grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org,
	rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org,
	rob-VoJi6FS/r0vR7s880joybQ@public.gmane.org,
	balbi-l0cyMroinI0@public.gmane.org,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org,
	kishon-l0cyMroinI0@public.gmane.org,
	s-guiriec-l0cyMroinI0@public.gmane.org,
	gg-kDsPt+C1G03kYMGBc/C6ZA@public.gmane.org,
	sameo-VuQAYsv1563Yd54FQh9/CA@public.gmane.org,
	broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org,
	ldewangan-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
	linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-omap-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: [PATCH 3/4] USB: Palmas OTG Transceiver Driver
Date: Tue, 5 Mar 2013 19:51:59 +0530	[thread overview]
Message-ID: <1362493320-13913-4-git-send-email-kishon@ti.com> (raw)
In-Reply-To: <1362493320-13913-1-git-send-email-kishon-l0cyMroinI0@public.gmane.org>

From: Graeme Gregory <gg-kDsPt+C1G03kYMGBc/C6ZA@public.gmane.org>

This is the driver for the OTG transceiver built into the Palmas chip. It
handles the various USB OTG events that can be generated by cable
insertion/removal.

Signed-off-by: Graeme Gregory <gg-kDsPt+C1G03kYMGBc/C6ZA@public.gmane.org>
Signed-off-by: Moiz Sonasath <m-sonasath-l0cyMroinI0@public.gmane.org>
Signed-off-by: Ruchika Kharwar <ruchika-l0cyMroinI0@public.gmane.org>
Signed-off-by: Kishon Vijay Abraham I <kishon-l0cyMroinI0@public.gmane.org>
Signed-off-by: Sebastien Guiriec <s-guiriec-l0cyMroinI0@public.gmane.org>
---
This driver is contributed by a lot of people fixing various issues that
came along. All the fixes has been squashed into this single patch.
I've included their *Signed-off-by*.
 .../devicetree/bindings/usb/twlxxxx-usb.txt        |   15 +
 drivers/usb/otg/Kconfig                            |    6 +
 drivers/usb/otg/Makefile                           |    1 +
 drivers/usb/otg/palmas-usb.c                       |  399 ++++++++++++++++++++
 include/linux/mfd/palmas.h                         |    7 +-
 5 files changed, 427 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/otg/palmas-usb.c

diff --git a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
index 36b9aed..6d941ef 100644
--- a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
+++ b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
@@ -38,3 +38,18 @@ twl4030-usb {
 	usb3v1-supply = <&vusb3v1>;
 	usb_mode = <1>;
 };
+
+PALMAS USB COMPARATOR
+Required Properties:
+ - compatible : Should be "ti,palmas-usb"
+ - vbus-supply : phandle to the regulator device tree node.
+
+Optional Properties:
+ - ti,wakeup : To enable the wakeup comparator in probe
+ - ti,no_control_vbus: if the platform wishes its own vbus control
+
+palmas-usb {
+	compatible = "ti,palmas-usb";
+	vbus-supply = <&smps10_reg>;
+	ti,wakeup;
+};
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index 37962c9..5b40e04 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -138,4 +138,10 @@ config USB_MV_OTG
 
 	  To compile this driver as a module, choose M here.
 
+config PALMAS_USB
+	tristate "Palmas USB Transceiver Driver"
+	depends on MFD_PALMAS
+	help
+	  Enable this to support the Palmas OTG transceiver
+
 endif # USB || OTG
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
index a844b8d..7ae90ba 100644
--- a/drivers/usb/otg/Makefile
+++ b/drivers/usb/otg/Makefile
@@ -22,3 +22,4 @@ fsl_usb2_otg-objs		:= fsl_otg.o otg_fsm.o
 obj-$(CONFIG_FSL_USB2_OTG)	+= fsl_usb2_otg.o
 obj-$(CONFIG_USB_MXS_PHY)	+= mxs-phy.o
 obj-$(CONFIG_USB_MV_OTG)	+= mv_otg.o
+obj-$(CONFIG_PALMAS_USB)	+= palmas-usb.o
diff --git a/drivers/usb/otg/palmas-usb.c b/drivers/usb/otg/palmas-usb.c
new file mode 100644
index 0000000..1bd8d7e
--- /dev/null
+++ b/drivers/usb/otg/palmas-usb.c
@@ -0,0 +1,399 @@
+/*
+ * Palmas USB transceiver 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: Graeme Gregory <gg-kDsPt+C1G03kYMGBc/C6ZA@public.gmane.org>
+ * Author: Kishon Vijay Abraham I <kishon-l0cyMroinI0@public.gmane.org>
+ *
+ * Based on twl6030_usb.c
+ *
+ * Author: Hema HK <hemahk-l0cyMroinI0@public.gmane.org>
+ *
+ * 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/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/phy_companion.h>
+#include <linux/usb/omap_usb.h>
+#include <linux/usb/dwc3-omap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/notifier.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mfd/palmas.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+static int palmas_usb_read(struct palmas *palmas, unsigned int reg,
+		unsigned int *dest)
+{
+	unsigned int addr;
+	int slave;
+
+	slave = PALMAS_BASE_TO_SLAVE(PALMAS_USB_OTG_BASE);
+	addr = PALMAS_BASE_TO_REG(PALMAS_USB_OTG_BASE, reg);
+
+	return regmap_read(palmas->regmap[slave], addr, dest);
+}
+
+static int palmas_usb_write(struct palmas *palmas, unsigned int reg,
+		unsigned int data)
+{
+	unsigned int addr;
+	int slave;
+
+	slave = PALMAS_BASE_TO_SLAVE(PALMAS_USB_OTG_BASE);
+	addr = PALMAS_BASE_TO_REG(PALMAS_USB_OTG_BASE, reg);
+
+	return regmap_write(palmas->regmap[slave], addr, data);
+}
+
+static void palmas_usb_wakeup(struct palmas *palmas, int enable)
+{
+	if (enable)
+		palmas_usb_write(palmas, PALMAS_USB_WAKEUP,
+				PALMAS_USB_WAKEUP_ID_WK_UP_COMP);
+	else
+		palmas_usb_write(palmas, PALMAS_USB_WAKEUP, 0);
+}
+
+static ssize_t palmas_usb_vbus_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	unsigned long		flags;
+	int			ret = -EINVAL;
+	struct palmas_usb	*palmas_usb = dev_get_drvdata(dev);
+
+	spin_lock_irqsave(&palmas_usb->lock, flags);
+
+	switch (palmas_usb->linkstat) {
+	case OMAP_DWC3_VBUS_VALID:
+	       ret = snprintf(buf, PAGE_SIZE, "vbus\n");
+	       break;
+	case OMAP_DWC3_ID_GROUND:
+	       ret = snprintf(buf, PAGE_SIZE, "id\n");
+	       break;
+	case OMAP_DWC3_ID_FLOAT:
+	case OMAP_DWC3_VBUS_OFF:
+	       ret = snprintf(buf, PAGE_SIZE, "none\n");
+	       break;
+	default:
+	       ret = snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
+	}
+	spin_unlock_irqrestore(&palmas_usb->lock, flags);
+
+	return ret;
+}
+static DEVICE_ATTR(vbus, 0444, palmas_usb_vbus_show, NULL);
+
+static irqreturn_t palmas_vbus_wakeup_irq(int irq, void *_palmas_usb)
+{
+	struct palmas_usb *palmas_usb = _palmas_usb;
+	enum omap_dwc3_vbus_id_status status = OMAP_DWC3_UNKNOWN;
+	int slave;
+	unsigned int vbus_line_state, addr;
+
+	slave = PALMAS_BASE_TO_SLAVE(PALMAS_INTERRUPT_BASE);
+	addr = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE,
+			PALMAS_INT3_LINE_STATE);
+
+	regmap_read(palmas_usb->palmas->regmap[slave], addr, &vbus_line_state);
+
+	if (vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS) {
+		if (palmas_usb->linkstat != OMAP_DWC3_VBUS_VALID) {
+			if (!IS_ERR_OR_NULL(palmas_usb->vbus_reg))
+				regulator_enable(palmas_usb->vbus_reg);
+			status = OMAP_DWC3_VBUS_VALID;
+		} else {
+			dev_dbg(palmas_usb->dev,
+				"Spurious connect event detected\n");
+		}
+	} else if (!(vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS)) {
+		if (palmas_usb->linkstat == OMAP_DWC3_VBUS_VALID) {
+			if (!IS_ERR_OR_NULL(palmas_usb->vbus_reg))
+				regulator_disable(palmas_usb->vbus_reg);
+			status = OMAP_DWC3_VBUS_OFF;
+		} else {
+			dev_dbg(palmas_usb->dev,
+				"Spurious disconnect event detected\n");
+		}
+	}
+
+	palmas_usb->linkstat = status;
+	if (status != OMAP_DWC3_UNKNOWN)
+		return dwc3_omap_mailbox(status);
+
+	return IRQ_NONE;
+}
+
+static irqreturn_t palmas_id_wakeup_irq(int irq, void *_palmas_usb)
+{
+	enum omap_dwc3_vbus_id_status status = OMAP_DWC3_UNKNOWN;
+	unsigned int		set;
+	struct palmas_usb	*palmas_usb = _palmas_usb;
+
+	palmas_usb_read(palmas_usb->palmas, PALMAS_USB_ID_INT_LATCH_SET, &set);
+
+	if (set & PALMAS_USB_ID_INT_SRC_ID_GND) {
+		if (!IS_ERR_OR_NULL(palmas_usb->vbus_reg))
+			regulator_enable(palmas_usb->vbus_reg);
+		palmas_usb_write(palmas_usb->palmas,
+					PALMAS_USB_ID_INT_EN_HI_SET,
+					PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
+		palmas_usb_write(palmas_usb->palmas,
+					PALMAS_USB_ID_INT_EN_HI_CLR,
+					PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
+		status = OMAP_DWC3_ID_GROUND;
+	} else if (set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) {
+		palmas_usb_write(palmas_usb->palmas,
+					PALMAS_USB_ID_INT_EN_HI_SET,
+					PALMAS_USB_ID_INT_EN_HI_SET_ID_GND);
+		palmas_usb_write(palmas_usb->palmas,
+					PALMAS_USB_ID_INT_EN_HI_CLR,
+					PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
+		if (!IS_ERR_OR_NULL(palmas_usb->vbus_reg))
+			regulator_disable(palmas_usb->vbus_reg);
+		status = OMAP_DWC3_ID_FLOAT;
+	}
+
+	palmas_usb->linkstat = status;
+	if (status != OMAP_DWC3_UNKNOWN)
+		return dwc3_omap_mailbox(status);
+
+	return IRQ_NONE;
+}
+
+static int palmas_enable_irq(struct palmas_usb *palmas_usb)
+{
+	int ret;
+
+	palmas_usb_write(palmas_usb->palmas, PALMAS_USB_VBUS_CTRL_SET,
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP);
+
+	palmas_usb_write(palmas_usb->palmas, PALMAS_USB_ID_CTRL_SET,
+			PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP);
+
+	palmas_usb_write(palmas_usb->palmas, PALMAS_USB_ID_INT_EN_HI_SET,
+			PALMAS_USB_ID_INT_EN_HI_SET_ID_GND);
+
+	ret = palmas_vbus_wakeup_irq(palmas_usb->irq4, palmas_usb);
+
+	if (palmas_usb->linkstat == OMAP_DWC3_UNKNOWN)
+		ret = palmas_id_wakeup_irq(palmas_usb->irq2, palmas_usb);
+
+	return ret;
+}
+
+static void palmas_set_vbus_work(struct work_struct *data)
+{
+	struct palmas_usb *palmas_usb = container_of(data, struct palmas_usb,
+								set_vbus_work);
+
+	if (IS_ERR_OR_NULL(palmas_usb->vbus_reg)) {
+		dev_err(palmas_usb->dev, "invalid regulator\n");
+		return;
+	}
+
+	/*
+	 * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1
+	 * register. This enables boost mode.
+	 */
+
+	if (palmas_usb->vbus_enable)
+		regulator_enable(palmas_usb->vbus_reg);
+	else
+		regulator_disable(palmas_usb->vbus_reg);
+}
+
+static int palmas_set_vbus(struct phy_companion *comparator, bool enabled)
+{
+	struct palmas_usb *palmas_usb = comparator_to_palmas(comparator);
+
+	palmas_usb->vbus_enable = enabled;
+	schedule_work(&palmas_usb->set_vbus_work);
+
+	return 0;
+}
+
+static int palmas_start_srp(struct phy_companion *comparator)
+{
+	struct palmas_usb *palmas_usb = comparator_to_palmas(comparator);
+
+	palmas_usb_write(palmas_usb->palmas, PALMAS_USB_VBUS_CTRL_SET,
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_DISCHRG |
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SINK);
+	palmas_usb_write(palmas_usb->palmas, PALMAS_USB_VBUS_CTRL_SET,
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_CHRG_VSYS |
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SINK);
+
+	mdelay(100);
+
+	palmas_usb_write(palmas_usb->palmas, PALMAS_USB_VBUS_CTRL_CLR,
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_CHRG_VSYS |
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_CHRG_VSYS);
+
+	return 0;
+}
+
+static void palmas_dt_to_pdata(struct device_node *node,
+		struct palmas_usb_platform_data *pdata)
+{
+	pdata->no_control_vbus = of_property_read_bool(node,
+					"ti,no_control_vbus");
+	pdata->wakeup = of_property_read_bool(node, "ti,wakeup");
+}
+
+static int palmas_usb_probe(struct platform_device *pdev)
+{
+	u32 ret;
+	struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
+	struct palmas_usb_platform_data	*pdata = pdev->dev.platform_data;
+	struct device_node *node = pdev->dev.of_node;
+	struct palmas_usb *palmas_usb;
+	int status;
+
+	if (node && !pdata) {
+		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+
+		if (!pdata)
+			return -ENOMEM;
+
+		palmas_dt_to_pdata(node, pdata);
+	}
+
+	if (!pdata)
+		return -EINVAL;
+
+	palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL);
+	if (!palmas_usb)
+		return -ENOMEM;
+
+	palmas->usb		= palmas_usb;
+	palmas_usb->palmas	= palmas;
+
+	palmas_usb->dev		= &pdev->dev;
+
+	palmas_usb->irq1 = regmap_irq_get_virq(palmas->irq_data,
+						PALMAS_ID_OTG_IRQ);
+	palmas_usb->irq2 = regmap_irq_get_virq(palmas->irq_data,
+						PALMAS_ID_IRQ);
+	palmas_usb->irq3 = regmap_irq_get_virq(palmas->irq_data,
+						PALMAS_VBUS_OTG_IRQ);
+	palmas_usb->irq4 = regmap_irq_get_virq(palmas->irq_data,
+						PALMAS_VBUS_IRQ);
+
+	palmas_usb->comparator.set_vbus	= palmas_set_vbus;
+	palmas_usb->comparator.start_srp = palmas_start_srp;
+
+	ret = omap_usb2_set_comparator(&palmas_usb->comparator);
+	if (ret == -ENODEV) {
+		dev_dbg(&pdev->dev, "phy not ready, deferring probe");
+		return -EPROBE_DEFER;
+	}
+
+	palmas_usb_wakeup(palmas, pdata->wakeup);
+
+	/* init spinlock for workqueue */
+	spin_lock_init(&palmas_usb->lock);
+
+	if (!pdata->no_control_vbus) {
+		palmas_usb->vbus_reg = devm_regulator_get(&pdev->dev, "vbus");
+		if (IS_ERR(palmas_usb->vbus_reg)) {
+			dev_err(&pdev->dev, "vbus init failed\n");
+			return PTR_ERR(palmas_usb->vbus_reg);
+		}
+	}
+
+	platform_set_drvdata(pdev, palmas_usb);
+
+	if (device_create_file(&pdev->dev, &dev_attr_vbus))
+		dev_warn(&pdev->dev, "could not create sysfs file\n");
+
+	/* init spinlock for workqueue */
+	spin_lock_init(&palmas_usb->lock);
+
+	INIT_WORK(&palmas_usb->set_vbus_work, palmas_set_vbus_work);
+
+	status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->irq2,
+			NULL, palmas_id_wakeup_irq,
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+			"palmas_usb", palmas_usb);
+	if (status < 0) {
+		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+					palmas_usb->irq2, status);
+		goto fail_irq;
+	}
+
+	status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->irq4,
+			NULL, palmas_vbus_wakeup_irq,
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+			"palmas_usb", palmas_usb);
+	if (status < 0) {
+		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+					palmas_usb->irq4, status);
+		goto fail_irq;
+	}
+
+	dev_info(&pdev->dev, "Initialized Palmas USB module\n");
+
+	status = palmas_enable_irq(palmas_usb);
+	if (status < 0) {
+		dev_dbg(&pdev->dev, "enable irq failed\n");
+		goto fail_irq;
+	}
+
+	return 0;
+
+fail_irq:
+	cancel_work_sync(&palmas_usb->set_vbus_work);
+	device_remove_file(palmas_usb->dev, &dev_attr_vbus);
+
+	return status;
+}
+
+static int palmas_usb_remove(struct platform_device *pdev)
+{
+	struct palmas_usb *palmas_usb = platform_get_drvdata(pdev);
+
+	device_remove_file(palmas_usb->dev, &dev_attr_vbus);
+	cancel_work_sync(&palmas_usb->set_vbus_work);
+
+	return 0;
+}
+
+static struct of_device_id of_palmas_match_tbl[] = {
+	{ .compatible = "ti,palmas-usb", },
+	{ /* end */ }
+};
+
+static struct platform_driver palmas_usb_driver = {
+	.probe = palmas_usb_probe,
+	.remove = palmas_usb_remove,
+	.driver = {
+		.name = "palmas-usb",
+		.of_match_table = of_palmas_match_tbl,
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(palmas_usb_driver);
+
+MODULE_ALIAS("platform:palmas-usb");
+MODULE_AUTHOR("Graeme Gregory <gg-kDsPt+C1G03kYMGBc/C6ZA@public.gmane.org>");
+MODULE_DESCRIPTION("Palmas USB transceiver driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, of_palmas_match_tbl);
diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
index a4d13d7..f1c936c 100644
--- a/include/linux/mfd/palmas.h
+++ b/include/linux/mfd/palmas.h
@@ -19,6 +19,9 @@
 #include <linux/leds.h>
 #include <linux/regmap.h>
 #include <linux/regulator/driver.h>
+#include <linux/usb/phy_companion.h>
+#include <linux/usb/dwc3-omap.h>
+#include <linux/platform_data/dwc3-omap.h>
 
 #define PALMAS_NUM_CLIENTS		3
 
@@ -341,6 +344,8 @@ struct palmas_usb {
 	struct palmas *palmas;
 	struct device *dev;
 
+	struct phy_companion comparator;
+
 	/* for vbus reporting with irqs disabled */
 	spinlock_t lock;
 
@@ -356,7 +361,7 @@ struct palmas_usb {
 
 	int vbus_enable;
 
-	u8 linkstat;
+	enum omap_dwc3_vbus_id_status linkstat;
 };
 
 #define comparator_to_palmas(x) container_of((x), struct palmas_usb, comparator)
-- 
1.7.10.4

WARNING: multiple messages have this Message-ID (diff)
From: Kishon Vijay Abraham I <kishon@ti.com>
To: <grant.likely@secretlab.ca>, <rob.herring@calxeda.com>,
	<rob@landley.net>, <balbi@ti.com>, <gregkh@linuxfoundation.org>,
	<kishon@ti.com>, <s-guiriec@ti.com>, <gg@slimlogic.co.uk>,
	<sameo@linux.intel.com>, <broonie@opensource.wolfsonmicro.com>,
	<ldewangan@nvidia.com>, <devicetree-discuss@lists.ozlabs.org>,
	<linux-doc@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<linux-usb@vger.kernel.org>, <linux-omap@vger.kernel.org>
Subject: [PATCH 3/4] USB: Palmas OTG Transceiver Driver
Date: Tue, 5 Mar 2013 19:51:59 +0530	[thread overview]
Message-ID: <1362493320-13913-4-git-send-email-kishon@ti.com> (raw)
In-Reply-To: <1362493320-13913-1-git-send-email-kishon@ti.com>

From: Graeme Gregory <gg@slimlogic.co.uk>

This is the driver for the OTG transceiver built into the Palmas chip. It
handles the various USB OTG events that can be generated by cable
insertion/removal.

Signed-off-by: Graeme Gregory <gg@slimlogic.co.uk>
Signed-off-by: Moiz Sonasath <m-sonasath@ti.com>
Signed-off-by: Ruchika Kharwar <ruchika@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Sebastien Guiriec <s-guiriec@ti.com>
---
This driver is contributed by a lot of people fixing various issues that
came along. All the fixes has been squashed into this single patch.
I've included their *Signed-off-by*.
 .../devicetree/bindings/usb/twlxxxx-usb.txt        |   15 +
 drivers/usb/otg/Kconfig                            |    6 +
 drivers/usb/otg/Makefile                           |    1 +
 drivers/usb/otg/palmas-usb.c                       |  399 ++++++++++++++++++++
 include/linux/mfd/palmas.h                         |    7 +-
 5 files changed, 427 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/otg/palmas-usb.c

diff --git a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
index 36b9aed..6d941ef 100644
--- a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
+++ b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
@@ -38,3 +38,18 @@ twl4030-usb {
 	usb3v1-supply = <&vusb3v1>;
 	usb_mode = <1>;
 };
+
+PALMAS USB COMPARATOR
+Required Properties:
+ - compatible : Should be "ti,palmas-usb"
+ - vbus-supply : phandle to the regulator device tree node.
+
+Optional Properties:
+ - ti,wakeup : To enable the wakeup comparator in probe
+ - ti,no_control_vbus: if the platform wishes its own vbus control
+
+palmas-usb {
+	compatible = "ti,palmas-usb";
+	vbus-supply = <&smps10_reg>;
+	ti,wakeup;
+};
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index 37962c9..5b40e04 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -138,4 +138,10 @@ config USB_MV_OTG
 
 	  To compile this driver as a module, choose M here.
 
+config PALMAS_USB
+	tristate "Palmas USB Transceiver Driver"
+	depends on MFD_PALMAS
+	help
+	  Enable this to support the Palmas OTG transceiver
+
 endif # USB || OTG
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
index a844b8d..7ae90ba 100644
--- a/drivers/usb/otg/Makefile
+++ b/drivers/usb/otg/Makefile
@@ -22,3 +22,4 @@ fsl_usb2_otg-objs		:= fsl_otg.o otg_fsm.o
 obj-$(CONFIG_FSL_USB2_OTG)	+= fsl_usb2_otg.o
 obj-$(CONFIG_USB_MXS_PHY)	+= mxs-phy.o
 obj-$(CONFIG_USB_MV_OTG)	+= mv_otg.o
+obj-$(CONFIG_PALMAS_USB)	+= palmas-usb.o
diff --git a/drivers/usb/otg/palmas-usb.c b/drivers/usb/otg/palmas-usb.c
new file mode 100644
index 0000000..1bd8d7e
--- /dev/null
+++ b/drivers/usb/otg/palmas-usb.c
@@ -0,0 +1,399 @@
+/*
+ * Palmas USB transceiver 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: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * Based on twl6030_usb.c
+ *
+ * Author: Hema HK <hemahk@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/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/phy_companion.h>
+#include <linux/usb/omap_usb.h>
+#include <linux/usb/dwc3-omap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/notifier.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mfd/palmas.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+static int palmas_usb_read(struct palmas *palmas, unsigned int reg,
+		unsigned int *dest)
+{
+	unsigned int addr;
+	int slave;
+
+	slave = PALMAS_BASE_TO_SLAVE(PALMAS_USB_OTG_BASE);
+	addr = PALMAS_BASE_TO_REG(PALMAS_USB_OTG_BASE, reg);
+
+	return regmap_read(palmas->regmap[slave], addr, dest);
+}
+
+static int palmas_usb_write(struct palmas *palmas, unsigned int reg,
+		unsigned int data)
+{
+	unsigned int addr;
+	int slave;
+
+	slave = PALMAS_BASE_TO_SLAVE(PALMAS_USB_OTG_BASE);
+	addr = PALMAS_BASE_TO_REG(PALMAS_USB_OTG_BASE, reg);
+
+	return regmap_write(palmas->regmap[slave], addr, data);
+}
+
+static void palmas_usb_wakeup(struct palmas *palmas, int enable)
+{
+	if (enable)
+		palmas_usb_write(palmas, PALMAS_USB_WAKEUP,
+				PALMAS_USB_WAKEUP_ID_WK_UP_COMP);
+	else
+		palmas_usb_write(palmas, PALMAS_USB_WAKEUP, 0);
+}
+
+static ssize_t palmas_usb_vbus_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	unsigned long		flags;
+	int			ret = -EINVAL;
+	struct palmas_usb	*palmas_usb = dev_get_drvdata(dev);
+
+	spin_lock_irqsave(&palmas_usb->lock, flags);
+
+	switch (palmas_usb->linkstat) {
+	case OMAP_DWC3_VBUS_VALID:
+	       ret = snprintf(buf, PAGE_SIZE, "vbus\n");
+	       break;
+	case OMAP_DWC3_ID_GROUND:
+	       ret = snprintf(buf, PAGE_SIZE, "id\n");
+	       break;
+	case OMAP_DWC3_ID_FLOAT:
+	case OMAP_DWC3_VBUS_OFF:
+	       ret = snprintf(buf, PAGE_SIZE, "none\n");
+	       break;
+	default:
+	       ret = snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
+	}
+	spin_unlock_irqrestore(&palmas_usb->lock, flags);
+
+	return ret;
+}
+static DEVICE_ATTR(vbus, 0444, palmas_usb_vbus_show, NULL);
+
+static irqreturn_t palmas_vbus_wakeup_irq(int irq, void *_palmas_usb)
+{
+	struct palmas_usb *palmas_usb = _palmas_usb;
+	enum omap_dwc3_vbus_id_status status = OMAP_DWC3_UNKNOWN;
+	int slave;
+	unsigned int vbus_line_state, addr;
+
+	slave = PALMAS_BASE_TO_SLAVE(PALMAS_INTERRUPT_BASE);
+	addr = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE,
+			PALMAS_INT3_LINE_STATE);
+
+	regmap_read(palmas_usb->palmas->regmap[slave], addr, &vbus_line_state);
+
+	if (vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS) {
+		if (palmas_usb->linkstat != OMAP_DWC3_VBUS_VALID) {
+			if (!IS_ERR_OR_NULL(palmas_usb->vbus_reg))
+				regulator_enable(palmas_usb->vbus_reg);
+			status = OMAP_DWC3_VBUS_VALID;
+		} else {
+			dev_dbg(palmas_usb->dev,
+				"Spurious connect event detected\n");
+		}
+	} else if (!(vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS)) {
+		if (palmas_usb->linkstat == OMAP_DWC3_VBUS_VALID) {
+			if (!IS_ERR_OR_NULL(palmas_usb->vbus_reg))
+				regulator_disable(palmas_usb->vbus_reg);
+			status = OMAP_DWC3_VBUS_OFF;
+		} else {
+			dev_dbg(palmas_usb->dev,
+				"Spurious disconnect event detected\n");
+		}
+	}
+
+	palmas_usb->linkstat = status;
+	if (status != OMAP_DWC3_UNKNOWN)
+		return dwc3_omap_mailbox(status);
+
+	return IRQ_NONE;
+}
+
+static irqreturn_t palmas_id_wakeup_irq(int irq, void *_palmas_usb)
+{
+	enum omap_dwc3_vbus_id_status status = OMAP_DWC3_UNKNOWN;
+	unsigned int		set;
+	struct palmas_usb	*palmas_usb = _palmas_usb;
+
+	palmas_usb_read(palmas_usb->palmas, PALMAS_USB_ID_INT_LATCH_SET, &set);
+
+	if (set & PALMAS_USB_ID_INT_SRC_ID_GND) {
+		if (!IS_ERR_OR_NULL(palmas_usb->vbus_reg))
+			regulator_enable(palmas_usb->vbus_reg);
+		palmas_usb_write(palmas_usb->palmas,
+					PALMAS_USB_ID_INT_EN_HI_SET,
+					PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
+		palmas_usb_write(palmas_usb->palmas,
+					PALMAS_USB_ID_INT_EN_HI_CLR,
+					PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
+		status = OMAP_DWC3_ID_GROUND;
+	} else if (set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) {
+		palmas_usb_write(palmas_usb->palmas,
+					PALMAS_USB_ID_INT_EN_HI_SET,
+					PALMAS_USB_ID_INT_EN_HI_SET_ID_GND);
+		palmas_usb_write(palmas_usb->palmas,
+					PALMAS_USB_ID_INT_EN_HI_CLR,
+					PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
+		if (!IS_ERR_OR_NULL(palmas_usb->vbus_reg))
+			regulator_disable(palmas_usb->vbus_reg);
+		status = OMAP_DWC3_ID_FLOAT;
+	}
+
+	palmas_usb->linkstat = status;
+	if (status != OMAP_DWC3_UNKNOWN)
+		return dwc3_omap_mailbox(status);
+
+	return IRQ_NONE;
+}
+
+static int palmas_enable_irq(struct palmas_usb *palmas_usb)
+{
+	int ret;
+
+	palmas_usb_write(palmas_usb->palmas, PALMAS_USB_VBUS_CTRL_SET,
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP);
+
+	palmas_usb_write(palmas_usb->palmas, PALMAS_USB_ID_CTRL_SET,
+			PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP);
+
+	palmas_usb_write(palmas_usb->palmas, PALMAS_USB_ID_INT_EN_HI_SET,
+			PALMAS_USB_ID_INT_EN_HI_SET_ID_GND);
+
+	ret = palmas_vbus_wakeup_irq(palmas_usb->irq4, palmas_usb);
+
+	if (palmas_usb->linkstat == OMAP_DWC3_UNKNOWN)
+		ret = palmas_id_wakeup_irq(palmas_usb->irq2, palmas_usb);
+
+	return ret;
+}
+
+static void palmas_set_vbus_work(struct work_struct *data)
+{
+	struct palmas_usb *palmas_usb = container_of(data, struct palmas_usb,
+								set_vbus_work);
+
+	if (IS_ERR_OR_NULL(palmas_usb->vbus_reg)) {
+		dev_err(palmas_usb->dev, "invalid regulator\n");
+		return;
+	}
+
+	/*
+	 * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1
+	 * register. This enables boost mode.
+	 */
+
+	if (palmas_usb->vbus_enable)
+		regulator_enable(palmas_usb->vbus_reg);
+	else
+		regulator_disable(palmas_usb->vbus_reg);
+}
+
+static int palmas_set_vbus(struct phy_companion *comparator, bool enabled)
+{
+	struct palmas_usb *palmas_usb = comparator_to_palmas(comparator);
+
+	palmas_usb->vbus_enable = enabled;
+	schedule_work(&palmas_usb->set_vbus_work);
+
+	return 0;
+}
+
+static int palmas_start_srp(struct phy_companion *comparator)
+{
+	struct palmas_usb *palmas_usb = comparator_to_palmas(comparator);
+
+	palmas_usb_write(palmas_usb->palmas, PALMAS_USB_VBUS_CTRL_SET,
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_DISCHRG |
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SINK);
+	palmas_usb_write(palmas_usb->palmas, PALMAS_USB_VBUS_CTRL_SET,
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_CHRG_VSYS |
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SINK);
+
+	mdelay(100);
+
+	palmas_usb_write(palmas_usb->palmas, PALMAS_USB_VBUS_CTRL_CLR,
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_CHRG_VSYS |
+			PALMAS_USB_VBUS_CTRL_SET_VBUS_CHRG_VSYS);
+
+	return 0;
+}
+
+static void palmas_dt_to_pdata(struct device_node *node,
+		struct palmas_usb_platform_data *pdata)
+{
+	pdata->no_control_vbus = of_property_read_bool(node,
+					"ti,no_control_vbus");
+	pdata->wakeup = of_property_read_bool(node, "ti,wakeup");
+}
+
+static int palmas_usb_probe(struct platform_device *pdev)
+{
+	u32 ret;
+	struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
+	struct palmas_usb_platform_data	*pdata = pdev->dev.platform_data;
+	struct device_node *node = pdev->dev.of_node;
+	struct palmas_usb *palmas_usb;
+	int status;
+
+	if (node && !pdata) {
+		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+
+		if (!pdata)
+			return -ENOMEM;
+
+		palmas_dt_to_pdata(node, pdata);
+	}
+
+	if (!pdata)
+		return -EINVAL;
+
+	palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL);
+	if (!palmas_usb)
+		return -ENOMEM;
+
+	palmas->usb		= palmas_usb;
+	palmas_usb->palmas	= palmas;
+
+	palmas_usb->dev		= &pdev->dev;
+
+	palmas_usb->irq1 = regmap_irq_get_virq(palmas->irq_data,
+						PALMAS_ID_OTG_IRQ);
+	palmas_usb->irq2 = regmap_irq_get_virq(palmas->irq_data,
+						PALMAS_ID_IRQ);
+	palmas_usb->irq3 = regmap_irq_get_virq(palmas->irq_data,
+						PALMAS_VBUS_OTG_IRQ);
+	palmas_usb->irq4 = regmap_irq_get_virq(palmas->irq_data,
+						PALMAS_VBUS_IRQ);
+
+	palmas_usb->comparator.set_vbus	= palmas_set_vbus;
+	palmas_usb->comparator.start_srp = palmas_start_srp;
+
+	ret = omap_usb2_set_comparator(&palmas_usb->comparator);
+	if (ret == -ENODEV) {
+		dev_dbg(&pdev->dev, "phy not ready, deferring probe");
+		return -EPROBE_DEFER;
+	}
+
+	palmas_usb_wakeup(palmas, pdata->wakeup);
+
+	/* init spinlock for workqueue */
+	spin_lock_init(&palmas_usb->lock);
+
+	if (!pdata->no_control_vbus) {
+		palmas_usb->vbus_reg = devm_regulator_get(&pdev->dev, "vbus");
+		if (IS_ERR(palmas_usb->vbus_reg)) {
+			dev_err(&pdev->dev, "vbus init failed\n");
+			return PTR_ERR(palmas_usb->vbus_reg);
+		}
+	}
+
+	platform_set_drvdata(pdev, palmas_usb);
+
+	if (device_create_file(&pdev->dev, &dev_attr_vbus))
+		dev_warn(&pdev->dev, "could not create sysfs file\n");
+
+	/* init spinlock for workqueue */
+	spin_lock_init(&palmas_usb->lock);
+
+	INIT_WORK(&palmas_usb->set_vbus_work, palmas_set_vbus_work);
+
+	status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->irq2,
+			NULL, palmas_id_wakeup_irq,
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+			"palmas_usb", palmas_usb);
+	if (status < 0) {
+		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+					palmas_usb->irq2, status);
+		goto fail_irq;
+	}
+
+	status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->irq4,
+			NULL, palmas_vbus_wakeup_irq,
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+			"palmas_usb", palmas_usb);
+	if (status < 0) {
+		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+					palmas_usb->irq4, status);
+		goto fail_irq;
+	}
+
+	dev_info(&pdev->dev, "Initialized Palmas USB module\n");
+
+	status = palmas_enable_irq(palmas_usb);
+	if (status < 0) {
+		dev_dbg(&pdev->dev, "enable irq failed\n");
+		goto fail_irq;
+	}
+
+	return 0;
+
+fail_irq:
+	cancel_work_sync(&palmas_usb->set_vbus_work);
+	device_remove_file(palmas_usb->dev, &dev_attr_vbus);
+
+	return status;
+}
+
+static int palmas_usb_remove(struct platform_device *pdev)
+{
+	struct palmas_usb *palmas_usb = platform_get_drvdata(pdev);
+
+	device_remove_file(palmas_usb->dev, &dev_attr_vbus);
+	cancel_work_sync(&palmas_usb->set_vbus_work);
+
+	return 0;
+}
+
+static struct of_device_id of_palmas_match_tbl[] = {
+	{ .compatible = "ti,palmas-usb", },
+	{ /* end */ }
+};
+
+static struct platform_driver palmas_usb_driver = {
+	.probe = palmas_usb_probe,
+	.remove = palmas_usb_remove,
+	.driver = {
+		.name = "palmas-usb",
+		.of_match_table = of_palmas_match_tbl,
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(palmas_usb_driver);
+
+MODULE_ALIAS("platform:palmas-usb");
+MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
+MODULE_DESCRIPTION("Palmas USB transceiver driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, of_palmas_match_tbl);
diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
index a4d13d7..f1c936c 100644
--- a/include/linux/mfd/palmas.h
+++ b/include/linux/mfd/palmas.h
@@ -19,6 +19,9 @@
 #include <linux/leds.h>
 #include <linux/regmap.h>
 #include <linux/regulator/driver.h>
+#include <linux/usb/phy_companion.h>
+#include <linux/usb/dwc3-omap.h>
+#include <linux/platform_data/dwc3-omap.h>
 
 #define PALMAS_NUM_CLIENTS		3
 
@@ -341,6 +344,8 @@ struct palmas_usb {
 	struct palmas *palmas;
 	struct device *dev;
 
+	struct phy_companion comparator;
+
 	/* for vbus reporting with irqs disabled */
 	spinlock_t lock;
 
@@ -356,7 +361,7 @@ struct palmas_usb {
 
 	int vbus_enable;
 
-	u8 linkstat;
+	enum omap_dwc3_vbus_id_status linkstat;
 };
 
 #define comparator_to_palmas(x) container_of((x), struct palmas_usb, comparator)
-- 
1.7.10.4


  parent reply	other threads:[~2013-03-05 14:21 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-03-05 14:21 [PATCH 0/4] usb: added palmas-usb driver and a few misc fixes Kishon Vijay Abraham I
2013-03-05 14:21 ` Kishon Vijay Abraham I
2013-03-05 14:21 ` [PATCH 1/4] usb: dwc3: dwc3-omap: set dma_mask for dwc3 inorder for host mode to work Kishon Vijay Abraham I
2013-03-05 14:21   ` Kishon Vijay Abraham I
     [not found]   ` <1362493320-13913-2-git-send-email-kishon-l0cyMroinI0@public.gmane.org>
2013-03-05 14:54     ` Felipe Balbi
2013-03-05 14:54       ` Felipe Balbi
     [not found]       ` <20130305145458.GF12123-S8G//mZuvNWo5Im9Ml3/Zg@public.gmane.org>
2013-03-05 14:59         ` kishon
2013-03-05 14:59           ` kishon
2013-03-05 15:11           ` Felipe Balbi
2013-03-05 15:11             ` Felipe Balbi
2013-03-05 14:21 ` [PATCH 2/4] usb: dwc3: dwc3-omap: return -EPROBE_DEFER if probe has not yet executed Kishon Vijay Abraham I
2013-03-05 14:21   ` Kishon Vijay Abraham I
2013-03-05 14:56   ` Felipe Balbi
2013-03-05 14:56     ` Felipe Balbi
     [not found]     ` <20130305145645.GG12123-S8G//mZuvNWo5Im9Ml3/Zg@public.gmane.org>
2013-03-05 15:01       ` kishon
2013-03-05 15:01         ` kishon
     [not found]         ` <513608E6.3010502-l0cyMroinI0@public.gmane.org>
2013-03-05 15:06           ` Felipe Balbi
2013-03-05 15:06             ` Felipe Balbi
2013-03-05 15:18             ` kishon
2013-03-05 15:18               ` kishon
     [not found]               ` <51360CC0.9080108-l0cyMroinI0@public.gmane.org>
2013-03-05 15:21                 ` Felipe Balbi
2013-03-05 15:21                   ` Felipe Balbi
     [not found] ` <1362493320-13913-1-git-send-email-kishon-l0cyMroinI0@public.gmane.org>
2013-03-05 14:21   ` Kishon Vijay Abraham I [this message]
2013-03-05 14:21     ` [PATCH 3/4] USB: Palmas OTG Transceiver Driver Kishon Vijay Abraham I
2013-03-05 16:48     ` Stephen Warren
2013-03-05 14:22 ` [PATCH 4/4] usb: musb: omap2430: replace *_* with *-* in property names Kishon Vijay Abraham I
2013-03-05 14:22   ` Kishon Vijay Abraham I

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=1362493320-13913-4-git-send-email-kishon@ti.com \
    --to=kishon-l0cymroini0@public.gmane.org \
    --cc=balbi-l0cyMroinI0@public.gmane.org \
    --cc=broonie-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E@public.gmane.org \
    --cc=devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org \
    --cc=gg-kDsPt+C1G03kYMGBc/C6ZA@public.gmane.org \
    --cc=grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org \
    --cc=gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org \
    --cc=ldewangan-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org \
    --cc=linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-omap-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=rob-VoJi6FS/r0vR7s880joybQ@public.gmane.org \
    --cc=rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org \
    --cc=s-guiriec-l0cyMroinI0@public.gmane.org \
    --cc=sameo-VuQAYsv1563Yd54FQh9/CA@public.gmane.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.