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