diff options
author | Wolfgang Denk <wd@denx.de> | 2011-12-12 07:58:58 +0100 |
---|---|---|
committer | Wolfgang Denk <wd@denx.de> | 2011-12-12 07:58:58 +0100 |
commit | b2eb7d9bc6032e16b7dd898f7c0ea654f63b61db (patch) | |
tree | b8b649483183d93dedfcb5512d0b9720aa91644f /drivers/usb/ulpi/ulpi.c | |
parent | 4f1a2cd1637027f31de7796aedb1fa5fc0ec0f97 (diff) | |
parent | d98d8bc1c913a5a1aea6b17365f90c430d1fc95a (diff) | |
download | u-boot-imx-b2eb7d9bc6032e16b7dd898f7c0ea654f63b61db.zip u-boot-imx-b2eb7d9bc6032e16b7dd898f7c0ea654f63b61db.tar.gz u-boot-imx-b2eb7d9bc6032e16b7dd898f7c0ea654f63b61db.tar.bz2 |
Merge branch 'master' of git://git.denx.de/u-boot-usb
* 'master' of git://git.denx.de/u-boot-usb:
USB: efikamx: Enable USB on EfikaMX and EfikaSB
USB: Add generic ULPI layer and a viewport
USB: EHCI: Allow EHCI post-powerup configuration in board files
USB: mx51evk: add end enable USB host support on port 1
USB: mx53loco: add end enable USB host support on port 1
USB: MX5: Add MX5 usb post-init callback
USB: MX5: Abstract out mx51 USB pixmux configuration
USB: MX5: add generic USB EHCI support for mx51 and mx53
USB: MX5: add helper functions to enable USB clocks
usb:gadget:s5p Enable the USB Gadget framework at GONI
usb:gadget:s5p USB Device Controller (UDC) implementation
ehci: speed up initialization
usb: add help for missing start subcommand
cosmetic: remove excess whitespace from usb command help
usb: align usb_endpoint_descriptor to 16-bit boundary
usbtty: init endpoints prior to startup events
pxa: convert pxa27x_udc to use read and write functions
pxa: activate the first usb host port on pxa27x by default
pxa: fix usb host register mismatch
ehci-fsl: correct size of ehci caplength
USB: Add usb_event_poll() to get keyboards working with EHCI
USB: gadaget: add Marvell controller support
USB: Fix complaints about strict aliasing in OHCI-HCD
USB: Drop dead code from usb_kbd.c
USB: Rework usb_kbd.c
USB: Add functionality to poll the USB keyboard via control EP
Diffstat (limited to 'drivers/usb/ulpi/ulpi.c')
-rw-r--r-- | drivers/usb/ulpi/ulpi.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/drivers/usb/ulpi/ulpi.c b/drivers/usb/ulpi/ulpi.c new file mode 100644 index 0000000..805e29d --- /dev/null +++ b/drivers/usb/ulpi/ulpi.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com> + * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il> + * + * Authors: Jana Rapava <fermata7@gmail.com> + * Igor Grinberg <grinberg@compulab.co.il> + * + * Based on: + * linux/drivers/usb/otg/ulpi.c + * Generic ULPI USB transceiver support + * + * Original Copyright follow: + * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de> + * + * Based on sources from + * + * Sascha Hauer <s.hauer@pengutronix.de> + * Freescale Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <common.h> +#include <exports.h> +#include <usb/ulpi.h> + +#define ULPI_ID_REGS_COUNT 4 +#define ULPI_TEST_VALUE 0x55 /* 0x55 == 0b01010101 */ + +static struct ulpi_regs *ulpi = (struct ulpi_regs *)0; + +static int ulpi_integrity_check(u32 ulpi_viewport) +{ + u32 err, val, tval = ULPI_TEST_VALUE; + int i; + + /* Use the 'special' test value to check all bits */ + for (i = 0; i < 2; i++, tval <<= 1) { + err = ulpi_write(ulpi_viewport, &ulpi->scratch, tval); + if (err) + return err; + + val = ulpi_read(ulpi_viewport, &ulpi->scratch); + if (val != tval) { + printf("ULPI integrity check failed\n"); + return val; + } + } + + return 0; +} + +int ulpi_init(u32 ulpi_viewport) +{ + u32 val, id = 0; + u8 *reg = &ulpi->product_id_high; + int i; + + /* Assemble ID from four ULPI ID registers (8 bits each). */ + for (i = 0; i < ULPI_ID_REGS_COUNT; i++) { + val = ulpi_read(ulpi_viewport, reg - i); + if (val == ULPI_ERROR) + return val; + + id = (id << 8) | val; + } + + /* Split ID into vendor and product ID. */ + debug("ULPI transceiver ID 0x%04x:0x%04x\n", id >> 16, id & 0xffff); + + return ulpi_integrity_check(ulpi_viewport); +} + +int ulpi_select_transceiver(u32 ulpi_viewport, u8 speed) +{ + u8 tspeed = ULPI_FC_FULL_SPEED; + u32 val; + + switch (speed) { + case ULPI_FC_HIGH_SPEED: + case ULPI_FC_FULL_SPEED: + case ULPI_FC_LOW_SPEED: + case ULPI_FC_FS4LS: + tspeed = speed; + break; + default: + printf("ULPI: %s: wrong transceiver speed specified, " + "falling back to full speed\n", __func__); + } + + val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl); + if (val == ULPI_ERROR) + return val; + + /* clear the previous speed setting */ + val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed; + + return ulpi_write(ulpi_viewport, &ulpi->function_ctrl, val); +} + +int ulpi_set_vbus(u32 ulpi_viewport, int on, int ext_power, int ext_ind) +{ + u32 flags = ULPI_OTG_DRVVBUS; + u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear; + + if (ext_power) + flags |= ULPI_OTG_DRVVBUS_EXT; + if (ext_ind) + flags |= ULPI_OTG_EXTVBUSIND; + + return ulpi_write(ulpi_viewport, reg, flags); +} + +int ulpi_set_pd(u32 ulpi_viewport, int enable) +{ + u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN; + u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear; + + return ulpi_write(ulpi_viewport, reg, val); +} + +int ulpi_opmode_sel(u32 ulpi_viewport, u8 opmode) +{ + u8 topmode = ULPI_FC_OPMODE_NORMAL; + u32 val; + + switch (opmode) { + case ULPI_FC_OPMODE_NORMAL: + case ULPI_FC_OPMODE_NONDRIVING: + case ULPI_FC_OPMODE_DISABLE_NRZI: + case ULPI_FC_OPMODE_NOSYNC_NOEOP: + topmode = opmode; + break; + default: + printf("ULPI: %s: wrong OpMode specified, " + "falling back to OpMode Normal\n", __func__); + } + + val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl); + if (val == ULPI_ERROR) + return val; + + /* clear the previous opmode setting */ + val = (val & ~ULPI_FC_OPMODE_MASK) | topmode; + + return ulpi_write(ulpi_viewport, &ulpi->function_ctrl, val); +} + +int ulpi_serial_mode_enable(u32 ulpi_viewport, u8 smode) +{ + switch (smode) { + case ULPI_IFACE_6_PIN_SERIAL_MODE: + case ULPI_IFACE_3_PIN_SERIAL_MODE: + break; + default: + printf("ULPI: %s: unrecognized Serial Mode specified\n", + __func__); + return ULPI_ERROR; + } + + return ulpi_write(ulpi_viewport, &ulpi->iface_ctrl_set, smode); +} + +int ulpi_suspend(u32 ulpi_viewport) +{ + u32 err; + + err = ulpi_write(ulpi_viewport, &ulpi->function_ctrl_clear, + ULPI_FC_SUSPENDM); + if (err) + printf("ULPI: %s: failed writing the suspend bit\n", __func__); + + return err; +} + +/* + * Wait for ULPI PHY reset to complete. + * Actual wait for reset must be done in a view port specific way, + * because it involves checking the DIR line. + */ +static int __ulpi_reset_wait(u32 ulpi_viewport) +{ + u32 val; + int timeout = CONFIG_USB_ULPI_TIMEOUT; + + /* Wait for the RESET bit to become zero */ + while (--timeout) { + /* + * This function is generic and suppose to work + * with any viewport, so we cheat here and don't check + * for the error of ulpi_read(), if there is one, then + * there will be a timeout. + */ + val = ulpi_read(ulpi_viewport, &ulpi->function_ctrl); + if (!(val & ULPI_FC_RESET)) + return 0; + + udelay(1); + } + + printf("ULPI: %s: reset timed out\n", __func__); + + return ULPI_ERROR; +} +int ulpi_reset_wait(u32) __attribute__((weak, alias("__ulpi_reset_wait"))); + +int ulpi_reset(u32 ulpi_viewport) +{ + u32 err; + + err = ulpi_write(ulpi_viewport, + &ulpi->function_ctrl_set, ULPI_FC_RESET); + if (err) { + printf("ULPI: %s: failed writing reset bit\n", __func__); + return err; + } + + return ulpi_reset_wait(ulpi_viewport); +} |