@@ -27,9 +27,14 @@ config USB_GPIO_VBUS
optionally control of a D+ pullup GPIO as well as a VBUS
current limit regulator.
+config OMAP_OTG
+ tristate
+ depends on ARCH_OMAP_OTG
+
config ISP1301_OMAP
tristate "Philips ISP1301 with OMAP OTG"
depends on I2C && ARCH_OMAP_OTG
+ select OMAP_OTG if USB_OTG
select USB_OTG_UTILS
help
If you say yes here you get support for the Philips ISP1301
@@ -10,6 +10,7 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg.o
# transceiver drivers
obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
+obj-$(CONFIG_OMAP_OTG) += omap-otg.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
obj-$(CONFIG_TWL6030_USB) += twl6030-usb.o
@@ -28,6 +28,7 @@
#include <linux/gpio.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/usb/omap-otg.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
#include <linux/i2c.h>
@@ -74,22 +75,6 @@ struct isp1301 {
# define WORK_STOP 7 /* don't resubmit */
};
-
-/* bits in OTG_CTRL */
-
-#define OTG_XCEIV_OUTPUTS \
- (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID)
-#define OTG_XCEIV_INPUTS \
- (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID)
-#define OTG_CTRL_BITS \
- (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP)
- /* and OTG_PULLUP is sometimes written */
-
-#define OTG_CTRL_MASK (OTG_DRIVER_SEL| \
- OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \
- OTG_CTRL_BITS)
-
-
/*-------------------------------------------------------------------------*/
/* board-specific PM hooks */
@@ -822,15 +807,10 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
return ret;
}
-static struct platform_device *otg_dev;
-
static int isp1301_otg_init(struct isp1301 *isp)
{
u32 l;
- if (!otg_dev)
- return -ENODEV;
-
dump_regs(isp, __func__);
/* some of these values are board-specific... */
l = omap_readl(OTG_SYSCON_2);
@@ -864,58 +844,6 @@ static int isp1301_otg_init(struct isp1301 *isp)
return 0;
}
-static int otg_probe(struct platform_device *dev)
-{
- // struct omap_usb_config *config = dev->platform_data;
-
- otg_dev = dev;
- return 0;
-}
-
-static int otg_remove(struct platform_device *dev)
-{
- otg_dev = NULL;
- return 0;
-}
-
-static struct platform_driver omap_otg_driver = {
- .probe = otg_probe,
- .remove = otg_remove,
- .driver = {
- .owner = THIS_MODULE,
- .name = "omap_otg",
- },
-};
-
-static int otg_bind(struct isp1301 *isp)
-{
- int status;
-
- if (otg_dev)
- return -EBUSY;
-
- status = platform_driver_register(&omap_otg_driver);
- if (status < 0)
- return status;
-
- if (otg_dev)
- status = request_irq(otg_dev->resource[1].start, omap_otg_irq,
- 0, DRIVER_NAME, isp);
- else
- status = -ENODEV;
-
- if (status < 0)
- platform_driver_unregister(&omap_otg_driver);
- return status;
-}
-
-static void otg_unbind(struct isp1301 *isp)
-{
- if (!otg_dev)
- return;
- free_irq(otg_dev->resource[1].start, isp);
-}
-
#else
/* OTG controller isn't clocked */
@@ -1222,7 +1150,7 @@ static int __exit isp1301_remove(struct i2c_client *i2c)
isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
free_irq(i2c->irq, isp);
#ifdef CONFIG_USB_OTG
- otg_unbind(isp);
+ omap_otg_unbind(isp);
#endif
if (machine_is_omap_h2())
gpio_free(2);
@@ -1555,7 +1483,7 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
#ifdef CONFIG_USB_OTG
- status = otg_bind(isp);
+ status = omap_otg_bind(isp, omap_otg_irq);
if (status < 0) {
dev_dbg(&i2c->dev, "can't bind OTG\n");
goto fail;
new file mode 100644
@@ -0,0 +1,99 @@
+/*
+ * OMAP OTG driver
+ *
+ * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2004 David Brownell
+ *
+ * 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.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/usb/omap-otg.h>
+#include <linux/platform_device.h>
+
+static void *omap_otg_user;
+static DEFINE_MUTEX(omap_otg_lock);
+static struct platform_device *omap_otg_dev;
+
+static int omap_otg_probe(struct platform_device *dev)
+{
+ int ret;
+
+ mutex_lock(&omap_otg_lock);
+ if (omap_otg_dev) {
+ ret = -EBUSY;
+ } else {
+ omap_otg_dev = dev;
+ ret = 0;
+ }
+ mutex_unlock(&omap_otg_lock);
+
+ return ret;
+}
+
+static int omap_otg_remove(struct platform_device *dev)
+{
+ int ret;
+
+ mutex_lock(&omap_otg_lock);
+ if (omap_otg_user) {
+ ret = -EBUSY;
+ } else {
+ omap_otg_dev = NULL;
+ ret = 0;
+ }
+ mutex_unlock(&omap_otg_lock);
+
+ return ret;
+}
+
+int omap_otg_bind(void *transceiver, irq_handler_t irq_handler)
+{
+ int ret;
+
+ mutex_lock(&omap_otg_lock);
+ if (!omap_otg_dev) {
+ ret = -EPROBE_DEFER;
+ } else if (omap_otg_user) {
+ ret = -EBUSY;
+ } else {
+ ret = request_irq(omap_otg_dev->resource[1].start, irq_handler,
+ 0, "OMAP OTG", transceiver);
+ if (!ret)
+ omap_otg_user = transceiver;
+ }
+ mutex_unlock(&omap_otg_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(omap_otg_bind);
+
+void omap_otg_unbind(void *transceiver)
+{
+ mutex_lock(&omap_otg_lock);
+ BUG_ON(!omap_otg_dev || !omap_otg_user || omap_otg_user != transceiver);
+ free_irq(omap_otg_dev->resource[1].start, transceiver);
+ omap_otg_user = NULL;
+ mutex_unlock(&omap_otg_lock);
+}
+EXPORT_SYMBOL_GPL(omap_otg_unbind);
+
+static struct platform_driver omap_otg_driver = {
+ .probe = omap_otg_probe,
+ .remove = omap_otg_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "omap_otg",
+ },
+};
+module_platform_driver(omap_otg_driver);
new file mode 100644
@@ -0,0 +1,30 @@
+/*
+ * OMAP OTG driver
+ *
+ * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2004 David Brownell
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+/* bits in OTG_CTRL */
+#define OTG_XCEIV_OUTPUTS \
+ (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID)
+#define OTG_XCEIV_INPUTS \
+ (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID)
+#define OTG_CTRL_BITS \
+ (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP)
+ /* and OTG_PULLUP is sometimes written */
+#define OTG_CTRL_MASK \
+ (OTG_DRIVER_SEL|OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS|OTG_CTRL_BITS)
+
+int omap_otg_bind(void *, irq_handler_t);
+void omap_otg_unbind(void *);
omap-otg platform device will be needed also by other transceivers. It's not possible to have multiple instances of the driver, so it needs to be moved into a separate file so that other drivers can hook into it. Start this change with a very simplest implementation, much of the OMAP OTG code in isp1301 is tightly coupled with isp1301 and cannot be trivially moved out, but still this provides a way for other drivers to register to OTG interrupt. Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi> --- drivers/usb/otg/Kconfig | 5 ++ drivers/usb/otg/Makefile | 1 + drivers/usb/otg/isp1301_omap.c | 78 ++----------------------------- drivers/usb/otg/omap-otg.c | 99 ++++++++++++++++++++++++++++++++++++++++ include/linux/usb/omap-otg.h | 30 ++++++++++++ 5 files changed, 138 insertions(+), 75 deletions(-) create mode 100644 drivers/usb/otg/omap-otg.c create mode 100644 include/linux/usb/omap-otg.h