* "fsl,imx23-usbphy" for imx23 and imx28
* "fsl,imx6q-usbphy" for imx6dq and imx6dl
* "fsl,imx6sl-usbphy" for imx6sl
+ * "fsl,vf610-usbphy" for Vybrid vf610
+ * "fsl,imx6sx-usbphy" for imx6sx
"fsl,imx23-usbphy" is still a fallback for other strings
- reg: Should contain registers location and length
- interrupts: Should contain phy interrupt
F: drivers/i2c/busses/i2c-st.c
F: drivers/tty/serial/st-asc.c
F: drivers/mmc/host/sdhci-st.c
+F: drivers/usb/dwc3/dwc3-st.c
ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
M: Lennert Buytenhek <kernel@wantstofly.org>
F: drivers/scsi/nsp32*
NTB DRIVER
- M: Jon Mason <jon.mason@intel.com>
+ M: Jon Mason <jdmason@kudzu.us>
+ M: Dave Jiang <dave.jiang@intel.com>
S: Supported
W: https://github.com/jonmason/ntb/wiki
T: git git://github.com/jonmason/ntb.git
F: drivers/pinctrl/sh-pfc/
PIN CONTROLLER - SAMSUNG
- M: Tomasz Figa <t.figa@samsung.com>
+ M: Tomasz Figa <tomasz.figa@gmail.com>
M: Thomas Abraham <thomas.abraham@linaro.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
F: drivers/media/i2c/s5k5baf.c
SAMSUNG SOC CLOCK DRIVERS
- M: Tomasz Figa <t.figa@samsung.com>
+ M: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ M: Tomasz Figa <tomasz.figa@gmail.com>
S: Supported
L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
F: drivers/clk/samsung/
L: netdev@vger.kernel.org
F: drivers/net/ethernet/samsung/sxgbe/
+ SAMSUNG USB2 PHY DRIVER
+ M: Kamil Debski <k.debski@samsung.com>
+ L: linux-kernel@vger.kernel.org
+ S: Supported
+ F: Documentation/devicetree/bindings/phy/samsung-phy.txt
+ F: Documentation/phy/samsung-usb2.txt
+ F: drivers/phy/phy-exynos4210-usb2.c
+ F: drivers/phy/phy-exynos4x12-usb2.c
+ F: drivers/phy/phy-exynos5250-usb2.c
+ F: drivers/phy/phy-s5pv210-usb2.c
+ F: drivers/phy/phy-samsung-usb2.c
+ F: drivers/phy/phy-samsung-usb2.h
+
SERIAL DRIVERS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
L: linux-serial@vger.kernel.org
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-usb@vger.kernel.org
S: Maintained
-F: drivers/usb/gadget/function/*uvc*.c
+F: drivers/usb/gadget/function/*uvc*
F: drivers/usb/gadget/legacy/webcam.c
USB WIRELESS RNDIS DRIVER (rndis_wlan)
dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
GFP_KERNEL);
- if (!dwc->ev_buffs) {
- dev_err(dwc->dev, "can't allocate event buffers array\n");
+ if (!dwc->ev_buffs)
return -ENOMEM;
- }
for (i = 0; i < num; i++) {
struct dwc3_event_buffer *evt;
void *mem;
mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
- if (!mem) {
- dev_err(dev, "not enough memory\n");
+ if (!mem)
return -ENOMEM;
- }
+
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
dwc->mem = mem;
dwc->dev = dev;
{
struct dwc3 *dwc = platform_get_drvdata(pdev);
+ dwc3_debugfs_exit(dwc);
+ dwc3_core_exit_mode(dwc);
+ dwc3_event_buffers_cleanup(dwc);
+ dwc3_free_event_buffers(dwc);
+
usb_phy_set_suspend(dwc->usb2_phy, 1);
usb_phy_set_suspend(dwc->usb3_phy, 1);
phy_power_off(dwc->usb2_generic_phy);
phy_power_off(dwc->usb3_generic_phy);
+ dwc3_core_exit(dwc);
+
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- dwc3_debugfs_exit(dwc);
- dwc3_core_exit_mode(dwc);
- dwc3_event_buffers_cleanup(dwc);
- dwc3_free_event_buffers(dwc);
- dwc3_core_exit(dwc);
-
return 0;
}
}
omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
- if (!omap) {
- dev_err(dev, "not enough memory\n");
+ if (!omap)
return -ENOMEM;
- }
platform_set_drvdata(pdev, omap);
if (omap->extcon_id_dev.edev)
extcon_unregister_interest(&omap->extcon_id_dev);
dwc3_omap_disable_irqs(omap);
+ device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
return 0;
}
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include "debug.h"
#include "core.h"
#include "gadget.h"
#include "io.h"
dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
req, dep->name, req->request.actual,
req->request.length, status);
+ trace_dwc3_gadget_giveback(req);
spin_unlock(&dwc->lock);
req->request.complete(&dep->endpoint, &req->request);
spin_lock(&dwc->lock);
}
-static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
-{
- switch (cmd) {
- case DWC3_DEPCMD_DEPSTARTCFG:
- return "Start New Configuration";
- case DWC3_DEPCMD_ENDTRANSFER:
- return "End Transfer";
- case DWC3_DEPCMD_UPDATETRANSFER:
- return "Update Transfer";
- case DWC3_DEPCMD_STARTTRANSFER:
- return "Start Transfer";
- case DWC3_DEPCMD_CLEARSTALL:
- return "Clear Stall";
- case DWC3_DEPCMD_SETSTALL:
- return "Set Stall";
- case DWC3_DEPCMD_GETEPSTATE:
- return "Get Endpoint State";
- case DWC3_DEPCMD_SETTRANSFRESOURCE:
- return "Set Endpoint Transfer Resource";
- case DWC3_DEPCMD_SETEPCONFIG:
- return "Set Endpoint Configuration";
- default:
- return "UNKNOWN command";
- }
-}
-
-static const char *dwc3_gadget_generic_cmd_string(u8 cmd)
-{
- switch (cmd) {
- case DWC3_DGCMD_SET_LMP:
- return "Set LMP";
- case DWC3_DGCMD_SET_PERIODIC_PAR:
- return "Set Periodic Parameters";
- case DWC3_DGCMD_XMIT_FUNCTION:
- return "Transmit Function Wake Device Notification";
- case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO:
- return "Set Scratchpad Buffer Array Address Lo";
- case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI:
- return "Set Scratchpad Buffer Array Address Hi";
- case DWC3_DGCMD_SELECTED_FIFO_FLUSH:
- return "Selected FIFO Flush";
- case DWC3_DGCMD_ALL_FIFO_FLUSH:
- return "All FIFO Flush";
- case DWC3_DGCMD_SET_ENDPOINT_NRDY:
- return "Set Endpoint NRDY";
- case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK:
- return "Run SoC Bus Loopback Test";
- default:
- return "UNKNOWN";
- }
-}
-
-static const char *dwc3_gadget_link_string(enum dwc3_link_state link_state)
-{
- switch (link_state) {
- case DWC3_LINK_STATE_U0:
- return "U0";
- case DWC3_LINK_STATE_U1:
- return "U1";
- case DWC3_LINK_STATE_U2:
- return "U2";
- case DWC3_LINK_STATE_U3:
- return "U3";
- case DWC3_LINK_STATE_SS_DIS:
- return "SS.Disabled";
- case DWC3_LINK_STATE_RX_DET:
- return "RX.Detect";
- case DWC3_LINK_STATE_SS_INACT:
- return "SS.Inactive";
- case DWC3_LINK_STATE_POLL:
- return "Polling";
- case DWC3_LINK_STATE_RECOV:
- return "Recovery";
- case DWC3_LINK_STATE_HRESET:
- return "Hot Reset";
- case DWC3_LINK_STATE_CMPLY:
- return "Compliance";
- case DWC3_LINK_STATE_LPBK:
- return "Loopback";
- case DWC3_LINK_STATE_RESET:
- return "Reset";
- case DWC3_LINK_STATE_RESUME:
- return "Resume";
- default:
- return "UNKNOWN link state\n";
- }
-}
-
-int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param)
+int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
{
u32 timeout = 500;
u32 reg;
- dev_vdbg(dwc->dev, "generic cmd '%s' [%d] param %08x\n",
- dwc3_gadget_generic_cmd_string(cmd), cmd, param);
+ trace_dwc3_gadget_generic_cmd(cmd, param);
dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
u32 timeout = 500;
u32 reg;
- dev_vdbg(dwc->dev, "%s: cmd '%s' [%d] params %08x %08x %08x\n",
- dep->name,
- dwc3_gadget_ep_cmd_string(cmd), cmd, params->param0,
- params->param1, params->param2);
+ trace_dwc3_gadget_ep_cmd(dep, cmd, params);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
dep->stream_capable = true;
}
- if (usb_endpoint_xfer_isoc(desc))
+ if (!usb_endpoint_xfer_control(desc))
params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN;
/*
{
struct dwc3_request *req;
struct dwc3_ep *dep = to_dwc3_ep(ep);
- struct dwc3 *dwc = dep->dwc;
req = kzalloc(sizeof(*req), gfp_flags);
- if (!req) {
- dev_err(dwc->dev, "not enough memory\n");
+ if (!req)
return NULL;
- }
req->epnum = dep->number;
req->dep = dep;
+ trace_dwc3_alloc_request(req);
+
return &req->request;
}
{
struct dwc3_request *req = to_dwc3_request(request);
+ trace_dwc3_free_request(req);
kfree(req);
}
trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
trb->ctrl |= DWC3_TRB_CTRL_HWO;
+
+ trace_dwc3_prepare_trb(dep, trb);
}
/*
int ret;
+ spin_lock_irqsave(&dwc->lock, flags);
if (!dep->endpoint.desc) {
dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
request, ep->name);
+ spin_unlock_irqrestore(&dwc->lock, flags);
return -ESHUTDOWN;
}
dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
request, ep->name, request->length);
+ trace_dwc3_ep_queue(req);
- spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_queue(dep, req);
spin_unlock_irqrestore(&dwc->lock, flags);
unsigned long flags;
int ret = 0;
+ trace_dwc3_ep_dequeue(req);
+
spin_lock_irqsave(&dwc->lock, flags);
list_for_each_entry(r, &dep->request_list, list) {
u8 epnum = (i << 1) | (!!direction);
dep = kzalloc(sizeof(*dep), GFP_KERNEL);
- if (!dep) {
- dev_err(dwc->dev, "can't allocate endpoint %d\n",
- epnum);
+ if (!dep)
return -ENOMEM;
- }
dep->dwc = dwc;
dep->number = epnum;
unsigned int s_pkt = 0;
unsigned int trb_status;
+ trace_dwc3_complete_trb(dep, trb);
+
if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
/*
* We continue despite the error. There is not much we
if (!(dep->flags & DWC3_EP_ENABLED))
return;
- dev_vdbg(dwc->dev, "%s: %s\n", dep->name,
- dwc3_ep_event_string(event->endpoint_event));
-
if (epnum == 0 || epnum == 1) {
dwc3_ep0_interrupt(dwc, event);
return;
dwc3_endpoint_transfer_complete(dwc, dep, event);
break;
case DWC3_DEPEVT_XFERINPROGRESS:
- if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
- dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n",
- dep->name);
- return;
- }
-
dwc3_endpoint_transfer_complete(dwc, dep, event);
break;
case DWC3_DEPEVT_XFERNOTREADY:
{
int reg;
- dev_vdbg(dwc->dev, "%s\n", __func__);
-
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_INITU1ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
{
u32 reg;
- dev_vdbg(dwc->dev, "%s\n", __func__);
-
/*
* WORKAROUND: DWC3 revisions <1.88a have an issue which
* would cause a missing Disconnect Event if there's a
u32 reg;
u8 speed;
- dev_vdbg(dwc->dev, "%s\n", __func__);
-
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
speed = reg & DWC3_DSTS_CONNECTSPD;
dwc->speed = speed;
static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
{
- dev_vdbg(dwc->dev, "%s\n", __func__);
-
/*
* TODO take core out of low power mode when that's
* implemented.
break;
}
- dev_vdbg(dwc->dev, "link change: %s [%d] -> %s [%d]\n",
- dwc3_gadget_link_string(dwc->link_state),
- dwc->link_state, dwc3_gadget_link_string(next), next);
-
dwc->link_state = next;
}
static void dwc3_process_event_entry(struct dwc3 *dwc,
const union dwc3_event *event)
{
+ trace_dwc3_event(event->raw);
+
/* Endpoint IRQ, handle it and return early */
if (event->type.is_devspec == 0) {
/* depevt */
dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
if (!dwc->setup_buf) {
- dev_err(dwc->dev, "failed to allocate setup buffer\n");
ret = -ENOMEM;
goto err2;
}
struct usb_request *req;
};
+ struct ffs_desc_helper {
+ struct ffs_data *ffs;
+ unsigned interfaces_count;
+ unsigned eps_count;
+ };
+
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
case FUNCTIONFS_ENDPOINT_REVMAP:
ret = epfile->ep->num;
break;
+ case FUNCTIONFS_ENDPOINT_DESC:
+ {
+ int desc_idx;
+ struct usb_endpoint_descriptor *desc;
+
+ switch (epfile->ffs->gadget->speed) {
+ case USB_SPEED_SUPER:
+ desc_idx = 2;
+ break;
+ case USB_SPEED_HIGH:
+ desc_idx = 1;
+ break;
+ default:
+ desc_idx = 0;
+ }
+ desc = epfile->ep->descs[desc_idx];
+
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ ret = copy_to_user((void *)value, desc, sizeof(*desc));
+ if (ret)
+ ret = -EFAULT;
+ return ret;
+ }
default:
ret = -ENOTTY;
}
u8 *valuep, struct usb_descriptor_header *desc,
void *priv)
{
- struct ffs_data *ffs = priv;
+ struct ffs_desc_helper *helper = priv;
+ struct usb_endpoint_descriptor *d;
ENTER();
* encountered interface "n" then there are at least
* "n+1" interfaces.
*/
- if (*valuep >= ffs->interfaces_count)
- ffs->interfaces_count = *valuep + 1;
+ if (*valuep >= helper->interfaces_count)
+ helper->interfaces_count = *valuep + 1;
break;
case FFS_STRING:
* Strings are indexed from 1 (0 is magic ;) reserved
* for languages list or some such)
*/
- if (*valuep > ffs->strings_count)
- ffs->strings_count = *valuep;
+ if (*valuep > helper->ffs->strings_count)
+ helper->ffs->strings_count = *valuep;
break;
case FFS_ENDPOINT:
- /* Endpoints are indexed from 1 as well. */
- if ((*valuep & USB_ENDPOINT_NUMBER_MASK) > ffs->eps_count)
- ffs->eps_count = (*valuep & USB_ENDPOINT_NUMBER_MASK);
+ d = (void *)desc;
+ helper->eps_count++;
+ if (helper->eps_count >= 15)
+ return -EINVAL;
+ /* Check if descriptors for any speed were already parsed */
+ if (!helper->ffs->eps_count && !helper->ffs->interfaces_count)
+ helper->ffs->eps_addrmap[helper->eps_count] =
+ d->bEndpointAddress;
+ else if (helper->ffs->eps_addrmap[helper->eps_count] !=
+ d->bEndpointAddress)
+ return -EINVAL;
break;
}
char *data = _data, *raw_descs;
unsigned os_descs_count = 0, counts[3], flags;
int ret = -EINVAL, i;
+ struct ffs_desc_helper helper;
ENTER();
/* Read descriptors */
raw_descs = data;
+ helper.ffs = ffs;
for (i = 0; i < 3; ++i) {
if (!counts[i])
continue;
+ helper.interfaces_count = 0;
+ helper.eps_count = 0;
ret = ffs_do_descs(counts[i], data, len,
- __ffs_data_do_entity, ffs);
+ __ffs_data_do_entity, &helper);
if (ret < 0)
goto error;
+ if (!ffs->eps_count && !ffs->interfaces_count) {
+ ffs->eps_count = helper.eps_count;
+ ffs->interfaces_count = helper.interfaces_count;
+ } else {
+ if (ffs->eps_count != helper.eps_count) {
+ ret = -EINVAL;
+ goto error;
+ }
+ if (ffs->interfaces_count != helper.interfaces_count) {
+ ret = -EINVAL;
+ goto error;
+ }
+ }
data += ret;
len -= ret;
}
break;
default:
- BUG();
+ WARN(1, "%d: unknown event, this should not happen\n", type);
+ return;
}
{
spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
}
-
/* Bind/unbind USB function hooks *******************************************/
+ static int ffs_ep_addr2idx(struct ffs_data *ffs, u8 endpoint_address)
+ {
+ int i;
+
+ for (i = 1; i < ARRAY_SIZE(ffs->eps_addrmap); ++i)
+ if (ffs->eps_addrmap[i] == endpoint_address)
+ return i;
+ return -ENOENT;
+ }
+
static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
struct usb_descriptor_header *desc,
void *priv)
struct usb_endpoint_descriptor *ds = (void *)desc;
struct ffs_function *func = priv;
struct ffs_ep *ffs_ep;
- unsigned ep_desc_id, idx;
+ unsigned ep_desc_id;
+ int idx;
static const char *speed_names[] = { "full", "high", "super" };
if (type != FFS_DESCRIPTOR)
if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
return 0;
- idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;
+ idx = ffs_ep_addr2idx(func->ffs, ds->bEndpointAddress) - 1;
+ if (idx < 0)
+ return idx;
+
ffs_ep = func->eps + idx;
if (unlikely(ffs_ep->descs[ep_desc_id])) {
u32 transferred;
u32 packet_sz;
struct list_head tx_check;
+ int tx_zlp;
};
#define MUSB_DMA_NUM_CHANNELS 15
{
struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
struct musb *musb = hw_ep->musb;
+ void __iomem *epio = hw_ep->regs;
+ u16 csr;
if (!cppi41_channel->prog_len ||
(cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)) {
cppi41_channel->transferred;
cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
cppi41_channel->channel.rx_packet_done = true;
+
+ /*
+ * transmit ZLP using PIO mode for transfers which size is
+ * multiple of EP packet size.
+ */
+ if (cppi41_channel->tx_zlp && (cppi41_channel->transferred %
+ cppi41_channel->packet_sz) == 0) {
+ musb_ep_select(musb->mregs, hw_ep->epnum);
+ csr = MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ }
musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx);
} else {
/* next iteration, reload */
struct dma_chan *dc = cppi41_channel->dc;
struct dma_async_tx_descriptor *dma_desc;
enum dma_transfer_direction direction;
- u16 csr;
u32 remain_bytes;
- void __iomem *epio = cppi41_channel->hw_ep->regs;
cppi41_channel->buf_addr += cppi41_channel->packet_sz;
if (!list_empty(&controller->early_tx_list)) {
ret = HRTIMER_RESTART;
hrtimer_forward_now(&controller->early_tx,
- ktime_set(0, 50 * NSEC_PER_USEC));
+ ktime_set(0, 20 * NSEC_PER_USEC));
}
spin_unlock_irqrestore(&musb->lock, flags);
hrtimer_start_range_ns(&controller->early_tx,
ktime_set(0, usecs * NSEC_PER_USEC),
- 40 * NSEC_PER_USEC,
+ 20 * NSEC_PER_USEC,
HRTIMER_MODE_REL);
}
}
cppi41_channel->total_len = len;
cppi41_channel->transferred = 0;
cppi41_channel->packet_sz = packet_sz;
+ cppi41_channel->tx_zlp = (cppi41_channel->is_tx && mode) ? 1 : 0;
/*
* Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more
/*
- * Copyright 2012-2013 Freescale Semiconductor, Inc.
+ * Copyright 2012-2014 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Marek Vasut <marex@denx.de>
* on behalf of DENX Software Engineering GmbH
*
MXS_PHY_NEED_IP_FIX,
};
+static const struct mxs_phy_data vf610_phy_data = {
+ .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
+ MXS_PHY_NEED_IP_FIX,
+};
+
+ static const struct mxs_phy_data imx6sx_phy_data = {
+ .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
+ MXS_PHY_NEED_IP_FIX,
+ };
+
static const struct of_device_id mxs_phy_dt_ids[] = {
+ { .compatible = "fsl,imx6sx-usbphy", .data = &imx6sx_phy_data, },
{ .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
{ .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, },
{ .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, },
+ { .compatible = "fsl,vf610-usbphy", .data = &vf610_phy_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);