* Author: Li Yang <leoli@freescale.com>
* Jiang Bo <tanya.jiang@freescale.com>
*
+ * Copyright (C) 2010-2011 NVIDIA Corporation
+ *
* Description:
* Freescale high-speed USB SOC DR module device controller driver.
* This can be found on MPC8349E/MPC8313E/MPC5121E cpus.
#include <linux/fsl_devices.h>
#include <linux/dmapool.h>
#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
#include <asm/byteorder.h>
#include <asm/io.h>
static struct usb_sys_interface *usb_sys_regs;
#endif
+/* Charger current limit=1800mA, as per the USB charger spec */
+#define USB_CHARGING_CURRENT_LIMIT_MA 1800
+/* 1 sec wait time for charger detection after vbus is detected */
+#define USB_CHARGER_DETECTION_WAIT_TIME_MS 1000
+
/* it is initialized in probe() */
static struct fsl_udc *udc_controller = NULL;
.wMaxPacketSize = USB_MAX_CTRL_PAYLOAD,
};
+static u32 *control_reg = NULL;
static void fsl_ep_fifo_flush(struct usb_ep *_ep);
+static int reset_queues(struct fsl_udc *udc);
#ifdef CONFIG_PPC32
/*
#define hc32_to_cpu(x) le32_to_cpu(x)
#endif /* CONFIG_PPC32 */
+/*
+ * High speed test mode packet(53 bytes).
+ * See USB 2.0 spec, section 7.1.20.
+ */
+static const u8 fsl_udc_test_packet[53] = {
+ /* JKJKJKJK x9 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* JJKKJJKK x8 */
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ /* JJJJKKKK x8 */
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ /* JJJJJJJKKKKKKK x8 */
+ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ /* JJJJJJJK x8 */
+ 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd,
+ /* JKKKKKKK x10, JK */
+ 0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e
+};
+
/********************************************************************
* Internal Used Function
********************************************************************/
+/*-----------------------------------------------------------------
+ * vbus_enabled() - checks vbus status
+ *--------------------------------------------------------------*/
+static inline bool vbus_enabled(void)
+{
+ bool status = false;
+#ifdef CONFIG_TEGRA_SILICON_PLATFORM
+ status = (fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS);
+#else
+ /*On FPGA VBUS is detected through VBUS A Session instead of VBUS status. */
+ status = (fsl_readl(&usb_sys_regs->vbus_sensors) & USB_SYS_VBUS_ASESSION);
+#endif
+ return status;
+}
+
/*-----------------------------------------------------------------
* done() - retire a request; caller blocked irqs
* @status : request status to be set, only works when
Internal Hardware related function
------------------------------------------------------------------*/
+#define FSL_UDC_RESET_TIMEOUT 1000
+static int dr_controller_reset(struct fsl_udc *udc)
+{
+ unsigned int tmp;
+ unsigned long timeout;
+
+ /* Stop and reset the usb controller */
+ tmp = fsl_readl(&dr_regs->usbcmd);
+ tmp &= ~USB_CMD_RUN_STOP;
+ fsl_writel(tmp, &dr_regs->usbcmd);
+
+ tmp = fsl_readl(&dr_regs->usbcmd);
+ tmp |= USB_CMD_CTRL_RESET;
+ fsl_writel(tmp, &dr_regs->usbcmd);
+
+ /* Wait for reset to complete */
+ timeout = jiffies + FSL_UDC_RESET_TIMEOUT;
+ while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) {
+ if (time_after(jiffies, timeout)) {
+ ERR("udc reset timeout!\n");
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+ return 0;
+}
+
static int dr_controller_setup(struct fsl_udc *udc)
{
unsigned int tmp, portctrl, ep_num;
#if !defined(CONFIG_ARCH_MXC) && !defined(CONFIG_ARCH_TEGRA)
unsigned int ctrl;
#endif
+#ifdef CONFIG_ARCH_TEGRA
unsigned long timeout;
-#define FSL_UDC_RESET_TIMEOUT 1000
+#endif
+ int status;
/* Config PHY interface */
- portctrl = fsl_readl(&dr_regs->portsc1);
+ portctrl = fsl_readl(control_reg);
portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
switch (udc->phy_mode) {
case FSL_USB2_PHY_ULPI:
default:
return -EINVAL;
}
- fsl_writel(portctrl, &dr_regs->portsc1);
+ fsl_writel(portctrl, control_reg);
- /* Stop and reset the usb controller */
- tmp = fsl_readl(&dr_regs->usbcmd);
- tmp &= ~USB_CMD_RUN_STOP;
- fsl_writel(tmp, &dr_regs->usbcmd);
-
- tmp = fsl_readl(&dr_regs->usbcmd);
- tmp |= USB_CMD_CTRL_RESET;
- fsl_writel(tmp, &dr_regs->usbcmd);
-
- /* Wait for reset to complete */
- timeout = jiffies + FSL_UDC_RESET_TIMEOUT;
- while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) {
- if (time_after(jiffies, timeout)) {
- ERR("udc reset timeout!\n");
- return -ETIMEDOUT;
- }
- cpu_relax();
- }
+ status = dr_controller_reset(udc);
+ if (status)
+ return status;
/* Set the controller as device mode */
tmp = fsl_readl(&dr_regs->usbmode);
unsigned long timeout;
#define FSL_UDC_RUN_TIMEOUT 1000
#endif
+ /* Clear stopped bit */
+ udc->stopped = 0;
+/* If OTG transceiver is available, then it handles the VBUS detection */
+ if (!udc_controller->transceiver) {
+#ifdef CONFIG_TEGRA_SILICON_PLATFORM
+ /* Enable cable detection interrupt, without setting the
+ * USB_SYS_VBUS_WAKEUP_INT bit. USB_SYS_VBUS_WAKEUP_INT is
+ * clear on write */
+ temp = fsl_readl(&usb_sys_regs->vbus_wakeup);
+ temp |= (USB_SYS_VBUS_WAKEUP_INT_ENABLE | USB_SYS_VBUS_WAKEUP_ENABLE);
+ temp &= ~USB_SYS_VBUS_WAKEUP_INT_STATUS;
+ fsl_writel(temp, &usb_sys_regs->vbus_wakeup);
+#else
+ /*On FPGA VBUS is detected through VBUS A Session instead of VBUS
+ * status. */
+ temp = fsl_readl(&usb_sys_regs->vbus_sensors);
+ temp |= USB_SYS_VBUS_ASESSION_INT_EN;
+ temp &= ~USB_SYS_VBUS_ASESSION_CHANGED;
+ fsl_writel(temp, &usb_sys_regs->vbus_sensors);
+#endif
+ }
/* Enable DR irq reg */
temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN
| USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN
fsl_writel(temp, &dr_regs->usbintr);
- /* Clear stopped bit */
- udc->stopped = 0;
-
/* Set the controller as device mode */
temp = fsl_readl(&dr_regs->usbmode);
temp |= USB_MODE_CTRL_MODE_DEVICE;
{
unsigned int tmp;
- pr_debug("%s\n", __func__);
-
- /* if we're in OTG mode, and the Host is currently using the port,
- * stop now and don't rip the controller out from under the
- * ehci driver
- */
- if (udc->gadget.is_otg) {
- if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) {
- pr_debug("udc: Leaving early\n");
- return;
- }
- }
+ /* Clear pending interrupt status bits */
+ tmp = fsl_readl(&dr_regs->usbsts);
+ fsl_writel(tmp, &dr_regs->usbsts);
/* disable all INTR */
fsl_writel(0, &dr_regs->usbintr);
/* the intialization of an ep includes: fields in QH, Regs,
* fsl_ep struct */
struct_ep_qh_setup(udc, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL,
- USB_MAX_CTRL_PAYLOAD, 0, 0);
+ USB_MAX_CTRL_PAYLOAD, 1, 0);
struct_ep_qh_setup(udc, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL,
- USB_MAX_CTRL_PAYLOAD, 0, 0);
+ USB_MAX_CTRL_PAYLOAD, 1, 0);
dr_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL);
dr_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL);
/* disable ep on controller */
ep_num = ep_index(ep);
- epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
- if (ep_is_in(ep)) {
- epctrl &= ~(EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE);
- epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT;
- } else {
- epctrl &= ~(EPCTRL_RX_ENABLE | EPCTRL_TX_TYPE);
- epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT;
+#if defined(CONFIG_ARCH_TEGRA)
+ /* Touch the registers if cable is connected and phy is on */
+ if (vbus_enabled())
+#endif
+ {
+ epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+ if (ep_is_in(ep)) {
+ epctrl &= ~(EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE);
+ epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT;
+ } else {
+ epctrl &= ~(EPCTRL_RX_ENABLE | EPCTRL_TX_TYPE);
+ epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT;
+ }
+ fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
}
- fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
udc = (struct fsl_udc *)ep->udc;
spin_lock_irqsave(&udc->lock, flags);
* @is_last: return flag if it is the last dTD of the request
* return: pointer to the built dTD */
static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
- dma_addr_t *dma, int *is_last)
+ dma_addr_t *dma, int *is_last, gfp_t gfp_flags)
{
u32 swap_temp;
struct ep_td_struct *dtd;
*length = min(req->req.length - req->req.actual,
(unsigned)EP_MAX_LENGTH_TRANSFER);
- dtd = dma_pool_alloc(udc_controller->td_pool, GFP_KERNEL, dma);
+ dtd = dma_pool_alloc(udc_controller->td_pool, gfp_flags, dma);
if (dtd == NULL)
return dtd;
}
/* Generate dtd chain for a request */
-static int fsl_req_to_dtd(struct fsl_req *req)
+static int fsl_req_to_dtd(struct fsl_req *req, gfp_t gfp_flags)
{
unsigned count;
int is_last;
dma_addr_t dma;
do {
- dtd = fsl_build_dtd(req, &count, &dma, &is_last);
+ dtd = fsl_build_dtd(req, &count, &dma, &is_last, gfp_flags);
if (dtd == NULL)
return -ENOMEM;
{
struct fsl_ep *ep = container_of(_ep, struct fsl_ep, ep);
struct fsl_req *req = container_of(_req, struct fsl_req, req);
- struct fsl_udc *udc;
+ struct fsl_udc *udc = ep->udc;
unsigned long flags;
+ enum dma_data_direction dir;
+ int status;
/* catch various bogus parameters */
if (!_req || !req->req.complete || !req->req.buf
VDBG("%s, bad params", __func__);
return -EINVAL;
}
- if (unlikely(!_ep || !ep->desc)) {
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (unlikely(!ep->desc)) {
VDBG("%s, bad ep", __func__);
+ spin_unlock_irqrestore(&udc->lock, flags);
return -EINVAL;
}
+
if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
- if (req->req.length > ep->ep.maxpacket)
+ if (req->req.length > ep->ep.maxpacket) {
+ spin_unlock_irqrestore(&udc->lock, flags);
return -EMSGSIZE;
+ }
}
- udc = ep->udc;
+ dir = ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
return -ESHUTDOWN;
/* map virtual address to hardware */
if (req->req.dma == DMA_ADDR_INVALID) {
- req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
- req->req.buf,
- req->req.length, ep_is_in(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
+ req->req.dma = dma_map_single(udc->gadget.dev.parent,
+ req->req.buf, req->req.length, dir);
req->mapped = 1;
} else {
- dma_sync_single_for_device(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ep_is_in(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
+ dma_sync_single_for_device(udc->gadget.dev.parent,
+ req->req.dma, req->req.length, dir);
req->mapped = 0;
}
req->req.actual = 0;
req->dtd_count = 0;
- spin_lock_irqsave(&udc->lock, flags);
/* build dtds and push them to device queue */
- if (!fsl_req_to_dtd(req)) {
- fsl_queue_td(ep, req);
- } else {
+ status = fsl_req_to_dtd(req, gfp_flags);
+ if (status)
+ goto err_unmap;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* re-check if the ep has not been disabled */
+ if (unlikely(!ep->desc)) {
spin_unlock_irqrestore(&udc->lock, flags);
- return -ENOMEM;
+ status = -EINVAL;
+ goto err_unmap;
}
+ fsl_queue_td(ep, req);
+
/* Update ep0 state */
if ((ep_index(ep) == 0))
udc->ep0_state = DATA_STATE_XMIT;
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
+
+err_unmap:
+ if (req->mapped) {
+ dma_unmap_single(udc->gadget.dev.parent,
+ req->req.dma, req->req.length, dir);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ }
+ return status;
}
/* dequeues (cancels, unlinks) an I/O request from an endpoint */
/* Stop the ep before we deal with the queue */
ep->stopped = 1;
ep_num = ep_index(ep);
- epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
- if (ep_is_in(ep))
- epctrl &= ~EPCTRL_TX_ENABLE;
- else
- epctrl &= ~EPCTRL_RX_ENABLE;
- fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
+
+#if defined(CONFIG_ARCH_TEGRA)
+ /* Touch the registers if cable is connected and phy is on */
+ if(vbus_enabled())
+#endif
+ {
+ epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+ if (ep_is_in(ep))
+ epctrl &= ~EPCTRL_TX_ENABLE;
+ else
+ epctrl &= ~EPCTRL_RX_ENABLE;
+ fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
+ }
/* make sure it's actually queued on this endpoint */
list_for_each_entry(req, &ep->queue, queue) {
done(ep, req, -ECONNRESET);
/* Enable EP */
-out: epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
- if (ep_is_in(ep))
- epctrl |= EPCTRL_TX_ENABLE;
- else
- epctrl |= EPCTRL_RX_ENABLE;
- fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
+out:
+#if defined(CONFIG_ARCH_TEGRA)
+ /* Touch the registers if cable is connected and phy is on */
+ if(vbus_enabled())
+#endif
+ {
+ epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+ if (ep_is_in(ep))
+ epctrl |= EPCTRL_TX_ENABLE;
+ else
+ epctrl |= EPCTRL_RX_ENABLE;
+ fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
+ }
ep->stopped = stopped;
spin_unlock_irqrestore(&ep->udc->lock, flags);
unsigned long timeout;
#define FSL_UDC_FLUSH_TIMEOUT 1000
+#if defined(CONFIG_ARCH_TEGRA)
+ /* Touch the registers if cable is connected and phy is on */
+ if (!vbus_enabled())
+ return;
+#endif
+
if (!_ep) {
return;
} else {
/*-----------------------------------------------------------------------
* Tries to wake up the host connected to this gadget
-----------------------------------------------------------------------*/
+#ifndef CONFIG_USB_ANDROID
static int fsl_wakeup(struct usb_gadget *gadget)
{
struct fsl_udc *udc = container_of(gadget, struct fsl_udc, gadget);
fsl_writel(portsc, &dr_regs->portsc1);
return 0;
}
+#endif
static int can_pullup(struct fsl_udc *udc)
{
unsigned long flags;
udc = container_of(gadget, struct fsl_udc, gadget);
- spin_lock_irqsave(&udc->lock, flags);
+
VDBG("VBUS %s", is_active ? "on" : "off");
+
+ if (udc->transceiver) {
+ if (udc->vbus_active && !is_active) {
+ /* If cable disconnected, cancel any delayed work */
+ cancel_delayed_work(&udc->work);
+ spin_lock_irqsave(&udc->lock, flags);
+ /* reset all internal Queues and inform client driver */
+ reset_queues(udc);
+ /* stop the controller and turn off the clocks */
+ dr_controller_stop(udc);
+ dr_controller_reset(udc);
+ udc->vbus_active = 0;
+ udc->usb_state = USB_STATE_DEFAULT;
+ spin_unlock_irqrestore(&udc->lock, flags);
+ fsl_udc_clk_suspend(false);
+ if (udc->vbus_regulator) {
+ /* set the current limit to 0mA */
+ regulator_set_current_limit(
+ udc->vbus_regulator, 0, 0);
+ }
+ } else if (!udc->vbus_active && is_active) {
+ fsl_udc_clk_resume(false);
+ /* setup the controller in the device mode */
+ dr_controller_setup(udc);
+ /* setup EP0 for setup packet */
+ ep0_setup(udc);
+ /* initialize the USB and EP states */
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ udc->vbus_active = 1;
+ /* start the controller */
+ dr_controller_run(udc);
+ if (udc->vbus_regulator) {
+ /* set the current limit to 100mA */
+ regulator_set_current_limit(
+ udc->vbus_regulator, 0, 100);
+ }
+ /* Schedule work to wait for 1000 msec and check for
+ * charger if setup packet is not received */
+ schedule_delayed_work(&udc->work,
+ USB_CHARGER_DETECTION_WAIT_TIME_MS);
+ }
+
+#ifndef CONFIG_USB_G_ANDROID
+ return 0;
+#endif
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
udc->vbus_active = (is_active != 0);
if (can_pullup(udc))
fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
struct fsl_udc *udc;
udc = container_of(gadget, struct fsl_udc, gadget);
+ /* check udc regulator is available for drawing the vbus current */
+ if (udc->vbus_regulator) {
+ udc->current_limit = mA;
+ schedule_work(&udc->charger_work);
+ }
+
if (udc->transceiver)
return otg_set_power(udc->transceiver, mA);
return -ENOTSUPP;
udc = container_of(gadget, struct fsl_udc, gadget);
udc->softconnect = (is_on != 0);
- if (can_pullup(udc))
- fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
- &dr_regs->usbcmd);
- else
- fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),
- &dr_regs->usbcmd);
-
+ if (udc_controller->transceiver) {
+ if (udc_controller->transceiver->state == OTG_STATE_B_PERIPHERAL) {
+ if (can_pullup(udc))
+ fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
+ &dr_regs->usbcmd);
+ else
+ fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),
+ &dr_regs->usbcmd);
+ }
+ }
return 0;
}
/* defined in gadget.h */
static struct usb_gadget_ops fsl_gadget_ops = {
.get_frame = fsl_get_frame,
+#ifndef CONFIG_USB_ANDROID
.wakeup = fsl_wakeup,
+#endif
/* .set_selfpowered = fsl_set_selfpowered, */ /* Always selfpowered */
.vbus_session = fsl_vbus_session,
.vbus_draw = fsl_vbus_draw,
ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->mapped = 1;
- if (fsl_req_to_dtd(req) == 0)
+ if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0)
fsl_queue_td(ep, req);
else
return -ENOMEM;
req->req.complete = NULL;
req->dtd_count = 0;
- req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
- req->req.buf, req->req.length,
- ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 1;
+ /* map virtual address to hardware */
+ if (req->req.dma == DMA_ADDR_INVALID) {
+ req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
+ req->req.buf,
+ req->req.length, ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->mapped = 0;
+ }
/* prime the data phase */
- if ((fsl_req_to_dtd(req) == 0))
+ if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0))
fsl_queue_td(ep, req);
else /* no mem */
goto stall;
ep0stall(udc);
}
+static void udc_test_mode(struct fsl_udc *udc, u32 test_mode)
+{
+ struct fsl_req *req;
+ struct fsl_ep *ep;
+ u32 portsc, bitmask;
+ unsigned long timeout;
+
+ /* Ack the ep0 IN */
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ ep0stall(udc);
+
+ /* get the ep0 */
+ ep = &udc->eps[0];
+ bitmask = ep_is_in(ep)
+ ? (1 << (ep_index(ep) + 16))
+ : (1 << (ep_index(ep)));
+
+ timeout = jiffies + HZ;
+ /* Wait until ep0 IN endpoint txfr is complete */
+ while (!(fsl_readl(&dr_regs->endptcomplete) & bitmask)) {
+ if (time_after(jiffies, timeout)) {
+ pr_err("Timeout for Ep0 IN Ack\n");
+ break;
+ }
+ cpu_relax();
+ }
+
+ switch (test_mode << PORTSCX_PTC_BIT_POS) {
+ case PORTSCX_PTC_JSTATE:
+ VDBG("TEST_J\n");
+ break;
+ case PORTSCX_PTC_KSTATE:
+ VDBG("TEST_K\n");
+ break;
+ case PORTSCX_PTC_SEQNAK:
+ VDBG("TEST_SE0_NAK\n");
+ break;
+ case PORTSCX_PTC_PACKET:
+ VDBG("TEST_PACKET\n");
+
+ /* get the ep and configure for IN direction */
+ ep = &udc->eps[0];
+ udc->ep0_dir = USB_DIR_IN;
+
+ /* Initialize ep0 status request structure */
+ req = container_of(fsl_alloc_request(NULL, GFP_ATOMIC),
+ struct fsl_req, req);
+ /* allocate a small amount of memory to get valid address */
+ req->req.buf = kmalloc(sizeof(fsl_udc_test_packet), GFP_ATOMIC);
+ req->req.dma = virt_to_phys(req->req.buf);
+
+ /* Fill in the reqest structure */
+ memcpy(req->req.buf, fsl_udc_test_packet, sizeof(fsl_udc_test_packet));
+ req->ep = ep;
+ req->req.length = sizeof(fsl_udc_test_packet);
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->req.complete = NULL;
+ req->dtd_count = 0;
+ req->mapped = 0;
+
+ dma_sync_single_for_device(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+
+ /* prime the data phase */
+ if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0))
+ fsl_queue_td(ep, req);
+ else /* no mem */
+ goto stall;
+
+ list_add_tail(&req->queue, &ep->queue);
+ udc->ep0_state = DATA_STATE_XMIT;
+ break;
+ case PORTSCX_PTC_FORCE_EN:
+ VDBG("TEST_FORCE_EN\n");
+ break;
+ default:
+ ERR("udc unknown test mode[%d]!\n", test_mode);
+ goto stall;
+ }
+
+ /* read the portsc register */
+ portsc = fsl_readl(&dr_regs->portsc1);
+ /* set the test mode selector */
+ portsc |= test_mode << PORTSCX_PTC_BIT_POS;
+ fsl_writel(portsc, &dr_regs->portsc1);
+
+ /*
+ * The device must have its power cycled to exit test mode.
+ * See USB 2.0 spec, section 9.4.9 for test modes operation in "Set Feature"
+ * See USB 2.0 spec, section 7.1.20 for test modes.
+ */
+ pr_info("udc entering the test mode, power cycle to exit test mode\n");
+ return;
+stall:
+ ep0stall(udc);
+}
+
static void setup_received_irq(struct fsl_udc *udc,
struct usb_ctrlrequest *setup)
{
if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD
| USB_RECIP_DEVICE))
break;
+#ifdef CONFIG_ARCH_TEGRA
+ /* This delay is necessary for some windows drivers to
+ * properly recognize the device */
+ mdelay(1);
+#endif
ch9setaddress(udc, wValue, wIndex, wLength);
return;
int rc = -EOPNOTSUPP;
u16 ptc = 0;
- if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))
+ if (setup->bRequestType == USB_RECIP_DEVICE &&
+ wValue == USB_DEVICE_TEST_MODE) {
+ /*
+ * If the feature selector is TEST_MODE, then the most
+ * significant byte of wIndex is used to specify the specific
+ * test mode and the lower byte of wIndex must be zero.
+ */
+ udc_test_mode(udc, wIndex >> 8);
+ return;
+
+ } else if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))
== (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
int pipe = get_pipe_by_windex(wIndex);
struct fsl_ep *ep;
udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
? USB_DIR_IN : USB_DIR_OUT;
spin_unlock(&udc->lock);
- if (udc->driver->setup(&udc->gadget,
+ if (udc->driver && udc->driver->setup(&udc->gadget,
&udc->local_setup_buff) < 0)
ep0stall(udc);
spin_lock(&udc->lock);
/* No data phase, IN status from gadget */
udc->ep0_dir = USB_DIR_IN;
spin_unlock(&udc->lock);
- if (udc->driver->setup(&udc->gadget,
+ if (udc->driver && udc->driver->setup(&udc->gadget,
&udc->local_setup_buff) < 0)
ep0stall(udc);
spin_lock(&udc->lock);
{
u32 speed;
- if (udc->bus_reset)
- udc->bus_reset = 0;
-
/* Bus resetting is finished */
if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) {
/* Get the speed */
- speed = (fsl_readl(&dr_regs->portsc1)
+ speed = (fsl_readl(control_reg)
& PORTSCX_PORT_SPEED_MASK);
switch (speed) {
case PORTSCX_PORT_SPEED_HIGH:
udc->usb_state = USB_STATE_SUSPENDED;
/* report suspend to the driver, serial.c does not support this */
- if (udc->driver->suspend)
+ if (udc->driver && udc->driver->suspend)
udc->driver->suspend(&udc->gadget);
}
udc->resume_state = 0;
/* report resume to the driver, serial.c does not support this */
- if (udc->driver->resume)
+ if (udc->driver && udc->driver->resume)
udc->driver->resume(&udc->gadget);
}
/* report disconnect; the driver is already quiesced */
spin_unlock(&udc->lock);
- udc->driver->disconnect(&udc->gadget);
+ if (udc->driver && udc->driver->disconnect)
+ udc->driver->disconnect(&udc->gadget);
spin_lock(&udc->lock);
return 0;
#else
if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {
VDBG("Bus reset");
- /* Bus is reseting */
- udc->bus_reset = 1;
/* Reset all the queues, include XD, dTD, EP queue
* head and TR Queue */
reset_queues(udc);
#endif
}
+static void fsl_udc_set_current_limit_work(struct work_struct* work)
+{
+ struct fsl_udc *udc = container_of (work, struct fsl_udc, charger_work);
+
+ /* check udc regulator is available for drawing vbus current*/
+ if (udc->vbus_regulator) {
+ /* set the current limit in uA */
+ regulator_set_current_limit(
+ udc->vbus_regulator, 0,
+ udc->current_limit *1000);
+ }
+}
+
+/*
+ * If VBUS is detected and setup packet is not received in 100ms then
+ * work thread starts and checks for the USB charger detection.
+ */
+static void fsl_udc_charger_detect_work(struct work_struct* work)
+{
+ struct fsl_udc *udc = container_of (work, struct fsl_udc, work.work);
+
+ /* check for the platform charger detection */
+ if (fsl_udc_charger_detect()) {
+ printk(KERN_INFO "USB compliant charger detected\n");
+ /* check udc regulator is available for drawing vbus current*/
+ if (udc->vbus_regulator) {
+ /* set the current limit in uA */
+ regulator_set_current_limit(
+ udc->vbus_regulator, 0,
+ USB_CHARGING_CURRENT_LIMIT_MA*1000);
+ }
+ }
+}
+
+#if defined(CONFIG_ARCH_TEGRA)
+/*
+ * Restart device controller in the OTG mode on VBUS detection
+ */
+static void fsl_udc_restart(struct fsl_udc *udc)
+{
+ /* setup the controller in the device mode */
+ dr_controller_setup(udc);
+ /* setup EP0 for setup packet */
+ ep0_setup(udc);
+ /* start the controller */
+ dr_controller_run(udc);
+ /* initialize the USB and EP states */
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ udc->vbus_active = 1;
+}
+#endif
+
/*
* USB device controller interrupt handler
*/
spin_lock_irqsave(&udc->lock, flags);
-#ifdef CONFIG_ARCH_TEGRA
- if (udc->transceiver) {
- if (udc->transceiver->state == OTG_STATE_B_PERIPHERAL) {
- if (!udc->vbus_active) {
- /* set vbus active and enable the usb clocks */
- udc->vbus_active = 1;
- fsl_udc_clk_resume();
- /* setup the controller in the device mode */
- dr_controller_setup(udc);
- /* setup EP0 for setup packet */
- ep0_setup(udc);
- /* start the controller */
- dr_controller_run(udc);
- /* initialize the USB and EP states */
- udc->usb_state = USB_STATE_ATTACHED;
- udc->ep0_state = WAIT_FOR_SETUP;
- udc->ep0_dir = 0;
- }
- } else if (udc->transceiver->state == OTG_STATE_A_SUSPEND) {
- if (udc->vbus_active) {
- /* Reset all internal Queues and inform client driver */
- reset_queues(udc);
- /* stop the controller and turn off the clocks */
- dr_controller_stop(udc);
- fsl_udc_clk_suspend();
- udc->vbus_active = 0;
- udc->usb_state = USB_STATE_DEFAULT;
- } else {
- spin_unlock_irqrestore(&udc->lock, flags);
- return IRQ_HANDLED;
- }
- } else {
- spin_unlock_irqrestore(&udc->lock, flags);
- return IRQ_HANDLED;
- }
- }
-#endif
-
/* Disable ISR for OTG host mode */
if (udc->stopped) {
spin_unlock_irqrestore(&udc->lock, flags);
return IRQ_NONE;
}
-
+#ifndef CONFIG_TEGRA_SILICON_PLATFORM
+ {
+ u32 temp = fsl_readl(&usb_sys_regs->vbus_sensors);
+ udc->vbus_active = (temp & USB_SYS_VBUS_ASESSION) ? true : false;
+ /* write back the register to clear the interrupt */
+ fsl_writel(temp, &usb_sys_regs->vbus_sensors);
+ }
+#endif
irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr);
/* Clear notification bits */
fsl_writel(irq_src, &dr_regs->usbsts);
/* VDBG("irq_src [0x%8x]", irq_src); */
-#ifdef CONFIG_ARCH_TEGRA
- if (!udc->transceiver) {
- /* VBUS A session detection interrupts. When the interrupt is received,
- * the mark the vbus active shadow.
- */
- temp = fsl_readl(&usb_sys_regs->vbus_wakeup);
- if (temp & USB_SYS_VBUS_WAKEUP_INT_STATUS) {
- if (temp & USB_SYS_VBUS_STATUS) {
- udc->vbus_active = 1;
- } else {
- reset_queues(udc);
- udc->vbus_active = 0;
- udc->usb_state = USB_STATE_DEFAULT;
- }
- /* write back the register to clear the interrupt */
- fsl_writel(temp, &usb_sys_regs->vbus_wakeup);
-
- if (udc->vbus_active)
- fsl_udc_clk_resume();
- else
- fsl_udc_clk_suspend();
-
- status = IRQ_HANDLED;
- }
- }
-#endif
-
/* Need to resume? */
if (udc->usb_state == USB_STATE_SUSPENDED)
if ((fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_SUSPEND) == 0)
VDBG("Packet int");
/* Setup package, we only support ep0 as control ep */
if (fsl_readl(&dr_regs->endptsetupstat) & EP_SETUP_STATUS_EP0) {
+ /* Setup packet received, we are connected to host and
+ * not charger. Cancel any delayed work */
+ __cancel_delayed_work(&udc->work);
tripwire_handler(udc, 0,
(u8 *) (&udc->local_setup_buff));
setup_received_irq(udc, &udc->local_setup_buff);
/* Reset Received */
if (irq_src & USB_STS_RESET) {
- VDBG("reset int");
reset_irq(udc);
status = IRQ_HANDLED;
}
goto out;
}
- if (udc_controller->transceiver) {
- /* Suspend the controller until OTG enable it */
- udc_controller->stopped = 1;
- printk(KERN_INFO "Suspend udc for OTG auto detect\n");
-
- /* connect to bus through transceiver */
- if (udc_controller->transceiver) {
- retval = otg_set_peripheral(udc_controller->transceiver,
- &udc_controller->gadget);
- if (retval < 0) {
- ERR("can't bind to transceiver\n");
- driver->unbind(&udc_controller->gadget);
- udc_controller->gadget.dev.driver = 0;
- udc_controller->driver = 0;
- return retval;
- }
- }
- } else {
- /* Enable DR IRQ reg and set USBCMD reg Run bit */
+ /* Enable DR IRQ reg and Set usbcmd reg Run bit */
+ if (!udc_controller->transceiver) {
dr_controller_run(udc_controller);
udc_controller->usb_state = USB_STATE_ATTACHED;
udc_controller->ep0_state = WAIT_FOR_SETUP;
udc_controller->ep0_dir = 0;
}
+
printk(KERN_INFO "%s: bind to driver %s\n",
udc_controller->gadget.name, driver->driver.name);
unsigned long flags;
int t, i;
u32 tmp_reg;
+ u32 tmp_reg2;
struct fsl_ep *ep = NULL;
struct fsl_req *req;
next += t;
tmp_reg = fsl_readl(&dr_regs->portsc1);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ tmp_reg2 = tmp_reg;
+#else
+ /* In Tegra3 the Phy Type Select(PTS) and Port Speed fields are specified in
+ * hostpc1devlc register instead of portsc1 register. */
+ tmp_reg2 = fsl_readl(&dr_regs->hostpc1devlc);
+#endif
t = scnprintf(next, size,
"USB Port Status&Control Reg:\n"
"Port Transceiver Type : %s Port Speed: %s\n"
"Port Enabled/Disabled: %s "
"Current Connect Status: %s\n\n", ( {
char *s;
- switch (tmp_reg & PORTSCX_PTS_FSLS) {
+ switch (tmp_reg2 & PORTSCX_PTS_FSLS) {
case PORTSCX_PTS_UTMI:
s = "UTMI"; break;
case PORTSCX_PTS_ULPI:
}
s;} ), ( {
char *s;
- switch (tmp_reg & PORTSCX_PORT_SPEED_UNDEF) {
+ switch (tmp_reg2 & PORTSCX_PORT_SPEED_UNDEF) {
case PORTSCX_PORT_SPEED_FULL:
s = "Full Speed"; break;
case PORTSCX_PORT_SPEED_LOW:
spin_lock_init(&udc_controller->lock);
udc_controller->stopped = 1;
-#ifdef CONFIG_USB_OTG
- if (pdata->operating_mode == FSL_USB2_DR_OTG) {
- udc_controller->transceiver = otg_get_transceiver();
- if (!udc_controller->transceiver) {
- ERR("Can't find OTG driver!\n");
- ret = -ENODEV;
- goto err_kfree;
- }
- }
-#endif
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENXIO;
goto err_kfree;
}
- if (pdata->operating_mode == FSL_USB2_DR_DEVICE) {
- if (!request_mem_region(res->start, resource_size(res),
- driver_name)) {
- ERR("request mem region for %s failed\n", pdev->name);
- ret = -EBUSY;
- goto err_kfree;
- }
+ if (!request_mem_region(res->start, resource_size(res),
+ driver_name)) {
+ ERR("request mem region for %s failed\n", pdev->name);
+ ret = -EBUSY;
+ goto err_kfree;
}
dr_regs = ioremap(res->start, resource_size(res));
}
#endif
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ control_reg = &dr_regs->portsc1;
+#else
+ control_reg = &dr_regs->hostpc1devlc;
+#endif
#if !defined(CONFIG_ARCH_MXC) && !defined(CONFIG_ARCH_TEGRA)
if (pdata->have_sysif_regs)
usb_sys_regs = (struct usb_sys_interface *)
goto err_free_irq;
}
- if (!udc_controller->transceiver) {
- /* initialize usb hw reg except for regs for EP,
- * leave usbintr reg untouched */
- dr_controller_setup(udc_controller);
- }
+ /* initialize usb hw reg except for regs for EP,
+ * leave usbintr reg untouched */
+ dr_controller_setup(udc_controller);
fsl_udc_clk_finalize(pdev);
if (ret < 0)
goto err_free_irq;
- if (udc_controller->transceiver)
- udc_controller->gadget.is_otg = 1;
-
/* setup QH and epctrl for ep0 */
ep0_setup(udc_controller);
create_proc_file();
+ /* create a delayed work for detecting the USB charger */
+ INIT_DELAYED_WORK(&udc_controller->work, fsl_udc_charger_detect_work);
+ INIT_WORK(&udc_controller->charger_work, fsl_udc_set_current_limit_work);
+
+ /* Get the regulator for drawing the vbus current in udc driver */
+ udc_controller->vbus_regulator = regulator_get(NULL, "usb_bat_chg");
+ if (IS_ERR(udc_controller->vbus_regulator)) {
+ dev_err(&pdev->dev,
+ "can't get charge regulator,err:%ld\n",
+ PTR_ERR(udc_controller->vbus_regulator));
+ udc_controller->vbus_regulator = NULL;
+ }
+
#ifdef CONFIG_USB_OTG_UTILS
+ udc_controller->transceiver = otg_get_transceiver();
if (udc_controller->transceiver) {
dr_controller_stop(udc_controller);
- fsl_udc_clk_suspend();
+ dr_controller_reset(udc_controller);
+ fsl_udc_clk_suspend(false);
udc_controller->vbus_active = 0;
udc_controller->usb_state = USB_STATE_DEFAULT;
otg_set_peripheral(udc_controller->transceiver, &udc_controller->gadget);
#else
#ifdef CONFIG_ARCH_TEGRA
/* Power down the phy if cable is not connected */
- if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS))
- fsl_udc_clk_suspend();
+ if(!vbus_enabled())
+ fsl_udc_clk_suspend(false);
#endif
#endif
err_iounmap_noclk:
iounmap(dr_regs);
err_release_mem_region:
- if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
- release_mem_region(res->start, resource_size(res));
+ release_mem_region(res->start, resource_size(res));
err_kfree:
kfree(udc_controller);
udc_controller = NULL;
usb_del_gadget_udc(&udc_controller->gadget);
udc_controller->done = &done;
+ cancel_delayed_work(&udc_controller->work);
+ if (udc_controller->vbus_regulator)
+ regulator_put(udc_controller->vbus_regulator);
+
if (udc_controller->transceiver)
otg_set_peripheral(udc_controller->transceiver, NULL);
dma_pool_destroy(udc_controller->td_pool);
free_irq(udc_controller->irq, udc_controller);
iounmap(dr_regs);
- if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
- release_mem_region(res->start, resource_size(res));
+ release_mem_region(res->start, resource_size(res));
device_unregister(&udc_controller->gadget.dev);
/* free udc --wait for the release() finished */
-----------------------------------------------------------------*/
static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state)
{
- dr_controller_stop(udc_controller);
- return 0;
+ if (udc_controller->transceiver) {
+ if (udc_controller->transceiver->state != OTG_STATE_B_PERIPHERAL) {
+ /* we are not in device mode, return */
+ return 0;
+ }
+ }
+ if (udc_controller->vbus_active) {
+ spin_lock(&udc_controller->lock);
+ /* Reset all internal Queues and inform client driver */
+ reset_queues(udc_controller);
+ udc_controller->vbus_active = 0;
+ udc_controller->usb_state = USB_STATE_DEFAULT;
+ spin_unlock(&udc_controller->lock);
+ }
+ /* stop the controller and turn off the clocks */
+ dr_controller_stop(udc_controller);
+ if (udc_controller->transceiver) {
+ udc_controller->transceiver->state = OTG_STATE_UNDEFINED;
+ }
+ fsl_udc_clk_suspend(true);
+ return 0;
}
/*-----------------------------------------------------------------
*-----------------------------------------------------------------*/
static int fsl_udc_resume(struct platform_device *pdev)
{
+ if (udc_controller->transceiver) {
+ fsl_udc_clk_resume(true);
+ if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_ID_PIN_STATUS)) {
+ /* If ID status is low means host is connected, return */
+ fsl_udc_clk_suspend(false);
+ return 0;
+ }
+ /* check for VBUS */
+ if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) {
+ /* if there is no VBUS then power down the clocks and return */
+ fsl_udc_clk_suspend(false);
+ return 0;
+ } else {
+ fsl_udc_clk_suspend(false);
+ if (udc_controller->transceiver->state == OTG_STATE_A_HOST)
+ return 0;
+ /* Detected VBUS set the transceiver state to device mode */
+ udc_controller->transceiver->state = OTG_STATE_B_PERIPHERAL;
+ }
+ }
+ fsl_udc_clk_resume(true);
+#if defined(CONFIG_ARCH_TEGRA)
+ fsl_udc_restart(udc_controller);
+#else
/* Enable DR irq reg and set controller Run */
if (udc_controller->stopped) {
dr_controller_setup(udc_controller);
udc_controller->usb_state = USB_STATE_ATTACHED;
udc_controller->ep0_state = WAIT_FOR_SETUP;
udc_controller->ep0_dir = 0;
- return 0;
-}
-
-static int fsl_udc_otg_suspend(struct device *dev, pm_message_t state)
-{
- struct fsl_udc *udc = udc_controller;
- u32 mode, usbcmd;
-
- mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK;
-
- pr_debug("%s(): mode 0x%x stopped %d\n", __func__, mode, udc->stopped);
-
- /*
- * If the controller is already stopped, then this must be a
- * PM suspend. Remember this fact, so that we will leave the
- * controller stopped at PM resume time.
- */
- if (udc->stopped) {
- pr_debug("gadget already stopped, leaving early\n");
- udc->already_stopped = 1;
- return 0;
- }
-
- if (mode != USB_MODE_CTRL_MODE_DEVICE) {
- pr_debug("gadget not in device mode, leaving early\n");
- return 0;
- }
-
- /* stop the controller */
- usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP;
- fsl_writel(usbcmd, &dr_regs->usbcmd);
-
- udc->stopped = 1;
-
- pr_info("USB Gadget suspended\n");
+#endif
+ /* Power down the phy if cable is not connected */
+ if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS))
+ fsl_udc_clk_suspend(false);
return 0;
}
-static int fsl_udc_otg_resume(struct device *dev)
-{
- pr_debug("%s(): stopped %d already_stopped %d\n", __func__,
- udc_controller->stopped, udc_controller->already_stopped);
-
- /*
- * If the controller was stopped at suspend time, then
- * don't resume it now.
- */
- if (udc_controller->already_stopped) {
- udc_controller->already_stopped = 0;
- pr_debug("gadget was already stopped, leaving early\n");
- return 0;
- }
-
- pr_info("USB Gadget resume\n");
-
- return fsl_udc_resume(NULL);
-}
-
/*-------------------------------------------------------------------------
Register entry point for the peripheral controller driver
--------------------------------------------------------------------------*/
.driver = {
.name = (char *)driver_name,
.owner = THIS_MODULE,
- /* udc suspend/resume called from OTG driver */
- .suspend = fsl_udc_otg_suspend,
- .resume = fsl_udc_otg_resume,
},
};