linux/drivers/usb/chipidea/ulpi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2016 Linaro Ltd.
   4 */
   5
   6#include <linux/device.h>
   7#include <linux/usb/chipidea.h>
   8#include <linux/ulpi/interface.h>
   9
  10#include "ci.h"
  11
  12#define ULPI_WAKEUP             BIT(31)
  13#define ULPI_RUN                BIT(30)
  14#define ULPI_WRITE              BIT(29)
  15#define ULPI_SYNC_STATE         BIT(27)
  16#define ULPI_ADDR(n)            ((n) << 16)
  17#define ULPI_DATA(n)            (n)
  18
  19static int ci_ulpi_wait(struct ci_hdrc *ci, u32 mask)
  20{
  21        unsigned long usec = 10000;
  22
  23        while (usec--) {
  24                if (!hw_read(ci, OP_ULPI_VIEWPORT, mask))
  25                        return 0;
  26
  27                udelay(1);
  28        }
  29
  30        return -ETIMEDOUT;
  31}
  32
  33static int ci_ulpi_read(struct device *dev, u8 addr)
  34{
  35        struct ci_hdrc *ci = dev_get_drvdata(dev);
  36        int ret;
  37
  38        hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_WRITE | ULPI_WAKEUP);
  39        ret = ci_ulpi_wait(ci, ULPI_WAKEUP);
  40        if (ret)
  41                return ret;
  42
  43        hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_RUN | ULPI_ADDR(addr));
  44        ret = ci_ulpi_wait(ci, ULPI_RUN);
  45        if (ret)
  46                return ret;
  47
  48        return hw_read(ci, OP_ULPI_VIEWPORT, GENMASK(15, 8)) >> 8;
  49}
  50
  51static int ci_ulpi_write(struct device *dev, u8 addr, u8 val)
  52{
  53        struct ci_hdrc *ci = dev_get_drvdata(dev);
  54        int ret;
  55
  56        hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_WRITE | ULPI_WAKEUP);
  57        ret = ci_ulpi_wait(ci, ULPI_WAKEUP);
  58        if (ret)
  59                return ret;
  60
  61        hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff,
  62                 ULPI_RUN | ULPI_WRITE | ULPI_ADDR(addr) | val);
  63        return ci_ulpi_wait(ci, ULPI_RUN);
  64}
  65
  66int ci_ulpi_init(struct ci_hdrc *ci)
  67{
  68        if (ci->platdata->phy_mode != USBPHY_INTERFACE_MODE_ULPI)
  69                return 0;
  70
  71        /*
  72         * Set PORTSC correctly so we can read/write ULPI registers for
  73         * identification purposes
  74         */
  75        hw_phymode_configure(ci);
  76
  77        ci->ulpi_ops.read = ci_ulpi_read;
  78        ci->ulpi_ops.write = ci_ulpi_write;
  79        ci->ulpi = ulpi_register_interface(ci->dev, &ci->ulpi_ops);
  80        if (IS_ERR(ci->ulpi))
  81                dev_err(ci->dev, "failed to register ULPI interface");
  82
  83        return PTR_ERR_OR_ZERO(ci->ulpi);
  84}
  85
  86void ci_ulpi_exit(struct ci_hdrc *ci)
  87{
  88        if (ci->ulpi) {
  89                ulpi_unregister_interface(ci->ulpi);
  90                ci->ulpi = NULL;
  91        }
  92}
  93
  94int ci_ulpi_resume(struct ci_hdrc *ci)
  95{
  96        int cnt = 100000;
  97
  98        if (ci->platdata->phy_mode != USBPHY_INTERFACE_MODE_ULPI)
  99                return 0;
 100
 101        while (cnt-- > 0) {
 102                if (hw_read(ci, OP_ULPI_VIEWPORT, ULPI_SYNC_STATE))
 103                        return 0;
 104                udelay(1);
 105        }
 106
 107        return -ETIMEDOUT;
 108}
 109