xref: /rk3399_rockchip-uboot/drivers/usb/ulpi/ulpi.c (revision cf9f95f29390c2cdce80bab86d24b002c8d08f58)
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  *
20f93022c3SJana Rapava  * This program is free software; you can redistribute it and/or modify
21f93022c3SJana Rapava  * it under the terms of the GNU General Public License as published by
22f93022c3SJana Rapava  * the Free Software Foundation; either version 2 of the License, or
23f93022c3SJana Rapava  * (at your option) any later version.
24f93022c3SJana Rapava  *
25f93022c3SJana Rapava  * This program is distributed in the hope that it will be useful,
26f93022c3SJana Rapava  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27f93022c3SJana Rapava  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28f93022c3SJana Rapava  * GNU General Public License for more details.
29f93022c3SJana Rapava  */
30f93022c3SJana Rapava 
31f93022c3SJana Rapava #include <common.h>
32f93022c3SJana Rapava #include <exports.h>
33f93022c3SJana Rapava #include <usb/ulpi.h>
34f93022c3SJana Rapava 
35f93022c3SJana Rapava #define ULPI_ID_REGS_COUNT	4
36f93022c3SJana Rapava #define ULPI_TEST_VALUE		0x55	/* 0x55 == 0b01010101 */
37f93022c3SJana Rapava 
38f93022c3SJana Rapava static struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
39f93022c3SJana Rapava 
40f93022c3SJana Rapava static int ulpi_integrity_check(u32 ulpi_viewport)
41f93022c3SJana Rapava {
424256101fSIgor Grinberg 	u32 val, tval = ULPI_TEST_VALUE;
434256101fSIgor Grinberg 	int err, i;
44f93022c3SJana Rapava 
45f93022c3SJana Rapava 	/* Use the 'special' test value to check all bits */
46f93022c3SJana Rapava 	for (i = 0; i < 2; i++, tval <<= 1) {
47f93022c3SJana Rapava 		err = ulpi_write(ulpi_viewport, &ulpi->scratch, tval);
48f93022c3SJana Rapava 		if (err)
49f93022c3SJana Rapava 			return err;
50f93022c3SJana Rapava 
51f93022c3SJana Rapava 		val = ulpi_read(ulpi_viewport, &ulpi->scratch);
52f93022c3SJana Rapava 		if (val != tval) {
53f93022c3SJana Rapava 			printf("ULPI integrity check failed\n");
54f93022c3SJana Rapava 			return val;
55f93022c3SJana Rapava 		}
56f93022c3SJana Rapava 	}
57f93022c3SJana Rapava 
58f93022c3SJana Rapava 	return 0;
59f93022c3SJana Rapava }
60f93022c3SJana Rapava 
61f93022c3SJana Rapava int ulpi_init(u32 ulpi_viewport)
62f93022c3SJana Rapava {
63f93022c3SJana Rapava 	u32 val, id = 0;
64f93022c3SJana Rapava 	u8 *reg = &ulpi->product_id_high;
65f93022c3SJana Rapava 	int i;
66f93022c3SJana Rapava 
67f93022c3SJana Rapava 	/* Assemble ID from four ULPI ID registers (8 bits each). */
68f93022c3SJana Rapava 	for (i = 0; i < ULPI_ID_REGS_COUNT; i++) {
69f93022c3SJana Rapava 		val = ulpi_read(ulpi_viewport, reg - i);
70f93022c3SJana Rapava 		if (val == ULPI_ERROR)
71f93022c3SJana Rapava 			return val;
72f93022c3SJana Rapava 
73f93022c3SJana Rapava 		id = (id << 8) | val;
74f93022c3SJana Rapava 	}
75f93022c3SJana Rapava 
76f93022c3SJana Rapava 	/* Split ID into vendor and product ID. */
77f93022c3SJana Rapava 	debug("ULPI transceiver ID 0x%04x:0x%04x\n", id >> 16, id & 0xffff);
78f93022c3SJana Rapava 
79f93022c3SJana Rapava 	return ulpi_integrity_check(ulpi_viewport);
80f93022c3SJana Rapava }
81f93022c3SJana Rapava 
821113a79bSIgor Grinberg int ulpi_select_transceiver(u32 ulpi_viewport, unsigned speed)
83f93022c3SJana Rapava {
841113a79bSIgor Grinberg 	u32 tspeed = ULPI_FC_FULL_SPEED;
85f93022c3SJana Rapava 	u32 val;
86f93022c3SJana Rapava 
87f93022c3SJana Rapava 	switch (speed) {
88f93022c3SJana Rapava 	case ULPI_FC_HIGH_SPEED:
89f93022c3SJana Rapava 	case ULPI_FC_FULL_SPEED:
90f93022c3SJana Rapava 	case ULPI_FC_LOW_SPEED:
91f93022c3SJana Rapava 	case ULPI_FC_FS4LS:
92f93022c3SJana Rapava 		tspeed = speed;
93f93022c3SJana Rapava 		break;
94f93022c3SJana Rapava 	default:
95*cf9f95f2SIgor Grinberg 		printf("ULPI: %s: wrong transceiver speed specified: %u, "
96*cf9f95f2SIgor Grinberg 			"falling back to full speed\n", __func__, speed);
97f93022c3SJana Rapava 	}
98f93022c3SJana Rapava 
99f93022c3SJana Rapava 	val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl);
100f93022c3SJana Rapava 	if (val == ULPI_ERROR)
101f93022c3SJana Rapava 		return val;
102f93022c3SJana Rapava 
103f93022c3SJana Rapava 	/* clear the previous speed setting */
104f93022c3SJana Rapava 	val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed;
105f93022c3SJana Rapava 
106f93022c3SJana Rapava 	return ulpi_write(ulpi_viewport, &ulpi->function_ctrl, val);
107f93022c3SJana Rapava }
108f93022c3SJana Rapava 
109f93022c3SJana Rapava int ulpi_set_vbus(u32 ulpi_viewport, int on, int ext_power, int ext_ind)
110f93022c3SJana Rapava {
111f93022c3SJana Rapava 	u32 flags = ULPI_OTG_DRVVBUS;
112f93022c3SJana Rapava 	u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
113f93022c3SJana Rapava 
114f93022c3SJana Rapava 	if (ext_power)
115f93022c3SJana Rapava 		flags |= ULPI_OTG_DRVVBUS_EXT;
116f93022c3SJana Rapava 	if (ext_ind)
117f93022c3SJana Rapava 		flags |= ULPI_OTG_EXTVBUSIND;
118f93022c3SJana Rapava 
119f93022c3SJana Rapava 	return ulpi_write(ulpi_viewport, reg, flags);
120f93022c3SJana Rapava }
121f93022c3SJana Rapava 
122f93022c3SJana Rapava int ulpi_set_pd(u32 ulpi_viewport, int enable)
123f93022c3SJana Rapava {
124f93022c3SJana Rapava 	u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN;
125f93022c3SJana Rapava 	u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
126f93022c3SJana Rapava 
127f93022c3SJana Rapava 	return ulpi_write(ulpi_viewport, reg, val);
128f93022c3SJana Rapava }
129f93022c3SJana Rapava 
1301113a79bSIgor Grinberg int ulpi_opmode_sel(u32 ulpi_viewport, unsigned opmode)
131f93022c3SJana Rapava {
1321113a79bSIgor Grinberg 	u32 topmode = ULPI_FC_OPMODE_NORMAL;
133f93022c3SJana Rapava 	u32 val;
134f93022c3SJana Rapava 
135f93022c3SJana Rapava 	switch (opmode) {
136f93022c3SJana Rapava 	case ULPI_FC_OPMODE_NORMAL:
137f93022c3SJana Rapava 	case ULPI_FC_OPMODE_NONDRIVING:
138f93022c3SJana Rapava 	case ULPI_FC_OPMODE_DISABLE_NRZI:
139f93022c3SJana Rapava 	case ULPI_FC_OPMODE_NOSYNC_NOEOP:
140f93022c3SJana Rapava 		topmode = opmode;
141f93022c3SJana Rapava 		break;
142f93022c3SJana Rapava 	default:
143*cf9f95f2SIgor Grinberg 		printf("ULPI: %s: wrong OpMode specified: %u, "
144*cf9f95f2SIgor Grinberg 			"falling back to OpMode Normal\n", __func__, opmode);
145f93022c3SJana Rapava 	}
146f93022c3SJana Rapava 
147f93022c3SJana Rapava 	val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl);
148f93022c3SJana Rapava 	if (val == ULPI_ERROR)
149f93022c3SJana Rapava 		return val;
150f93022c3SJana Rapava 
151f93022c3SJana Rapava 	/* clear the previous opmode setting */
152f93022c3SJana Rapava 	val = (val & ~ULPI_FC_OPMODE_MASK) | topmode;
153f93022c3SJana Rapava 
154f93022c3SJana Rapava 	return ulpi_write(ulpi_viewport, &ulpi->function_ctrl, val);
155f93022c3SJana Rapava }
156f93022c3SJana Rapava 
1571113a79bSIgor Grinberg int ulpi_serial_mode_enable(u32 ulpi_viewport, unsigned smode)
158f93022c3SJana Rapava {
159f93022c3SJana Rapava 	switch (smode) {
160f93022c3SJana Rapava 	case ULPI_IFACE_6_PIN_SERIAL_MODE:
161f93022c3SJana Rapava 	case ULPI_IFACE_3_PIN_SERIAL_MODE:
162f93022c3SJana Rapava 		break;
163f93022c3SJana Rapava 	default:
164*cf9f95f2SIgor Grinberg 		printf("ULPI: %s: unrecognized Serial Mode specified: %u\n",
165*cf9f95f2SIgor Grinberg 			__func__, smode);
166f93022c3SJana Rapava 		return ULPI_ERROR;
167f93022c3SJana Rapava 	}
168f93022c3SJana Rapava 
169f93022c3SJana Rapava 	return ulpi_write(ulpi_viewport, &ulpi->iface_ctrl_set, smode);
170f93022c3SJana Rapava }
171f93022c3SJana Rapava 
172f93022c3SJana Rapava int ulpi_suspend(u32 ulpi_viewport)
173f93022c3SJana Rapava {
1744256101fSIgor Grinberg 	int err;
175f93022c3SJana Rapava 
176f93022c3SJana Rapava 	err = ulpi_write(ulpi_viewport, &ulpi->function_ctrl_clear,
177f93022c3SJana Rapava 			ULPI_FC_SUSPENDM);
178f93022c3SJana Rapava 	if (err)
179f93022c3SJana Rapava 		printf("ULPI: %s: failed writing the suspend bit\n", __func__);
180f93022c3SJana Rapava 
181f93022c3SJana Rapava 	return err;
182f93022c3SJana Rapava }
183f93022c3SJana Rapava 
184f93022c3SJana Rapava /*
185f93022c3SJana Rapava  * Wait for ULPI PHY reset to complete.
186f93022c3SJana Rapava  * Actual wait for reset must be done in a view port specific way,
187f93022c3SJana Rapava  * because it involves checking the DIR line.
188f93022c3SJana Rapava  */
189f93022c3SJana Rapava static int __ulpi_reset_wait(u32 ulpi_viewport)
190f93022c3SJana Rapava {
191f93022c3SJana Rapava 	u32 val;
192f93022c3SJana Rapava 	int timeout = CONFIG_USB_ULPI_TIMEOUT;
193f93022c3SJana Rapava 
194f93022c3SJana Rapava 	/* Wait for the RESET bit to become zero */
195f93022c3SJana Rapava 	while (--timeout) {
196f93022c3SJana Rapava 		/*
197f93022c3SJana Rapava 		 * This function is generic and suppose to work
198f93022c3SJana Rapava 		 * with any viewport, so we cheat here and don't check
199f93022c3SJana Rapava 		 * for the error of ulpi_read(), if there is one, then
200f93022c3SJana Rapava 		 * there will be a timeout.
201f93022c3SJana Rapava 		 */
202f93022c3SJana Rapava 		val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl);
203f93022c3SJana Rapava 		if (!(val & ULPI_FC_RESET))
204f93022c3SJana Rapava 			return 0;
205f93022c3SJana Rapava 
206f93022c3SJana Rapava 		udelay(1);
207f93022c3SJana Rapava 	}
208f93022c3SJana Rapava 
209f93022c3SJana Rapava 	printf("ULPI: %s: reset timed out\n", __func__);
210f93022c3SJana Rapava 
211f93022c3SJana Rapava 	return ULPI_ERROR;
212f93022c3SJana Rapava }
213f93022c3SJana Rapava int ulpi_reset_wait(u32) __attribute__((weak, alias("__ulpi_reset_wait")));
214f93022c3SJana Rapava 
215f93022c3SJana Rapava int ulpi_reset(u32 ulpi_viewport)
216f93022c3SJana Rapava {
2174256101fSIgor Grinberg 	int err;
218f93022c3SJana Rapava 
219f93022c3SJana Rapava 	err = ulpi_write(ulpi_viewport,
220f93022c3SJana Rapava 			&ulpi->function_ctrl_set, ULPI_FC_RESET);
221f93022c3SJana Rapava 	if (err) {
222f93022c3SJana Rapava 		printf("ULPI: %s: failed writing reset bit\n", __func__);
223f93022c3SJana Rapava 		return err;
224f93022c3SJana Rapava 	}
225f93022c3SJana Rapava 
226f93022c3SJana Rapava 	return ulpi_reset_wait(ulpi_viewport);
227f93022c3SJana Rapava }
228