uboot/drivers/usb/ulpi/ulpi.c
<<
>>
Prefs
   1/*
   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
  40static int ulpi_integrity_check(struct ulpi_viewport *ulpi_vp)
  41{
  42        u32 val, tval = ULPI_TEST_VALUE;
  43        int err, i;
  44
  45        /* Use the 'special' test value to check all bits */
  46        for (i = 0; i < 2; i++, tval <<= 1) {
  47                err = ulpi_write(ulpi_vp, &ulpi->scratch, tval);
  48                if (err)
  49                        return err;
  50
  51                val = ulpi_read(ulpi_vp, &ulpi->scratch);
  52                if (val != tval) {
  53                        printf("ULPI integrity check failed\n");
  54                        return val;
  55                }
  56        }
  57
  58        return 0;
  59}
  60
  61int ulpi_init(struct ulpi_viewport *ulpi_vp)
  62{
  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++) {
  69                val = ulpi_read(ulpi_vp, reg - i);
  70                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
  79        return ulpi_integrity_check(ulpi_vp);
  80}
  81
  82int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed)
  83{
  84        u32 tspeed = ULPI_FC_FULL_SPEED;
  85        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:
  95                printf("ULPI: %s: wrong transceiver speed specified: %u, "
  96                        "falling back to full speed\n", __func__, speed);
  97        }
  98
  99        val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
 100        if (val == ULPI_ERROR)
 101                return val;
 102
 103        /* clear the previous speed setting */
 104        val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed;
 105
 106        return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
 107}
 108
 109int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power,
 110                        int ext_ind)
 111{
 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
 120        return ulpi_write(ulpi_vp, reg, flags);
 121}
 122
 123int ulpi_set_pd(struct ulpi_viewport *ulpi_vp, int enable)
 124{
 125        u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN;
 126        u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
 127
 128        return ulpi_write(ulpi_vp, reg, val);
 129}
 130
 131int ulpi_opmode_sel(struct ulpi_viewport *ulpi_vp, unsigned opmode)
 132{
 133        u32 topmode = ULPI_FC_OPMODE_NORMAL;
 134        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:
 144                printf("ULPI: %s: wrong OpMode specified: %u, "
 145                        "falling back to OpMode Normal\n", __func__, opmode);
 146        }
 147
 148        val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
 149        if (val == ULPI_ERROR)
 150                return val;
 151
 152        /* clear the previous opmode setting */
 153        val = (val & ~ULPI_FC_OPMODE_MASK) | topmode;
 154
 155        return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
 156}
 157
 158int ulpi_serial_mode_enable(struct ulpi_viewport *ulpi_vp, unsigned smode)
 159{
 160        switch (smode) {
 161        case ULPI_IFACE_6_PIN_SERIAL_MODE:
 162        case ULPI_IFACE_3_PIN_SERIAL_MODE:
 163                break;
 164        default:
 165                printf("ULPI: %s: unrecognized Serial Mode specified: %u\n",
 166                        __func__, smode);
 167                return ULPI_ERROR;
 168        }
 169
 170        return ulpi_write(ulpi_vp, &ulpi->iface_ctrl_set, smode);
 171}
 172
 173int ulpi_suspend(struct ulpi_viewport *ulpi_vp)
 174{
 175        int err;
 176
 177        err = ulpi_write(ulpi_vp, &ulpi->function_ctrl_clear,
 178                        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 */
 190static int __ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
 191{
 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                 */
 203                val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
 204                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}
 214int ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
 215        __attribute__((weak, alias("__ulpi_reset_wait")));
 216
 217int ulpi_reset(struct ulpi_viewport *ulpi_vp)
 218{
 219        int err;
 220
 221        err = ulpi_write(ulpi_vp,
 222                        &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
 228        return ulpi_reset_wait(ulpi_vp);
 229}
 230