1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2f93022c3SJana Rapava /*
3f93022c3SJana Rapava * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
4f93022c3SJana Rapava * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
5f93022c3SJana Rapava *
6f93022c3SJana Rapava * Authors: Jana Rapava <fermata7@gmail.com>
7f93022c3SJana Rapava * Igor Grinberg <grinberg@compulab.co.il>
8f93022c3SJana Rapava *
9f93022c3SJana Rapava * Based on:
10f93022c3SJana Rapava * linux/drivers/usb/otg/ulpi.c
11f93022c3SJana Rapava * Generic ULPI USB transceiver support
12f93022c3SJana Rapava *
13f93022c3SJana Rapava * Original Copyright follow:
14f93022c3SJana Rapava * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
15f93022c3SJana Rapava *
16f93022c3SJana Rapava * Based on sources from
17f93022c3SJana Rapava *
18f93022c3SJana Rapava * Sascha Hauer <s.hauer@pengutronix.de>
19f93022c3SJana Rapava * Freescale Semiconductors
20f93022c3SJana Rapava */
21f93022c3SJana Rapava
22f93022c3SJana Rapava #include <common.h>
23f93022c3SJana Rapava #include <exports.h>
24f93022c3SJana Rapava #include <usb/ulpi.h>
25f93022c3SJana Rapava
26f93022c3SJana Rapava #define ULPI_ID_REGS_COUNT 4
27f93022c3SJana Rapava #define ULPI_TEST_VALUE 0x55 /* 0x55 == 0b01010101 */
28f93022c3SJana Rapava
29f93022c3SJana Rapava static struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
30f93022c3SJana Rapava
ulpi_integrity_check(struct ulpi_viewport * ulpi_vp)313e6e809fSGovindraj.R static int ulpi_integrity_check(struct ulpi_viewport *ulpi_vp)
32f93022c3SJana Rapava {
334256101fSIgor Grinberg u32 val, tval = ULPI_TEST_VALUE;
344256101fSIgor Grinberg int err, i;
35f93022c3SJana Rapava
36f93022c3SJana Rapava /* Use the 'special' test value to check all bits */
37f93022c3SJana Rapava for (i = 0; i < 2; i++, tval <<= 1) {
383e6e809fSGovindraj.R err = ulpi_write(ulpi_vp, &ulpi->scratch, tval);
39f93022c3SJana Rapava if (err)
40f93022c3SJana Rapava return err;
41f93022c3SJana Rapava
423e6e809fSGovindraj.R val = ulpi_read(ulpi_vp, &ulpi->scratch);
43f93022c3SJana Rapava if (val != tval) {
44f93022c3SJana Rapava printf("ULPI integrity check failed\n");
45f93022c3SJana Rapava return val;
46f93022c3SJana Rapava }
47f93022c3SJana Rapava }
48f93022c3SJana Rapava
49f93022c3SJana Rapava return 0;
50f93022c3SJana Rapava }
51f93022c3SJana Rapava
ulpi_init(struct ulpi_viewport * ulpi_vp)523e6e809fSGovindraj.R int ulpi_init(struct ulpi_viewport *ulpi_vp)
53f93022c3SJana Rapava {
54f93022c3SJana Rapava u32 val, id = 0;
55f93022c3SJana Rapava u8 *reg = &ulpi->product_id_high;
56f93022c3SJana Rapava int i;
57f93022c3SJana Rapava
58f93022c3SJana Rapava /* Assemble ID from four ULPI ID registers (8 bits each). */
59f93022c3SJana Rapava for (i = 0; i < ULPI_ID_REGS_COUNT; i++) {
603e6e809fSGovindraj.R val = ulpi_read(ulpi_vp, reg - i);
61f93022c3SJana Rapava if (val == ULPI_ERROR)
62f93022c3SJana Rapava return val;
63f93022c3SJana Rapava
64f93022c3SJana Rapava id = (id << 8) | val;
65f93022c3SJana Rapava }
66f93022c3SJana Rapava
67f93022c3SJana Rapava /* Split ID into vendor and product ID. */
68f93022c3SJana Rapava debug("ULPI transceiver ID 0x%04x:0x%04x\n", id >> 16, id & 0xffff);
69f93022c3SJana Rapava
703e6e809fSGovindraj.R return ulpi_integrity_check(ulpi_vp);
71f93022c3SJana Rapava }
72f93022c3SJana Rapava
ulpi_select_transceiver(struct ulpi_viewport * ulpi_vp,unsigned speed)733e6e809fSGovindraj.R int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed)
74f93022c3SJana Rapava {
751113a79bSIgor Grinberg u32 tspeed = ULPI_FC_FULL_SPEED;
76f93022c3SJana Rapava u32 val;
77f93022c3SJana Rapava
78f93022c3SJana Rapava switch (speed) {
79f93022c3SJana Rapava case ULPI_FC_HIGH_SPEED:
80f93022c3SJana Rapava case ULPI_FC_FULL_SPEED:
81f93022c3SJana Rapava case ULPI_FC_LOW_SPEED:
82f93022c3SJana Rapava case ULPI_FC_FS4LS:
83f93022c3SJana Rapava tspeed = speed;
84f93022c3SJana Rapava break;
85f93022c3SJana Rapava default:
86cf9f95f2SIgor Grinberg printf("ULPI: %s: wrong transceiver speed specified: %u, "
87cf9f95f2SIgor Grinberg "falling back to full speed\n", __func__, speed);
88f93022c3SJana Rapava }
89f93022c3SJana Rapava
903e6e809fSGovindraj.R val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
91f93022c3SJana Rapava if (val == ULPI_ERROR)
92f93022c3SJana Rapava return val;
93f93022c3SJana Rapava
94f93022c3SJana Rapava /* clear the previous speed setting */
95f93022c3SJana Rapava val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed;
96f93022c3SJana Rapava
973e6e809fSGovindraj.R return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
98f93022c3SJana Rapava }
99f93022c3SJana Rapava
ulpi_set_vbus(struct ulpi_viewport * ulpi_vp,int on,int ext_power)100141288b3SLucas Stach int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power)
101f93022c3SJana Rapava {
102f93022c3SJana Rapava u32 flags = ULPI_OTG_DRVVBUS;
103f93022c3SJana Rapava u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
104f93022c3SJana Rapava
105f93022c3SJana Rapava if (ext_power)
106f93022c3SJana Rapava flags |= ULPI_OTG_DRVVBUS_EXT;
107f93022c3SJana Rapava
1083e6e809fSGovindraj.R return ulpi_write(ulpi_vp, reg, flags);
109f93022c3SJana Rapava }
110f93022c3SJana Rapava
ulpi_set_vbus_indicator(struct ulpi_viewport * ulpi_vp,int external,int passthu,int complement)111141288b3SLucas Stach int ulpi_set_vbus_indicator(struct ulpi_viewport *ulpi_vp, int external,
112141288b3SLucas Stach int passthu, int complement)
113141288b3SLucas Stach {
114141288b3SLucas Stach u32 flags, val;
115141288b3SLucas Stach u8 *reg;
116141288b3SLucas Stach
117141288b3SLucas Stach reg = external ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
118141288b3SLucas Stach val = ulpi_write(ulpi_vp, reg, ULPI_OTG_EXTVBUSIND);
119141288b3SLucas Stach if (val)
120141288b3SLucas Stach return val;
121141288b3SLucas Stach
122141288b3SLucas Stach flags = passthu ? ULPI_IFACE_PASSTHRU : 0;
123141288b3SLucas Stach flags |= complement ? ULPI_IFACE_EXTVBUS_COMPLEMENT : 0;
124141288b3SLucas Stach
125141288b3SLucas Stach val = ulpi_read(ulpi_vp, &ulpi->iface_ctrl);
126141288b3SLucas Stach if (val == ULPI_ERROR)
127141288b3SLucas Stach return val;
128141288b3SLucas Stach
129141288b3SLucas Stach val = val & ~(ULPI_IFACE_PASSTHRU & ULPI_IFACE_EXTVBUS_COMPLEMENT);
130141288b3SLucas Stach val |= flags;
131141288b3SLucas Stach val = ulpi_write(ulpi_vp, &ulpi->iface_ctrl, val);
132141288b3SLucas Stach if (val)
133141288b3SLucas Stach return val;
134141288b3SLucas Stach
135141288b3SLucas Stach return 0;
136141288b3SLucas Stach }
137141288b3SLucas Stach
ulpi_set_pd(struct ulpi_viewport * ulpi_vp,int enable)1383e6e809fSGovindraj.R int ulpi_set_pd(struct ulpi_viewport *ulpi_vp, int enable)
139f93022c3SJana Rapava {
140f93022c3SJana Rapava u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN;
141f93022c3SJana Rapava u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
142f93022c3SJana Rapava
1433e6e809fSGovindraj.R return ulpi_write(ulpi_vp, reg, val);
144f93022c3SJana Rapava }
145f93022c3SJana Rapava
ulpi_opmode_sel(struct ulpi_viewport * ulpi_vp,unsigned opmode)1463e6e809fSGovindraj.R int ulpi_opmode_sel(struct ulpi_viewport *ulpi_vp, unsigned opmode)
147f93022c3SJana Rapava {
1481113a79bSIgor Grinberg u32 topmode = ULPI_FC_OPMODE_NORMAL;
149f93022c3SJana Rapava u32 val;
150f93022c3SJana Rapava
151f93022c3SJana Rapava switch (opmode) {
152f93022c3SJana Rapava case ULPI_FC_OPMODE_NORMAL:
153f93022c3SJana Rapava case ULPI_FC_OPMODE_NONDRIVING:
154f93022c3SJana Rapava case ULPI_FC_OPMODE_DISABLE_NRZI:
155f93022c3SJana Rapava case ULPI_FC_OPMODE_NOSYNC_NOEOP:
156f93022c3SJana Rapava topmode = opmode;
157f93022c3SJana Rapava break;
158f93022c3SJana Rapava default:
159cf9f95f2SIgor Grinberg printf("ULPI: %s: wrong OpMode specified: %u, "
160cf9f95f2SIgor Grinberg "falling back to OpMode Normal\n", __func__, opmode);
161f93022c3SJana Rapava }
162f93022c3SJana Rapava
1633e6e809fSGovindraj.R val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
164f93022c3SJana Rapava if (val == ULPI_ERROR)
165f93022c3SJana Rapava return val;
166f93022c3SJana Rapava
167f93022c3SJana Rapava /* clear the previous opmode setting */
168f93022c3SJana Rapava val = (val & ~ULPI_FC_OPMODE_MASK) | topmode;
169f93022c3SJana Rapava
1703e6e809fSGovindraj.R return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
171f93022c3SJana Rapava }
172f93022c3SJana Rapava
ulpi_serial_mode_enable(struct ulpi_viewport * ulpi_vp,unsigned smode)1733e6e809fSGovindraj.R int ulpi_serial_mode_enable(struct ulpi_viewport *ulpi_vp, unsigned smode)
174f93022c3SJana Rapava {
175f93022c3SJana Rapava switch (smode) {
176f93022c3SJana Rapava case ULPI_IFACE_6_PIN_SERIAL_MODE:
177f93022c3SJana Rapava case ULPI_IFACE_3_PIN_SERIAL_MODE:
178f93022c3SJana Rapava break;
179f93022c3SJana Rapava default:
180cf9f95f2SIgor Grinberg printf("ULPI: %s: unrecognized Serial Mode specified: %u\n",
181cf9f95f2SIgor Grinberg __func__, smode);
182f93022c3SJana Rapava return ULPI_ERROR;
183f93022c3SJana Rapava }
184f93022c3SJana Rapava
1853e6e809fSGovindraj.R return ulpi_write(ulpi_vp, &ulpi->iface_ctrl_set, smode);
186f93022c3SJana Rapava }
187f93022c3SJana Rapava
ulpi_suspend(struct ulpi_viewport * ulpi_vp)1883e6e809fSGovindraj.R int ulpi_suspend(struct ulpi_viewport *ulpi_vp)
189f93022c3SJana Rapava {
1904256101fSIgor Grinberg int err;
191f93022c3SJana Rapava
1923e6e809fSGovindraj.R err = ulpi_write(ulpi_vp, &ulpi->function_ctrl_clear,
193f93022c3SJana Rapava ULPI_FC_SUSPENDM);
194f93022c3SJana Rapava if (err)
195f93022c3SJana Rapava printf("ULPI: %s: failed writing the suspend bit\n", __func__);
196f93022c3SJana Rapava
197f93022c3SJana Rapava return err;
198f93022c3SJana Rapava }
199f93022c3SJana Rapava
200f93022c3SJana Rapava /*
201f93022c3SJana Rapava * Wait for ULPI PHY reset to complete.
202f93022c3SJana Rapava * Actual wait for reset must be done in a view port specific way,
203f93022c3SJana Rapava * because it involves checking the DIR line.
204f93022c3SJana Rapava */
__ulpi_reset_wait(struct ulpi_viewport * ulpi_vp)2053e6e809fSGovindraj.R static int __ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
206f93022c3SJana Rapava {
207f93022c3SJana Rapava u32 val;
208f93022c3SJana Rapava int timeout = CONFIG_USB_ULPI_TIMEOUT;
209f93022c3SJana Rapava
210f93022c3SJana Rapava /* Wait for the RESET bit to become zero */
211f93022c3SJana Rapava while (--timeout) {
212f93022c3SJana Rapava /*
213f93022c3SJana Rapava * This function is generic and suppose to work
214f93022c3SJana Rapava * with any viewport, so we cheat here and don't check
215f93022c3SJana Rapava * for the error of ulpi_read(), if there is one, then
216f93022c3SJana Rapava * there will be a timeout.
217f93022c3SJana Rapava */
2183e6e809fSGovindraj.R val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
219f93022c3SJana Rapava if (!(val & ULPI_FC_RESET))
220f93022c3SJana Rapava return 0;
221f93022c3SJana Rapava
222f93022c3SJana Rapava udelay(1);
223f93022c3SJana Rapava }
224f93022c3SJana Rapava
225f93022c3SJana Rapava printf("ULPI: %s: reset timed out\n", __func__);
226f93022c3SJana Rapava
227f93022c3SJana Rapava return ULPI_ERROR;
228f93022c3SJana Rapava }
2293e6e809fSGovindraj.R int ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
2303e6e809fSGovindraj.R __attribute__((weak, alias("__ulpi_reset_wait")));
231f93022c3SJana Rapava
ulpi_reset(struct ulpi_viewport * ulpi_vp)2323e6e809fSGovindraj.R int ulpi_reset(struct ulpi_viewport *ulpi_vp)
233f93022c3SJana Rapava {
2344256101fSIgor Grinberg int err;
235f93022c3SJana Rapava
2363e6e809fSGovindraj.R err = ulpi_write(ulpi_vp,
237f93022c3SJana Rapava &ulpi->function_ctrl_set, ULPI_FC_RESET);
238f93022c3SJana Rapava if (err) {
239f93022c3SJana Rapava printf("ULPI: %s: failed writing reset bit\n", __func__);
240f93022c3SJana Rapava return err;
241f93022c3SJana Rapava }
242f93022c3SJana Rapava
2433e6e809fSGovindraj.R return ulpi_reset_wait(ulpi_vp);
244f93022c3SJana Rapava }
245