blob: dde2585c58b8419465278701b925de8858a9430b [file] [log] [blame]
Jana Rapavaa5235952011-12-05 11:07:00 +02001/*
2 * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
3 * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
4 *
5 * Authors: Jana Rapava <fermata7@gmail.com>
6 * Igor Grinberg <grinberg@compulab.co.il>
7 *
8 * Based on:
9 * linux/drivers/usb/otg/ulpi.c
10 * Generic ULPI USB transceiver support
11 *
12 * Original Copyright follow:
13 * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
14 *
15 * Based on sources from
16 *
17 * Sascha Hauer <s.hauer@pengutronix.de>
18 * Freescale Semiconductors
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 */
30
31#include <common.h>
32#include <exports.h>
33#include <usb/ulpi.h>
34
35#define ULPI_ID_REGS_COUNT 4
36#define ULPI_TEST_VALUE 0x55 /* 0x55 == 0b01010101 */
37
38static struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
39
Govindraj.R6645d9e2012-02-06 03:55:31 +000040static int ulpi_integrity_check(struct ulpi_viewport *ulpi_vp)
Jana Rapavaa5235952011-12-05 11:07:00 +020041{
Igor Grinberg7b4d7682011-12-12 12:08:33 +020042 u32 val, tval = ULPI_TEST_VALUE;
43 int err, i;
Jana Rapavaa5235952011-12-05 11:07:00 +020044
45 /* Use the 'special' test value to check all bits */
46 for (i = 0; i < 2; i++, tval <<= 1) {
Govindraj.R6645d9e2012-02-06 03:55:31 +000047 err = ulpi_write(ulpi_vp, &ulpi->scratch, tval);
Jana Rapavaa5235952011-12-05 11:07:00 +020048 if (err)
49 return err;
50
Govindraj.R6645d9e2012-02-06 03:55:31 +000051 val = ulpi_read(ulpi_vp, &ulpi->scratch);
Jana Rapavaa5235952011-12-05 11:07:00 +020052 if (val != tval) {
53 printf("ULPI integrity check failed\n");
54 return val;
55 }
56 }
57
58 return 0;
59}
60
Govindraj.R6645d9e2012-02-06 03:55:31 +000061int ulpi_init(struct ulpi_viewport *ulpi_vp)
Jana Rapavaa5235952011-12-05 11:07:00 +020062{
63 u32 val, id = 0;
64 u8 *reg = &ulpi->product_id_high;
65 int i;
66
67 /* Assemble ID from four ULPI ID registers (8 bits each). */
68 for (i = 0; i < ULPI_ID_REGS_COUNT; i++) {
Govindraj.R6645d9e2012-02-06 03:55:31 +000069 val = ulpi_read(ulpi_vp, reg - i);
Jana Rapavaa5235952011-12-05 11:07:00 +020070 if (val == ULPI_ERROR)
71 return val;
72
73 id = (id << 8) | val;
74 }
75
76 /* Split ID into vendor and product ID. */
77 debug("ULPI transceiver ID 0x%04x:0x%04x\n", id >> 16, id & 0xffff);
78
Govindraj.R6645d9e2012-02-06 03:55:31 +000079 return ulpi_integrity_check(ulpi_vp);
Jana Rapavaa5235952011-12-05 11:07:00 +020080}
81
Govindraj.R6645d9e2012-02-06 03:55:31 +000082int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed)
Jana Rapavaa5235952011-12-05 11:07:00 +020083{
Igor Grinberg1e794742011-12-14 08:16:03 +020084 u32 tspeed = ULPI_FC_FULL_SPEED;
Jana Rapavaa5235952011-12-05 11:07:00 +020085 u32 val;
86
87 switch (speed) {
88 case ULPI_FC_HIGH_SPEED:
89 case ULPI_FC_FULL_SPEED:
90 case ULPI_FC_LOW_SPEED:
91 case ULPI_FC_FS4LS:
92 tspeed = speed;
93 break;
94 default:
Igor Grinberg695207a2011-12-12 12:08:34 +020095 printf("ULPI: %s: wrong transceiver speed specified: %u, "
96 "falling back to full speed\n", __func__, speed);
Jana Rapavaa5235952011-12-05 11:07:00 +020097 }
98
Govindraj.R6645d9e2012-02-06 03:55:31 +000099 val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
Jana Rapavaa5235952011-12-05 11:07:00 +0200100 if (val == ULPI_ERROR)
101 return val;
102
103 /* clear the previous speed setting */
104 val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed;
105
Govindraj.R6645d9e2012-02-06 03:55:31 +0000106 return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
Jana Rapavaa5235952011-12-05 11:07:00 +0200107}
108
Govindraj.R6645d9e2012-02-06 03:55:31 +0000109int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power,
110 int ext_ind)
Jana Rapavaa5235952011-12-05 11:07:00 +0200111{
112 u32 flags = ULPI_OTG_DRVVBUS;
113 u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
114
115 if (ext_power)
116 flags |= ULPI_OTG_DRVVBUS_EXT;
117 if (ext_ind)
118 flags |= ULPI_OTG_EXTVBUSIND;
119
Govindraj.R6645d9e2012-02-06 03:55:31 +0000120 return ulpi_write(ulpi_vp, reg, flags);
Jana Rapavaa5235952011-12-05 11:07:00 +0200121}
122
Govindraj.R6645d9e2012-02-06 03:55:31 +0000123int ulpi_set_pd(struct ulpi_viewport *ulpi_vp, int enable)
Jana Rapavaa5235952011-12-05 11:07:00 +0200124{
125 u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN;
126 u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
127
Govindraj.R6645d9e2012-02-06 03:55:31 +0000128 return ulpi_write(ulpi_vp, reg, val);
Jana Rapavaa5235952011-12-05 11:07:00 +0200129}
130
Govindraj.R6645d9e2012-02-06 03:55:31 +0000131int ulpi_opmode_sel(struct ulpi_viewport *ulpi_vp, unsigned opmode)
Jana Rapavaa5235952011-12-05 11:07:00 +0200132{
Igor Grinberg1e794742011-12-14 08:16:03 +0200133 u32 topmode = ULPI_FC_OPMODE_NORMAL;
Jana Rapavaa5235952011-12-05 11:07:00 +0200134 u32 val;
135
136 switch (opmode) {
137 case ULPI_FC_OPMODE_NORMAL:
138 case ULPI_FC_OPMODE_NONDRIVING:
139 case ULPI_FC_OPMODE_DISABLE_NRZI:
140 case ULPI_FC_OPMODE_NOSYNC_NOEOP:
141 topmode = opmode;
142 break;
143 default:
Igor Grinberg695207a2011-12-12 12:08:34 +0200144 printf("ULPI: %s: wrong OpMode specified: %u, "
145 "falling back to OpMode Normal\n", __func__, opmode);
Jana Rapavaa5235952011-12-05 11:07:00 +0200146 }
147
Govindraj.R6645d9e2012-02-06 03:55:31 +0000148 val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
Jana Rapavaa5235952011-12-05 11:07:00 +0200149 if (val == ULPI_ERROR)
150 return val;
151
152 /* clear the previous opmode setting */
153 val = (val & ~ULPI_FC_OPMODE_MASK) | topmode;
154
Govindraj.R6645d9e2012-02-06 03:55:31 +0000155 return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
Jana Rapavaa5235952011-12-05 11:07:00 +0200156}
157
Govindraj.R6645d9e2012-02-06 03:55:31 +0000158int ulpi_serial_mode_enable(struct ulpi_viewport *ulpi_vp, unsigned smode)
Jana Rapavaa5235952011-12-05 11:07:00 +0200159{
160 switch (smode) {
161 case ULPI_IFACE_6_PIN_SERIAL_MODE:
162 case ULPI_IFACE_3_PIN_SERIAL_MODE:
163 break;
164 default:
Igor Grinberg695207a2011-12-12 12:08:34 +0200165 printf("ULPI: %s: unrecognized Serial Mode specified: %u\n",
166 __func__, smode);
Jana Rapavaa5235952011-12-05 11:07:00 +0200167 return ULPI_ERROR;
168 }
169
Govindraj.R6645d9e2012-02-06 03:55:31 +0000170 return ulpi_write(ulpi_vp, &ulpi->iface_ctrl_set, smode);
Jana Rapavaa5235952011-12-05 11:07:00 +0200171}
172
Govindraj.R6645d9e2012-02-06 03:55:31 +0000173int ulpi_suspend(struct ulpi_viewport *ulpi_vp)
Jana Rapavaa5235952011-12-05 11:07:00 +0200174{
Igor Grinberg7b4d7682011-12-12 12:08:33 +0200175 int err;
Jana Rapavaa5235952011-12-05 11:07:00 +0200176
Govindraj.R6645d9e2012-02-06 03:55:31 +0000177 err = ulpi_write(ulpi_vp, &ulpi->function_ctrl_clear,
Jana Rapavaa5235952011-12-05 11:07:00 +0200178 ULPI_FC_SUSPENDM);
179 if (err)
180 printf("ULPI: %s: failed writing the suspend bit\n", __func__);
181
182 return err;
183}
184
185/*
186 * Wait for ULPI PHY reset to complete.
187 * Actual wait for reset must be done in a view port specific way,
188 * because it involves checking the DIR line.
189 */
Govindraj.R6645d9e2012-02-06 03:55:31 +0000190static int __ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
Jana Rapavaa5235952011-12-05 11:07:00 +0200191{
192 u32 val;
193 int timeout = CONFIG_USB_ULPI_TIMEOUT;
194
195 /* Wait for the RESET bit to become zero */
196 while (--timeout) {
197 /*
198 * This function is generic and suppose to work
199 * with any viewport, so we cheat here and don't check
200 * for the error of ulpi_read(), if there is one, then
201 * there will be a timeout.
202 */
Govindraj.R6645d9e2012-02-06 03:55:31 +0000203 val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
Jana Rapavaa5235952011-12-05 11:07:00 +0200204 if (!(val & ULPI_FC_RESET))
205 return 0;
206
207 udelay(1);
208 }
209
210 printf("ULPI: %s: reset timed out\n", __func__);
211
212 return ULPI_ERROR;
213}
Govindraj.R6645d9e2012-02-06 03:55:31 +0000214int ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
215 __attribute__((weak, alias("__ulpi_reset_wait")));
Jana Rapavaa5235952011-12-05 11:07:00 +0200216
Govindraj.R6645d9e2012-02-06 03:55:31 +0000217int ulpi_reset(struct ulpi_viewport *ulpi_vp)
Jana Rapavaa5235952011-12-05 11:07:00 +0200218{
Igor Grinberg7b4d7682011-12-12 12:08:33 +0200219 int err;
Jana Rapavaa5235952011-12-05 11:07:00 +0200220
Govindraj.R6645d9e2012-02-06 03:55:31 +0000221 err = ulpi_write(ulpi_vp,
Jana Rapavaa5235952011-12-05 11:07:00 +0200222 &ulpi->function_ctrl_set, ULPI_FC_RESET);
223 if (err) {
224 printf("ULPI: %s: failed writing reset bit\n", __func__);
225 return err;
226 }
227
Govindraj.R6645d9e2012-02-06 03:55:31 +0000228 return ulpi_reset_wait(ulpi_vp);
Jana Rapavaa5235952011-12-05 11:07:00 +0200229}