linux/drivers/usb/dwc3/ulpi.c
<<
>>
Prefs
   1/**
   2 * ulpi.c - DesignWare USB3 Controller's ULPI PHY interface
   3 *
   4 * Copyright (C) 2015 Intel Corporation
   5 *
   6 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/ulpi/regs.h>
  14
  15#include "core.h"
  16#include "io.h"
  17
  18#define DWC3_ULPI_ADDR(a) \
  19                ((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \
  20                DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \
  21                DWC3_GUSB2PHYACC_EXTEND_ADDR(a) : DWC3_GUSB2PHYACC_ADDR(a))
  22
  23static int dwc3_ulpi_busyloop(struct dwc3 *dwc)
  24{
  25        unsigned count = 1000;
  26        u32 reg;
  27
  28        while (count--) {
  29                reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
  30                if (!(reg & DWC3_GUSB2PHYACC_BUSY))
  31                        return 0;
  32                cpu_relax();
  33        }
  34
  35        return -ETIMEDOUT;
  36}
  37
  38static int dwc3_ulpi_read(struct device *dev, u8 addr)
  39{
  40        struct dwc3 *dwc = dev_get_drvdata(dev);
  41        u32 reg;
  42        int ret;
  43
  44        reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
  45        dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
  46
  47        ret = dwc3_ulpi_busyloop(dwc);
  48        if (ret)
  49                return ret;
  50
  51        reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
  52
  53        return DWC3_GUSB2PHYACC_DATA(reg);
  54}
  55
  56static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val)
  57{
  58        struct dwc3 *dwc = dev_get_drvdata(dev);
  59        u32 reg;
  60
  61        reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
  62        reg |= DWC3_GUSB2PHYACC_WRITE | val;
  63        dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
  64
  65        return dwc3_ulpi_busyloop(dwc);
  66}
  67
  68static const struct ulpi_ops dwc3_ulpi_ops = {
  69        .read = dwc3_ulpi_read,
  70        .write = dwc3_ulpi_write,
  71};
  72
  73int dwc3_ulpi_init(struct dwc3 *dwc)
  74{
  75        /* Register the interface */
  76        dwc->ulpi = ulpi_register_interface(dwc->dev, &dwc3_ulpi_ops);
  77        if (IS_ERR(dwc->ulpi)) {
  78                dev_err(dwc->dev, "failed to register ULPI interface");
  79                return PTR_ERR(dwc->ulpi);
  80        }
  81
  82        return 0;
  83}
  84
  85void dwc3_ulpi_exit(struct dwc3 *dwc)
  86{
  87        if (dwc->ulpi) {
  88                ulpi_unregister_interface(dwc->ulpi);
  89                dwc->ulpi = NULL;
  90        }
  91}
  92