2 * Gemini EHCI Host Controller driver
4 * Copyright (C) 2014 Roman Yeryomin <roman@advem.lv>
5 * Copyright (C) 2012 Tobias Waldvogel
6 * based on GPLd code from Sony Computer Entertainment Inc.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
12 #include <linux/kernel.h>
13 #include <linux/hrtimer.h>
15 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/usb.h>
18 #include <linux/usb/hcd.h>
19 #include <linux/usb/ehci_pdriver.h>
21 #include <mach/hardware.h>
22 #include <mach/global_reg.h>
26 #define DRV_NAME "ehci-fotg2"
31 #define OTGC_INT_STS 0x84
32 #define OTGC_INT_EN 0x88
34 #define GLOBAL_ISR 0xC0
35 #define GLOBAL_ICR 0xC4
37 #define GLOBAL_INT_POLARITY (1 << 3)
38 #define GLOBAL_INT_MASK_HC (1 << 2)
39 #define GLOBAL_INT_MASK_OTG (1 << 1)
40 #define GLOBAL_INT_MASK_DEV (1 << 0)
42 #define OTGC_SCR_ID (1 << 21)
43 #define OTGC_SCR_CROLE (1 << 20)
44 #define OTGC_SCR_VBUS_VLD (1 << 19)
45 #define OTGC_SCR_A_SRP_RESP_TYPE (1 << 8)
46 #define OTGC_SCR_A_SRP_DET_EN (1 << 7)
47 #define OTGC_SCR_A_SET_B_HNP_EN (1 << 6)
48 #define OTGC_SCR_A_BUS_DROP (1 << 5)
49 #define OTGC_SCR_A_BUS_REQ (1 << 4)
51 #define OTGC_INT_APLGRMV (1 << 12)
52 #define OTGC_INT_BPLGRMV (1 << 11)
53 #define OTGC_INT_OVC (1 << 10)
54 #define OTGC_INT_IDCHG (1 << 9)
55 #define OTGC_INT_RLCHG (1 << 8)
56 #define OTGC_INT_AVBUSERR (1 << 5)
57 #define OTGC_INT_ASRPDET (1 << 4)
58 #define OTGC_INT_BSRPDN (1 << 0)
60 #define OTGC_INT_A_TYPE ( \
68 #define OTGC_INT_B_TYPE ( \
76 static void fotg2_otg_init(struct usb_hcd
*hcd
)
80 writel(GLOBAL_INT_POLARITY
| GLOBAL_INT_MASK_HC
|
81 GLOBAL_INT_MASK_OTG
| GLOBAL_INT_MASK_DEV
,
82 hcd
->regs
+ GLOBAL_ICR
);
84 val
= readl(hcd
->regs
+ OTGC_SCR
);
85 val
&= ~(OTGC_SCR_A_SRP_RESP_TYPE
| OTGC_SCR_A_SRP_DET_EN
|
86 OTGC_SCR_A_BUS_DROP
| OTGC_SCR_A_SET_B_HNP_EN
);
87 val
|= OTGC_SCR_A_BUS_REQ
;
88 writel(val
, hcd
->regs
+ OTGC_SCR
);
90 writel(OTGC_INT_A_TYPE
, hcd
->regs
+ OTGC_INT_EN
);
92 /* setup MISC register, fixes timing problems */
93 val
= readl(hcd
->regs
+ HCD_MISC
);
95 writel(val
, hcd
->regs
+ HCD_MISC
);
97 writel(~0, hcd
->regs
+ GLOBAL_ISR
);
98 writel(~0, hcd
->regs
+ OTGC_INT_STS
);
101 static int fotg2_ehci_reset(struct usb_hcd
*hcd
)
105 retval
= ehci_setup(hcd
);
109 writel(GLOBAL_INT_POLARITY
, hcd
->regs
+ GLOBAL_ICR
);
113 static const struct hc_driver fotg2_ehci_hc_driver
= {
114 .description
= hcd_name
,
115 .product_desc
= "FOTG2 EHCI Host Controller",
116 .hcd_priv_size
= sizeof(struct ehci_hcd
),
118 .flags
= HCD_MEMORY
| HCD_USB2
,
119 .reset
= fotg2_ehci_reset
,
122 .shutdown
= ehci_shutdown
,
123 .urb_enqueue
= ehci_urb_enqueue
,
124 .urb_dequeue
= ehci_urb_dequeue
,
125 .endpoint_disable
= ehci_endpoint_disable
,
126 .endpoint_reset
= ehci_endpoint_reset
,
127 .get_frame_number
= ehci_get_frame
,
128 .hub_status_data
= ehci_hub_status_data
,
129 .hub_control
= ehci_hub_control
,
130 #if defined(CONFIG_PM)
131 .bus_suspend
= ehci_bus_suspend
,
132 .bus_resume
= ehci_bus_resume
,
134 .relinquish_port
= ehci_relinquish_port
,
135 .port_handed_over
= ehci_port_handed_over
,
137 .clear_tt_buffer_complete
= ehci_clear_tt_buffer_complete
,
140 static irqreturn_t
fotg2_ehci_irq(int irq
, void *data
)
142 struct usb_hcd
*hcd
= data
;
146 icr
= readl(hcd
->regs
+ GLOBAL_ICR
);
147 writel(GLOBAL_INT_POLARITY
| GLOBAL_INT_MASK_HC
|
148 GLOBAL_INT_MASK_OTG
| GLOBAL_INT_MASK_DEV
,
149 hcd
->regs
+ GLOBAL_ICR
);
154 sts
&= GLOBAL_INT_MASK_HC
| GLOBAL_INT_MASK_OTG
| GLOBAL_INT_MASK_DEV
;
155 sts
&= readl(hcd
->regs
+ GLOBAL_ISR
);
156 writel(sts
, hcd
->regs
+ GLOBAL_ISR
);
158 if (unlikely(sts
& GLOBAL_INT_MASK_DEV
)) {
159 ehci_warn(hcd_to_ehci(hcd
),
160 "Received unexpected irq for device role\n");
161 retval
= IRQ_HANDLED
;
164 if (unlikely(sts
& GLOBAL_INT_MASK_OTG
)) {
167 otg_sts
= readl(hcd
->regs
+ OTGC_INT_STS
);
168 writel(otg_sts
, hcd
->regs
+ OTGC_INT_STS
);
170 ehci_warn(hcd_to_ehci(hcd
),
171 "Received unexpected irq for OTG management\n");
172 retval
= IRQ_HANDLED
;
175 if (sts
& GLOBAL_INT_MASK_HC
) {
179 writel(icr
, hcd
->regs
+ GLOBAL_ICR
);
183 static int fotg2_ehci_probe(struct platform_device
*pdev
)
186 struct resource
*res
;
189 irq
= platform_get_irq(pdev
, 0);
191 pr_err("no irq provided");
195 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
197 pr_err("no memory resource provided");
201 hcd
= usb_create_hcd(&fotg2_ehci_hc_driver
, &pdev
->dev
,
202 dev_name(&pdev
->dev
));
206 hcd
->rsrc_start
= res
->start
;
207 hcd
->rsrc_len
= resource_size(res
);
209 hcd
->regs
= devm_request_and_ioremap(&pdev
->dev
, res
);
216 hcd_to_ehci(hcd
)->caps
= hcd
->regs
;
220 err
= request_irq(irq
, &fotg2_ehci_irq
, IRQF_SHARED
, "fotg2", hcd
);
224 err
= usb_add_hcd(hcd
, irq
, IRQF_SHARED
);
228 platform_set_drvdata(pdev
, hcd
);
236 static int fotg2_ehci_remove(struct platform_device
*pdev
)
238 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
240 writel(GLOBAL_INT_POLARITY
| GLOBAL_INT_MASK_HC
|
241 GLOBAL_INT_MASK_OTG
| GLOBAL_INT_MASK_DEV
,
242 hcd
->regs
+ GLOBAL_ICR
);
244 free_irq(hcd
->irq
, hcd
);
247 platform_set_drvdata(pdev
, NULL
);
252 MODULE_ALIAS("platform:" DRV_NAME
);
254 static struct platform_driver ehci_fotg2_driver
= {
255 .probe
= fotg2_ehci_probe
,
256 .remove
= fotg2_ehci_remove
,
257 .driver
.name
= DRV_NAME
,