]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0 |
28a15ef7 HG |
2 | /* |
3 | * Allwinner SUNXI "glue layer" | |
4 | * | |
5 | * Copyright © 2015 Hans de Goede <hdegoede@redhat.com> | |
6 | * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> | |
7 | * | |
8 | * Based on the sw_usb "Allwinner OTG Dual Role Controller" code. | |
9 | * Copyright 2007-2012 (C) Allwinner Technology Co., Ltd. | |
10 | * javen <javen@allwinnertech.com> | |
11 | * | |
12 | * Based on the DA8xx "glue layer" code. | |
13 | * Copyright (c) 2008-2009 MontaVista Software, Inc. <source@mvista.com> | |
14 | * Copyright (C) 2005-2006 by Texas Instruments | |
15 | * | |
16 | * This file is part of the Inventra Controller Driver for Linux. | |
28a15ef7 | 17 | */ |
d678a59d | 18 | #include <common.h> |
b9aa0a93 | 19 | #include <clk.h> |
9d922450 | 20 | #include <dm.h> |
dd322817 | 21 | #include <generic-phy.h> |
f7ae49fc | 22 | #include <log.h> |
336d4615 | 23 | #include <malloc.h> |
dd322817 | 24 | #include <phy-sun4i-usb.h> |
b9aa0a93 | 25 | #include <reset.h> |
28a15ef7 | 26 | #include <asm/arch/cpu.h> |
375de017 | 27 | #include <asm/arch/clock.h> |
336d4615 | 28 | #include <dm/device_compat.h> |
91183bab HG |
29 | #include <dm/lists.h> |
30 | #include <dm/root.h> | |
cd93d625 | 31 | #include <linux/bitops.h> |
c05ed00a | 32 | #include <linux/delay.h> |
1e94b46f | 33 | #include <linux/printk.h> |
d42faf31 | 34 | #include <linux/usb/musb.h> |
28a15ef7 HG |
35 | #include "linux-compat.h" |
36 | #include "musb_core.h" | |
91183bab | 37 | #include "musb_uboot.h" |
28a15ef7 HG |
38 | |
39 | /****************************************************************************** | |
40 | ****************************************************************************** | |
41 | * From the Allwinner driver | |
42 | ****************************************************************************** | |
43 | ******************************************************************************/ | |
44 | ||
45 | /****************************************************************************** | |
46 | * From include/sunxi_usb_bsp.h | |
47 | ******************************************************************************/ | |
48 | ||
49 | /* reg offsets */ | |
50 | #define USBC_REG_o_ISCR 0x0400 | |
51 | #define USBC_REG_o_PHYCTL 0x0404 | |
52 | #define USBC_REG_o_PHYBIST 0x0408 | |
53 | #define USBC_REG_o_PHYTUNE 0x040c | |
54 | ||
55 | #define USBC_REG_o_VEND0 0x0043 | |
56 | ||
57 | /* Interface Status and Control */ | |
58 | #define USBC_BP_ISCR_VBUS_VALID_FROM_DATA 30 | |
59 | #define USBC_BP_ISCR_VBUS_VALID_FROM_VBUS 29 | |
60 | #define USBC_BP_ISCR_EXT_ID_STATUS 28 | |
61 | #define USBC_BP_ISCR_EXT_DM_STATUS 27 | |
62 | #define USBC_BP_ISCR_EXT_DP_STATUS 26 | |
63 | #define USBC_BP_ISCR_MERGED_VBUS_STATUS 25 | |
64 | #define USBC_BP_ISCR_MERGED_ID_STATUS 24 | |
65 | ||
66 | #define USBC_BP_ISCR_ID_PULLUP_EN 17 | |
67 | #define USBC_BP_ISCR_DPDM_PULLUP_EN 16 | |
68 | #define USBC_BP_ISCR_FORCE_ID 14 | |
69 | #define USBC_BP_ISCR_FORCE_VBUS_VALID 12 | |
70 | #define USBC_BP_ISCR_VBUS_VALID_SRC 10 | |
71 | ||
72 | #define USBC_BP_ISCR_HOSC_EN 7 | |
73 | #define USBC_BP_ISCR_VBUS_CHANGE_DETECT 6 | |
74 | #define USBC_BP_ISCR_ID_CHANGE_DETECT 5 | |
75 | #define USBC_BP_ISCR_DPDM_CHANGE_DETECT 4 | |
76 | #define USBC_BP_ISCR_IRQ_ENABLE 3 | |
77 | #define USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN 2 | |
78 | #define USBC_BP_ISCR_ID_CHANGE_DETECT_EN 1 | |
79 | #define USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN 0 | |
80 | ||
81 | /****************************************************************************** | |
82 | * From usbc/usbc.c | |
83 | ******************************************************************************/ | |
84 | ||
97202dd6 JT |
85 | struct sunxi_musb_config { |
86 | struct musb_hdrc_config *config; | |
87 | }; | |
88 | ||
831cc98b JT |
89 | struct sunxi_glue { |
90 | struct musb_host_data mdata; | |
b9aa0a93 JT |
91 | struct clk clk; |
92 | struct reset_ctl rst; | |
97202dd6 | 93 | struct sunxi_musb_config *cfg; |
831cc98b | 94 | struct device dev; |
622fd2b9 | 95 | struct phy phy; |
831cc98b JT |
96 | }; |
97 | #define to_sunxi_glue(d) container_of(d, struct sunxi_glue, dev) | |
98 | ||
28a15ef7 HG |
99 | static u32 USBC_WakeUp_ClearChangeDetect(u32 reg_val) |
100 | { | |
101 | u32 temp = reg_val; | |
102 | ||
5c5fe883 JT |
103 | temp &= ~BIT(USBC_BP_ISCR_VBUS_CHANGE_DETECT); |
104 | temp &= ~BIT(USBC_BP_ISCR_ID_CHANGE_DETECT); | |
105 | temp &= ~BIT(USBC_BP_ISCR_DPDM_CHANGE_DETECT); | |
28a15ef7 HG |
106 | |
107 | return temp; | |
108 | } | |
109 | ||
110 | static void USBC_EnableIdPullUp(__iomem void *base) | |
111 | { | |
112 | u32 reg_val; | |
113 | ||
114 | reg_val = musb_readl(base, USBC_REG_o_ISCR); | |
5c5fe883 | 115 | reg_val |= BIT(USBC_BP_ISCR_ID_PULLUP_EN); |
28a15ef7 HG |
116 | reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); |
117 | musb_writel(base, USBC_REG_o_ISCR, reg_val); | |
118 | } | |
119 | ||
28a15ef7 HG |
120 | static void USBC_EnableDpDmPullUp(__iomem void *base) |
121 | { | |
122 | u32 reg_val; | |
123 | ||
124 | reg_val = musb_readl(base, USBC_REG_o_ISCR); | |
5c5fe883 | 125 | reg_val |= BIT(USBC_BP_ISCR_DPDM_PULLUP_EN); |
28a15ef7 HG |
126 | reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); |
127 | musb_writel(base, USBC_REG_o_ISCR, reg_val); | |
128 | } | |
129 | ||
28a15ef7 HG |
130 | static void USBC_ForceIdToLow(__iomem void *base) |
131 | { | |
132 | u32 reg_val; | |
133 | ||
134 | reg_val = musb_readl(base, USBC_REG_o_ISCR); | |
135 | reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID); | |
136 | reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID); | |
137 | reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); | |
138 | musb_writel(base, USBC_REG_o_ISCR, reg_val); | |
139 | } | |
140 | ||
141 | static void USBC_ForceIdToHigh(__iomem void *base) | |
142 | { | |
143 | u32 reg_val; | |
144 | ||
145 | reg_val = musb_readl(base, USBC_REG_o_ISCR); | |
146 | reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID); | |
147 | reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID); | |
148 | reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); | |
149 | musb_writel(base, USBC_REG_o_ISCR, reg_val); | |
150 | } | |
151 | ||
e1abfa43 HG |
152 | static void USBC_ForceVbusValidToLow(__iomem void *base) |
153 | { | |
154 | u32 reg_val; | |
155 | ||
156 | reg_val = musb_readl(base, USBC_REG_o_ISCR); | |
157 | reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); | |
158 | reg_val |= (0x02 << USBC_BP_ISCR_FORCE_VBUS_VALID); | |
159 | reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); | |
160 | musb_writel(base, USBC_REG_o_ISCR, reg_val); | |
161 | } | |
162 | ||
28a15ef7 HG |
163 | static void USBC_ForceVbusValidToHigh(__iomem void *base) |
164 | { | |
165 | u32 reg_val; | |
166 | ||
167 | reg_val = musb_readl(base, USBC_REG_o_ISCR); | |
168 | reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); | |
169 | reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); | |
170 | reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); | |
171 | musb_writel(base, USBC_REG_o_ISCR, reg_val); | |
172 | } | |
173 | ||
174 | static void USBC_ConfigFIFO_Base(void) | |
175 | { | |
176 | u32 reg_value; | |
177 | ||
178 | /* config usb fifo, 8kb mode */ | |
179 | reg_value = readl(SUNXI_SRAMC_BASE + 0x04); | |
180 | reg_value &= ~(0x03 << 0); | |
5c5fe883 | 181 | reg_value |= BIT(0); |
28a15ef7 HG |
182 | writel(reg_value, SUNXI_SRAMC_BASE + 0x04); |
183 | } | |
184 | ||
6047a3a9 SS |
185 | /****************************************************************************** |
186 | * Needed for the DFU polling magic | |
187 | ******************************************************************************/ | |
188 | ||
189 | static u8 last_int_usb; | |
190 | ||
191 | bool dfu_usb_get_reset(void) | |
192 | { | |
193 | return !!(last_int_usb & MUSB_INTR_RESET); | |
194 | } | |
195 | ||
28a15ef7 HG |
196 | /****************************************************************************** |
197 | * MUSB Glue code | |
198 | ******************************************************************************/ | |
199 | ||
200 | static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci) | |
201 | { | |
202 | struct musb *musb = __hci; | |
203 | irqreturn_t retval = IRQ_NONE; | |
204 | ||
205 | /* read and flush interrupts */ | |
206 | musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); | |
6047a3a9 | 207 | last_int_usb = musb->int_usb; |
28a15ef7 HG |
208 | if (musb->int_usb) |
209 | musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb); | |
210 | musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); | |
211 | if (musb->int_tx) | |
212 | musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx); | |
213 | musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); | |
214 | if (musb->int_rx) | |
215 | musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx); | |
216 | ||
217 | if (musb->int_usb || musb->int_tx || musb->int_rx) | |
218 | retval |= musb_interrupt(musb); | |
219 | ||
220 | return retval; | |
221 | } | |
222 | ||
e1abfa43 HG |
223 | /* musb_core does not call enable / disable in a balanced manner <sigh> */ |
224 | static bool enabled = false; | |
225 | ||
15837236 | 226 | static int sunxi_musb_enable(struct musb *musb) |
28a15ef7 | 227 | { |
dd322817 | 228 | struct sunxi_glue *glue = to_sunxi_glue(musb->controller); |
57075a47 CYT |
229 | int ret; |
230 | ||
28a15ef7 HG |
231 | pr_debug("%s():\n", __func__); |
232 | ||
1feda63e MR |
233 | musb_ep_select(musb->mregs, 0); |
234 | musb_writeb(musb->mregs, MUSB_FADDR, 0); | |
235 | ||
e1abfa43 | 236 | if (enabled) |
15837236 | 237 | return 0; |
e1abfa43 | 238 | |
28a15ef7 HG |
239 | /* select PIO mode */ |
240 | musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0); | |
241 | ||
b41972e7 | 242 | if (is_host_enabled(musb)) { |
622fd2b9 | 243 | ret = sun4i_usb_phy_id_detect(&glue->phy); |
57075a47 | 244 | if (ret == 1) { |
71cbe0d6 HG |
245 | printf("No host cable detected: "); |
246 | return -ENODEV; | |
247 | } | |
dd322817 | 248 | |
622fd2b9 | 249 | ret = generic_phy_power_on(&glue->phy); |
dd322817 | 250 | if (ret) { |
c1e1dbb8 | 251 | pr_debug("failed to power on USB PHY\n"); |
dd322817 JT |
252 | return ret; |
253 | } | |
b41972e7 | 254 | } |
e1abfa43 HG |
255 | |
256 | USBC_ForceVbusValidToHigh(musb->mregs); | |
257 | ||
258 | enabled = true; | |
15837236 | 259 | return 0; |
28a15ef7 HG |
260 | } |
261 | ||
262 | static void sunxi_musb_disable(struct musb *musb) | |
263 | { | |
dd322817 JT |
264 | struct sunxi_glue *glue = to_sunxi_glue(musb->controller); |
265 | int ret; | |
266 | ||
28a15ef7 HG |
267 | pr_debug("%s():\n", __func__); |
268 | ||
e1abfa43 HG |
269 | if (!enabled) |
270 | return; | |
375de017 | 271 | |
dd322817 | 272 | if (is_host_enabled(musb)) { |
622fd2b9 | 273 | ret = generic_phy_power_off(&glue->phy); |
dd322817 | 274 | if (ret) { |
c1e1dbb8 | 275 | pr_debug("failed to power off USB PHY\n"); |
dd322817 JT |
276 | return; |
277 | } | |
278 | } | |
57075a47 | 279 | |
e1abfa43 HG |
280 | USBC_ForceVbusValidToLow(musb->mregs); |
281 | mdelay(200); /* Wait for the current session to timeout */ | |
282 | ||
283 | enabled = false; | |
28a15ef7 HG |
284 | } |
285 | ||
286 | static int sunxi_musb_init(struct musb *musb) | |
287 | { | |
831cc98b | 288 | struct sunxi_glue *glue = to_sunxi_glue(musb->controller); |
dd322817 | 289 | int ret; |
28a15ef7 HG |
290 | |
291 | pr_debug("%s():\n", __func__); | |
292 | ||
b9aa0a93 | 293 | ret = clk_enable(&glue->clk); |
dd322817 | 294 | if (ret) { |
7fe8cfdc | 295 | dev_err(musb->controller, "failed to enable clock\n"); |
dd322817 JT |
296 | return ret; |
297 | } | |
298 | ||
b9aa0a93 JT |
299 | if (reset_valid(&glue->rst)) { |
300 | ret = reset_deassert(&glue->rst); | |
301 | if (ret) { | |
7fe8cfdc | 302 | dev_err(musb->controller, "failed to deassert reset\n"); |
b9aa0a93 JT |
303 | goto err_clk; |
304 | } | |
305 | } | |
1034bcc2 | 306 | |
b9aa0a93 JT |
307 | ret = generic_phy_init(&glue->phy); |
308 | if (ret) { | |
7fe8cfdc | 309 | dev_dbg(musb->controller, "failed to init USB PHY\n"); |
b9aa0a93 JT |
310 | goto err_rst; |
311 | } | |
1034bcc2 | 312 | |
b9aa0a93 | 313 | musb->isr = sunxi_musb_interrupt; |
9d12a82e | 314 | |
28a15ef7 HG |
315 | USBC_ConfigFIFO_Base(); |
316 | USBC_EnableDpDmPullUp(musb->mregs); | |
317 | USBC_EnableIdPullUp(musb->mregs); | |
318 | ||
319 | if (is_host_enabled(musb)) { | |
320 | /* Host mode */ | |
321 | USBC_ForceIdToLow(musb->mregs); | |
28a15ef7 HG |
322 | } else { |
323 | /* Peripheral mode */ | |
324 | USBC_ForceIdToHigh(musb->mregs); | |
28a15ef7 | 325 | } |
b1b912dd | 326 | USBC_ForceVbusValidToHigh(musb->mregs); |
28a15ef7 HG |
327 | |
328 | return 0; | |
b9aa0a93 JT |
329 | |
330 | err_rst: | |
331 | if (reset_valid(&glue->rst)) | |
332 | reset_assert(&glue->rst); | |
333 | err_clk: | |
334 | clk_disable(&glue->clk); | |
335 | return ret; | |
28a15ef7 HG |
336 | } |
337 | ||
14b6a07c JT |
338 | static int sunxi_musb_exit(struct musb *musb) |
339 | { | |
340 | struct sunxi_glue *glue = to_sunxi_glue(musb->controller); | |
341 | int ret = 0; | |
342 | ||
343 | if (generic_phy_valid(&glue->phy)) { | |
344 | ret = generic_phy_exit(&glue->phy); | |
345 | if (ret) { | |
7fe8cfdc SA |
346 | dev_dbg(musb->controller, |
347 | "failed to power off usb phy\n"); | |
14b6a07c JT |
348 | return ret; |
349 | } | |
350 | } | |
351 | ||
b9aa0a93 JT |
352 | if (reset_valid(&glue->rst)) |
353 | reset_assert(&glue->rst); | |
354 | clk_disable(&glue->clk); | |
14b6a07c JT |
355 | |
356 | return 0; | |
357 | } | |
358 | ||
aa29b11b JT |
359 | static void sunxi_musb_pre_root_reset_end(struct musb *musb) |
360 | { | |
361 | struct sunxi_glue *glue = to_sunxi_glue(musb->controller); | |
362 | ||
622fd2b9 | 363 | sun4i_usb_phy_set_squelch_detect(&glue->phy, false); |
aa29b11b JT |
364 | } |
365 | ||
366 | static void sunxi_musb_post_root_reset_end(struct musb *musb) | |
367 | { | |
368 | struct sunxi_glue *glue = to_sunxi_glue(musb->controller); | |
369 | ||
622fd2b9 | 370 | sun4i_usb_phy_set_squelch_detect(&glue->phy, true); |
aa29b11b JT |
371 | } |
372 | ||
d42faf31 | 373 | static const struct musb_platform_ops sunxi_musb_ops = { |
28a15ef7 | 374 | .init = sunxi_musb_init, |
14b6a07c | 375 | .exit = sunxi_musb_exit, |
28a15ef7 HG |
376 | .enable = sunxi_musb_enable, |
377 | .disable = sunxi_musb_disable, | |
aa29b11b JT |
378 | .pre_root_reset_end = sunxi_musb_pre_root_reset_end, |
379 | .post_root_reset_end = sunxi_musb_post_root_reset_end, | |
28a15ef7 | 380 | }; |
d42faf31 | 381 | |
ae8b78de JT |
382 | /* Allwinner OTG supports up to 5 endpoints */ |
383 | #define SUNXI_MUSB_MAX_EP_NUM 6 | |
384 | #define SUNXI_MUSB_RAM_BITS 11 | |
385 | ||
97202dd6 JT |
386 | static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = { |
387 | MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512), | |
388 | MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512), | |
389 | MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512), | |
390 | MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512), | |
391 | MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512), | |
392 | MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512), | |
393 | MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512), | |
394 | MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512), | |
395 | MUSB_EP_FIFO_SINGLE(5, FIFO_TX, 512), | |
396 | MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512), | |
397 | }; | |
398 | ||
399 | /* H3/V3s OTG supports only 4 endpoints */ | |
400 | #define SUNXI_MUSB_MAX_EP_NUM_H3 5 | |
401 | ||
402 | static struct musb_fifo_cfg sunxi_musb_mode_cfg_h3[] = { | |
403 | MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512), | |
404 | MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512), | |
405 | MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512), | |
406 | MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512), | |
407 | MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512), | |
408 | MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512), | |
409 | MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512), | |
410 | MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512), | |
411 | }; | |
412 | ||
d42faf31 | 413 | static struct musb_hdrc_config musb_config = { |
97202dd6 JT |
414 | .fifo_cfg = sunxi_musb_mode_cfg, |
415 | .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg), | |
ae8b78de JT |
416 | .multipoint = true, |
417 | .dyn_fifo = true, | |
418 | .num_eps = SUNXI_MUSB_MAX_EP_NUM, | |
419 | .ram_bits = SUNXI_MUSB_RAM_BITS, | |
d42faf31 HG |
420 | }; |
421 | ||
97202dd6 JT |
422 | static struct musb_hdrc_config musb_config_h3 = { |
423 | .fifo_cfg = sunxi_musb_mode_cfg_h3, | |
424 | .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg_h3), | |
425 | .multipoint = true, | |
426 | .dyn_fifo = true, | |
427 | .soft_con = true, | |
428 | .num_eps = SUNXI_MUSB_MAX_EP_NUM_H3, | |
429 | .ram_bits = SUNXI_MUSB_RAM_BITS, | |
430 | }; | |
431 | ||
7c22e26e | 432 | static int musb_usb_probe(struct udevice *dev) |
91183bab | 433 | { |
831cc98b JT |
434 | struct sunxi_glue *glue = dev_get_priv(dev); |
435 | struct musb_host_data *host = &glue->mdata; | |
98424b70 | 436 | struct musb_hdrc_platform_data pdata; |
f4f9896a | 437 | void *base = dev_read_addr_ptr(dev); |
56a20854 | 438 | int ret; |
91183bab | 439 | |
46a3f276 SM |
440 | #ifdef CONFIG_USB_MUSB_HOST |
441 | struct usb_bus_priv *priv = dev_get_uclass_priv(dev); | |
442 | #endif | |
443 | ||
f4f9896a CYT |
444 | if (!base) |
445 | return -EINVAL; | |
446 | ||
97202dd6 JT |
447 | glue->cfg = (struct sunxi_musb_config *)dev_get_driver_data(dev); |
448 | if (!glue->cfg) | |
449 | return -EINVAL; | |
450 | ||
b9aa0a93 JT |
451 | ret = clk_get_by_index(dev, 0, &glue->clk); |
452 | if (ret) { | |
453 | dev_err(dev, "failed to get clock\n"); | |
454 | return ret; | |
455 | } | |
831cc98b | 456 | |
b9aa0a93 JT |
457 | ret = reset_get_by_index(dev, 0, &glue->rst); |
458 | if (ret && ret != -ENOENT) { | |
459 | dev_err(dev, "failed to get reset\n"); | |
460 | return ret; | |
461 | } | |
1034bcc2 | 462 | |
622fd2b9 | 463 | ret = generic_phy_get_by_name(dev, "usb", &glue->phy); |
dd322817 JT |
464 | if (ret) { |
465 | pr_err("failed to get usb PHY\n"); | |
466 | return ret; | |
467 | } | |
468 | ||
98424b70 JT |
469 | memset(&pdata, 0, sizeof(pdata)); |
470 | pdata.power = 250; | |
471 | pdata.platform_ops = &sunxi_musb_ops; | |
97202dd6 | 472 | pdata.config = glue->cfg->config; |
98424b70 | 473 | |
3a61b080 | 474 | #ifdef CONFIG_USB_MUSB_HOST |
46a3f276 SM |
475 | priv->desc_before_addr = true; |
476 | ||
98424b70 JT |
477 | pdata.mode = MUSB_HOST; |
478 | host->host = musb_init_controller(&pdata, &glue->dev, base); | |
38b4a3e1 HG |
479 | if (!host->host) |
480 | return -EIO; | |
481 | ||
56a20854 | 482 | ret = musb_lowlevel_init(host); |
3a61b080 MR |
483 | if (!ret) |
484 | printf("Allwinner mUSB OTG (Host)\n"); | |
485 | #else | |
98424b70 | 486 | pdata.mode = MUSB_PERIPHERAL; |
8b8d59f3 | 487 | host->host = musb_register(&pdata, &glue->dev, base); |
3cbd92da | 488 | if (IS_ERR_OR_NULL(host->host)) |
8b8d59f3 JT |
489 | return -EIO; |
490 | ||
491 | printf("Allwinner mUSB OTG (Peripheral)\n"); | |
3a61b080 | 492 | #endif |
91183bab | 493 | |
56a20854 | 494 | return ret; |
91183bab HG |
495 | } |
496 | ||
7c22e26e | 497 | static int musb_usb_remove(struct udevice *dev) |
91183bab | 498 | { |
831cc98b JT |
499 | struct sunxi_glue *glue = dev_get_priv(dev); |
500 | struct musb_host_data *host = &glue->mdata; | |
91183bab HG |
501 | |
502 | musb_stop(host->host); | |
7c22e26e HG |
503 | free(host->host); |
504 | host->host = NULL; | |
505 | ||
91183bab HG |
506 | return 0; |
507 | } | |
508 | ||
6f68b9ce AP |
509 | /* |
510 | * The Linux driver has a config struct, its fields mapping to this driver | |
511 | * like this: | |
512 | * .hdrc_config: | |
513 | * sunxi_musb_hdrc_config_5eps => musb_config | |
514 | * sunxi_musb_hdrc_config_4eps => musb_config_h3 | |
515 | * .has_sram: always enabled, ideally no-op on SoCs not using it | |
516 | * .has_reset: automatically detected from DT | |
517 | * .no_configdata: handled via Kconfig's CONFIG_USB_MUSB_FIXED_CONFIGDATA | |
518 | */ | |
97202dd6 JT |
519 | static const struct sunxi_musb_config sun4i_a10_cfg = { |
520 | .config = &musb_config, | |
1034bcc2 JT |
521 | }; |
522 | ||
523 | static const struct sunxi_musb_config sun6i_a31_cfg = { | |
524 | .config = &musb_config, | |
97202dd6 JT |
525 | }; |
526 | ||
527 | static const struct sunxi_musb_config sun8i_h3_cfg = { | |
528 | .config = &musb_config_h3, | |
529 | }; | |
530 | ||
6f68b9ce AP |
531 | static const struct sunxi_musb_config suniv_f1c100s_cfg = { |
532 | .config = &musb_config, | |
533 | }; | |
534 | ||
3a61b080 | 535 | static const struct udevice_id sunxi_musb_ids[] = { |
97202dd6 JT |
536 | { .compatible = "allwinner,sun4i-a10-musb", |
537 | .data = (ulong)&sun4i_a10_cfg }, | |
538 | { .compatible = "allwinner,sun6i-a31-musb", | |
1034bcc2 | 539 | .data = (ulong)&sun6i_a31_cfg }, |
97202dd6 | 540 | { .compatible = "allwinner,sun8i-a33-musb", |
1034bcc2 | 541 | .data = (ulong)&sun6i_a31_cfg }, |
97202dd6 JT |
542 | { .compatible = "allwinner,sun8i-h3-musb", |
543 | .data = (ulong)&sun8i_h3_cfg }, | |
6f68b9ce AP |
544 | { .compatible = "allwinner,suniv-f1c100s-musb", |
545 | .data = (ulong)&suniv_f1c100s_cfg }, | |
3a61b080 | 546 | { } |
91183bab | 547 | }; |
91183bab | 548 | |
3a61b080 MR |
549 | U_BOOT_DRIVER(usb_musb) = { |
550 | .name = "sunxi-musb", | |
95de1e2f | 551 | #ifdef CONFIG_USB_MUSB_HOST |
3a61b080 | 552 | .id = UCLASS_USB, |
91183bab | 553 | #else |
01311624 | 554 | .id = UCLASS_USB_GADGET_GENERIC, |
91183bab | 555 | #endif |
3a61b080 MR |
556 | .of_match = sunxi_musb_ids, |
557 | .probe = musb_usb_probe, | |
558 | .remove = musb_usb_remove, | |
559 | #ifdef CONFIG_USB_MUSB_HOST | |
560 | .ops = &musb_usb_ops, | |
561 | #endif | |
8a8d24bd | 562 | .plat_auto = sizeof(struct usb_plat), |
41575d8e | 563 | .priv_auto = sizeof(struct sunxi_glue), |
3a61b080 | 564 | }; |