summaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/fsl_udc_core.c
diff options
context:
space:
mode:
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>2014-07-15 13:09:45 +0200
committerFelipe Balbi <balbi@ti.com>2014-07-16 12:15:28 -0500
commit90fccb529d241b55829701cfb9eb3086570f38b8 (patch)
tree4e788b13b8c35bc5c9d24597479cda82d503bf7c /drivers/usb/gadget/fsl_udc_core.c
parent8443f2d2b7782fef35fe579bf1eb612c24951486 (diff)
usb: gadget: Gadget directory cleanup - group UDC drivers
The drivers/usb/gadget directory contains many files. Files which are related can be distributed into separate directories. This patch moves the UDC drivers into a separate directory. Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/fsl_udc_core.c')
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c2682
1 files changed, 0 insertions, 2682 deletions
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
deleted file mode 100644
index 57944ee8ad90..000000000000
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ /dev/null
@@ -1,2682 +0,0 @@
-/*
- * Copyright (C) 2004-2007,2011-2012 Freescale Semiconductor, Inc.
- * All rights reserved.
- *
- * Author: Li Yang <leoli@freescale.com>
- * Jiang Bo <tanya.jiang@freescale.com>
- *
- * Description:
- * Freescale high-speed USB SOC DR module device controller driver.
- * This can be found on MPC8349E/MPC8313E/MPC5121E cpus.
- * The driver is previously named as mpc_udc. Based on bare board
- * code from Dave Liu and Shlomi Gridish.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#undef VERBOSE
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/mm.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/otg.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#include <linux/fsl_devices.h>
-#include <linux/dmapool.h>
-#include <linux/delay.h>
-#include <linux/of_device.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/unaligned.h>
-#include <asm/dma.h>
-
-#include "fsl_usb2_udc.h"
-
-#define DRIVER_DESC "Freescale High-Speed USB SOC Device Controller driver"
-#define DRIVER_AUTHOR "Li Yang/Jiang Bo"
-#define DRIVER_VERSION "Apr 20, 2007"
-
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
-static const char driver_name[] = "fsl-usb2-udc";
-static const char driver_desc[] = DRIVER_DESC;
-
-static struct usb_dr_device *dr_regs;
-
-static struct usb_sys_interface *usb_sys_regs;
-
-/* it is initialized in probe() */
-static struct fsl_udc *udc_controller = NULL;
-
-static const struct usb_endpoint_descriptor
-fsl_ep0_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0,
- .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
- .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD,
-};
-
-static void fsl_ep_fifo_flush(struct usb_ep *_ep);
-
-#ifdef CONFIG_PPC32
-/*
- * On some SoCs, the USB controller registers can be big or little endian,
- * depending on the version of the chip. In order to be able to run the
- * same kernel binary on 2 different versions of an SoC, the BE/LE decision
- * must be made at run time. _fsl_readl and fsl_writel are pointers to the
- * BE or LE readl() and writel() functions, and fsl_readl() and fsl_writel()
- * call through those pointers. Platform code for SoCs that have BE USB
- * registers should set pdata->big_endian_mmio flag.
- *
- * This also applies to controller-to-cpu accessors for the USB descriptors,
- * since their endianness is also SoC dependant. Platform code for SoCs that
- * have BE USB descriptors should set pdata->big_endian_desc flag.
- */
-static u32 _fsl_readl_be(const unsigned __iomem *p)
-{
- return in_be32(p);
-}
-
-static u32 _fsl_readl_le(const unsigned __iomem *p)
-{
- return in_le32(p);
-}
-
-static void _fsl_writel_be(u32 v, unsigned __iomem *p)
-{
- out_be32(p, v);
-}
-
-static void _fsl_writel_le(u32 v, unsigned __iomem *p)
-{
- out_le32(p, v);
-}
-
-static u32 (*_fsl_readl)(const unsigned __iomem *p);
-static void (*_fsl_writel)(u32 v, unsigned __iomem *p);
-
-#define fsl_readl(p) (*_fsl_readl)((p))
-#define fsl_writel(v, p) (*_fsl_writel)((v), (p))
-
-static inline void fsl_set_accessors(struct fsl_usb2_platform_data *pdata)
-{
- if (pdata->big_endian_mmio) {
- _fsl_readl = _fsl_readl_be;
- _fsl_writel = _fsl_writel_be;
- } else {
- _fsl_readl = _fsl_readl_le;
- _fsl_writel = _fsl_writel_le;
- }
-}
-
-static inline u32 cpu_to_hc32(const u32 x)
-{
- return udc_controller->pdata->big_endian_desc
- ? (__force u32)cpu_to_be32(x)
- : (__force u32)cpu_to_le32(x);
-}
-
-static inline u32 hc32_to_cpu(const u32 x)
-{
- return udc_controller->pdata->big_endian_desc
- ? be32_to_cpu((__force __be32)x)
- : le32_to_cpu((__force __le32)x);
-}
-#else /* !CONFIG_PPC32 */
-static inline void fsl_set_accessors(struct fsl_usb2_platform_data *pdata) {}
-
-#define fsl_readl(addr) readl(addr)
-#define fsl_writel(val32, addr) writel(val32, addr)
-#define cpu_to_hc32(x) cpu_to_le32(x)
-#define hc32_to_cpu(x) le32_to_cpu(x)
-#endif /* CONFIG_PPC32 */
-
-/********************************************************************
- * Internal Used Function
-********************************************************************/
-/*-----------------------------------------------------------------
- * done() - retire a request; caller blocked irqs
- * @status : request status to be set, only works when
- * request is still in progress.
- *--------------------------------------------------------------*/
-static void done(struct fsl_ep *ep, struct fsl_req *req, int status)
-{
- struct fsl_udc *udc = NULL;
- unsigned char stopped = ep->stopped;
- struct ep_td_struct *curr_td, *next_td;
- int j;
-
- udc = (struct fsl_udc *)ep->udc;
- /* Removed the req from fsl_ep->queue */
- list_del_init(&req->queue);
-
- /* req.status should be set as -EINPROGRESS in ep_queue() */
- if (req->req.status == -EINPROGRESS)
- req->req.status = status;
- else
- status = req->req.status;
-
- /* Free dtd for the request */
- next_td = req->head;
- for (j = 0; j < req->dtd_count; j++) {
- curr_td = next_td;
- if (j != req->dtd_count - 1) {
- next_td = curr_td->next_td_virt;
- }
- dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
- }
-
- usb_gadget_unmap_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
-
- if (status && (status != -ESHUTDOWN))
- VDBG("complete %s req %p stat %d len %u/%u",
- ep->ep.name, &req->req, status,
- req->req.actual, req->req.length);
-
- ep->stopped = 1;
-
- spin_unlock(&ep->udc->lock);
- /* complete() is from gadget layer,
- * eg fsg->bulk_in_complete() */
- if (req->req.complete)
- req->req.complete(&ep->ep, &req->req);
-
- spin_lock(&ep->udc->lock);
- ep->stopped = stopped;
-}
-
-/*-----------------------------------------------------------------
- * nuke(): delete all requests related to this ep
- * called with spinlock held
- *--------------------------------------------------------------*/
-static void nuke(struct fsl_ep *ep, int status)
-{
- ep->stopped = 1;
-
- /* Flush fifo */
- fsl_ep_fifo_flush(&ep->ep);
-
- /* Whether this eq has request linked */
- while (!list_empty(&ep->queue)) {
- struct fsl_req *req = NULL;
-
- req = list_entry(ep->queue.next, struct fsl_req, queue);
- done(ep, req, status);
- }
-}
-
-/*------------------------------------------------------------------
- Internal Hardware related function
- ------------------------------------------------------------------*/
-
-static int dr_controller_setup(struct fsl_udc *udc)
-{
- unsigned int tmp, portctrl, ep_num;
- unsigned int max_no_of_ep;
- unsigned int ctrl;
- unsigned long timeout;
-
-#define FSL_UDC_RESET_TIMEOUT 1000
-
- /* Config PHY interface */
- portctrl = fsl_readl(&dr_regs->portsc1);
- portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
- switch (udc->phy_mode) {
- case FSL_USB2_PHY_ULPI:
- if (udc->pdata->have_sysif_regs) {
- if (udc->pdata->controller_ver) {
- /* controller version 1.6 or above */
- ctrl = __raw_readl(&usb_sys_regs->control);
- ctrl &= ~USB_CTRL_UTMI_PHY_EN;
- ctrl |= USB_CTRL_USB_EN;
- __raw_writel(ctrl, &usb_sys_regs->control);
- }
- }
- portctrl |= PORTSCX_PTS_ULPI;
- break;
- case FSL_USB2_PHY_UTMI_WIDE:
- portctrl |= PORTSCX_PTW_16BIT;
- /* fall through */
- case FSL_USB2_PHY_UTMI:
- if (udc->pdata->have_sysif_regs) {
- if (udc->pdata->controller_ver) {
- /* controller version 1.6 or above */
- ctrl = __raw_readl(&usb_sys_regs->control);
- ctrl |= (USB_CTRL_UTMI_PHY_EN |
- USB_CTRL_USB_EN);
- __raw_writel(ctrl, &usb_sys_regs->control);
- mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI
- PHY CLK to become stable - 10ms*/
- }
- }
- portctrl |= PORTSCX_PTS_UTMI;
- break;
- case FSL_USB2_PHY_SERIAL:
- portctrl |= PORTSCX_PTS_FSLS;
- break;
- default:
- return -EINVAL;
- }
- fsl_writel(portctrl, &dr_regs->portsc1);
-
- /* 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();
- }
-
- /* Set the controller as device mode */
- tmp = fsl_readl(&dr_regs->usbmode);
- tmp &= ~USB_MODE_CTRL_MODE_MASK; /* clear mode bits */
- tmp |= USB_MODE_CTRL_MODE_DEVICE;
- /* Disable Setup Lockout */
- tmp |= USB_MODE_SETUP_LOCK_OFF;
- if (udc->pdata->es)
- tmp |= USB_MODE_ES;
- fsl_writel(tmp, &dr_regs->usbmode);
-
- /* Clear the setup status */
- fsl_writel(0, &dr_regs->usbsts);
-
- tmp = udc->ep_qh_dma;
- tmp &= USB_EP_LIST_ADDRESS_MASK;
- fsl_writel(tmp, &dr_regs->endpointlistaddr);
-
- VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x",
- udc->ep_qh, (int)tmp,
- fsl_readl(&dr_regs->endpointlistaddr));
-
- max_no_of_ep = (0x0000001F & fsl_readl(&dr_regs->dccparams));
- for (ep_num = 1; ep_num < max_no_of_ep; ep_num++) {
- tmp = fsl_readl(&dr_regs->endptctrl[ep_num]);
- tmp &= ~(EPCTRL_TX_TYPE | EPCTRL_RX_TYPE);
- tmp |= (EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT)
- | (EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT);
- fsl_writel(tmp, &dr_regs->endptctrl[ep_num]);
- }
- /* Config control enable i/o output, cpu endian register */
-#ifndef CONFIG_ARCH_MXC
- if (udc->pdata->have_sysif_regs) {
- ctrl = __raw_readl(&usb_sys_regs->control);
- ctrl |= USB_CTRL_IOENB;
- __raw_writel(ctrl, &usb_sys_regs->control);
- }
-#endif
-
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- /* Turn on cache snooping hardware, since some PowerPC platforms
- * wholly rely on hardware to deal with cache coherent. */
-
- if (udc->pdata->have_sysif_regs) {
- /* Setup Snooping for all the 4GB space */
- tmp = SNOOP_SIZE_2GB; /* starts from 0x0, size 2G */
- __raw_writel(tmp, &usb_sys_regs->snoop1);
- tmp |= 0x80000000; /* starts from 0x8000000, size 2G */
- __raw_writel(tmp, &usb_sys_regs->snoop2);
- }
-#endif
-
- return 0;
-}
-
-/* Enable DR irq and set controller to run state */
-static void dr_controller_run(struct fsl_udc *udc)
-{
- u32 temp;
-
- /* Enable DR irq reg */
- temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN
- | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN
- | USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_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;
- fsl_writel(temp, &dr_regs->usbmode);
-
- /* Set controller to Run */
- temp = fsl_readl(&dr_regs->usbcmd);
- temp |= USB_CMD_RUN_STOP;
- fsl_writel(temp, &dr_regs->usbcmd);
-}
-
-static void dr_controller_stop(struct fsl_udc *udc)
-{
- 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;
- }
- }
-
- /* disable all INTR */
- fsl_writel(0, &dr_regs->usbintr);
-
- /* Set stopped bit for isr */
- udc->stopped = 1;
-
- /* disable IO output */
-/* usb_sys_regs->control = 0; */
-
- /* set controller to Stop */
- tmp = fsl_readl(&dr_regs->usbcmd);
- tmp &= ~USB_CMD_RUN_STOP;
- fsl_writel(tmp, &dr_regs->usbcmd);
-}
-
-static void dr_ep_setup(unsigned char ep_num, unsigned char dir,
- unsigned char ep_type)
-{
- unsigned int tmp_epctrl = 0;
-
- tmp_epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
- if (dir) {
- if (ep_num)
- tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
- tmp_epctrl |= EPCTRL_TX_ENABLE;
- tmp_epctrl &= ~EPCTRL_TX_TYPE;
- tmp_epctrl |= ((unsigned int)(ep_type)
- << EPCTRL_TX_EP_TYPE_SHIFT);
- } else {
- if (ep_num)
- tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
- tmp_epctrl |= EPCTRL_RX_ENABLE;
- tmp_epctrl &= ~EPCTRL_RX_TYPE;
- tmp_epctrl |= ((unsigned int)(ep_type)
- << EPCTRL_RX_EP_TYPE_SHIFT);
- }
-
- fsl_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]);
-}
-
-static void
-dr_ep_change_stall(unsigned char ep_num, unsigned char dir, int value)
-{
- u32 tmp_epctrl = 0;
-
- tmp_epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
-
- if (value) {
- /* set the stall bit */
- if (dir)
- tmp_epctrl |= EPCTRL_TX_EP_STALL;
- else
- tmp_epctrl |= EPCTRL_RX_EP_STALL;
- } else {
- /* clear the stall bit and reset data toggle */
- if (dir) {
- tmp_epctrl &= ~EPCTRL_TX_EP_STALL;
- tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
- } else {
- tmp_epctrl &= ~EPCTRL_RX_EP_STALL;
- tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
- }
- }
- fsl_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]);
-}
-
-/* Get stall status of a specific ep
- Return: 0: not stalled; 1:stalled */
-static int dr_ep_get_stall(unsigned char ep_num, unsigned char dir)
-{
- u32 epctrl;
-
- epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
- if (dir)
- return (epctrl & EPCTRL_TX_EP_STALL) ? 1 : 0;
- else
- return (epctrl & EPCTRL_RX_EP_STALL) ? 1 : 0;
-}
-
-/********************************************************************
- Internal Structure Build up functions
-********************************************************************/
-
-/*------------------------------------------------------------------
-* struct_ep_qh_setup(): set the Endpoint Capabilites field of QH
- * @zlt: Zero Length Termination Select (1: disable; 0: enable)
- * @mult: Mult field
- ------------------------------------------------------------------*/
-static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num,
- unsigned char dir, unsigned char ep_type,
- unsigned int max_pkt_len,
- unsigned int zlt, unsigned char mult)
-{
- struct ep_queue_head *p_QH = &udc->ep_qh[2 * ep_num + dir];
- unsigned int tmp = 0;
-
- /* set the Endpoint Capabilites in QH */
- switch (ep_type) {
- case USB_ENDPOINT_XFER_CONTROL:
- /* Interrupt On Setup (IOS). for control ep */
- tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
- | EP_QUEUE_HEAD_IOS;
- break;
- case USB_ENDPOINT_XFER_ISOC:
- tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
- | (mult << EP_QUEUE_HEAD_MULT_POS);
- break;
- case USB_ENDPOINT_XFER_BULK:
- case USB_ENDPOINT_XFER_INT:
- tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS;
- break;
- default:
- VDBG("error ep type is %d", ep_type);
- return;
- }
- if (zlt)
- tmp |= EP_QUEUE_HEAD_ZLT_SEL;
-
- p_QH->max_pkt_length = cpu_to_hc32(tmp);
- p_QH->next_dtd_ptr = 1;
- p_QH->size_ioc_int_sts = 0;
-}
-
-/* Setup qh structure and ep register for ep0. */
-static void ep0_setup(struct fsl_udc *udc)
-{
- /* 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);
- struct_ep_qh_setup(udc, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL,
- USB_MAX_CTRL_PAYLOAD, 0, 0);
- dr_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL);
- dr_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL);
-
- return;
-
-}
-
-/***********************************************************************
- Endpoint Management Functions
-***********************************************************************/
-
-/*-------------------------------------------------------------------------
- * when configurations are set, or when interface settings change
- * for example the do_set_interface() in gadget layer,
- * the driver will enable or disable the relevant endpoints
- * ep0 doesn't use this routine. It is always enabled.
--------------------------------------------------------------------------*/
-static int fsl_ep_enable(struct usb_ep *_ep,
- const struct usb_endpoint_descriptor *desc)
-{
- struct fsl_udc *udc = NULL;
- struct fsl_ep *ep = NULL;
- unsigned short max = 0;
- unsigned char mult = 0, zlt;
- int retval = -EINVAL;
- unsigned long flags = 0;
-
- ep = container_of(_ep, struct fsl_ep, ep);
-
- /* catch various bogus parameters */
- if (!_ep || !desc
- || (desc->bDescriptorType != USB_DT_ENDPOINT))
- return -EINVAL;
-
- udc = ep->udc;
-
- if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN))
- return -ESHUTDOWN;
-
- max = usb_endpoint_maxp(desc);
-
- /* Disable automatic zlp generation. Driver is responsible to indicate
- * explicitly through req->req.zero. This is needed to enable multi-td
- * request. */
- zlt = 1;
-
- /* Assume the max packet size from gadget is always correct */
- switch (desc->bmAttributes & 0x03) {
- case USB_ENDPOINT_XFER_CONTROL:
- case USB_ENDPOINT_XFER_BULK:
- case USB_ENDPOINT_XFER_INT:
- /* mult = 0. Execute N Transactions as demonstrated by
- * the USB variable length packet protocol where N is
- * computed using the Maximum Packet Length (dQH) and
- * the Total Bytes field (dTD) */
- mult = 0;
- break;
- case USB_ENDPOINT_XFER_ISOC:
- /* Calculate transactions needed for high bandwidth iso */
- mult = (unsigned char)(1 + ((max >> 11) & 0x03));
- max = max & 0x7ff; /* bit 0~10 */
- /* 3 transactions at most */
- if (mult > 3)
- goto en_done;
- break;
- default:
- goto en_done;
- }
-
- spin_lock_irqsave(&udc->lock, flags);
- ep->ep.maxpacket = max;
- ep->ep.desc = desc;
- ep->stopped = 0;
-
- /* Controller related setup */
- /* Init EPx Queue Head (Ep Capabilites field in QH
- * according to max, zlt, mult) */
- struct_ep_qh_setup(udc, (unsigned char) ep_index(ep),
- (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN)
- ? USB_SEND : USB_RECV),
- (unsigned char) (desc->bmAttributes
- & USB_ENDPOINT_XFERTYPE_MASK),
- max, zlt, mult);
-
- /* Init endpoint ctrl register */
- dr_ep_setup((unsigned char) ep_index(ep),
- (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN)
- ? USB_SEND : USB_RECV),
- (unsigned char) (desc->bmAttributes
- & USB_ENDPOINT_XFERTYPE_MASK));
-
- spin_unlock_irqrestore(&udc->lock, flags);
- retval = 0;
-
- VDBG("enabled %s (ep%d%s) maxpacket %d",ep->ep.name,
- ep->ep.desc->bEndpointAddress & 0x0f,
- (desc->bEndpointAddress & USB_DIR_IN)
- ? "in" : "out", max);
-en_done:
- return retval;
-}
-
-/*---------------------------------------------------------------------
- * @ep : the ep being unconfigured. May not be ep0
- * Any pending and uncomplete req will complete with status (-ESHUTDOWN)
-*---------------------------------------------------------------------*/
-static int fsl_ep_disable(struct usb_ep *_ep)
-{
- struct fsl_udc *udc = NULL;
- struct fsl_ep *ep = NULL;
- unsigned long flags = 0;
- u32 epctrl;
- int ep_num;
-
- ep = container_of(_ep, struct fsl_ep, ep);
- if (!_ep || !ep->ep.desc) {
- VDBG("%s not enabled", _ep ? ep->ep.name : NULL);
- return -EINVAL;
- }
-
- /* 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;
- }
- fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
-
- udc = (struct fsl_udc *)ep->udc;
- spin_lock_irqsave(&udc->lock, flags);
-
- /* nuke all pending requests (does flush) */
- nuke(ep, -ESHUTDOWN);
-
- ep->ep.desc = NULL;
- ep->stopped = 1;
- spin_unlock_irqrestore(&udc->lock, flags);
-
- VDBG("disabled %s OK", _ep->name);
- return 0;
-}
-
-/*---------------------------------------------------------------------
- * allocate a request object used by this endpoint
- * the main operation is to insert the req->queue to the eq->queue
- * Returns the request, or null if one could not be allocated
-*---------------------------------------------------------------------*/
-static struct usb_request *
-fsl_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
-{
- struct fsl_req *req = NULL;
-
- req = kzalloc(sizeof *req, gfp_flags);
- if (!req)
- return NULL;
-
- req->req.dma = DMA_ADDR_INVALID;
- INIT_LIST_HEAD(&req->queue);
-
- return &req->req;
-}
-
-static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct fsl_req *req = NULL;
-
- req = container_of(_req, struct fsl_req, req);
-
- if (_req)
- kfree(req);
-}
-
-/* Actually add a dTD chain to an empty dQH and let go */
-static void fsl_prime_ep(struct fsl_ep *ep, struct ep_td_struct *td)
-{
- struct ep_queue_head *qh = get_qh_by_ep(ep);
-
- /* Write dQH next pointer and terminate bit to 0 */
- qh->next_dtd_ptr = cpu_to_hc32(td->td_dma
- & EP_QUEUE_HEAD_NEXT_POINTER_MASK);
-
- /* Clear active and halt bit */
- qh->size_ioc_int_sts &= cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
- | EP_QUEUE_HEAD_STATUS_HALT));
-
- /* Ensure that updates to the QH will occur before priming. */
- wmb();
-
- /* Prime endpoint by writing correct bit to ENDPTPRIME */
- fsl_writel(ep_is_in(ep) ? (1 << (ep_index(ep) + 16))
- : (1 << (ep_index(ep))), &dr_regs->endpointprime);
-}
-
-/* Add dTD chain to the dQH of an EP */
-static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
-{
- u32 temp, bitmask, tmp_stat;
-
- /* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr);
- VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */
-
- bitmask = ep_is_in(ep)
- ? (1 << (ep_index(ep) + 16))
- : (1 << (ep_index(ep)));
-
- /* check if the pipe is empty */
- if (!(list_empty(&ep->queue)) && !(ep_index(ep) == 0)) {
- /* Add td to the end */
- struct fsl_req *lastreq;
- lastreq = list_entry(ep->queue.prev, struct fsl_req, queue);
- lastreq->tail->next_td_ptr =
- cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK);
- /* Ensure dTD's next dtd pointer to be updated */
- wmb();
- /* Read prime bit, if 1 goto done */
- if (fsl_readl(&dr_regs->endpointprime) & bitmask)
- return;
-
- do {
- /* Set ATDTW bit in USBCMD */
- temp = fsl_readl(&dr_regs->usbcmd);
- fsl_writel(temp | USB_CMD_ATDTW, &dr_regs->usbcmd);
-
- /* Read correct status bit */
- tmp_stat = fsl_readl(&dr_regs->endptstatus) & bitmask;
-
- } while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_ATDTW));
-
- /* Write ATDTW bit to 0 */
- temp = fsl_readl(&dr_regs->usbcmd);
- fsl_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd);
-
- if (tmp_stat)
- return;
- }
-
- fsl_prime_ep(ep, req->head);
-}
-
-/* Fill in the dTD structure
- * @req: request that the transfer belongs to
- * @length: return actually data length of the dTD
- * @dma: return dma address of the dTD
- * @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, gfp_t gfp_flags)
-{
- u32 swap_temp;
- struct ep_td_struct *dtd;
-
- /* how big will this transfer be? */
- *length = min(req->req.length - req->req.actual,
- (unsigned)EP_MAX_LENGTH_TRANSFER);
-
- dtd = dma_pool_alloc(udc_controller->td_pool, gfp_flags, dma);
- if (dtd == NULL)
- return dtd;
-
- dtd->td_dma = *dma;
- /* Clear reserved field */
- swap_temp = hc32_to_cpu(dtd->size_ioc_sts);
- swap_temp &= ~DTD_RESERVED_FIELDS;
- dtd->size_ioc_sts = cpu_to_hc32(swap_temp);
-
- /* Init all of buffer page pointers */
- swap_temp = (u32) (req->req.dma + req->req.actual);
- dtd->buff_ptr0 = cpu_to_hc32(swap_temp);
- dtd->buff_ptr1 = cpu_to_hc32(swap_temp + 0x1000);
- dtd->buff_ptr2 = cpu_to_hc32(swap_temp + 0x2000);
- dtd->buff_ptr3 = cpu_to_hc32(swap_temp + 0x3000);
- dtd->buff_ptr4 = cpu_to_hc32(swap_temp + 0x4000);
-
- req->req.actual += *length;
-
- /* zlp is needed if req->req.zero is set */
- if (req->req.zero) {
- if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
- *is_last = 1;
- else
- *is_last = 0;
- } else if (req->req.length == req->req.actual)
- *is_last = 1;
- else
- *is_last = 0;
-
- if ((*is_last) == 0)
- VDBG("multi-dtd request!");
- /* Fill in the transfer size; set active bit */
- swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE);
-
- /* Enable interrupt for the last dtd of a request */
- if (*is_last && !req->req.no_interrupt)
- swap_temp |= DTD_IOC;
-
- dtd->size_ioc_sts = cpu_to_hc32(swap_temp);
-
- mb();
-
- VDBG("length = %d address= 0x%x", *length, (int)*dma);
-
- return dtd;
-}
-
-/* Generate dtd chain for a request */
-static int fsl_req_to_dtd(struct fsl_req *req, gfp_t gfp_flags)
-{
- unsigned count;
- int is_last;
- int is_first =1;
- struct ep_td_struct *last_dtd = NULL, *dtd;
- dma_addr_t dma;
-
- do {
- dtd = fsl_build_dtd(req, &count, &dma, &is_last, gfp_flags);
- if (dtd == NULL)
- return -ENOMEM;
-
- if (is_first) {
- is_first = 0;
- req->head = dtd;
- } else {
- last_dtd->next_td_ptr = cpu_to_hc32(dma);
- last_dtd->next_td_virt = dtd;
- }
- last_dtd = dtd;
-
- req->dtd_count++;
- } while (!is_last);
-
- dtd->next_td_ptr = cpu_to_hc32(DTD_NEXT_TERMINATE);
-
- req->tail = dtd;
-
- return 0;
-}
-
-/* queues (submits) an I/O request to an endpoint */
-static int
-fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
-{
- 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;
- unsigned long flags;
- int ret;
-
- /* catch various bogus parameters */
- if (!_req || !req->req.complete || !req->req.buf
- || !list_empty(&req->queue)) {
- VDBG("%s, bad params", __func__);
- return -EINVAL;
- }
- if (unlikely(!_ep || !ep->ep.desc)) {
- VDBG("%s, bad ep", __func__);
- return -EINVAL;
- }
- if (usb_endpoint_xfer_isoc(ep->ep.desc)) {
- if (req->req.length > ep->ep.maxpacket)
- return -EMSGSIZE;
- }
-
- udc = ep->udc;
- if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
-
- req->ep = ep;
-
- ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
- if (ret)
- return ret;
-
- req->req.status = -EINPROGRESS;
- req->req.actual = 0;
- req->dtd_count = 0;
-
- /* build dtds and push them to device queue */
- if (!fsl_req_to_dtd(req, gfp_flags)) {
- spin_lock_irqsave(&udc->lock, flags);
- fsl_queue_td(ep, req);
- } else {
- return -ENOMEM;
- }
-
- /* irq handler advances the queue */
- if (req != NULL)
- list_add_tail(&req->queue, &ep->queue);
- spin_unlock_irqrestore(&udc->lock, flags);
-
- return 0;
-}
-
-/* dequeues (cancels, unlinks) an I/O request from an endpoint */
-static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct fsl_ep *ep = container_of(_ep, struct fsl_ep, ep);
- struct fsl_req *req;
- unsigned long flags;
- int ep_num, stopped, ret = 0;
- u32 epctrl;
-
- if (!_ep || !_req)
- return -EINVAL;
-
- spin_lock_irqsave(&ep->udc->lock, flags);
- stopped = ep->stopped;
-
- /* 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]);
-
- /* make sure it's actually queued on this endpoint */
- list_for_each_entry(req, &ep->queue, queue) {
- if (&req->req == _req)
- break;
- }
- if (&req->req != _req) {
- ret = -EINVAL;
- goto out;
- }
-
- /* The request is in progress, or completed but not dequeued */
- if (ep->queue.next == &req->queue) {
- _req->status = -ECONNRESET;
- fsl_ep_fifo_flush(_ep); /* flush current transfer */
-
- /* The request isn't the last request in this ep queue */
- if (req->queue.next != &ep->queue) {
- struct fsl_req *next_req;
-
- next_req = list_entry(req->queue.next, struct fsl_req,
- queue);
-
- /* prime with dTD of next request */
- fsl_prime_ep(ep, next_req->head);
- }
- /* The request hasn't been processed, patch up the TD chain */
- } else {
- struct fsl_req *prev_req;
-
- prev_req = list_entry(req->queue.prev, struct fsl_req, queue);
- prev_req->tail->next_td_ptr = req->tail->next_td_ptr;
- }
-
- 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]);
- ep->stopped = stopped;
-
- spin_unlock_irqrestore(&ep->udc->lock, flags);
- return ret;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*-----------------------------------------------------------------
- * modify the endpoint halt feature
- * @ep: the non-isochronous endpoint being stalled
- * @value: 1--set halt 0--clear halt
- * Returns zero, or a negative error code.
-*----------------------------------------------------------------*/
-static int fsl_ep_set_halt(struct usb_ep *_ep, int value)
-{
- struct fsl_ep *ep = NULL;
- unsigned long flags = 0;
- int status = -EOPNOTSUPP; /* operation not supported */
- unsigned char ep_dir = 0, ep_num = 0;
- struct fsl_udc *udc = NULL;
-
- ep = container_of(_ep, struct fsl_ep, ep);
- udc = ep->udc;
- if (!_ep || !ep->ep.desc) {
- status = -EINVAL;
- goto out;
- }
-
- if (usb_endpoint_xfer_isoc(ep->ep.desc)) {
- status = -EOPNOTSUPP;
- goto out;
- }
-
- /* Attempt to halt IN ep will fail if any transfer requests
- * are still queue */
- if (value && ep_is_in(ep) && !list_empty(&ep->queue)) {
- status = -EAGAIN;
- goto out;
- }
-
- status = 0;
- ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV;
- ep_num = (unsigned char)(ep_index(ep));
- spin_lock_irqsave(&ep->udc->lock, flags);
- dr_ep_change_stall(ep_num, ep_dir, value);
- spin_unlock_irqrestore(&ep->udc->lock, flags);
-
- if (ep_index(ep) == 0) {
- udc->ep0_state = WAIT_FOR_SETUP;
- udc->ep0_dir = 0;
- }
-out:
- VDBG(" %s %s halt stat %d", ep->ep.name,
- value ? "set" : "clear", status);
-
- return status;
-}
-
-static int fsl_ep_fifo_status(struct usb_ep *_ep)
-{
- struct fsl_ep *ep;
- struct fsl_udc *udc;
- int size = 0;
- u32 bitmask;
- struct ep_queue_head *qh;
-
- ep = container_of(_ep, struct fsl_ep, ep);
- if (!_ep || (!ep->ep.desc && ep_index(ep) != 0))
- return -ENODEV;
-
- udc = (struct fsl_udc *)ep->udc;
-
- if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
-
- qh = get_qh_by_ep(ep);
-
- bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
- (1 << (ep_index(ep)));
-
- if (fsl_readl(&dr_regs->endptstatus) & bitmask)
- size = (qh->size_ioc_int_sts & DTD_PACKET_SIZE)
- >> DTD_LENGTH_BIT_POS;
-
- pr_debug("%s %u\n", __func__, size);
- return size;
-}
-
-static void fsl_ep_fifo_flush(struct usb_ep *_ep)
-{
- struct fsl_ep *ep;
- int ep_num, ep_dir;
- u32 bits;
- unsigned long timeout;
-#define FSL_UDC_FLUSH_TIMEOUT 1000
-
- if (!_ep) {
- return;
- } else {
- ep = container_of(_ep, struct fsl_ep, ep);
- if (!ep->ep.desc)
- return;
- }
- ep_num = ep_index(ep);
- ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV;
-
- if (ep_num == 0)
- bits = (1 << 16) | 1;
- else if (ep_dir == USB_SEND)
- bits = 1 << (16 + ep_num);
- else
- bits = 1 << ep_num;
-
- timeout = jiffies + FSL_UDC_FLUSH_TIMEOUT;
- do {
- fsl_writel(bits, &dr_regs->endptflush);
-
- /* Wait until flush complete */
- while (fsl_readl(&dr_regs->endptflush)) {
- if (time_after(jiffies, timeout)) {
- ERR("ep flush timeout\n");
- return;