linux/drivers/usb/chipidea/ulpi.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2016 Linaro Ltd.
   3 *
   4 * This software is licensed under the terms of the GNU General Public
   5 * License version 2, as published by the Free Software Foundation, and
   6 * may be copied, distributed, and modified under those terms.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13
  14#include <linux/device.h>
  15#include <linux/usb/chipidea.h>
  16#include <linux/ulpi/interface.h>
  17
  18#include "ci.h"
  19
  20#define ULPI_WAKEUP             BIT(31)
  21#define ULPI_RUN                BIT(30)
  22#define ULPI_WRITE              BIT(29)
  23#define ULPI_SYNC_STATE         BIT(27)
  24#define ULPI_ADDR(n)            ((n) << 16)
  25#define ULPI_DATA(n)            (n)
  26
  27static int ci_ulpi_wait(struct ci_hdrc *ci, u32 mask)
  28{
  29        unsigned long usec = 10000;
  30
  31        while (usec--) {
  32                if (!hw_read(ci, OP_ULPI_VIEWPORT, mask))
  33                        return 0;
  34
  35                udelay(1);
  36        }
  37
  38        return -ETIMEDOUT;
  39}
  40
  41static int ci_ulpi_read(struct device *dev, u8 addr)
  42{
  43        struct ci_hdrc *ci = dev_get_drvdata(dev);
  44        int ret;
  45
  46        hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_WRITE | ULPI_WAKEUP);
  47        ret = ci_ulpi_wait(ci, ULPI_WAKEUP);
  48        if (ret)
  49                return ret;
  50
  51        hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_RUN | ULPI_ADDR(addr));
  52        ret = ci_ulpi_wait(ci, ULPI_RUN);
  53        if (ret)
  54                return ret;
  55
  56        return hw_read(ci, OP_ULPI_VIEWPORT, GENMASK(15, 8)) >> 8;
  57}
  58
  59static int ci_ulpi_write(struct device *dev, u8 addr, u8 val)
  60{
  61        struct ci_hdrc *ci = dev_get_drvdata(dev);
  62        int ret;
  63
  64        hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_WRITE | ULPI_WAKEUP);
  65        ret = ci_ulpi_wait(ci, ULPI_WAKEUP);
  66        if (ret)
  67                return ret;
  68
  69        hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff,
  70                 ULPI_RUN | ULPI_WRITE | ULPI_ADDR(addr) | val);
  71        return ci_ulpi_wait(ci, ULPI_RUN);
  72}
  73
  74int ci_ulpi_init(struct ci_hdrc *ci)
  75{
  76        if (ci->platdata->phy_mode != USBPHY_INTERFACE_MODE_ULPI)
  77                return 0;
  78
  79        /*
  80         * Set PORTSC correctly so we can read/write ULPI registers for
  81         * identification purposes
  82         */
  83        hw_phymode_configure(ci);
  84
  85        ci->ulpi_ops.read = ci_ulpi_read;
  86        ci->ulpi_ops.write = ci_ulpi_write;
  87        ci->ulpi = ulpi_register_interface(ci->dev, &ci->ulpi_ops);
  88        if (IS_ERR(ci->ulpi))
  89                dev_err(ci->dev, "failed to register ULPI interface");
  90
  91        return PTR_ERR_OR_ZERO(ci->ulpi);
  92}
  93
  94void ci_ulpi_exit(struct ci_hdrc *ci)
  95{
  96        if (ci->ulpi) {
  97                ulpi_unregister_interface(ci->ulpi);
  98                ci->ulpi = NULL;
  99        }
 100}
 101
 102int ci_ulpi_resume(struct ci_hdrc *ci)
 103{
 104        int cnt = 100000;
 105
 106        while (cnt-- > 0) {
 107                if (hw_read(ci, OP_ULPI_VIEWPORT, ULPI_SYNC_STATE))
 108                        return 0;
 109                udelay(1);
 110        }
 111
 112        return -ETIMEDOUT;
 113}
 114