uboot/drivers/usb/ulpi/ulpi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2011 Jana Rapava <fermata7@gmail.com>
   4 * Copyright (C) 2011 CompuLab, Ltd. <www.compulab.co.il>
   5 *
   6 * Authors: Jana Rapava <fermata7@gmail.com>
   7 *          Igor Grinberg <grinberg@compulab.co.il>
   8 *
   9 * Based on:
  10 * linux/drivers/usb/otg/ulpi.c
  11 * Generic ULPI USB transceiver support
  12 *
  13 * Original Copyright follow:
  14 * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
  15 *
  16 * Based on sources from
  17 *
  18 *   Sascha Hauer <s.hauer@pengutronix.de>
  19 *   Freescale Semiconductors
  20 */
  21
  22#include <common.h>
  23#include <exports.h>
  24#include <usb/ulpi.h>
  25
  26#define ULPI_ID_REGS_COUNT      4
  27#define ULPI_TEST_VALUE         0x55    /* 0x55 == 0b01010101 */
  28
  29static struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
  30
  31static int ulpi_integrity_check(struct ulpi_viewport *ulpi_vp)
  32{
  33        u32 val, tval = ULPI_TEST_VALUE;
  34        int err, i;
  35
  36        /* Use the 'special' test value to check all bits */
  37        for (i = 0; i < 2; i++, tval <<= 1) {
  38                err = ulpi_write(ulpi_vp, &ulpi->scratch, tval);
  39                if (err)
  40                        return err;
  41
  42                val = ulpi_read(ulpi_vp, &ulpi->scratch);
  43                if (val != tval) {
  44                        printf("ULPI integrity check failed\n");
  45                        return val;
  46                }
  47        }
  48
  49        return 0;
  50}
  51
  52int ulpi_init(struct ulpi_viewport *ulpi_vp)
  53{
  54        u32 val, id = 0;
  55        u8 *reg = &ulpi->product_id_high;
  56        int i;
  57
  58        /* Assemble ID from four ULPI ID registers (8 bits each). */
  59        for (i = 0; i < ULPI_ID_REGS_COUNT; i++) {
  60                val = ulpi_read(ulpi_vp, reg - i);
  61                if (val == ULPI_ERROR)
  62                        return val;
  63
  64                id = (id << 8) | val;
  65        }
  66
  67        /* Split ID into vendor and product ID. */
  68        debug("ULPI transceiver ID 0x%04x:0x%04x\n", id >> 16, id & 0xffff);
  69
  70        return ulpi_integrity_check(ulpi_vp);
  71}
  72
  73int ulpi_select_transceiver(struct ulpi_viewport *ulpi_vp, unsigned speed)
  74{
  75        u32 tspeed = ULPI_FC_FULL_SPEED;
  76        u32 val;
  77
  78        switch (speed) {
  79        case ULPI_FC_HIGH_SPEED:
  80        case ULPI_FC_FULL_SPEED:
  81        case ULPI_FC_LOW_SPEED:
  82        case ULPI_FC_FS4LS:
  83                tspeed = speed;
  84                break;
  85        default:
  86                printf("ULPI: %s: wrong transceiver speed specified: %u, "
  87                        "falling back to full speed\n", __func__, speed);
  88        }
  89
  90        val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
  91        if (val == ULPI_ERROR)
  92                return val;
  93
  94        /* clear the previous speed setting */
  95        val = (val & ~ULPI_FC_XCVRSEL_MASK) | tspeed;
  96
  97        return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
  98}
  99
 100int ulpi_set_vbus(struct ulpi_viewport *ulpi_vp, int on, int ext_power)
 101{
 102        u32 flags = ULPI_OTG_DRVVBUS;
 103        u8 *reg = on ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
 104
 105        if (ext_power)
 106                flags |= ULPI_OTG_DRVVBUS_EXT;
 107
 108        return ulpi_write(ulpi_vp, reg, flags);
 109}
 110
 111int ulpi_set_vbus_indicator(struct ulpi_viewport *ulpi_vp, int external,
 112                        int passthu, int complement)
 113{
 114        u32 flags, val;
 115        u8 *reg;
 116
 117        reg = external ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
 118        val = ulpi_write(ulpi_vp, reg, ULPI_OTG_EXTVBUSIND);
 119        if (val)
 120                return val;
 121
 122        flags = passthu ? ULPI_IFACE_PASSTHRU : 0;
 123        flags |= complement ? ULPI_IFACE_EXTVBUS_COMPLEMENT : 0;
 124
 125        val = ulpi_read(ulpi_vp, &ulpi->iface_ctrl);
 126        if (val == ULPI_ERROR)
 127                return val;
 128
 129        val = val & ~(ULPI_IFACE_PASSTHRU & ULPI_IFACE_EXTVBUS_COMPLEMENT);
 130        val |= flags;
 131        val = ulpi_write(ulpi_vp, &ulpi->iface_ctrl, val);
 132        if (val)
 133                return val;
 134
 135        return 0;
 136}
 137
 138int ulpi_set_pd(struct ulpi_viewport *ulpi_vp, int enable)
 139{
 140        u32 val = ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN;
 141        u8 *reg = enable ? &ulpi->otg_ctrl_set : &ulpi->otg_ctrl_clear;
 142
 143        return ulpi_write(ulpi_vp, reg, val);
 144}
 145
 146int ulpi_opmode_sel(struct ulpi_viewport *ulpi_vp, unsigned opmode)
 147{
 148        u32 topmode = ULPI_FC_OPMODE_NORMAL;
 149        u32 val;
 150
 151        switch (opmode) {
 152        case ULPI_FC_OPMODE_NORMAL:
 153        case ULPI_FC_OPMODE_NONDRIVING:
 154        case ULPI_FC_OPMODE_DISABLE_NRZI:
 155        case ULPI_FC_OPMODE_NOSYNC_NOEOP:
 156                topmode = opmode;
 157                break;
 158        default:
 159                printf("ULPI: %s: wrong OpMode specified: %u, "
 160                        "falling back to OpMode Normal\n", __func__, opmode);
 161        }
 162
 163        val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
 164        if (val == ULPI_ERROR)
 165                return val;
 166
 167        /* clear the previous opmode setting */
 168        val = (val & ~ULPI_FC_OPMODE_MASK) | topmode;
 169
 170        return ulpi_write(ulpi_vp, &ulpi->function_ctrl, val);
 171}
 172
 173int ulpi_serial_mode_enable(struct ulpi_viewport *ulpi_vp, unsigned smode)
 174{
 175        switch (smode) {
 176        case ULPI_IFACE_6_PIN_SERIAL_MODE:
 177        case ULPI_IFACE_3_PIN_SERIAL_MODE:
 178                break;
 179        default:
 180                printf("ULPI: %s: unrecognized Serial Mode specified: %u\n",
 181                        __func__, smode);
 182                return ULPI_ERROR;
 183        }
 184
 185        return ulpi_write(ulpi_vp, &ulpi->iface_ctrl_set, smode);
 186}
 187
 188int ulpi_suspend(struct ulpi_viewport *ulpi_vp)
 189{
 190        int err;
 191
 192        err = ulpi_write(ulpi_vp, &ulpi->function_ctrl_clear,
 193                        ULPI_FC_SUSPENDM);
 194        if (err)
 195                printf("ULPI: %s: failed writing the suspend bit\n", __func__);
 196
 197        return err;
 198}
 199
 200/*
 201 * Wait for ULPI PHY reset to complete.
 202 * Actual wait for reset must be done in a view port specific way,
 203 * because it involves checking the DIR line.
 204 */
 205static int __ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
 206{
 207        u32 val;
 208        int timeout = CONFIG_USB_ULPI_TIMEOUT;
 209
 210        /* Wait for the RESET bit to become zero */
 211        while (--timeout) {
 212                /*
 213                 * This function is generic and suppose to work
 214                 * with any viewport, so we cheat here and don't check
 215                 * for the error of ulpi_read(), if there is one, then
 216                 * there will be a timeout.
 217                 */
 218                val = ulpi_read(ulpi_vp, &ulpi->function_ctrl);
 219                if (!(val & ULPI_FC_RESET))
 220                        return 0;
 221
 222                udelay(1);
 223        }
 224
 225        printf("ULPI: %s: reset timed out\n", __func__);
 226
 227        return ULPI_ERROR;
 228}
 229int ulpi_reset_wait(struct ulpi_viewport *ulpi_vp)
 230        __attribute__((weak, alias("__ulpi_reset_wait")));
 231
 232int ulpi_reset(struct ulpi_viewport *ulpi_vp)
 233{
 234        int err;
 235
 236        err = ulpi_write(ulpi_vp,
 237                        &ulpi->function_ctrl_set, ULPI_FC_RESET);
 238        if (err) {
 239                printf("ULPI: %s: failed writing reset bit\n", __func__);
 240                return err;
 241        }
 242
 243        return ulpi_reset_wait(ulpi_vp);
 244}
 245