aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/chipidea/Kconfig6
-rw-r--r--drivers/usb/chipidea/Makefile1
-rw-r--r--drivers/usb/chipidea/bits.h1
-rw-r--r--drivers/usb/chipidea/ci.h7
-rw-r--r--drivers/usb/chipidea/core.c15
-rw-r--r--drivers/usb/chipidea/host.c158
-rw-r--r--drivers/usb/chipidea/host.h17
-rw-r--r--drivers/usb/chipidea/udc.c8
-rw-r--r--drivers/usb/host/ehci-hcd.c8
9 files changed, 212 insertions, 9 deletions
diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig
index 553c1976a66e..fd36dc8b889b 100644
--- a/drivers/usb/chipidea/Kconfig
+++ b/drivers/usb/chipidea/Kconfig
@@ -18,6 +18,12 @@ config USB_CHIPIDEA_UDC
18 Say Y here to enable device controller functionality of the 18 Say Y here to enable device controller functionality of the
19 ChipIdea driver. 19 ChipIdea driver.
20 20
21config USB_CHIPIDEA_HOST
22 bool "ChipIdea host controller"
23 help
24 Say Y here to enable host controller functionality of the
25 ChipIdea driver.
26
21config USB_CHIPIDEA_DEBUG 27config USB_CHIPIDEA_DEBUG
22 bool "ChipIdea driver debug" 28 bool "ChipIdea driver debug"
23 help 29 help
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index a8279aac6a4a..cc3493769724 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o
2 2
3ci_hdrc-y := core.o 3ci_hdrc-y := core.o
4ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o 4ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o
5ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST) += host.o
5ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o 6ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o
6 7
7ifneq ($(CONFIG_PCI),) 8ifneq ($(CONFIG_PCI),)
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index 44b3e254b6a5..050de8562a04 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -21,6 +21,7 @@
21/* DCCPARAMS */ 21/* DCCPARAMS */
22#define DCCPARAMS_DEN (0x1F << 0) 22#define DCCPARAMS_DEN (0x1F << 0)
23#define DCCPARAMS_DC BIT(7) 23#define DCCPARAMS_DC BIT(7)
24#define DCCPARAMS_HC BIT(8)
24 25
25/* TESTMODE */ 26/* TESTMODE */
26#define TESTMODE_FORCE BIT(0) 27#define TESTMODE_FORCE BIT(0)
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 0ab83411d800..c605acc5568a 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -15,6 +15,7 @@
15 15
16#include <linux/list.h> 16#include <linux/list.h>
17#include <linux/irqreturn.h> 17#include <linux/irqreturn.h>
18#include <linux/usb.h>
18#include <linux/usb/gadget.h> 19#include <linux/usb/gadget.h>
19 20
20/****************************************************************************** 21/******************************************************************************
@@ -84,6 +85,7 @@ struct ci_role_driver {
84/** 85/**
85 * struct hw_bank - hardware register mapping representation 86 * struct hw_bank - hardware register mapping representation
86 * @lpm: set if the device is LPM capable 87 * @lpm: set if the device is LPM capable
88 * @phys: physical address of the controller's registers
87 * @abs: absolute address of the beginning of register window 89 * @abs: absolute address of the beginning of register window
88 * @cap: capability registers 90 * @cap: capability registers
89 * @op: operational registers 91 * @op: operational registers
@@ -92,6 +94,7 @@ struct ci_role_driver {
92 */ 94 */
93struct hw_bank { 95struct hw_bank {
94 unsigned lpm; 96 unsigned lpm;
97 resource_size_t phys;
95 void __iomem *abs; 98 void __iomem *abs;
96 void __iomem *cap; 99 void __iomem *cap;
97 void __iomem *op; 100 void __iomem *op;
@@ -128,6 +131,7 @@ struct hw_bank {
128 * @udc_driver: platform specific information supplied by parent device 131 * @udc_driver: platform specific information supplied by parent device
129 * @vbus_active: is VBUS active 132 * @vbus_active: is VBUS active
130 * @transceiver: pointer to USB PHY, if any 133 * @transceiver: pointer to USB PHY, if any
134 * @hcd: pointer to usb_hcd for ehci host driver
131 */ 135 */
132struct ci13xxx { 136struct ci13xxx {
133 struct device *dev; 137 struct device *dev;
@@ -160,6 +164,7 @@ struct ci13xxx {
160 struct ci13xxx_udc_driver *udc_driver; 164 struct ci13xxx_udc_driver *udc_driver;
161 int vbus_active; 165 int vbus_active;
162 struct usb_phy *transceiver; 166 struct usb_phy *transceiver;
167 struct usb_hcd *hcd;
163}; 168};
164 169
165static inline struct ci_role_driver *ci_role(struct ci13xxx *ci) 170static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
@@ -302,7 +307,7 @@ static inline u32 hw_test_and_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
302 return (val & mask) >> ffs_nr(mask); 307 return (val & mask) >> ffs_nr(mask);
303} 308}
304 309
305int hw_device_reset(struct ci13xxx *ci); 310int hw_device_reset(struct ci13xxx *ci, u32 mode);
306 311
307int hw_port_test_set(struct ci13xxx *ci, u8 mode); 312int hw_port_test_set(struct ci13xxx *ci, u8 mode);
308 313
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 3d48c9be6923..f568b8e86cee 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -70,6 +70,7 @@
70#include "ci.h" 70#include "ci.h"
71#include "udc.h" 71#include "udc.h"
72#include "bits.h" 72#include "bits.h"
73#include "host.h"
73#include "debug.h" 74#include "debug.h"
74 75
75/* Controller register map */ 76/* Controller register map */
@@ -215,7 +216,7 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
215 * 216 *
216 * This function returns an error code 217 * This function returns an error code
217 */ 218 */
218int hw_device_reset(struct ci13xxx *ci) 219int hw_device_reset(struct ci13xxx *ci, u32 mode)
219{ 220{
220 /* should flush & stop before reset */ 221 /* should flush & stop before reset */
221 hw_write(ci, OP_ENDPTFLUSH, ~0, ~0); 222 hw_write(ci, OP_ENDPTFLUSH, ~0, ~0);
@@ -235,12 +236,12 @@ int hw_device_reset(struct ci13xxx *ci)
235 236
236 /* USBMODE should be configured step by step */ 237 /* USBMODE should be configured step by step */
237 hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); 238 hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
238 hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_DC); 239 hw_write(ci, OP_USBMODE, USBMODE_CM, mode);
239 /* HW >= 2.3 */ 240 /* HW >= 2.3 */
240 hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); 241 hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);
241 242
242 if (hw_read(ci, OP_USBMODE, USBMODE_CM) != USBMODE_CM_DC) { 243 if (hw_read(ci, OP_USBMODE, USBMODE_CM) != mode) {
243 pr_err("cannot enter in device mode"); 244 pr_err("cannot enter in %s mode", ci_role(ci)->name);
244 pr_err("lpm = %i", ci->hw_bank.lpm); 245 pr_err("lpm = %i", ci->hw_bank.lpm);
245 return -ENODEV; 246 return -ENODEV;
246 } 247 }
@@ -371,6 +372,8 @@ static int __devinit ci_hdrc_probe(struct platform_device *pdev)
371 return -ENODEV; 372 return -ENODEV;
372 } 373 }
373 374
375 ci->hw_bank.phys = res->start;
376
374 ci->irq = platform_get_irq(pdev, 0); 377 ci->irq = platform_get_irq(pdev, 0);
375 if (ci->irq < 0) { 378 if (ci->irq < 0) {
376 dev_err(dev, "missing IRQ\n"); 379 dev_err(dev, "missing IRQ\n");
@@ -385,6 +388,10 @@ static int __devinit ci_hdrc_probe(struct platform_device *pdev)
385 } 388 }
386 389
387 /* initialize role(s) before the interrupt is requested */ 390 /* initialize role(s) before the interrupt is requested */
391 ret = ci_hdrc_host_init(ci);
392 if (ret)
393 dev_info(dev, "doesn't support host\n");
394
388 ret = ci_hdrc_gadget_init(ci); 395 ret = ci_hdrc_gadget_init(ci);
389 if (ret) 396 if (ret)
390 dev_info(dev, "doesn't support gadget\n"); 397 dev_info(dev, "doesn't support gadget\n");
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
new file mode 100644
index 000000000000..8c8362c89a8c
--- /dev/null
+++ b/drivers/usb/chipidea/host.c
@@ -0,0 +1,158 @@
1/*
2 * host.c - ChipIdea USB host controller driver
3 *
4 * Copyright (c) 2012 Intel Corporation
5 *
6 * Author: Alexander Shishkin
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/kernel.h>
23#include <linux/usb.h>
24#include <linux/usb/hcd.h>
25#include <linux/usb/chipidea.h>
26
27#define CHIPIDEA_EHCI
28#include "../host/ehci-hcd.c"
29
30#include "ci.h"
31#include "bits.h"
32#include "host.h"
33
34static int ci_ehci_setup(struct usb_hcd *hcd)
35{
36 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
37 int ret;
38
39 hcd->has_tt = 1;
40
41 ret = ehci_setup(hcd);
42 if (ret)
43 return ret;
44
45 ehci_port_power(ehci, 0);
46
47 return ret;
48}
49
50static const struct hc_driver ci_ehci_hc_driver = {
51 .description = "ehci_hcd",
52 .product_desc = "ChipIdea HDRC EHCI",
53 .hcd_priv_size = sizeof(struct ehci_hcd),
54
55 /*
56 * generic hardware linkage
57 */
58 .irq = ehci_irq,
59 .flags = HCD_MEMORY | HCD_USB2,
60
61 /*
62 * basic lifecycle operations
63 */
64 .reset = ci_ehci_setup,
65 .start = ehci_run,
66 .stop = ehci_stop,
67 .shutdown = ehci_shutdown,
68
69 /*
70 * managing i/o requests and associated device resources
71 */
72 .urb_enqueue = ehci_urb_enqueue,
73 .urb_dequeue = ehci_urb_dequeue,
74 .endpoint_disable = ehci_endpoint_disable,
75 .endpoint_reset = ehci_endpoint_reset,
76
77 /*
78 * scheduling support
79 */
80 .get_frame_number = ehci_get_frame,
81
82 /*
83 * root hub support
84 */
85 .hub_status_data = ehci_hub_status_data,
86 .hub_control = ehci_hub_control,
87 .bus_suspend = ehci_bus_suspend,
88 .bus_resume = ehci_bus_resume,
89 .relinquish_port = ehci_relinquish_port,
90 .port_handed_over = ehci_port_handed_over,
91
92 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
93};
94
95static irqreturn_t host_irq(struct ci13xxx *ci)
96{
97 return usb_hcd_irq(ci->irq, ci->hcd);
98}
99
100static int host_start(struct ci13xxx *ci)
101{
102 struct usb_hcd *hcd;
103 struct ehci_hcd *ehci;
104 int ret;
105
106 if (usb_disabled())
107 return -ENODEV;
108
109 hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev));
110 if (!hcd)
111 return -ENOMEM;
112
113 dev_set_drvdata(ci->dev, ci);
114 hcd->rsrc_start = ci->hw_bank.phys;
115 hcd->rsrc_len = ci->hw_bank.size;
116 hcd->regs = ci->hw_bank.abs;
117 hcd->has_tt = 1;
118
119 ehci = hcd_to_ehci(hcd);
120 ehci->caps = ci->hw_bank.cap;
121 ehci->has_hostpc = ci->hw_bank.lpm;
122
123 ret = usb_add_hcd(hcd, 0, 0);
124 if (ret)
125 usb_remove_hcd(hcd);
126 else
127 ci->hcd = hcd;
128
129 return ret;
130}
131
132static void host_stop(struct ci13xxx *ci)
133{
134 struct usb_hcd *hcd = ci->hcd;
135
136 usb_remove_hcd(hcd);
137 usb_put_hcd(hcd);
138}
139
140int ci_hdrc_host_init(struct ci13xxx *ci)
141{
142 struct ci_role_driver *rdrv;
143
144 if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_HC))
145 return -ENXIO;
146
147 rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL);
148 if (!rdrv)
149 return -ENOMEM;
150
151 rdrv->start = host_start;
152 rdrv->stop = host_stop;
153 rdrv->irq = host_irq;
154 rdrv->name = "host";
155 ci->roles[CI_ROLE_HOST] = rdrv;
156
157 return 0;
158}
diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h
new file mode 100644
index 000000000000..761fb1fd6d99
--- /dev/null
+++ b/drivers/usb/chipidea/host.h
@@ -0,0 +1,17 @@
1#ifndef __DRIVERS_USB_CHIPIDEA_HOST_H
2#define __DRIVERS_USB_CHIPIDEA_HOST_H
3
4#ifdef CONFIG_USB_CHIPIDEA_HOST
5
6int ci_hdrc_host_init(struct ci13xxx *ci);
7
8#else
9
10static inline int ci_hdrc_host_init(struct ci13xxx *ci)
11{
12 return -ENXIO;
13}
14
15#endif
16
17#endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 290946d618d8..fb0a91158006 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * udc.h - ChipIdea UDC driver 2 * udc.c - ChipIdea UDC driver
3 * 3 *
4 * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. 4 * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
5 * 5 *
@@ -1396,7 +1396,7 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
1396 if (gadget_ready) { 1396 if (gadget_ready) {
1397 if (is_active) { 1397 if (is_active) {
1398 pm_runtime_get_sync(&_gadget->dev); 1398 pm_runtime_get_sync(&_gadget->dev);
1399 hw_device_reset(udc); 1399 hw_device_reset(udc, USBMODE_CM_DC);
1400 hw_device_state(udc, udc->ep0out->qh.dma); 1400 hw_device_state(udc, udc->ep0out->qh.dma);
1401 } else { 1401 } else {
1402 hw_device_state(udc, 0); 1402 hw_device_state(udc, 0);
@@ -1540,7 +1540,7 @@ static int ci13xxx_start(struct usb_gadget *gadget,
1540 if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) { 1540 if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
1541 if (udc->vbus_active) { 1541 if (udc->vbus_active) {
1542 if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) 1542 if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
1543 hw_device_reset(udc); 1543 hw_device_reset(udc, USBMODE_CM_DC);
1544 } else { 1544 } else {
1545 pm_runtime_put_sync(&udc->gadget.dev); 1545 pm_runtime_put_sync(&udc->gadget.dev);
1546 goto done; 1546 goto done;
@@ -1720,7 +1720,7 @@ static int udc_start(struct ci13xxx *udc)
1720 } 1720 }
1721 1721
1722 if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) { 1722 if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
1723 retval = hw_device_reset(udc); 1723 retval = hw_device_reset(udc, USBMODE_CM_DC);
1724 if (retval) 1724 if (retval)
1725 goto put_transceiver; 1725 goto put_transceiver;
1726 } 1726 }
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index de1e689d3df0..5cb775b1802d 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1246,6 +1246,13 @@ static int ehci_get_frame (struct usb_hcd *hcd)
1246} 1246}
1247 1247
1248/*-------------------------------------------------------------------------*/ 1248/*-------------------------------------------------------------------------*/
1249/*
1250 * The EHCI in ChipIdea HDRC cannot be a separate module or device,
1251 * because its registers (and irq) are shared between host/gadget/otg
1252 * functions and in order to facilitate role switching we cannot
1253 * give the ehci driver exclusive access to those.
1254 */
1255#ifndef CHIPIDEA_EHCI
1249 1256
1250MODULE_DESCRIPTION(DRIVER_DESC); 1257MODULE_DESCRIPTION(DRIVER_DESC);
1251MODULE_AUTHOR (DRIVER_AUTHOR); 1258MODULE_AUTHOR (DRIVER_AUTHOR);
@@ -1504,3 +1511,4 @@ static void __exit ehci_hcd_cleanup(void)
1504} 1511}
1505module_exit(ehci_hcd_cleanup); 1512module_exit(ehci_hcd_cleanup);
1506 1513
1514#endif /* CHIPIDEA_EHCI */