linux/arch/arm/plat-mxc/ulpi.c
<<
>>
Prefs
   1/*
   2 * Copyright 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
   3 * Copyright 2009 Daniel Mack <daniel@caiaq.de>
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License
   7 * as published by the Free Software Foundation; either version 2
   8 * of the License, or (at your option) any later version.
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software
  16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  17 * MA  02110-1301, USA.
  18 */
  19
  20#include <linux/module.h>
  21#include <linux/kernel.h>
  22#include <linux/io.h>
  23#include <linux/delay.h>
  24#include <linux/usb/otg.h>
  25#include <linux/usb/ulpi.h>
  26
  27#include <mach/ulpi.h>
  28
  29/* ULPIVIEW register bits */
  30#define ULPIVW_WU               (1 << 31)       /* Wakeup */
  31#define ULPIVW_RUN              (1 << 30)       /* read/write run */
  32#define ULPIVW_WRITE            (1 << 29)       /* 0 = read  1 = write */
  33#define ULPIVW_SS               (1 << 27)       /* SyncState */
  34#define ULPIVW_PORT_MASK        0x07    /* Port field */
  35#define ULPIVW_PORT_SHIFT       24
  36#define ULPIVW_ADDR_MASK        0xff    /* data address field */
  37#define ULPIVW_ADDR_SHIFT       16
  38#define ULPIVW_RDATA_MASK       0xff    /* read data field */
  39#define ULPIVW_RDATA_SHIFT      8
  40#define ULPIVW_WDATA_MASK       0xff    /* write data field */
  41#define ULPIVW_WDATA_SHIFT      0
  42
  43static int ulpi_poll(void __iomem *view, u32 bit)
  44{
  45        int timeout = 10000;
  46
  47        while (timeout--) {
  48                u32 data = __raw_readl(view);
  49
  50                if (!(data & bit))
  51                        return 0;
  52
  53                cpu_relax();
  54        };
  55
  56        printk(KERN_WARNING "timeout polling for ULPI device\n");
  57
  58        return -ETIMEDOUT;
  59}
  60
  61static int ulpi_read(struct usb_phy *otg, u32 reg)
  62{
  63        int ret;
  64        void __iomem *view = otg->io_priv;
  65
  66        /* make sure interface is running */
  67        if (!(__raw_readl(view) & ULPIVW_SS)) {
  68                __raw_writel(ULPIVW_WU, view);
  69
  70                /* wait for wakeup */
  71                ret = ulpi_poll(view, ULPIVW_WU);
  72                if (ret)
  73                        return ret;
  74        }
  75
  76        /* read the register */
  77        __raw_writel((ULPIVW_RUN | (reg << ULPIVW_ADDR_SHIFT)), view);
  78
  79        /* wait for completion */
  80        ret = ulpi_poll(view, ULPIVW_RUN);
  81        if (ret)
  82                return ret;
  83
  84        return (__raw_readl(view) >> ULPIVW_RDATA_SHIFT) & ULPIVW_RDATA_MASK;
  85}
  86
  87static int ulpi_write(struct usb_phy *otg, u32 val, u32 reg)
  88{
  89        int ret;
  90        void __iomem *view = otg->io_priv;
  91
  92        /* make sure the interface is running */
  93        if (!(__raw_readl(view) & ULPIVW_SS)) {
  94                __raw_writel(ULPIVW_WU, view);
  95                /* wait for wakeup */
  96                ret = ulpi_poll(view, ULPIVW_WU);
  97                if (ret)
  98                        return ret;
  99        }
 100
 101        __raw_writel((ULPIVW_RUN | ULPIVW_WRITE |
 102                      (reg << ULPIVW_ADDR_SHIFT) |
 103                      ((val & ULPIVW_WDATA_MASK) << ULPIVW_WDATA_SHIFT)), view);
 104
 105        /* wait for completion */
 106        return ulpi_poll(view, ULPIVW_RUN);
 107}
 108
 109struct usb_phy_io_ops mxc_ulpi_access_ops = {
 110        .read   = ulpi_read,
 111        .write  = ulpi_write,
 112};
 113EXPORT_SYMBOL_GPL(mxc_ulpi_access_ops);
 114
 115struct usb_phy *imx_otg_ulpi_create(unsigned int flags)
 116{
 117        return otg_ulpi_create(&mxc_ulpi_access_ops, flags);
 118}
 119