1f93022c3SJana Rapava /*
2f93022c3SJana Rapava * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
3f93022c3SJana Rapava * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
4f93022c3SJana Rapava *
5f93022c3SJana Rapava * Authors: Jana Rapava <fermata7@gmail.com>
6f93022c3SJana Rapava * Igor Grinberg <grinberg@compulab.co.il>
7f93022c3SJana Rapava *
8f93022c3SJana Rapava * Based on:
9f93022c3SJana Rapava * linux/drivers/usb/otg/ulpi.c
10f93022c3SJana Rapava * Generic ULPI USB transceiver support
11f93022c3SJana Rapava *
12f93022c3SJana Rapava * Original Copyright follow:
13f93022c3SJana Rapava * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
14f93022c3SJana Rapava *
15f93022c3SJana Rapava * Based on sources from
16f93022c3SJana Rapava *
17f93022c3SJana Rapava * Sascha Hauer <s.hauer@pengutronix.de>
18f93022c3SJana Rapava * Freescale Semiconductors
19f93022c3SJana Rapava *
20*1a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
21f93022c3SJana Rapava */
22f93022c3SJana Rapava
23f93022c3SJana Rapava #include <common.h>
24f93022c3SJana Rapava #include <exports.h>
25f93022c3SJana Rapava #include <usb/ulpi.h>
26f93022c3SJana Rapava
27f93022c3SJana Rapava #define ULPI_ID_REGS_COUNT 4
28f93022c3SJana Rapava #define ULPI_TEST_VALUE 0x55 /* 0x55 == 0b01010101 */
29f93022c3SJana Rapava
30f93022c3SJana Rapava static struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
31f93022c3SJana Rapava
ulpi_integrity_check(struct ulpi_viewport * ulpi_vp)323e6e809fSGovindraj.R static int ulpi_integrity_check(struct ulpi_viewport *ulpi_vp)
33f93022c3SJana Rapava {
344256101fSIgor Grinberg u32 val, tval = ULPI_TEST_VALUE;
354256101fSIgor Grinberg int err, i;
36f93022c3SJana Rapava
37f93022c3SJana Rapava /* Use the 'special' test value to check all bits */
38f93022c3SJana Rapava for (i = 0; i < 2; i++, tval <<= 1) {
393e6e809fSGovindraj.R err = ulpi_write(ulpi_vp, &ulpi->scratch, tval);
40f93022c3SJana Rapava if (err)
41f93022c3SJana Rapava return err;
42f93022c3SJana Rapava
433e6e809fSGovindraj.R val = ulpi_read(ulpi_vp, &ulpi->scratch);
44f93022c3SJana Rapava if (val != tval) {
45f93022c3SJana Rapava printf("ULPI integrity check failed\n");
46f93022c3SJana Rapava return val;
47f93022c3SJana Rapava }
48f93022c3SJana Rapava }
49f93022c3SJana Rapava
50f93022c3SJana Rapava return 0;
51f93022c3SJana Rapava }
52f93022c3SJana Rapava
ulpi_init(struct ulpi_viewport * ulpi_vp)533e6e809fSGovindraj.R int ulpi_init(struct ulpi_viewport *ulpi_vp)
54f93022c3SJana Rapava {
55f93022c3SJana Rapava u32 val, id = 0;
56f93022c3SJana Rapava u8 *reg = &ulpi->product_id_high;
57f93022c3SJana Rapava int i;
58f93022c3SJana Rapava
59f93022c3SJana Rapava /* Assemble ID from four ULPI ID registers (8 bits each). */
60f93022c3SJana Rapava for (i = 0; i < ULPI_ID_REGS_COUNT; i++) {
613e6e809fSGovindraj.R val = ulpi_read(ulpi_vp, reg - i);
62f93022c3SJana Rapava if (val == ULPI_ERROR)
63f93022c3SJana Rapava return val;
64f93022c3SJana Rapava
65f93022c3SJana Rapava id = (id << 8) | val;
66f93022c3SJana Rapava }
67f93022c3SJana Rapava
68f93022c3SJana Rapava /* Split ID into vendor and product ID. */
69f93022c3SJana Rapava debug("ULPI transceiver ID 0x%04x:0x%04x\n", id >> 16, id & 0xffff);
70f93022c3SJana Rapava
713e6e809fSGovindraj.R return ulpi_integrity_check(ulpi_vp);
72f93022c3SJana Rapava }
73f93022c3SJana Rapava
ulpi_select_transceiver(struct ulpi_viewport * ulpi_vp,unsigned speed)743e6e809fSGovindraj.R int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed)
75f93022c3SJana Rapava {
761113a79bSIgor Grinberg u32 tspeed = ULPI_FC_FULL_SPEED;
77f93022c3SJana Rapava u32 val;
78f93022c3SJana Rapava
79f93022c3SJana Rapava switch (speed) {
80f93022c3SJana Rapava case ULPI_FC_HIGH_SPEED:
81f93022c3SJana Rapava case ULPI_FC_FULL_SPEED:
82f93022c3SJana Rapava case ULPI_FC_LOW_SPEED:
83f93022c3SJana Rapava case ULPI_FC_FS4LS:
84f93022c3SJana Rapava tspeed = speed;
85f93022c3SJana Rapava break;
86f93022c3SJana Rapava default:
87cf9f95f2SIgor Grinberg printf("ULPI: %s: wrong transceiver speed specified: %u, "
88cf9f95f2SIgor Grinberg "falling back to full speed\n", __func__, speed);
89f93022c3SJana Rapava }
90f93022c3SJana Rapava
913e6e809fSGovindraj.R val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
92f93022c3SJana Rapava if (val == ULPI_ERROR)
93f93022c3SJana Rapava return val;
94f93022c3SJana Rapava
95f93022c3SJana Rapava /* clear the previous speed setting */
96f93022c3SJana Rapava val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed;
97f93022c3SJana Rapava
983e6e809fSGovindraj.R return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
99f93022c3SJana Rapava }
100f93022c3SJana Rapava
ulpi_set_vbus(struct ulpi_viewport * ulpi_vp,int on,int ext_power)101141288b3SLucas Stach int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power)
102f93022c3SJana Rapava {
103f93022c3SJana Rapava u32 flags = ULPI_OTG_DRVVBUS;
104f93022c3SJana Rapava u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
105f93022c3SJana Rapava
106f93022c3SJana Rapava if (ext_power)
107f93022c3SJana Rapava flags |= ULPI_OTG_DRVVBUS_EXT;
108f93022c3SJana Rapava
1093e6e809fSGovindraj.R return ulpi_write(ulpi_vp, reg, flags);
110f93022c3SJana Rapava }
111f93022c3SJana Rapava
ulpi_set_vbus_indicator(struct ulpi_viewport * ulpi_vp,int external,int passthu,int complement)112141288b3SLucas Stach int ulpi_set_vbus_indicator(struct ulpi_viewport *ulpi_vp, int external,
113141288b3SLucas Stach int passthu, int complement)
114141288b3SLucas Stach {
115141288b3SLucas Stach u32 flags, val;
116141288b3SLucas Stach u8 *reg;
117141288b3SLucas Stach
118141288b3SLucas Stach reg = external ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
119141288b3SLucas Stach val = ulpi_write(ulpi_vp, reg, ULPI_OTG_EXTVBUSIND);
120141288b3SLucas Stach if (val)
121141288b3SLucas Stach return val;
122141288b3SLucas Stach
123141288b3SLucas Stach flags = passthu ? ULPI_IFACE_PASSTHRU : 0;
124141288b3SLucas Stach flags |= complement ? ULPI_IFACE_EXTVBUS_COMPLEMENT : 0;
125141288b3SLucas Stach
126141288b3SLucas Stach val = ulpi_read(ulpi_vp, &ulpi->iface_ctrl);
127141288b3SLucas Stach if (val == ULPI_ERROR)
128141288b3SLucas Stach return val;
129141288b3SLucas Stach
130141288b3SLucas Stach val = val & ~(ULPI_IFACE_PASSTHRU & ULPI_IFACE_EXTVBUS_COMPLEMENT);
131141288b3SLucas Stach val |= flags;
132141288b3SLucas Stach val = ulpi_write(ulpi_vp, &ulpi->iface_ctrl, val);
133141288b3SLucas Stach if (val)
134141288b3SLucas Stach return val;
135141288b3SLucas Stach
136141288b3SLucas Stach return 0;
137141288b3SLucas Stach }
138141288b3SLucas Stach
ulpi_set_pd(struct ulpi_viewport * ulpi_vp,int enable)1393e6e809fSGovindraj.R int ulpi_set_pd(struct ulpi_viewport *ulpi_vp, int enable)
140f93022c3SJana Rapava {
141f93022c3SJana Rapava u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN;
142f93022c3SJana Rapava u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
143f93022c3SJana Rapava
1443e6e809fSGovindraj.R return ulpi_write(ulpi_vp, reg, val);
145f93022c3SJana Rapava }
146f93022c3SJana Rapava
ulpi_opmode_sel(struct ulpi_viewport * ulpi_vp,unsigned opmode)1473e6e809fSGovindraj.R int ulpi_opmode_sel(struct ulpi_viewport *ulpi_vp, unsigned opmode)
148f93022c3SJana Rapava {
1491113a79bSIgor Grinberg u32 topmode = ULPI_FC_OPMODE_NORMAL;
150f93022c3SJana Rapava u32 val;
151f93022c3SJana Rapava
152f93022c3SJana Rapava switch (opmode) {
153f93022c3SJana Rapava case ULPI_FC_OPMODE_NORMAL:
154f93022c3SJana Rapava case ULPI_FC_OPMODE_NONDRIVING:
155f93022c3SJana Rapava case ULPI_FC_OPMODE_DISABLE_NRZI:
156f93022c3SJana Rapava case ULPI_FC_OPMODE_NOSYNC_NOEOP:
157f93022c3SJana Rapava topmode = opmode;
158f93022c3SJana Rapava break;
159f93022c3SJana Rapava default:
160cf9f95f2SIgor Grinberg printf("ULPI: %s: wrong OpMode specified: %u, "
161cf9f95f2SIgor Grinberg "falling back to OpMode Normal\n", __func__, opmode);
162f93022c3SJana Rapava }
163f93022c3SJana Rapava
1643e6e809fSGovindraj.R val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
165f93022c3SJana Rapava if (val == ULPI_ERROR)
166f93022c3SJana Rapava return val;
167f93022c3SJana Rapava
168f93022c3SJana Rapava /* clear the previous opmode setting */
169f93022c3SJana Rapava val = (val & ~ULPI_FC_OPMODE_MASK) | topmode;
170f93022c3SJana Rapava
1713e6e809fSGovindraj.R return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
172f93022c3SJana Rapava }
173f93022c3SJana Rapava
ulpi_serial_mode_enable(struct ulpi_viewport * ulpi_vp,unsigned smode)1743e6e809fSGovindraj.R int ulpi_serial_mode_enable(struct ulpi_viewport *ulpi_vp, unsigned smode)
175f93022c3SJana Rapava {
176f93022c3SJana Rapava switch (smode) {
177f93022c3SJana Rapava case ULPI_IFACE_6_PIN_SERIAL_MODE:
178f93022c3SJana Rapava case ULPI_IFACE_3_PIN_SERIAL_MODE:
179f93022c3SJana Rapava break;
180f93022c3SJana Rapava default:
181cf9f95f2SIgor Grinberg printf("ULPI: %s: unrecognized Serial Mode specified: %u\n",
182cf9f95f2SIgor Grinberg __func__, smode);
183f93022c3SJana Rapava return ULPI_ERROR;
184f93022c3SJana Rapava }
185f93022c3SJana Rapava
1863e6e809fSGovindraj.R return ulpi_write(ulpi_vp, &ulpi->iface_ctrl_set, smode);
187f93022c3SJana Rapava }
188f93022c3SJana Rapava
ulpi_suspend(struct ulpi_viewport * ulpi_vp)1893e6e809fSGovindraj.R int ulpi_suspend(struct ulpi_viewport *ulpi_vp)
190f93022c3SJana Rapava {
1914256101fSIgor Grinberg int err;
192f93022c3SJana Rapava
1933e6e809fSGovindraj.R err = ulpi_write(ulpi_vp, &ulpi->function_ctrl_clear,
194f93022c3SJana Rapava ULPI_FC_SUSPENDM);
195f93022c3SJana Rapava if (err)
196f93022c3SJana Rapava printf("ULPI: %s: failed writing the suspend bit\n", __func__);
197f93022c3SJana Rapava
198f93022c3SJana Rapava return err;
199f93022c3SJana Rapava }
200f93022c3SJana Rapava
201f93022c3SJana Rapava /*
202f93022c3SJana Rapava * Wait for ULPI PHY reset to complete.
203f93022c3SJana Rapava * Actual wait for reset must be done in a view port specific way,
204f93022c3SJana Rapava * because it involves checking the DIR line.
205f93022c3SJana Rapava */
__ulpi_reset_wait(struct ulpi_viewport * ulpi_vp)2063e6e809fSGovindraj.R static int __ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
207f93022c3SJana Rapava {
208f93022c3SJana Rapava u32 val;
209f93022c3SJana Rapava int timeout = CONFIG_USB_ULPI_TIMEOUT;
210f93022c3SJana Rapava
211f93022c3SJana Rapava /* Wait for the RESET bit to become zero */
212f93022c3SJana Rapava while (--timeout) {
213f93022c3SJana Rapava /*
214f93022c3SJana Rapava * This function is generic and suppose to work
215f93022c3SJana Rapava * with any viewport, so we cheat here and don't check
216f93022c3SJana Rapava * for the error of ulpi_read(), if there is one, then
217f93022c3SJana Rapava * there will be a timeout.
218f93022c3SJana Rapava */
2193e6e809fSGovindraj.R val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
220f93022c3SJana Rapava if (!(val & ULPI_FC_RESET))
221f93022c3SJana Rapava return 0;
222f93022c3SJana Rapava
223f93022c3SJana Rapava udelay(1);
224f93022c3SJana Rapava }
225f93022c3SJana Rapava
226f93022c3SJana Rapava printf("ULPI: %s: reset timed out\n", __func__);
227f93022c3SJana Rapava
228f93022c3SJana Rapava return ULPI_ERROR;
229f93022c3SJana Rapava }
2303e6e809fSGovindraj.R int ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
2313e6e809fSGovindraj.R __attribute__((weak, alias("__ulpi_reset_wait")));
232f93022c3SJana Rapava
ulpi_reset(struct ulpi_viewport * ulpi_vp)2333e6e809fSGovindraj.R int ulpi_reset(struct ulpi_viewport *ulpi_vp)
234f93022c3SJana Rapava {
2354256101fSIgor Grinberg int err;
236f93022c3SJana Rapava
2373e6e809fSGovindraj.R err = ulpi_write(ulpi_vp,
238f93022c3SJana Rapava &ulpi->function_ctrl_set, ULPI_FC_RESET);
239f93022c3SJana Rapava if (err) {
240f93022c3SJana Rapava printf("ULPI: %s: failed writing reset bit\n", __func__);
241f93022c3SJana Rapava return err;
242f93022c3SJana Rapava }
243f93022c3SJana Rapava
2443e6e809fSGovindraj.R return ulpi_reset_wait(ulpi_vp);
245f93022c3SJana Rapava }
246