aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/otg
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/otg')
-rw-r--r--drivers/usb/otg/Kconfig9
-rw-r--r--drivers/usb/otg/Makefile1
-rw-r--r--drivers/usb/otg/ulpi.c136
3 files changed, 146 insertions, 0 deletions
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index aa884d072f0b..de56b3d743d7 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -41,6 +41,15 @@ config ISP1301_OMAP
41 This driver can also be built as a module. If so, the module 41 This driver can also be built as a module. If so, the module
42 will be called isp1301_omap. 42 will be called isp1301_omap.
43 43
44config USB_ULPI
45 bool "Generic ULPI Transceiver Driver"
46 depends on ARM
47 help
48 Enable this to support ULPI connected USB OTG transceivers which
49 are likely found on embedded boards.
50
51 The only chip currently supported is NXP's ISP1504
52
44config TWL4030_USB 53config TWL4030_USB
45 tristate "TWL4030 USB Transceiver Driver" 54 tristate "TWL4030 USB Transceiver Driver"
46 depends on TWL4030_CORE && REGULATOR_TWL4030 55 depends on TWL4030_CORE && REGULATOR_TWL4030
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
index 208167856529..aeb49a8ec412 100644
--- a/drivers/usb/otg/Makefile
+++ b/drivers/usb/otg/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
10obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o 10obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
11obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o 11obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
12obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o 12obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o
13obj-$(CONFIG_USB_ULPI) += ulpi.o
13 14
14ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG 15ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG
15ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG 16ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG
diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/otg/ulpi.c
new file mode 100644
index 000000000000..896527456b7e
--- /dev/null
+++ b/drivers/usb/otg/ulpi.c
@@ -0,0 +1,136 @@
1/*
2 * Generic ULPI USB transceiver support
3 *
4 * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
5 *
6 * Based on sources from
7 *
8 * Sascha Hauer <s.hauer@pengutronix.de>
9 * Freescale Semiconductors
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26#include <linux/kernel.h>
27#include <linux/usb.h>
28#include <linux/usb/otg.h>
29#include <linux/usb/ulpi.h>
30
31/* ULPI register addresses */
32#define ULPI_VID_LOW 0x00 /* Vendor ID low */
33#define ULPI_VID_HIGH 0x01 /* Vendor ID high */
34#define ULPI_PID_LOW 0x02 /* Product ID low */
35#define ULPI_PID_HIGH 0x03 /* Product ID high */
36#define ULPI_ITFCTL 0x07 /* Interface Control */
37#define ULPI_OTGCTL 0x0A /* OTG Control */
38
39/* add to above register address to access Set/Clear functions */
40#define ULPI_REG_SET 0x01
41#define ULPI_REG_CLEAR 0x02
42
43/* ULPI OTG Control Register bits */
44#define ID_PULL_UP (1 << 0) /* enable ID Pull Up */
45#define DP_PULL_DOWN (1 << 1) /* enable DP Pull Down */
46#define DM_PULL_DOWN (1 << 2) /* enable DM Pull Down */
47#define DISCHRG_VBUS (1 << 3) /* Discharge Vbus */
48#define CHRG_VBUS (1 << 4) /* Charge Vbus */
49#define DRV_VBUS (1 << 5) /* Drive Vbus */
50#define DRV_VBUS_EXT (1 << 6) /* Drive Vbus external */
51#define USE_EXT_VBUS_IND (1 << 7) /* Use ext. Vbus indicator */
52
53#define ULPI_ID(vendor, product) (((vendor) << 16) | (product))
54
55#define TR_FLAG(flags, a, b) (((flags) & a) ? b : 0)
56
57/* ULPI hardcoded IDs, used for probing */
58static unsigned int ulpi_ids[] = {
59 ULPI_ID(0x04cc, 0x1504), /* NXP ISP1504 */
60};
61
62static int ulpi_set_flags(struct otg_transceiver *otg)
63{
64 unsigned int flags = 0;
65
66 if (otg->flags & USB_OTG_PULLUP_ID)
67 flags |= ID_PULL_UP;
68
69 if (otg->flags & USB_OTG_PULLDOWN_DM)
70 flags |= DM_PULL_DOWN;
71
72 if (otg->flags & USB_OTG_PULLDOWN_DP)
73 flags |= DP_PULL_DOWN;
74
75 if (otg->flags & USB_OTG_EXT_VBUS_INDICATOR)
76 flags |= USE_EXT_VBUS_IND;
77
78 return otg_io_write(otg, flags, ULPI_OTGCTL + ULPI_REG_SET);
79}
80
81static int ulpi_init(struct otg_transceiver *otg)
82{
83 int i, vid, pid;
84
85 vid = (otg_io_read(otg, ULPI_VID_HIGH) << 8) |
86 otg_io_read(otg, ULPI_VID_LOW);
87 pid = (otg_io_read(otg, ULPI_PID_HIGH) << 8) |
88 otg_io_read(otg, ULPI_PID_LOW);
89
90 pr_info("ULPI transceiver vendor/product ID 0x%04x/0x%04x\n", vid, pid);
91
92 for (i = 0; i < ARRAY_SIZE(ulpi_ids); i++)
93 if (ulpi_ids[i] == ULPI_ID(vid, pid))
94 return ulpi_set_flags(otg);
95
96 pr_err("ULPI ID does not match any known transceiver.\n");
97 return -ENODEV;
98}
99
100static int ulpi_set_vbus(struct otg_transceiver *otg, bool on)
101{
102 unsigned int flags = otg_io_read(otg, ULPI_OTGCTL);
103
104 flags &= ~(DRV_VBUS | DRV_VBUS_EXT);
105
106 if (on) {
107 if (otg->flags & USB_OTG_DRV_VBUS)
108 flags |= DRV_VBUS;
109
110 if (otg->flags & USB_OTG_DRV_VBUS_EXT)
111 flags |= DRV_VBUS_EXT;
112 }
113
114 return otg_io_write(otg, flags, ULPI_OTGCTL + ULPI_REG_SET);
115}
116
117struct otg_transceiver *
118otg_ulpi_create(struct otg_io_access_ops *ops,
119 unsigned int flags)
120{
121 struct otg_transceiver *otg;
122
123 otg = kzalloc(sizeof(*otg), GFP_KERNEL);
124 if (!otg)
125 return NULL;
126
127 otg->label = "ULPI";
128 otg->flags = flags;
129 otg->io_ops = ops;
130 otg->init = ulpi_init;
131 otg->set_vbus = ulpi_set_vbus;
132
133 return otg;
134}
135EXPORT_SYMBOL_GPL(otg_ulpi_create);
136