190fccb52SAndrzej Pietrasiewicz /* 290fccb52SAndrzej Pietrasiewicz * USB Gadget driver for LPC32xx 390fccb52SAndrzej Pietrasiewicz * 490fccb52SAndrzej Pietrasiewicz * Authors: 590fccb52SAndrzej Pietrasiewicz * Kevin Wells <kevin.wells@nxp.com> 690fccb52SAndrzej Pietrasiewicz * Mike James 790fccb52SAndrzej Pietrasiewicz * Roland Stigge <stigge@antcom.de> 890fccb52SAndrzej Pietrasiewicz * 990fccb52SAndrzej Pietrasiewicz * Copyright (C) 2006 Philips Semiconductors 1090fccb52SAndrzej Pietrasiewicz * Copyright (C) 2009 NXP Semiconductors 1190fccb52SAndrzej Pietrasiewicz * Copyright (C) 2012 Roland Stigge 1290fccb52SAndrzej Pietrasiewicz * 1390fccb52SAndrzej Pietrasiewicz * Note: This driver is based on original work done by Mike James for 1490fccb52SAndrzej Pietrasiewicz * the LPC3180. 1590fccb52SAndrzej Pietrasiewicz * 1690fccb52SAndrzej Pietrasiewicz * This program is free software; you can redistribute it and/or modify 1790fccb52SAndrzej Pietrasiewicz * it under the terms of the GNU General Public License as published by 1890fccb52SAndrzej Pietrasiewicz * the Free Software Foundation; either version 2 of the License, or 1990fccb52SAndrzej Pietrasiewicz * (at your option) any later version. 2090fccb52SAndrzej Pietrasiewicz * 2190fccb52SAndrzej Pietrasiewicz * This program is distributed in the hope that it will be useful, 2290fccb52SAndrzej Pietrasiewicz * but WITHOUT ANY WARRANTY; without even the implied warranty of 2390fccb52SAndrzej Pietrasiewicz * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2490fccb52SAndrzej Pietrasiewicz * GNU General Public License for more details. 2590fccb52SAndrzej Pietrasiewicz * 2690fccb52SAndrzej Pietrasiewicz * You should have received a copy of the GNU General Public License 2790fccb52SAndrzej Pietrasiewicz * along with this program; if not, write to the Free Software 2890fccb52SAndrzej Pietrasiewicz * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2990fccb52SAndrzej Pietrasiewicz */ 3090fccb52SAndrzej Pietrasiewicz 3190fccb52SAndrzej Pietrasiewicz #include <linux/clk.h> 322de59c09SVladimir Zapolskiy #include <linux/delay.h> 3390fccb52SAndrzej Pietrasiewicz #include <linux/dma-mapping.h> 3490fccb52SAndrzej Pietrasiewicz #include <linux/dmapool.h> 352de59c09SVladimir Zapolskiy #include <linux/i2c.h> 362de59c09SVladimir Zapolskiy #include <linux/interrupt.h> 372de59c09SVladimir Zapolskiy #include <linux/module.h> 3890fccb52SAndrzej Pietrasiewicz #include <linux/of.h> 392de59c09SVladimir Zapolskiy #include <linux/platform_device.h> 402de59c09SVladimir Zapolskiy #include <linux/proc_fs.h> 412de59c09SVladimir Zapolskiy #include <linux/slab.h> 422de59c09SVladimir Zapolskiy #include <linux/usb/ch9.h> 432de59c09SVladimir Zapolskiy #include <linux/usb/gadget.h> 4490fccb52SAndrzej Pietrasiewicz #include <linux/usb/isp1301.h> 4590fccb52SAndrzej Pietrasiewicz 4690fccb52SAndrzej Pietrasiewicz #ifdef CONFIG_USB_GADGET_DEBUG_FILES 4790fccb52SAndrzej Pietrasiewicz #include <linux/debugfs.h> 4890fccb52SAndrzej Pietrasiewicz #include <linux/seq_file.h> 4990fccb52SAndrzej Pietrasiewicz #endif 5090fccb52SAndrzej Pietrasiewicz 512de59c09SVladimir Zapolskiy #include <mach/hardware.h> 522de59c09SVladimir Zapolskiy 5390fccb52SAndrzej Pietrasiewicz /* 5490fccb52SAndrzej Pietrasiewicz * USB device configuration structure 5590fccb52SAndrzej Pietrasiewicz */ 5690fccb52SAndrzej Pietrasiewicz typedef void (*usc_chg_event)(int); 5790fccb52SAndrzej Pietrasiewicz struct lpc32xx_usbd_cfg { 5890fccb52SAndrzej Pietrasiewicz int vbus_drv_pol; /* 0=active low drive for VBUS via ISP1301 */ 5990fccb52SAndrzej Pietrasiewicz usc_chg_event conn_chgb; /* Connection change event (optional) */ 6090fccb52SAndrzej Pietrasiewicz usc_chg_event susp_chgb; /* Suspend/resume event (optional) */ 6190fccb52SAndrzej Pietrasiewicz usc_chg_event rmwk_chgb; /* Enable/disable remote wakeup */ 6290fccb52SAndrzej Pietrasiewicz }; 6390fccb52SAndrzej Pietrasiewicz 6490fccb52SAndrzej Pietrasiewicz /* 6590fccb52SAndrzej Pietrasiewicz * controller driver data structures 6690fccb52SAndrzej Pietrasiewicz */ 6790fccb52SAndrzej Pietrasiewicz 6890fccb52SAndrzej Pietrasiewicz /* 16 endpoints (not to be confused with 32 hardware endpoints) */ 6990fccb52SAndrzej Pietrasiewicz #define NUM_ENDPOINTS 16 7090fccb52SAndrzej Pietrasiewicz 7190fccb52SAndrzej Pietrasiewicz /* 7290fccb52SAndrzej Pietrasiewicz * IRQ indices make reading the code a little easier 7390fccb52SAndrzej Pietrasiewicz */ 7490fccb52SAndrzej Pietrasiewicz #define IRQ_USB_LP 0 7590fccb52SAndrzej Pietrasiewicz #define IRQ_USB_HP 1 7690fccb52SAndrzej Pietrasiewicz #define IRQ_USB_DEVDMA 2 7790fccb52SAndrzej Pietrasiewicz #define IRQ_USB_ATX 3 7890fccb52SAndrzej Pietrasiewicz 7990fccb52SAndrzej Pietrasiewicz #define EP_OUT 0 /* RX (from host) */ 8090fccb52SAndrzej Pietrasiewicz #define EP_IN 1 /* TX (to host) */ 8190fccb52SAndrzej Pietrasiewicz 8290fccb52SAndrzej Pietrasiewicz /* Returns the interrupt mask for the selected hardware endpoint */ 8390fccb52SAndrzej Pietrasiewicz #define EP_MASK_SEL(ep, dir) (1 << (((ep) * 2) + dir)) 8490fccb52SAndrzej Pietrasiewicz 8590fccb52SAndrzej Pietrasiewicz #define EP_INT_TYPE 0 8690fccb52SAndrzej Pietrasiewicz #define EP_ISO_TYPE 1 8790fccb52SAndrzej Pietrasiewicz #define EP_BLK_TYPE 2 8890fccb52SAndrzej Pietrasiewicz #define EP_CTL_TYPE 3 8990fccb52SAndrzej Pietrasiewicz 9090fccb52SAndrzej Pietrasiewicz /* EP0 states */ 9190fccb52SAndrzej Pietrasiewicz #define WAIT_FOR_SETUP 0 /* Wait for setup packet */ 9290fccb52SAndrzej Pietrasiewicz #define DATA_IN 1 /* Expect dev->host transfer */ 9390fccb52SAndrzej Pietrasiewicz #define DATA_OUT 2 /* Expect host->dev transfer */ 9490fccb52SAndrzej Pietrasiewicz 9590fccb52SAndrzej Pietrasiewicz /* DD (DMA Descriptor) structure, requires word alignment, this is already 9690fccb52SAndrzej Pietrasiewicz * defined in the LPC32XX USB device header file, but this version is slightly 9790fccb52SAndrzej Pietrasiewicz * modified to tag some work data with each DMA descriptor. */ 9890fccb52SAndrzej Pietrasiewicz struct lpc32xx_usbd_dd_gad { 9990fccb52SAndrzej Pietrasiewicz u32 dd_next_phy; 10090fccb52SAndrzej Pietrasiewicz u32 dd_setup; 10190fccb52SAndrzej Pietrasiewicz u32 dd_buffer_addr; 10290fccb52SAndrzej Pietrasiewicz u32 dd_status; 10390fccb52SAndrzej Pietrasiewicz u32 dd_iso_ps_mem_addr; 10490fccb52SAndrzej Pietrasiewicz u32 this_dma; 10590fccb52SAndrzej Pietrasiewicz u32 iso_status[6]; /* 5 spare */ 10690fccb52SAndrzej Pietrasiewicz u32 dd_next_v; 10790fccb52SAndrzej Pietrasiewicz }; 10890fccb52SAndrzej Pietrasiewicz 10990fccb52SAndrzej Pietrasiewicz /* 11090fccb52SAndrzej Pietrasiewicz * Logical endpoint structure 11190fccb52SAndrzej Pietrasiewicz */ 11290fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep { 11390fccb52SAndrzej Pietrasiewicz struct usb_ep ep; 11490fccb52SAndrzej Pietrasiewicz struct list_head queue; 11590fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc; 11690fccb52SAndrzej Pietrasiewicz 11790fccb52SAndrzej Pietrasiewicz u32 hwep_num_base; /* Physical hardware EP */ 11890fccb52SAndrzej Pietrasiewicz u32 hwep_num; /* Maps to hardware endpoint */ 11990fccb52SAndrzej Pietrasiewicz u32 maxpacket; 12090fccb52SAndrzej Pietrasiewicz u32 lep; 12190fccb52SAndrzej Pietrasiewicz 12290fccb52SAndrzej Pietrasiewicz bool is_in; 12390fccb52SAndrzej Pietrasiewicz bool req_pending; 12490fccb52SAndrzej Pietrasiewicz u32 eptype; 12590fccb52SAndrzej Pietrasiewicz 12690fccb52SAndrzej Pietrasiewicz u32 totalints; 12790fccb52SAndrzej Pietrasiewicz 12890fccb52SAndrzej Pietrasiewicz bool wedge; 12990fccb52SAndrzej Pietrasiewicz }; 13090fccb52SAndrzej Pietrasiewicz 13190fccb52SAndrzej Pietrasiewicz /* 13290fccb52SAndrzej Pietrasiewicz * Common UDC structure 13390fccb52SAndrzej Pietrasiewicz */ 13490fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc { 13590fccb52SAndrzej Pietrasiewicz struct usb_gadget gadget; 13690fccb52SAndrzej Pietrasiewicz struct usb_gadget_driver *driver; 13790fccb52SAndrzej Pietrasiewicz struct platform_device *pdev; 13890fccb52SAndrzej Pietrasiewicz struct device *dev; 13990fccb52SAndrzej Pietrasiewicz struct dentry *pde; 14090fccb52SAndrzej Pietrasiewicz spinlock_t lock; 14190fccb52SAndrzej Pietrasiewicz struct i2c_client *isp1301_i2c_client; 14290fccb52SAndrzej Pietrasiewicz 14390fccb52SAndrzej Pietrasiewicz /* Board and device specific */ 14490fccb52SAndrzej Pietrasiewicz struct lpc32xx_usbd_cfg *board; 14590fccb52SAndrzej Pietrasiewicz u32 io_p_start; 14690fccb52SAndrzej Pietrasiewicz u32 io_p_size; 14790fccb52SAndrzej Pietrasiewicz void __iomem *udp_baseaddr; 14890fccb52SAndrzej Pietrasiewicz int udp_irq[4]; 14990fccb52SAndrzej Pietrasiewicz struct clk *usb_slv_clk; 15090fccb52SAndrzej Pietrasiewicz 15190fccb52SAndrzej Pietrasiewicz /* DMA support */ 15290fccb52SAndrzej Pietrasiewicz u32 *udca_v_base; 15390fccb52SAndrzej Pietrasiewicz u32 udca_p_base; 15490fccb52SAndrzej Pietrasiewicz struct dma_pool *dd_cache; 15590fccb52SAndrzej Pietrasiewicz 15690fccb52SAndrzej Pietrasiewicz /* Common EP and control data */ 15790fccb52SAndrzej Pietrasiewicz u32 enabled_devints; 15890fccb52SAndrzej Pietrasiewicz u32 enabled_hwepints; 15990fccb52SAndrzej Pietrasiewicz u32 dev_status; 16090fccb52SAndrzej Pietrasiewicz u32 realized_eps; 16190fccb52SAndrzej Pietrasiewicz 16290fccb52SAndrzej Pietrasiewicz /* VBUS detection, pullup, and power flags */ 16390fccb52SAndrzej Pietrasiewicz u8 vbus; 16490fccb52SAndrzej Pietrasiewicz u8 last_vbus; 16590fccb52SAndrzej Pietrasiewicz int pullup; 16690fccb52SAndrzej Pietrasiewicz int poweron; 16790fccb52SAndrzej Pietrasiewicz 16890fccb52SAndrzej Pietrasiewicz /* Work queues related to I2C support */ 16990fccb52SAndrzej Pietrasiewicz struct work_struct pullup_job; 17090fccb52SAndrzej Pietrasiewicz struct work_struct vbus_job; 17190fccb52SAndrzej Pietrasiewicz struct work_struct power_job; 17290fccb52SAndrzej Pietrasiewicz 17390fccb52SAndrzej Pietrasiewicz /* USB device peripheral - various */ 17490fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep ep[NUM_ENDPOINTS]; 17590fccb52SAndrzej Pietrasiewicz bool enabled; 17690fccb52SAndrzej Pietrasiewicz bool clocked; 17790fccb52SAndrzej Pietrasiewicz bool suspended; 17890fccb52SAndrzej Pietrasiewicz int ep0state; 17990fccb52SAndrzej Pietrasiewicz atomic_t enabled_ep_cnt; 18090fccb52SAndrzej Pietrasiewicz wait_queue_head_t ep_disable_wait_queue; 18190fccb52SAndrzej Pietrasiewicz }; 18290fccb52SAndrzej Pietrasiewicz 18390fccb52SAndrzej Pietrasiewicz /* 18490fccb52SAndrzej Pietrasiewicz * Endpoint request 18590fccb52SAndrzej Pietrasiewicz */ 18690fccb52SAndrzej Pietrasiewicz struct lpc32xx_request { 18790fccb52SAndrzej Pietrasiewicz struct usb_request req; 18890fccb52SAndrzej Pietrasiewicz struct list_head queue; 18990fccb52SAndrzej Pietrasiewicz struct lpc32xx_usbd_dd_gad *dd_desc_ptr; 19090fccb52SAndrzej Pietrasiewicz bool mapped; 19190fccb52SAndrzej Pietrasiewicz bool send_zlp; 19290fccb52SAndrzej Pietrasiewicz }; 19390fccb52SAndrzej Pietrasiewicz 19490fccb52SAndrzej Pietrasiewicz static inline struct lpc32xx_udc *to_udc(struct usb_gadget *g) 19590fccb52SAndrzej Pietrasiewicz { 19690fccb52SAndrzej Pietrasiewicz return container_of(g, struct lpc32xx_udc, gadget); 19790fccb52SAndrzej Pietrasiewicz } 19890fccb52SAndrzej Pietrasiewicz 19990fccb52SAndrzej Pietrasiewicz #define ep_dbg(epp, fmt, arg...) \ 20090fccb52SAndrzej Pietrasiewicz dev_dbg(epp->udc->dev, "%s: " fmt, __func__, ## arg) 20190fccb52SAndrzej Pietrasiewicz #define ep_err(epp, fmt, arg...) \ 20290fccb52SAndrzej Pietrasiewicz dev_err(epp->udc->dev, "%s: " fmt, __func__, ## arg) 20390fccb52SAndrzej Pietrasiewicz #define ep_info(epp, fmt, arg...) \ 20490fccb52SAndrzej Pietrasiewicz dev_info(epp->udc->dev, "%s: " fmt, __func__, ## arg) 20590fccb52SAndrzej Pietrasiewicz #define ep_warn(epp, fmt, arg...) \ 20690fccb52SAndrzej Pietrasiewicz dev_warn(epp->udc->dev, "%s:" fmt, __func__, ## arg) 20790fccb52SAndrzej Pietrasiewicz 20890fccb52SAndrzej Pietrasiewicz #define UDCA_BUFF_SIZE (128) 20990fccb52SAndrzej Pietrasiewicz 21090fccb52SAndrzej Pietrasiewicz /********************************************************************** 21190fccb52SAndrzej Pietrasiewicz * USB device controller register offsets 21290fccb52SAndrzej Pietrasiewicz **********************************************************************/ 21390fccb52SAndrzej Pietrasiewicz 21490fccb52SAndrzej Pietrasiewicz #define USBD_DEVINTST(x) ((x) + 0x200) 21590fccb52SAndrzej Pietrasiewicz #define USBD_DEVINTEN(x) ((x) + 0x204) 21690fccb52SAndrzej Pietrasiewicz #define USBD_DEVINTCLR(x) ((x) + 0x208) 21790fccb52SAndrzej Pietrasiewicz #define USBD_DEVINTSET(x) ((x) + 0x20C) 21890fccb52SAndrzej Pietrasiewicz #define USBD_CMDCODE(x) ((x) + 0x210) 21990fccb52SAndrzej Pietrasiewicz #define USBD_CMDDATA(x) ((x) + 0x214) 22090fccb52SAndrzej Pietrasiewicz #define USBD_RXDATA(x) ((x) + 0x218) 22190fccb52SAndrzej Pietrasiewicz #define USBD_TXDATA(x) ((x) + 0x21C) 22290fccb52SAndrzej Pietrasiewicz #define USBD_RXPLEN(x) ((x) + 0x220) 22390fccb52SAndrzej Pietrasiewicz #define USBD_TXPLEN(x) ((x) + 0x224) 22490fccb52SAndrzej Pietrasiewicz #define USBD_CTRL(x) ((x) + 0x228) 22590fccb52SAndrzej Pietrasiewicz #define USBD_DEVINTPRI(x) ((x) + 0x22C) 22690fccb52SAndrzej Pietrasiewicz #define USBD_EPINTST(x) ((x) + 0x230) 22790fccb52SAndrzej Pietrasiewicz #define USBD_EPINTEN(x) ((x) + 0x234) 22890fccb52SAndrzej Pietrasiewicz #define USBD_EPINTCLR(x) ((x) + 0x238) 22990fccb52SAndrzej Pietrasiewicz #define USBD_EPINTSET(x) ((x) + 0x23C) 23090fccb52SAndrzej Pietrasiewicz #define USBD_EPINTPRI(x) ((x) + 0x240) 23190fccb52SAndrzej Pietrasiewicz #define USBD_REEP(x) ((x) + 0x244) 23290fccb52SAndrzej Pietrasiewicz #define USBD_EPIND(x) ((x) + 0x248) 23390fccb52SAndrzej Pietrasiewicz #define USBD_EPMAXPSIZE(x) ((x) + 0x24C) 23490fccb52SAndrzej Pietrasiewicz /* DMA support registers only below */ 23590fccb52SAndrzej Pietrasiewicz /* Set, clear, or get enabled state of the DMA request status. If 23690fccb52SAndrzej Pietrasiewicz * enabled, an IN or OUT token will start a DMA transfer for the EP */ 23790fccb52SAndrzej Pietrasiewicz #define USBD_DMARST(x) ((x) + 0x250) 23890fccb52SAndrzej Pietrasiewicz #define USBD_DMARCLR(x) ((x) + 0x254) 23990fccb52SAndrzej Pietrasiewicz #define USBD_DMARSET(x) ((x) + 0x258) 24090fccb52SAndrzej Pietrasiewicz /* DMA UDCA head pointer */ 24190fccb52SAndrzej Pietrasiewicz #define USBD_UDCAH(x) ((x) + 0x280) 24290fccb52SAndrzej Pietrasiewicz /* EP DMA status, enable, and disable. This is used to specifically 24390fccb52SAndrzej Pietrasiewicz * enabled or disable DMA for a specific EP */ 24490fccb52SAndrzej Pietrasiewicz #define USBD_EPDMAST(x) ((x) + 0x284) 24590fccb52SAndrzej Pietrasiewicz #define USBD_EPDMAEN(x) ((x) + 0x288) 24690fccb52SAndrzej Pietrasiewicz #define USBD_EPDMADIS(x) ((x) + 0x28C) 24790fccb52SAndrzej Pietrasiewicz /* DMA master interrupts enable and pending interrupts */ 24890fccb52SAndrzej Pietrasiewicz #define USBD_DMAINTST(x) ((x) + 0x290) 24990fccb52SAndrzej Pietrasiewicz #define USBD_DMAINTEN(x) ((x) + 0x294) 25090fccb52SAndrzej Pietrasiewicz /* DMA end of transfer interrupt enable, disable, status */ 25190fccb52SAndrzej Pietrasiewicz #define USBD_EOTINTST(x) ((x) + 0x2A0) 25290fccb52SAndrzej Pietrasiewicz #define USBD_EOTINTCLR(x) ((x) + 0x2A4) 25390fccb52SAndrzej Pietrasiewicz #define USBD_EOTINTSET(x) ((x) + 0x2A8) 25490fccb52SAndrzej Pietrasiewicz /* New DD request interrupt enable, disable, status */ 25590fccb52SAndrzej Pietrasiewicz #define USBD_NDDRTINTST(x) ((x) + 0x2AC) 25690fccb52SAndrzej Pietrasiewicz #define USBD_NDDRTINTCLR(x) ((x) + 0x2B0) 25790fccb52SAndrzej Pietrasiewicz #define USBD_NDDRTINTSET(x) ((x) + 0x2B4) 25890fccb52SAndrzej Pietrasiewicz /* DMA error interrupt enable, disable, status */ 25990fccb52SAndrzej Pietrasiewicz #define USBD_SYSERRTINTST(x) ((x) + 0x2B8) 26090fccb52SAndrzej Pietrasiewicz #define USBD_SYSERRTINTCLR(x) ((x) + 0x2BC) 26190fccb52SAndrzej Pietrasiewicz #define USBD_SYSERRTINTSET(x) ((x) + 0x2C0) 26290fccb52SAndrzej Pietrasiewicz 26390fccb52SAndrzej Pietrasiewicz /********************************************************************** 26490fccb52SAndrzej Pietrasiewicz * USBD_DEVINTST/USBD_DEVINTEN/USBD_DEVINTCLR/USBD_DEVINTSET/ 26590fccb52SAndrzej Pietrasiewicz * USBD_DEVINTPRI register definitions 26690fccb52SAndrzej Pietrasiewicz **********************************************************************/ 26790fccb52SAndrzej Pietrasiewicz #define USBD_ERR_INT (1 << 9) 26890fccb52SAndrzej Pietrasiewicz #define USBD_EP_RLZED (1 << 8) 26990fccb52SAndrzej Pietrasiewicz #define USBD_TXENDPKT (1 << 7) 27090fccb52SAndrzej Pietrasiewicz #define USBD_RXENDPKT (1 << 6) 27190fccb52SAndrzej Pietrasiewicz #define USBD_CDFULL (1 << 5) 27290fccb52SAndrzej Pietrasiewicz #define USBD_CCEMPTY (1 << 4) 27390fccb52SAndrzej Pietrasiewicz #define USBD_DEV_STAT (1 << 3) 27490fccb52SAndrzej Pietrasiewicz #define USBD_EP_SLOW (1 << 2) 27590fccb52SAndrzej Pietrasiewicz #define USBD_EP_FAST (1 << 1) 27690fccb52SAndrzej Pietrasiewicz #define USBD_FRAME (1 << 0) 27790fccb52SAndrzej Pietrasiewicz 27890fccb52SAndrzej Pietrasiewicz /********************************************************************** 27990fccb52SAndrzej Pietrasiewicz * USBD_EPINTST/USBD_EPINTEN/USBD_EPINTCLR/USBD_EPINTSET/ 28090fccb52SAndrzej Pietrasiewicz * USBD_EPINTPRI register definitions 28190fccb52SAndrzej Pietrasiewicz **********************************************************************/ 28290fccb52SAndrzej Pietrasiewicz /* End point selection macro (RX) */ 28390fccb52SAndrzej Pietrasiewicz #define USBD_RX_EP_SEL(e) (1 << ((e) << 1)) 28490fccb52SAndrzej Pietrasiewicz 28590fccb52SAndrzej Pietrasiewicz /* End point selection macro (TX) */ 28690fccb52SAndrzej Pietrasiewicz #define USBD_TX_EP_SEL(e) (1 << (((e) << 1) + 1)) 28790fccb52SAndrzej Pietrasiewicz 28890fccb52SAndrzej Pietrasiewicz /********************************************************************** 28990fccb52SAndrzej Pietrasiewicz * USBD_REEP/USBD_DMARST/USBD_DMARCLR/USBD_DMARSET/USBD_EPDMAST/ 29090fccb52SAndrzej Pietrasiewicz * USBD_EPDMAEN/USBD_EPDMADIS/ 29190fccb52SAndrzej Pietrasiewicz * USBD_NDDRTINTST/USBD_NDDRTINTCLR/USBD_NDDRTINTSET/ 29290fccb52SAndrzej Pietrasiewicz * USBD_EOTINTST/USBD_EOTINTCLR/USBD_EOTINTSET/ 29390fccb52SAndrzej Pietrasiewicz * USBD_SYSERRTINTST/USBD_SYSERRTINTCLR/USBD_SYSERRTINTSET 29490fccb52SAndrzej Pietrasiewicz * register definitions 29590fccb52SAndrzej Pietrasiewicz **********************************************************************/ 29690fccb52SAndrzej Pietrasiewicz /* Endpoint selection macro */ 29790fccb52SAndrzej Pietrasiewicz #define USBD_EP_SEL(e) (1 << (e)) 29890fccb52SAndrzej Pietrasiewicz 29990fccb52SAndrzej Pietrasiewicz /********************************************************************** 30090fccb52SAndrzej Pietrasiewicz * SBD_DMAINTST/USBD_DMAINTEN 30190fccb52SAndrzej Pietrasiewicz **********************************************************************/ 30290fccb52SAndrzej Pietrasiewicz #define USBD_SYS_ERR_INT (1 << 2) 30390fccb52SAndrzej Pietrasiewicz #define USBD_NEW_DD_INT (1 << 1) 30490fccb52SAndrzej Pietrasiewicz #define USBD_EOT_INT (1 << 0) 30590fccb52SAndrzej Pietrasiewicz 30690fccb52SAndrzej Pietrasiewicz /********************************************************************** 30790fccb52SAndrzej Pietrasiewicz * USBD_RXPLEN register definitions 30890fccb52SAndrzej Pietrasiewicz **********************************************************************/ 30990fccb52SAndrzej Pietrasiewicz #define USBD_PKT_RDY (1 << 11) 31090fccb52SAndrzej Pietrasiewicz #define USBD_DV (1 << 10) 31190fccb52SAndrzej Pietrasiewicz #define USBD_PK_LEN_MASK 0x3FF 31290fccb52SAndrzej Pietrasiewicz 31390fccb52SAndrzej Pietrasiewicz /********************************************************************** 31490fccb52SAndrzej Pietrasiewicz * USBD_CTRL register definitions 31590fccb52SAndrzej Pietrasiewicz **********************************************************************/ 31690fccb52SAndrzej Pietrasiewicz #define USBD_LOG_ENDPOINT(e) ((e) << 2) 31790fccb52SAndrzej Pietrasiewicz #define USBD_WR_EN (1 << 1) 31890fccb52SAndrzej Pietrasiewicz #define USBD_RD_EN (1 << 0) 31990fccb52SAndrzej Pietrasiewicz 32090fccb52SAndrzej Pietrasiewicz /********************************************************************** 32190fccb52SAndrzej Pietrasiewicz * USBD_CMDCODE register definitions 32290fccb52SAndrzej Pietrasiewicz **********************************************************************/ 32390fccb52SAndrzej Pietrasiewicz #define USBD_CMD_CODE(c) ((c) << 16) 32490fccb52SAndrzej Pietrasiewicz #define USBD_CMD_PHASE(p) ((p) << 8) 32590fccb52SAndrzej Pietrasiewicz 32690fccb52SAndrzej Pietrasiewicz /********************************************************************** 32790fccb52SAndrzej Pietrasiewicz * USBD_DMARST/USBD_DMARCLR/USBD_DMARSET register definitions 32890fccb52SAndrzej Pietrasiewicz **********************************************************************/ 32990fccb52SAndrzej Pietrasiewicz #define USBD_DMAEP(e) (1 << (e)) 33090fccb52SAndrzej Pietrasiewicz 33190fccb52SAndrzej Pietrasiewicz /* DD (DMA Descriptor) structure, requires word alignment */ 33290fccb52SAndrzej Pietrasiewicz struct lpc32xx_usbd_dd { 33390fccb52SAndrzej Pietrasiewicz u32 *dd_next; 33490fccb52SAndrzej Pietrasiewicz u32 dd_setup; 33590fccb52SAndrzej Pietrasiewicz u32 dd_buffer_addr; 33690fccb52SAndrzej Pietrasiewicz u32 dd_status; 33790fccb52SAndrzej Pietrasiewicz u32 dd_iso_ps_mem_addr; 33890fccb52SAndrzej Pietrasiewicz }; 33990fccb52SAndrzej Pietrasiewicz 34090fccb52SAndrzej Pietrasiewicz /* dd_setup bit defines */ 34190fccb52SAndrzej Pietrasiewicz #define DD_SETUP_ATLE_DMA_MODE 0x01 34290fccb52SAndrzej Pietrasiewicz #define DD_SETUP_NEXT_DD_VALID 0x04 34390fccb52SAndrzej Pietrasiewicz #define DD_SETUP_ISO_EP 0x10 34490fccb52SAndrzej Pietrasiewicz #define DD_SETUP_PACKETLEN(n) (((n) & 0x7FF) << 5) 34590fccb52SAndrzej Pietrasiewicz #define DD_SETUP_DMALENBYTES(n) (((n) & 0xFFFF) << 16) 34690fccb52SAndrzej Pietrasiewicz 34790fccb52SAndrzej Pietrasiewicz /* dd_status bit defines */ 34890fccb52SAndrzej Pietrasiewicz #define DD_STATUS_DD_RETIRED 0x01 34990fccb52SAndrzej Pietrasiewicz #define DD_STATUS_STS_MASK 0x1E 35090fccb52SAndrzej Pietrasiewicz #define DD_STATUS_STS_NS 0x00 /* Not serviced */ 35190fccb52SAndrzej Pietrasiewicz #define DD_STATUS_STS_BS 0x02 /* Being serviced */ 35290fccb52SAndrzej Pietrasiewicz #define DD_STATUS_STS_NC 0x04 /* Normal completion */ 35390fccb52SAndrzej Pietrasiewicz #define DD_STATUS_STS_DUR 0x06 /* Data underrun (short packet) */ 35490fccb52SAndrzej Pietrasiewicz #define DD_STATUS_STS_DOR 0x08 /* Data overrun */ 35590fccb52SAndrzej Pietrasiewicz #define DD_STATUS_STS_SE 0x12 /* System error */ 35690fccb52SAndrzej Pietrasiewicz #define DD_STATUS_PKT_VAL 0x20 /* Packet valid */ 35790fccb52SAndrzej Pietrasiewicz #define DD_STATUS_LSB_EX 0x40 /* LS byte extracted (ATLE) */ 35890fccb52SAndrzej Pietrasiewicz #define DD_STATUS_MSB_EX 0x80 /* MS byte extracted (ATLE) */ 35990fccb52SAndrzej Pietrasiewicz #define DD_STATUS_MLEN(n) (((n) >> 8) & 0x3F) 36090fccb52SAndrzej Pietrasiewicz #define DD_STATUS_CURDMACNT(n) (((n) >> 16) & 0xFFFF) 36190fccb52SAndrzej Pietrasiewicz 36290fccb52SAndrzej Pietrasiewicz /* 36390fccb52SAndrzej Pietrasiewicz * 36490fccb52SAndrzej Pietrasiewicz * Protocol engine bits below 36590fccb52SAndrzej Pietrasiewicz * 36690fccb52SAndrzej Pietrasiewicz */ 36790fccb52SAndrzej Pietrasiewicz /* Device Interrupt Bit Definitions */ 36890fccb52SAndrzej Pietrasiewicz #define FRAME_INT 0x00000001 36990fccb52SAndrzej Pietrasiewicz #define EP_FAST_INT 0x00000002 37090fccb52SAndrzej Pietrasiewicz #define EP_SLOW_INT 0x00000004 37190fccb52SAndrzej Pietrasiewicz #define DEV_STAT_INT 0x00000008 37290fccb52SAndrzej Pietrasiewicz #define CCEMTY_INT 0x00000010 37390fccb52SAndrzej Pietrasiewicz #define CDFULL_INT 0x00000020 37490fccb52SAndrzej Pietrasiewicz #define RxENDPKT_INT 0x00000040 37590fccb52SAndrzej Pietrasiewicz #define TxENDPKT_INT 0x00000080 37690fccb52SAndrzej Pietrasiewicz #define EP_RLZED_INT 0x00000100 37790fccb52SAndrzej Pietrasiewicz #define ERR_INT 0x00000200 37890fccb52SAndrzej Pietrasiewicz 37990fccb52SAndrzej Pietrasiewicz /* Rx & Tx Packet Length Definitions */ 38090fccb52SAndrzej Pietrasiewicz #define PKT_LNGTH_MASK 0x000003FF 38190fccb52SAndrzej Pietrasiewicz #define PKT_DV 0x00000400 38290fccb52SAndrzej Pietrasiewicz #define PKT_RDY 0x00000800 38390fccb52SAndrzej Pietrasiewicz 38490fccb52SAndrzej Pietrasiewicz /* USB Control Definitions */ 38590fccb52SAndrzej Pietrasiewicz #define CTRL_RD_EN 0x00000001 38690fccb52SAndrzej Pietrasiewicz #define CTRL_WR_EN 0x00000002 38790fccb52SAndrzej Pietrasiewicz 38890fccb52SAndrzej Pietrasiewicz /* Command Codes */ 38990fccb52SAndrzej Pietrasiewicz #define CMD_SET_ADDR 0x00D00500 39090fccb52SAndrzej Pietrasiewicz #define CMD_CFG_DEV 0x00D80500 39190fccb52SAndrzej Pietrasiewicz #define CMD_SET_MODE 0x00F30500 39290fccb52SAndrzej Pietrasiewicz #define CMD_RD_FRAME 0x00F50500 39390fccb52SAndrzej Pietrasiewicz #define DAT_RD_FRAME 0x00F50200 39490fccb52SAndrzej Pietrasiewicz #define CMD_RD_TEST 0x00FD0500 39590fccb52SAndrzej Pietrasiewicz #define DAT_RD_TEST 0x00FD0200 39690fccb52SAndrzej Pietrasiewicz #define CMD_SET_DEV_STAT 0x00FE0500 39790fccb52SAndrzej Pietrasiewicz #define CMD_GET_DEV_STAT 0x00FE0500 39890fccb52SAndrzej Pietrasiewicz #define DAT_GET_DEV_STAT 0x00FE0200 39990fccb52SAndrzej Pietrasiewicz #define CMD_GET_ERR_CODE 0x00FF0500 40090fccb52SAndrzej Pietrasiewicz #define DAT_GET_ERR_CODE 0x00FF0200 40190fccb52SAndrzej Pietrasiewicz #define CMD_RD_ERR_STAT 0x00FB0500 40290fccb52SAndrzej Pietrasiewicz #define DAT_RD_ERR_STAT 0x00FB0200 40390fccb52SAndrzej Pietrasiewicz #define DAT_WR_BYTE(x) (0x00000100 | ((x) << 16)) 40490fccb52SAndrzej Pietrasiewicz #define CMD_SEL_EP(x) (0x00000500 | ((x) << 16)) 40590fccb52SAndrzej Pietrasiewicz #define DAT_SEL_EP(x) (0x00000200 | ((x) << 16)) 40690fccb52SAndrzej Pietrasiewicz #define CMD_SEL_EP_CLRI(x) (0x00400500 | ((x) << 16)) 40790fccb52SAndrzej Pietrasiewicz #define DAT_SEL_EP_CLRI(x) (0x00400200 | ((x) << 16)) 40890fccb52SAndrzej Pietrasiewicz #define CMD_SET_EP_STAT(x) (0x00400500 | ((x) << 16)) 40990fccb52SAndrzej Pietrasiewicz #define CMD_CLR_BUF 0x00F20500 41090fccb52SAndrzej Pietrasiewicz #define DAT_CLR_BUF 0x00F20200 41190fccb52SAndrzej Pietrasiewicz #define CMD_VALID_BUF 0x00FA0500 41290fccb52SAndrzej Pietrasiewicz 41390fccb52SAndrzej Pietrasiewicz /* Device Address Register Definitions */ 41490fccb52SAndrzej Pietrasiewicz #define DEV_ADDR_MASK 0x7F 41590fccb52SAndrzej Pietrasiewicz #define DEV_EN 0x80 41690fccb52SAndrzej Pietrasiewicz 41790fccb52SAndrzej Pietrasiewicz /* Device Configure Register Definitions */ 41890fccb52SAndrzej Pietrasiewicz #define CONF_DVICE 0x01 41990fccb52SAndrzej Pietrasiewicz 42090fccb52SAndrzej Pietrasiewicz /* Device Mode Register Definitions */ 42190fccb52SAndrzej Pietrasiewicz #define AP_CLK 0x01 42290fccb52SAndrzej Pietrasiewicz #define INAK_CI 0x02 42390fccb52SAndrzej Pietrasiewicz #define INAK_CO 0x04 42490fccb52SAndrzej Pietrasiewicz #define INAK_II 0x08 42590fccb52SAndrzej Pietrasiewicz #define INAK_IO 0x10 42690fccb52SAndrzej Pietrasiewicz #define INAK_BI 0x20 42790fccb52SAndrzej Pietrasiewicz #define INAK_BO 0x40 42890fccb52SAndrzej Pietrasiewicz 42990fccb52SAndrzej Pietrasiewicz /* Device Status Register Definitions */ 43090fccb52SAndrzej Pietrasiewicz #define DEV_CON 0x01 43190fccb52SAndrzej Pietrasiewicz #define DEV_CON_CH 0x02 43290fccb52SAndrzej Pietrasiewicz #define DEV_SUS 0x04 43390fccb52SAndrzej Pietrasiewicz #define DEV_SUS_CH 0x08 43490fccb52SAndrzej Pietrasiewicz #define DEV_RST 0x10 43590fccb52SAndrzej Pietrasiewicz 43690fccb52SAndrzej Pietrasiewicz /* Error Code Register Definitions */ 43790fccb52SAndrzej Pietrasiewicz #define ERR_EC_MASK 0x0F 43890fccb52SAndrzej Pietrasiewicz #define ERR_EA 0x10 43990fccb52SAndrzej Pietrasiewicz 44090fccb52SAndrzej Pietrasiewicz /* Error Status Register Definitions */ 44190fccb52SAndrzej Pietrasiewicz #define ERR_PID 0x01 44290fccb52SAndrzej Pietrasiewicz #define ERR_UEPKT 0x02 44390fccb52SAndrzej Pietrasiewicz #define ERR_DCRC 0x04 44490fccb52SAndrzej Pietrasiewicz #define ERR_TIMOUT 0x08 44590fccb52SAndrzej Pietrasiewicz #define ERR_EOP 0x10 44690fccb52SAndrzej Pietrasiewicz #define ERR_B_OVRN 0x20 44790fccb52SAndrzej Pietrasiewicz #define ERR_BTSTF 0x40 44890fccb52SAndrzej Pietrasiewicz #define ERR_TGL 0x80 44990fccb52SAndrzej Pietrasiewicz 45090fccb52SAndrzej Pietrasiewicz /* Endpoint Select Register Definitions */ 45190fccb52SAndrzej Pietrasiewicz #define EP_SEL_F 0x01 45290fccb52SAndrzej Pietrasiewicz #define EP_SEL_ST 0x02 45390fccb52SAndrzej Pietrasiewicz #define EP_SEL_STP 0x04 45490fccb52SAndrzej Pietrasiewicz #define EP_SEL_PO 0x08 45590fccb52SAndrzej Pietrasiewicz #define EP_SEL_EPN 0x10 45690fccb52SAndrzej Pietrasiewicz #define EP_SEL_B_1_FULL 0x20 45790fccb52SAndrzej Pietrasiewicz #define EP_SEL_B_2_FULL 0x40 45890fccb52SAndrzej Pietrasiewicz 45990fccb52SAndrzej Pietrasiewicz /* Endpoint Status Register Definitions */ 46090fccb52SAndrzej Pietrasiewicz #define EP_STAT_ST 0x01 46190fccb52SAndrzej Pietrasiewicz #define EP_STAT_DA 0x20 46290fccb52SAndrzej Pietrasiewicz #define EP_STAT_RF_MO 0x40 46390fccb52SAndrzej Pietrasiewicz #define EP_STAT_CND_ST 0x80 46490fccb52SAndrzej Pietrasiewicz 46590fccb52SAndrzej Pietrasiewicz /* Clear Buffer Register Definitions */ 46690fccb52SAndrzej Pietrasiewicz #define CLR_BUF_PO 0x01 46790fccb52SAndrzej Pietrasiewicz 46890fccb52SAndrzej Pietrasiewicz /* DMA Interrupt Bit Definitions */ 46990fccb52SAndrzej Pietrasiewicz #define EOT_INT 0x01 47090fccb52SAndrzej Pietrasiewicz #define NDD_REQ_INT 0x02 47190fccb52SAndrzej Pietrasiewicz #define SYS_ERR_INT 0x04 47290fccb52SAndrzej Pietrasiewicz 47390fccb52SAndrzej Pietrasiewicz #define DRIVER_VERSION "1.03" 47490fccb52SAndrzej Pietrasiewicz static const char driver_name[] = "lpc32xx_udc"; 47590fccb52SAndrzej Pietrasiewicz 47690fccb52SAndrzej Pietrasiewicz /* 47790fccb52SAndrzej Pietrasiewicz * 47890fccb52SAndrzej Pietrasiewicz * proc interface support 47990fccb52SAndrzej Pietrasiewicz * 48090fccb52SAndrzej Pietrasiewicz */ 48190fccb52SAndrzej Pietrasiewicz #ifdef CONFIG_USB_GADGET_DEBUG_FILES 48290fccb52SAndrzej Pietrasiewicz static char *epnames[] = {"INT", "ISO", "BULK", "CTRL"}; 48390fccb52SAndrzej Pietrasiewicz static const char debug_filename[] = "driver/udc"; 48490fccb52SAndrzej Pietrasiewicz 48590fccb52SAndrzej Pietrasiewicz static void proc_ep_show(struct seq_file *s, struct lpc32xx_ep *ep) 48690fccb52SAndrzej Pietrasiewicz { 48790fccb52SAndrzej Pietrasiewicz struct lpc32xx_request *req; 48890fccb52SAndrzej Pietrasiewicz 48990fccb52SAndrzej Pietrasiewicz seq_printf(s, "\n"); 49090fccb52SAndrzej Pietrasiewicz seq_printf(s, "%12s, maxpacket %4d %3s", 49190fccb52SAndrzej Pietrasiewicz ep->ep.name, ep->ep.maxpacket, 49290fccb52SAndrzej Pietrasiewicz ep->is_in ? "in" : "out"); 49390fccb52SAndrzej Pietrasiewicz seq_printf(s, " type %4s", epnames[ep->eptype]); 49490fccb52SAndrzej Pietrasiewicz seq_printf(s, " ints: %12d", ep->totalints); 49590fccb52SAndrzej Pietrasiewicz 49690fccb52SAndrzej Pietrasiewicz if (list_empty(&ep->queue)) 49790fccb52SAndrzej Pietrasiewicz seq_printf(s, "\t(queue empty)\n"); 49890fccb52SAndrzej Pietrasiewicz else { 49990fccb52SAndrzej Pietrasiewicz list_for_each_entry(req, &ep->queue, queue) { 50090fccb52SAndrzej Pietrasiewicz u32 length = req->req.actual; 50190fccb52SAndrzej Pietrasiewicz 50290fccb52SAndrzej Pietrasiewicz seq_printf(s, "\treq %p len %d/%d buf %p\n", 50390fccb52SAndrzej Pietrasiewicz &req->req, length, 50490fccb52SAndrzej Pietrasiewicz req->req.length, req->req.buf); 50590fccb52SAndrzej Pietrasiewicz } 50690fccb52SAndrzej Pietrasiewicz } 50790fccb52SAndrzej Pietrasiewicz } 50890fccb52SAndrzej Pietrasiewicz 50990fccb52SAndrzej Pietrasiewicz static int proc_udc_show(struct seq_file *s, void *unused) 51090fccb52SAndrzej Pietrasiewicz { 51190fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = s->private; 51290fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep; 51390fccb52SAndrzej Pietrasiewicz unsigned long flags; 51490fccb52SAndrzej Pietrasiewicz 51590fccb52SAndrzej Pietrasiewicz seq_printf(s, "%s: version %s\n", driver_name, DRIVER_VERSION); 51690fccb52SAndrzej Pietrasiewicz 51790fccb52SAndrzej Pietrasiewicz spin_lock_irqsave(&udc->lock, flags); 51890fccb52SAndrzej Pietrasiewicz 51990fccb52SAndrzej Pietrasiewicz seq_printf(s, "vbus %s, pullup %s, %s powered%s, gadget %s\n\n", 52090fccb52SAndrzej Pietrasiewicz udc->vbus ? "present" : "off", 52190fccb52SAndrzej Pietrasiewicz udc->enabled ? (udc->vbus ? "active" : "enabled") : 52290fccb52SAndrzej Pietrasiewicz "disabled", 523d60d9392SPeter Chen udc->gadget.is_selfpowered ? "self" : "VBUS", 52490fccb52SAndrzej Pietrasiewicz udc->suspended ? ", suspended" : "", 52590fccb52SAndrzej Pietrasiewicz udc->driver ? udc->driver->driver.name : "(none)"); 52690fccb52SAndrzej Pietrasiewicz 52790fccb52SAndrzej Pietrasiewicz if (udc->enabled && udc->vbus) { 52890fccb52SAndrzej Pietrasiewicz proc_ep_show(s, &udc->ep[0]); 52990fccb52SAndrzej Pietrasiewicz list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) 53090fccb52SAndrzej Pietrasiewicz proc_ep_show(s, ep); 53190fccb52SAndrzej Pietrasiewicz } 53290fccb52SAndrzej Pietrasiewicz 53390fccb52SAndrzej Pietrasiewicz spin_unlock_irqrestore(&udc->lock, flags); 53490fccb52SAndrzej Pietrasiewicz 53590fccb52SAndrzej Pietrasiewicz return 0; 53690fccb52SAndrzej Pietrasiewicz } 53790fccb52SAndrzej Pietrasiewicz 53890fccb52SAndrzej Pietrasiewicz static int proc_udc_open(struct inode *inode, struct file *file) 53990fccb52SAndrzej Pietrasiewicz { 54090fccb52SAndrzej Pietrasiewicz return single_open(file, proc_udc_show, PDE_DATA(inode)); 54190fccb52SAndrzej Pietrasiewicz } 54290fccb52SAndrzej Pietrasiewicz 54390fccb52SAndrzej Pietrasiewicz static const struct file_operations proc_ops = { 54490fccb52SAndrzej Pietrasiewicz .owner = THIS_MODULE, 54590fccb52SAndrzej Pietrasiewicz .open = proc_udc_open, 54690fccb52SAndrzej Pietrasiewicz .read = seq_read, 54790fccb52SAndrzej Pietrasiewicz .llseek = seq_lseek, 54890fccb52SAndrzej Pietrasiewicz .release = single_release, 54990fccb52SAndrzej Pietrasiewicz }; 55090fccb52SAndrzej Pietrasiewicz 55190fccb52SAndrzej Pietrasiewicz static void create_debug_file(struct lpc32xx_udc *udc) 55290fccb52SAndrzej Pietrasiewicz { 55390fccb52SAndrzej Pietrasiewicz udc->pde = debugfs_create_file(debug_filename, 0, NULL, udc, &proc_ops); 55490fccb52SAndrzej Pietrasiewicz } 55590fccb52SAndrzej Pietrasiewicz 55690fccb52SAndrzej Pietrasiewicz static void remove_debug_file(struct lpc32xx_udc *udc) 55790fccb52SAndrzej Pietrasiewicz { 55890fccb52SAndrzej Pietrasiewicz debugfs_remove(udc->pde); 55990fccb52SAndrzej Pietrasiewicz } 56090fccb52SAndrzej Pietrasiewicz 56190fccb52SAndrzej Pietrasiewicz #else 56290fccb52SAndrzej Pietrasiewicz static inline void create_debug_file(struct lpc32xx_udc *udc) {} 56390fccb52SAndrzej Pietrasiewicz static inline void remove_debug_file(struct lpc32xx_udc *udc) {} 56490fccb52SAndrzej Pietrasiewicz #endif 56590fccb52SAndrzej Pietrasiewicz 56690fccb52SAndrzej Pietrasiewicz /* Primary initialization sequence for the ISP1301 transceiver */ 56790fccb52SAndrzej Pietrasiewicz static void isp1301_udc_configure(struct lpc32xx_udc *udc) 56890fccb52SAndrzej Pietrasiewicz { 56990fccb52SAndrzej Pietrasiewicz /* LPC32XX only supports DAT_SE0 USB mode */ 57090fccb52SAndrzej Pietrasiewicz /* This sequence is important */ 57190fccb52SAndrzej Pietrasiewicz 57290fccb52SAndrzej Pietrasiewicz /* Disable transparent UART mode first */ 57390fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 57490fccb52SAndrzej Pietrasiewicz (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), 57590fccb52SAndrzej Pietrasiewicz MC1_UART_EN); 57690fccb52SAndrzej Pietrasiewicz 57790fccb52SAndrzej Pietrasiewicz /* Set full speed and SE0 mode */ 57890fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 57990fccb52SAndrzej Pietrasiewicz (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); 58090fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 58190fccb52SAndrzej Pietrasiewicz ISP1301_I2C_MODE_CONTROL_1, (MC1_SPEED_REG | MC1_DAT_SE0)); 58290fccb52SAndrzej Pietrasiewicz 58390fccb52SAndrzej Pietrasiewicz /* 58490fccb52SAndrzej Pietrasiewicz * The PSW_OE enable bit state is reversed in the ISP1301 User's Guide 58590fccb52SAndrzej Pietrasiewicz */ 58690fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 58790fccb52SAndrzej Pietrasiewicz (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); 58890fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 58990fccb52SAndrzej Pietrasiewicz ISP1301_I2C_MODE_CONTROL_2, (MC2_BI_DI | MC2_SPD_SUSP_CTRL)); 59090fccb52SAndrzej Pietrasiewicz 59190fccb52SAndrzej Pietrasiewicz /* Driver VBUS_DRV high or low depending on board setup */ 59290fccb52SAndrzej Pietrasiewicz if (udc->board->vbus_drv_pol != 0) 59390fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 59490fccb52SAndrzej Pietrasiewicz ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV); 59590fccb52SAndrzej Pietrasiewicz else 59690fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 59790fccb52SAndrzej Pietrasiewicz ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, 59890fccb52SAndrzej Pietrasiewicz OTG1_VBUS_DRV); 59990fccb52SAndrzej Pietrasiewicz 60090fccb52SAndrzej Pietrasiewicz /* Bi-directional mode with suspend control 60190fccb52SAndrzej Pietrasiewicz * Enable both pulldowns for now - the pullup will be enable when VBUS 60290fccb52SAndrzej Pietrasiewicz * is detected */ 60390fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 60490fccb52SAndrzej Pietrasiewicz (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); 60590fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 60690fccb52SAndrzej Pietrasiewicz ISP1301_I2C_OTG_CONTROL_1, 60790fccb52SAndrzej Pietrasiewicz (0 | OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN)); 60890fccb52SAndrzej Pietrasiewicz 60990fccb52SAndrzej Pietrasiewicz /* Discharge VBUS (just in case) */ 61090fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 61190fccb52SAndrzej Pietrasiewicz ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG); 61290fccb52SAndrzej Pietrasiewicz msleep(1); 61390fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 61490fccb52SAndrzej Pietrasiewicz (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), 61590fccb52SAndrzej Pietrasiewicz OTG1_VBUS_DISCHRG); 61690fccb52SAndrzej Pietrasiewicz 61790fccb52SAndrzej Pietrasiewicz /* Clear and enable VBUS high edge interrupt */ 61890fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 61990fccb52SAndrzej Pietrasiewicz ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, ~0); 62090fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 62190fccb52SAndrzej Pietrasiewicz ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); 62290fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 62390fccb52SAndrzej Pietrasiewicz ISP1301_I2C_INTERRUPT_FALLING, INT_VBUS_VLD); 62490fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 62590fccb52SAndrzej Pietrasiewicz ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); 62690fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 62790fccb52SAndrzej Pietrasiewicz ISP1301_I2C_INTERRUPT_RISING, INT_VBUS_VLD); 62890fccb52SAndrzej Pietrasiewicz 62990fccb52SAndrzej Pietrasiewicz dev_info(udc->dev, "ISP1301 Vendor ID : 0x%04x\n", 63090fccb52SAndrzej Pietrasiewicz i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00)); 63190fccb52SAndrzej Pietrasiewicz dev_info(udc->dev, "ISP1301 Product ID : 0x%04x\n", 63290fccb52SAndrzej Pietrasiewicz i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x02)); 63390fccb52SAndrzej Pietrasiewicz dev_info(udc->dev, "ISP1301 Version ID : 0x%04x\n", 63490fccb52SAndrzej Pietrasiewicz i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x14)); 63590fccb52SAndrzej Pietrasiewicz } 63690fccb52SAndrzej Pietrasiewicz 63790fccb52SAndrzej Pietrasiewicz /* Enables or disables the USB device pullup via the ISP1301 transceiver */ 63890fccb52SAndrzej Pietrasiewicz static void isp1301_pullup_set(struct lpc32xx_udc *udc) 63990fccb52SAndrzej Pietrasiewicz { 64090fccb52SAndrzej Pietrasiewicz if (udc->pullup) 64190fccb52SAndrzej Pietrasiewicz /* Enable pullup for bus signalling */ 64290fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 64390fccb52SAndrzej Pietrasiewicz ISP1301_I2C_OTG_CONTROL_1, OTG1_DP_PULLUP); 64490fccb52SAndrzej Pietrasiewicz else 64590fccb52SAndrzej Pietrasiewicz /* Enable pullup for bus signalling */ 64690fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 64790fccb52SAndrzej Pietrasiewicz ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, 64890fccb52SAndrzej Pietrasiewicz OTG1_DP_PULLUP); 64990fccb52SAndrzej Pietrasiewicz } 65090fccb52SAndrzej Pietrasiewicz 65190fccb52SAndrzej Pietrasiewicz static void pullup_work(struct work_struct *work) 65290fccb52SAndrzej Pietrasiewicz { 65390fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = 65490fccb52SAndrzej Pietrasiewicz container_of(work, struct lpc32xx_udc, pullup_job); 65590fccb52SAndrzej Pietrasiewicz 65690fccb52SAndrzej Pietrasiewicz isp1301_pullup_set(udc); 65790fccb52SAndrzej Pietrasiewicz } 65890fccb52SAndrzej Pietrasiewicz 65990fccb52SAndrzej Pietrasiewicz static void isp1301_pullup_enable(struct lpc32xx_udc *udc, int en_pullup, 66090fccb52SAndrzej Pietrasiewicz int block) 66190fccb52SAndrzej Pietrasiewicz { 66290fccb52SAndrzej Pietrasiewicz if (en_pullup == udc->pullup) 66390fccb52SAndrzej Pietrasiewicz return; 66490fccb52SAndrzej Pietrasiewicz 66590fccb52SAndrzej Pietrasiewicz udc->pullup = en_pullup; 66690fccb52SAndrzej Pietrasiewicz if (block) 66790fccb52SAndrzej Pietrasiewicz isp1301_pullup_set(udc); 66890fccb52SAndrzej Pietrasiewicz else 66990fccb52SAndrzej Pietrasiewicz /* defer slow i2c pull up setting */ 67090fccb52SAndrzej Pietrasiewicz schedule_work(&udc->pullup_job); 67190fccb52SAndrzej Pietrasiewicz } 67290fccb52SAndrzej Pietrasiewicz 67390fccb52SAndrzej Pietrasiewicz #ifdef CONFIG_PM 67490fccb52SAndrzej Pietrasiewicz /* Powers up or down the ISP1301 transceiver */ 67590fccb52SAndrzej Pietrasiewicz static void isp1301_set_powerstate(struct lpc32xx_udc *udc, int enable) 67690fccb52SAndrzej Pietrasiewicz { 67790fccb52SAndrzej Pietrasiewicz if (enable != 0) 67890fccb52SAndrzej Pietrasiewicz /* Power up ISP1301 - this ISP1301 will automatically wakeup 67990fccb52SAndrzej Pietrasiewicz when VBUS is detected */ 68090fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 68190fccb52SAndrzej Pietrasiewicz ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR, 68290fccb52SAndrzej Pietrasiewicz MC2_GLOBAL_PWR_DN); 68390fccb52SAndrzej Pietrasiewicz else 68490fccb52SAndrzej Pietrasiewicz /* Power down ISP1301 */ 68590fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 68690fccb52SAndrzej Pietrasiewicz ISP1301_I2C_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); 68790fccb52SAndrzej Pietrasiewicz } 68890fccb52SAndrzej Pietrasiewicz 68990fccb52SAndrzej Pietrasiewicz static void power_work(struct work_struct *work) 69090fccb52SAndrzej Pietrasiewicz { 69190fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = 69290fccb52SAndrzej Pietrasiewicz container_of(work, struct lpc32xx_udc, power_job); 69390fccb52SAndrzej Pietrasiewicz 69490fccb52SAndrzej Pietrasiewicz isp1301_set_powerstate(udc, udc->poweron); 69590fccb52SAndrzej Pietrasiewicz } 69690fccb52SAndrzej Pietrasiewicz #endif 69790fccb52SAndrzej Pietrasiewicz 69890fccb52SAndrzej Pietrasiewicz /* 69990fccb52SAndrzej Pietrasiewicz * 70090fccb52SAndrzej Pietrasiewicz * USB protocol engine command/data read/write helper functions 70190fccb52SAndrzej Pietrasiewicz * 70290fccb52SAndrzej Pietrasiewicz */ 70390fccb52SAndrzej Pietrasiewicz /* Issues a single command to the USB device state machine */ 70490fccb52SAndrzej Pietrasiewicz static void udc_protocol_cmd_w(struct lpc32xx_udc *udc, u32 cmd) 70590fccb52SAndrzej Pietrasiewicz { 70690fccb52SAndrzej Pietrasiewicz u32 pass = 0; 70790fccb52SAndrzej Pietrasiewicz int to; 70890fccb52SAndrzej Pietrasiewicz 70990fccb52SAndrzej Pietrasiewicz /* EP may lock on CLRI if this read isn't done */ 71090fccb52SAndrzej Pietrasiewicz u32 tmp = readl(USBD_DEVINTST(udc->udp_baseaddr)); 71190fccb52SAndrzej Pietrasiewicz (void) tmp; 71290fccb52SAndrzej Pietrasiewicz 71390fccb52SAndrzej Pietrasiewicz while (pass == 0) { 71490fccb52SAndrzej Pietrasiewicz writel(USBD_CCEMPTY, USBD_DEVINTCLR(udc->udp_baseaddr)); 71590fccb52SAndrzej Pietrasiewicz 71690fccb52SAndrzej Pietrasiewicz /* Write command code */ 71790fccb52SAndrzej Pietrasiewicz writel(cmd, USBD_CMDCODE(udc->udp_baseaddr)); 71890fccb52SAndrzej Pietrasiewicz to = 10000; 71990fccb52SAndrzej Pietrasiewicz while (((readl(USBD_DEVINTST(udc->udp_baseaddr)) & 72090fccb52SAndrzej Pietrasiewicz USBD_CCEMPTY) == 0) && (to > 0)) { 72190fccb52SAndrzej Pietrasiewicz to--; 72290fccb52SAndrzej Pietrasiewicz } 72390fccb52SAndrzej Pietrasiewicz 72490fccb52SAndrzej Pietrasiewicz if (to > 0) 72590fccb52SAndrzej Pietrasiewicz pass = 1; 72690fccb52SAndrzej Pietrasiewicz 72790fccb52SAndrzej Pietrasiewicz cpu_relax(); 72890fccb52SAndrzej Pietrasiewicz } 72990fccb52SAndrzej Pietrasiewicz } 73090fccb52SAndrzej Pietrasiewicz 73190fccb52SAndrzej Pietrasiewicz /* Issues 2 commands (or command and data) to the USB device state machine */ 73290fccb52SAndrzej Pietrasiewicz static inline void udc_protocol_cmd_data_w(struct lpc32xx_udc *udc, u32 cmd, 73390fccb52SAndrzej Pietrasiewicz u32 data) 73490fccb52SAndrzej Pietrasiewicz { 73590fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_w(udc, cmd); 73690fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_w(udc, data); 73790fccb52SAndrzej Pietrasiewicz } 73890fccb52SAndrzej Pietrasiewicz 73990fccb52SAndrzej Pietrasiewicz /* Issues a single command to the USB device state machine and reads 74090fccb52SAndrzej Pietrasiewicz * response data */ 74190fccb52SAndrzej Pietrasiewicz static u32 udc_protocol_cmd_r(struct lpc32xx_udc *udc, u32 cmd) 74290fccb52SAndrzej Pietrasiewicz { 74390fccb52SAndrzej Pietrasiewicz u32 tmp; 74490fccb52SAndrzej Pietrasiewicz int to = 1000; 74590fccb52SAndrzej Pietrasiewicz 74690fccb52SAndrzej Pietrasiewicz /* Write a command and read data from the protocol engine */ 74790fccb52SAndrzej Pietrasiewicz writel((USBD_CDFULL | USBD_CCEMPTY), 74890fccb52SAndrzej Pietrasiewicz USBD_DEVINTCLR(udc->udp_baseaddr)); 74990fccb52SAndrzej Pietrasiewicz 75090fccb52SAndrzej Pietrasiewicz /* Write command code */ 75190fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_w(udc, cmd); 75290fccb52SAndrzej Pietrasiewicz 75390fccb52SAndrzej Pietrasiewicz tmp = readl(USBD_DEVINTST(udc->udp_baseaddr)); 75490fccb52SAndrzej Pietrasiewicz while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) & USBD_CDFULL)) 75590fccb52SAndrzej Pietrasiewicz && (to > 0)) 75690fccb52SAndrzej Pietrasiewicz to--; 75790fccb52SAndrzej Pietrasiewicz if (!to) 75890fccb52SAndrzej Pietrasiewicz dev_dbg(udc->dev, 75990fccb52SAndrzej Pietrasiewicz "Protocol engine didn't receive response (CDFULL)\n"); 76090fccb52SAndrzej Pietrasiewicz 76190fccb52SAndrzej Pietrasiewicz return readl(USBD_CMDDATA(udc->udp_baseaddr)); 76290fccb52SAndrzej Pietrasiewicz } 76390fccb52SAndrzej Pietrasiewicz 76490fccb52SAndrzej Pietrasiewicz /* 76590fccb52SAndrzej Pietrasiewicz * 76690fccb52SAndrzej Pietrasiewicz * USB device interrupt mask support functions 76790fccb52SAndrzej Pietrasiewicz * 76890fccb52SAndrzej Pietrasiewicz */ 76990fccb52SAndrzej Pietrasiewicz /* Enable one or more USB device interrupts */ 77090fccb52SAndrzej Pietrasiewicz static inline void uda_enable_devint(struct lpc32xx_udc *udc, u32 devmask) 77190fccb52SAndrzej Pietrasiewicz { 77290fccb52SAndrzej Pietrasiewicz udc->enabled_devints |= devmask; 77390fccb52SAndrzej Pietrasiewicz writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr)); 77490fccb52SAndrzej Pietrasiewicz } 77590fccb52SAndrzej Pietrasiewicz 77690fccb52SAndrzej Pietrasiewicz /* Disable one or more USB device interrupts */ 77790fccb52SAndrzej Pietrasiewicz static inline void uda_disable_devint(struct lpc32xx_udc *udc, u32 mask) 77890fccb52SAndrzej Pietrasiewicz { 77990fccb52SAndrzej Pietrasiewicz udc->enabled_devints &= ~mask; 78090fccb52SAndrzej Pietrasiewicz writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr)); 78190fccb52SAndrzej Pietrasiewicz } 78290fccb52SAndrzej Pietrasiewicz 78390fccb52SAndrzej Pietrasiewicz /* Clear one or more USB device interrupts */ 78490fccb52SAndrzej Pietrasiewicz static inline void uda_clear_devint(struct lpc32xx_udc *udc, u32 mask) 78590fccb52SAndrzej Pietrasiewicz { 78690fccb52SAndrzej Pietrasiewicz writel(mask, USBD_DEVINTCLR(udc->udp_baseaddr)); 78790fccb52SAndrzej Pietrasiewicz } 78890fccb52SAndrzej Pietrasiewicz 78990fccb52SAndrzej Pietrasiewicz /* 79090fccb52SAndrzej Pietrasiewicz * 79190fccb52SAndrzej Pietrasiewicz * Endpoint interrupt disable/enable functions 79290fccb52SAndrzej Pietrasiewicz * 79390fccb52SAndrzej Pietrasiewicz */ 79490fccb52SAndrzej Pietrasiewicz /* Enable one or more USB endpoint interrupts */ 79590fccb52SAndrzej Pietrasiewicz static void uda_enable_hwepint(struct lpc32xx_udc *udc, u32 hwep) 79690fccb52SAndrzej Pietrasiewicz { 79790fccb52SAndrzej Pietrasiewicz udc->enabled_hwepints |= (1 << hwep); 79890fccb52SAndrzej Pietrasiewicz writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr)); 79990fccb52SAndrzej Pietrasiewicz } 80090fccb52SAndrzej Pietrasiewicz 80190fccb52SAndrzej Pietrasiewicz /* Disable one or more USB endpoint interrupts */ 80290fccb52SAndrzej Pietrasiewicz static void uda_disable_hwepint(struct lpc32xx_udc *udc, u32 hwep) 80390fccb52SAndrzej Pietrasiewicz { 80490fccb52SAndrzej Pietrasiewicz udc->enabled_hwepints &= ~(1 << hwep); 80590fccb52SAndrzej Pietrasiewicz writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr)); 80690fccb52SAndrzej Pietrasiewicz } 80790fccb52SAndrzej Pietrasiewicz 80890fccb52SAndrzej Pietrasiewicz /* Clear one or more USB endpoint interrupts */ 80990fccb52SAndrzej Pietrasiewicz static inline void uda_clear_hwepint(struct lpc32xx_udc *udc, u32 hwep) 81090fccb52SAndrzej Pietrasiewicz { 81190fccb52SAndrzej Pietrasiewicz writel((1 << hwep), USBD_EPINTCLR(udc->udp_baseaddr)); 81290fccb52SAndrzej Pietrasiewicz } 81390fccb52SAndrzej Pietrasiewicz 81490fccb52SAndrzej Pietrasiewicz /* Enable DMA for the HW channel */ 81590fccb52SAndrzej Pietrasiewicz static inline void udc_ep_dma_enable(struct lpc32xx_udc *udc, u32 hwep) 81690fccb52SAndrzej Pietrasiewicz { 81790fccb52SAndrzej Pietrasiewicz writel((1 << hwep), USBD_EPDMAEN(udc->udp_baseaddr)); 81890fccb52SAndrzej Pietrasiewicz } 81990fccb52SAndrzej Pietrasiewicz 82090fccb52SAndrzej Pietrasiewicz /* Disable DMA for the HW channel */ 82190fccb52SAndrzej Pietrasiewicz static inline void udc_ep_dma_disable(struct lpc32xx_udc *udc, u32 hwep) 82290fccb52SAndrzej Pietrasiewicz { 82390fccb52SAndrzej Pietrasiewicz writel((1 << hwep), USBD_EPDMADIS(udc->udp_baseaddr)); 82490fccb52SAndrzej Pietrasiewicz } 82590fccb52SAndrzej Pietrasiewicz 82690fccb52SAndrzej Pietrasiewicz /* 82790fccb52SAndrzej Pietrasiewicz * 82890fccb52SAndrzej Pietrasiewicz * Endpoint realize/unrealize functions 82990fccb52SAndrzej Pietrasiewicz * 83090fccb52SAndrzej Pietrasiewicz */ 83190fccb52SAndrzej Pietrasiewicz /* Before an endpoint can be used, it needs to be realized 83290fccb52SAndrzej Pietrasiewicz * in the USB protocol engine - this realizes the endpoint. 83390fccb52SAndrzej Pietrasiewicz * The interrupt (FIFO or DMA) is not enabled with this function */ 83490fccb52SAndrzej Pietrasiewicz static void udc_realize_hwep(struct lpc32xx_udc *udc, u32 hwep, 83590fccb52SAndrzej Pietrasiewicz u32 maxpacket) 83690fccb52SAndrzej Pietrasiewicz { 83790fccb52SAndrzej Pietrasiewicz int to = 1000; 83890fccb52SAndrzej Pietrasiewicz 83990fccb52SAndrzej Pietrasiewicz writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr)); 84090fccb52SAndrzej Pietrasiewicz writel(hwep, USBD_EPIND(udc->udp_baseaddr)); 84190fccb52SAndrzej Pietrasiewicz udc->realized_eps |= (1 << hwep); 84290fccb52SAndrzej Pietrasiewicz writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr)); 84390fccb52SAndrzej Pietrasiewicz writel(maxpacket, USBD_EPMAXPSIZE(udc->udp_baseaddr)); 84490fccb52SAndrzej Pietrasiewicz 84590fccb52SAndrzej Pietrasiewicz /* Wait until endpoint is realized in hardware */ 84690fccb52SAndrzej Pietrasiewicz while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) & 84790fccb52SAndrzej Pietrasiewicz USBD_EP_RLZED)) && (to > 0)) 84890fccb52SAndrzej Pietrasiewicz to--; 84990fccb52SAndrzej Pietrasiewicz if (!to) 85090fccb52SAndrzej Pietrasiewicz dev_dbg(udc->dev, "EP not correctly realized in hardware\n"); 85190fccb52SAndrzej Pietrasiewicz 85290fccb52SAndrzej Pietrasiewicz writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr)); 85390fccb52SAndrzej Pietrasiewicz } 85490fccb52SAndrzej Pietrasiewicz 85590fccb52SAndrzej Pietrasiewicz /* Unrealize an EP */ 85690fccb52SAndrzej Pietrasiewicz static void udc_unrealize_hwep(struct lpc32xx_udc *udc, u32 hwep) 85790fccb52SAndrzej Pietrasiewicz { 85890fccb52SAndrzej Pietrasiewicz udc->realized_eps &= ~(1 << hwep); 85990fccb52SAndrzej Pietrasiewicz writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr)); 86090fccb52SAndrzej Pietrasiewicz } 86190fccb52SAndrzej Pietrasiewicz 86290fccb52SAndrzej Pietrasiewicz /* 86390fccb52SAndrzej Pietrasiewicz * 86490fccb52SAndrzej Pietrasiewicz * Endpoint support functions 86590fccb52SAndrzej Pietrasiewicz * 86690fccb52SAndrzej Pietrasiewicz */ 86790fccb52SAndrzej Pietrasiewicz /* Select and clear endpoint interrupt */ 86890fccb52SAndrzej Pietrasiewicz static u32 udc_selep_clrint(struct lpc32xx_udc *udc, u32 hwep) 86990fccb52SAndrzej Pietrasiewicz { 87090fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_w(udc, CMD_SEL_EP_CLRI(hwep)); 87190fccb52SAndrzej Pietrasiewicz return udc_protocol_cmd_r(udc, DAT_SEL_EP_CLRI(hwep)); 87290fccb52SAndrzej Pietrasiewicz } 87390fccb52SAndrzej Pietrasiewicz 87490fccb52SAndrzej Pietrasiewicz /* Disables the endpoint in the USB protocol engine */ 87590fccb52SAndrzej Pietrasiewicz static void udc_disable_hwep(struct lpc32xx_udc *udc, u32 hwep) 87690fccb52SAndrzej Pietrasiewicz { 87790fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep), 87890fccb52SAndrzej Pietrasiewicz DAT_WR_BYTE(EP_STAT_DA)); 87990fccb52SAndrzej Pietrasiewicz } 88090fccb52SAndrzej Pietrasiewicz 88190fccb52SAndrzej Pietrasiewicz /* Stalls the endpoint - endpoint will return STALL */ 88290fccb52SAndrzej Pietrasiewicz static void udc_stall_hwep(struct lpc32xx_udc *udc, u32 hwep) 88390fccb52SAndrzej Pietrasiewicz { 88490fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep), 88590fccb52SAndrzej Pietrasiewicz DAT_WR_BYTE(EP_STAT_ST)); 88690fccb52SAndrzej Pietrasiewicz } 88790fccb52SAndrzej Pietrasiewicz 88890fccb52SAndrzej Pietrasiewicz /* Clear stall or reset endpoint */ 88990fccb52SAndrzej Pietrasiewicz static void udc_clrstall_hwep(struct lpc32xx_udc *udc, u32 hwep) 89090fccb52SAndrzej Pietrasiewicz { 89190fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep), 89290fccb52SAndrzej Pietrasiewicz DAT_WR_BYTE(0)); 89390fccb52SAndrzej Pietrasiewicz } 89490fccb52SAndrzej Pietrasiewicz 89590fccb52SAndrzej Pietrasiewicz /* Select an endpoint for endpoint status, clear, validate */ 89690fccb52SAndrzej Pietrasiewicz static void udc_select_hwep(struct lpc32xx_udc *udc, u32 hwep) 89790fccb52SAndrzej Pietrasiewicz { 89890fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_w(udc, CMD_SEL_EP(hwep)); 89990fccb52SAndrzej Pietrasiewicz } 90090fccb52SAndrzej Pietrasiewicz 90190fccb52SAndrzej Pietrasiewicz /* 90290fccb52SAndrzej Pietrasiewicz * 90390fccb52SAndrzej Pietrasiewicz * Endpoint buffer management functions 90490fccb52SAndrzej Pietrasiewicz * 90590fccb52SAndrzej Pietrasiewicz */ 90690fccb52SAndrzej Pietrasiewicz /* Clear the current endpoint's buffer */ 90790fccb52SAndrzej Pietrasiewicz static void udc_clr_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep) 90890fccb52SAndrzej Pietrasiewicz { 90990fccb52SAndrzej Pietrasiewicz udc_select_hwep(udc, hwep); 91090fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_w(udc, CMD_CLR_BUF); 91190fccb52SAndrzej Pietrasiewicz } 91290fccb52SAndrzej Pietrasiewicz 91390fccb52SAndrzej Pietrasiewicz /* Validate the current endpoint's buffer */ 91490fccb52SAndrzej Pietrasiewicz static void udc_val_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep) 91590fccb52SAndrzej Pietrasiewicz { 91690fccb52SAndrzej Pietrasiewicz udc_select_hwep(udc, hwep); 91790fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_w(udc, CMD_VALID_BUF); 91890fccb52SAndrzej Pietrasiewicz } 91990fccb52SAndrzej Pietrasiewicz 92090fccb52SAndrzej Pietrasiewicz static inline u32 udc_clearep_getsts(struct lpc32xx_udc *udc, u32 hwep) 92190fccb52SAndrzej Pietrasiewicz { 92290fccb52SAndrzej Pietrasiewicz /* Clear EP interrupt */ 92390fccb52SAndrzej Pietrasiewicz uda_clear_hwepint(udc, hwep); 92490fccb52SAndrzej Pietrasiewicz return udc_selep_clrint(udc, hwep); 92590fccb52SAndrzej Pietrasiewicz } 92690fccb52SAndrzej Pietrasiewicz 92790fccb52SAndrzej Pietrasiewicz /* 92890fccb52SAndrzej Pietrasiewicz * 92990fccb52SAndrzej Pietrasiewicz * USB EP DMA support 93090fccb52SAndrzej Pietrasiewicz * 93190fccb52SAndrzej Pietrasiewicz */ 93290fccb52SAndrzej Pietrasiewicz /* Allocate a DMA Descriptor */ 93390fccb52SAndrzej Pietrasiewicz static struct lpc32xx_usbd_dd_gad *udc_dd_alloc(struct lpc32xx_udc *udc) 93490fccb52SAndrzej Pietrasiewicz { 93590fccb52SAndrzej Pietrasiewicz dma_addr_t dma; 93690fccb52SAndrzej Pietrasiewicz struct lpc32xx_usbd_dd_gad *dd; 93790fccb52SAndrzej Pietrasiewicz 93890fccb52SAndrzej Pietrasiewicz dd = (struct lpc32xx_usbd_dd_gad *) dma_pool_alloc( 93990fccb52SAndrzej Pietrasiewicz udc->dd_cache, (GFP_KERNEL | GFP_DMA), &dma); 94090fccb52SAndrzej Pietrasiewicz if (dd) 94190fccb52SAndrzej Pietrasiewicz dd->this_dma = dma; 94290fccb52SAndrzej Pietrasiewicz 94390fccb52SAndrzej Pietrasiewicz return dd; 94490fccb52SAndrzej Pietrasiewicz } 94590fccb52SAndrzej Pietrasiewicz 94690fccb52SAndrzej Pietrasiewicz /* Free a DMA Descriptor */ 94790fccb52SAndrzej Pietrasiewicz static void udc_dd_free(struct lpc32xx_udc *udc, struct lpc32xx_usbd_dd_gad *dd) 94890fccb52SAndrzej Pietrasiewicz { 94990fccb52SAndrzej Pietrasiewicz dma_pool_free(udc->dd_cache, dd, dd->this_dma); 95090fccb52SAndrzej Pietrasiewicz } 95190fccb52SAndrzej Pietrasiewicz 95290fccb52SAndrzej Pietrasiewicz /* 95390fccb52SAndrzej Pietrasiewicz * 95490fccb52SAndrzej Pietrasiewicz * USB setup and shutdown functions 95590fccb52SAndrzej Pietrasiewicz * 95690fccb52SAndrzej Pietrasiewicz */ 95790fccb52SAndrzej Pietrasiewicz /* Enables or disables most of the USB system clocks when low power mode is 95890fccb52SAndrzej Pietrasiewicz * needed. Clocks are typically started on a connection event, and disabled 95990fccb52SAndrzej Pietrasiewicz * when a cable is disconnected */ 96090fccb52SAndrzej Pietrasiewicz static void udc_clk_set(struct lpc32xx_udc *udc, int enable) 96190fccb52SAndrzej Pietrasiewicz { 96290fccb52SAndrzej Pietrasiewicz if (enable != 0) { 96390fccb52SAndrzej Pietrasiewicz if (udc->clocked) 96490fccb52SAndrzej Pietrasiewicz return; 96590fccb52SAndrzej Pietrasiewicz 96690fccb52SAndrzej Pietrasiewicz udc->clocked = 1; 96759e05272SVladimir Zapolskiy clk_prepare_enable(udc->usb_slv_clk); 96890fccb52SAndrzej Pietrasiewicz } else { 96990fccb52SAndrzej Pietrasiewicz if (!udc->clocked) 97090fccb52SAndrzej Pietrasiewicz return; 97190fccb52SAndrzej Pietrasiewicz 97290fccb52SAndrzej Pietrasiewicz udc->clocked = 0; 97359e05272SVladimir Zapolskiy clk_disable_unprepare(udc->usb_slv_clk); 97490fccb52SAndrzej Pietrasiewicz } 97590fccb52SAndrzej Pietrasiewicz } 97690fccb52SAndrzej Pietrasiewicz 97790fccb52SAndrzej Pietrasiewicz /* Set/reset USB device address */ 97890fccb52SAndrzej Pietrasiewicz static void udc_set_address(struct lpc32xx_udc *udc, u32 addr) 97990fccb52SAndrzej Pietrasiewicz { 98090fccb52SAndrzej Pietrasiewicz /* Address will be latched at the end of the status phase, or 98190fccb52SAndrzej Pietrasiewicz latched immediately if function is called twice */ 98290fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_data_w(udc, CMD_SET_ADDR, 98390fccb52SAndrzej Pietrasiewicz DAT_WR_BYTE(DEV_EN | addr)); 98490fccb52SAndrzej Pietrasiewicz } 98590fccb52SAndrzej Pietrasiewicz 98690fccb52SAndrzej Pietrasiewicz /* Setup up a IN request for DMA transfer - this consists of determining the 98790fccb52SAndrzej Pietrasiewicz * list of DMA addresses for the transfer, allocating DMA Descriptors, 98890fccb52SAndrzej Pietrasiewicz * installing the DD into the UDCA, and then enabling the DMA for that EP */ 98990fccb52SAndrzej Pietrasiewicz static int udc_ep_in_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) 99090fccb52SAndrzej Pietrasiewicz { 99190fccb52SAndrzej Pietrasiewicz struct lpc32xx_request *req; 99290fccb52SAndrzej Pietrasiewicz u32 hwep = ep->hwep_num; 99390fccb52SAndrzej Pietrasiewicz 99490fccb52SAndrzej Pietrasiewicz ep->req_pending = 1; 99590fccb52SAndrzej Pietrasiewicz 99690fccb52SAndrzej Pietrasiewicz /* There will always be a request waiting here */ 99790fccb52SAndrzej Pietrasiewicz req = list_entry(ep->queue.next, struct lpc32xx_request, queue); 99890fccb52SAndrzej Pietrasiewicz 99990fccb52SAndrzej Pietrasiewicz /* Place the DD Descriptor into the UDCA */ 100090fccb52SAndrzej Pietrasiewicz udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma; 100190fccb52SAndrzej Pietrasiewicz 100290fccb52SAndrzej Pietrasiewicz /* Enable DMA and interrupt for the HW EP */ 100390fccb52SAndrzej Pietrasiewicz udc_ep_dma_enable(udc, hwep); 100490fccb52SAndrzej Pietrasiewicz 100590fccb52SAndrzej Pietrasiewicz /* Clear ZLP if last packet is not of MAXP size */ 100690fccb52SAndrzej Pietrasiewicz if (req->req.length % ep->ep.maxpacket) 100790fccb52SAndrzej Pietrasiewicz req->send_zlp = 0; 100890fccb52SAndrzej Pietrasiewicz 100990fccb52SAndrzej Pietrasiewicz return 0; 101090fccb52SAndrzej Pietrasiewicz } 101190fccb52SAndrzej Pietrasiewicz 101290fccb52SAndrzej Pietrasiewicz /* Setup up a OUT request for DMA transfer - this consists of determining the 101390fccb52SAndrzej Pietrasiewicz * list of DMA addresses for the transfer, allocating DMA Descriptors, 101490fccb52SAndrzej Pietrasiewicz * installing the DD into the UDCA, and then enabling the DMA for that EP */ 101590fccb52SAndrzej Pietrasiewicz static int udc_ep_out_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) 101690fccb52SAndrzej Pietrasiewicz { 101790fccb52SAndrzej Pietrasiewicz struct lpc32xx_request *req; 101890fccb52SAndrzej Pietrasiewicz u32 hwep = ep->hwep_num; 101990fccb52SAndrzej Pietrasiewicz 102090fccb52SAndrzej Pietrasiewicz ep->req_pending = 1; 102190fccb52SAndrzej Pietrasiewicz 102290fccb52SAndrzej Pietrasiewicz /* There will always be a request waiting here */ 102390fccb52SAndrzej Pietrasiewicz req = list_entry(ep->queue.next, struct lpc32xx_request, queue); 102490fccb52SAndrzej Pietrasiewicz 102590fccb52SAndrzej Pietrasiewicz /* Place the DD Descriptor into the UDCA */ 102690fccb52SAndrzej Pietrasiewicz udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma; 102790fccb52SAndrzej Pietrasiewicz 102890fccb52SAndrzej Pietrasiewicz /* Enable DMA and interrupt for the HW EP */ 102990fccb52SAndrzej Pietrasiewicz udc_ep_dma_enable(udc, hwep); 103090fccb52SAndrzej Pietrasiewicz return 0; 103190fccb52SAndrzej Pietrasiewicz } 103290fccb52SAndrzej Pietrasiewicz 103390fccb52SAndrzej Pietrasiewicz static void udc_disable(struct lpc32xx_udc *udc) 103490fccb52SAndrzej Pietrasiewicz { 103590fccb52SAndrzej Pietrasiewicz u32 i; 103690fccb52SAndrzej Pietrasiewicz 103790fccb52SAndrzej Pietrasiewicz /* Disable device */ 103890fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0)); 103990fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(0)); 104090fccb52SAndrzej Pietrasiewicz 104190fccb52SAndrzej Pietrasiewicz /* Disable all device interrupts (including EP0) */ 104290fccb52SAndrzej Pietrasiewicz uda_disable_devint(udc, 0x3FF); 104390fccb52SAndrzej Pietrasiewicz 104490fccb52SAndrzej Pietrasiewicz /* Disable and reset all endpoint interrupts */ 104590fccb52SAndrzej Pietrasiewicz for (i = 0; i < 32; i++) { 104690fccb52SAndrzej Pietrasiewicz uda_disable_hwepint(udc, i); 104790fccb52SAndrzej Pietrasiewicz uda_clear_hwepint(udc, i); 104890fccb52SAndrzej Pietrasiewicz udc_disable_hwep(udc, i); 104990fccb52SAndrzej Pietrasiewicz udc_unrealize_hwep(udc, i); 105090fccb52SAndrzej Pietrasiewicz udc->udca_v_base[i] = 0; 105190fccb52SAndrzej Pietrasiewicz 105290fccb52SAndrzej Pietrasiewicz /* Disable and clear all interrupts and DMA */ 105390fccb52SAndrzej Pietrasiewicz udc_ep_dma_disable(udc, i); 105490fccb52SAndrzej Pietrasiewicz writel((1 << i), USBD_EOTINTCLR(udc->udp_baseaddr)); 105590fccb52SAndrzej Pietrasiewicz writel((1 << i), USBD_NDDRTINTCLR(udc->udp_baseaddr)); 105690fccb52SAndrzej Pietrasiewicz writel((1 << i), USBD_SYSERRTINTCLR(udc->udp_baseaddr)); 105790fccb52SAndrzej Pietrasiewicz writel((1 << i), USBD_DMARCLR(udc->udp_baseaddr)); 105890fccb52SAndrzej Pietrasiewicz } 105990fccb52SAndrzej Pietrasiewicz 106090fccb52SAndrzej Pietrasiewicz /* Disable DMA interrupts */ 106190fccb52SAndrzej Pietrasiewicz writel(0, USBD_DMAINTEN(udc->udp_baseaddr)); 106290fccb52SAndrzej Pietrasiewicz 106390fccb52SAndrzej Pietrasiewicz writel(0, USBD_UDCAH(udc->udp_baseaddr)); 106490fccb52SAndrzej Pietrasiewicz } 106590fccb52SAndrzej Pietrasiewicz 106690fccb52SAndrzej Pietrasiewicz static void udc_enable(struct lpc32xx_udc *udc) 106790fccb52SAndrzej Pietrasiewicz { 106890fccb52SAndrzej Pietrasiewicz u32 i; 106990fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep = &udc->ep[0]; 107090fccb52SAndrzej Pietrasiewicz 107190fccb52SAndrzej Pietrasiewicz /* Start with known state */ 107290fccb52SAndrzej Pietrasiewicz udc_disable(udc); 107390fccb52SAndrzej Pietrasiewicz 107490fccb52SAndrzej Pietrasiewicz /* Enable device */ 107590fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(DEV_CON)); 107690fccb52SAndrzej Pietrasiewicz 107790fccb52SAndrzej Pietrasiewicz /* EP interrupts on high priority, FRAME interrupt on low priority */ 107890fccb52SAndrzej Pietrasiewicz writel(USBD_EP_FAST, USBD_DEVINTPRI(udc->udp_baseaddr)); 107990fccb52SAndrzej Pietrasiewicz writel(0xFFFF, USBD_EPINTPRI(udc->udp_baseaddr)); 108090fccb52SAndrzej Pietrasiewicz 108190fccb52SAndrzej Pietrasiewicz /* Clear any pending device interrupts */ 108290fccb52SAndrzej Pietrasiewicz writel(0x3FF, USBD_DEVINTCLR(udc->udp_baseaddr)); 108390fccb52SAndrzej Pietrasiewicz 108490fccb52SAndrzej Pietrasiewicz /* Setup UDCA - not yet used (DMA) */ 108590fccb52SAndrzej Pietrasiewicz writel(udc->udca_p_base, USBD_UDCAH(udc->udp_baseaddr)); 108690fccb52SAndrzej Pietrasiewicz 108790fccb52SAndrzej Pietrasiewicz /* Only enable EP0 in and out for now, EP0 only works in FIFO mode */ 108890fccb52SAndrzej Pietrasiewicz for (i = 0; i <= 1; i++) { 108990fccb52SAndrzej Pietrasiewicz udc_realize_hwep(udc, i, ep->ep.maxpacket); 109090fccb52SAndrzej Pietrasiewicz uda_enable_hwepint(udc, i); 109190fccb52SAndrzej Pietrasiewicz udc_select_hwep(udc, i); 109290fccb52SAndrzej Pietrasiewicz udc_clrstall_hwep(udc, i); 109390fccb52SAndrzej Pietrasiewicz udc_clr_buffer_hwep(udc, i); 109490fccb52SAndrzej Pietrasiewicz } 109590fccb52SAndrzej Pietrasiewicz 109690fccb52SAndrzej Pietrasiewicz /* Device interrupt setup */ 109790fccb52SAndrzej Pietrasiewicz uda_clear_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW | 109890fccb52SAndrzej Pietrasiewicz USBD_EP_FAST)); 109990fccb52SAndrzej Pietrasiewicz uda_enable_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW | 110090fccb52SAndrzej Pietrasiewicz USBD_EP_FAST)); 110190fccb52SAndrzej Pietrasiewicz 110290fccb52SAndrzej Pietrasiewicz /* Set device address to 0 - called twice to force a latch in the USB 110390fccb52SAndrzej Pietrasiewicz engine without the need of a setup packet status closure */ 110490fccb52SAndrzej Pietrasiewicz udc_set_address(udc, 0); 110590fccb52SAndrzej Pietrasiewicz udc_set_address(udc, 0); 110690fccb52SAndrzej Pietrasiewicz 110790fccb52SAndrzej Pietrasiewicz /* Enable master DMA interrupts */ 110890fccb52SAndrzej Pietrasiewicz writel((USBD_SYS_ERR_INT | USBD_EOT_INT), 110990fccb52SAndrzej Pietrasiewicz USBD_DMAINTEN(udc->udp_baseaddr)); 111090fccb52SAndrzej Pietrasiewicz 111190fccb52SAndrzej Pietrasiewicz udc->dev_status = 0; 111290fccb52SAndrzej Pietrasiewicz } 111390fccb52SAndrzej Pietrasiewicz 111490fccb52SAndrzej Pietrasiewicz /* 111590fccb52SAndrzej Pietrasiewicz * 111690fccb52SAndrzej Pietrasiewicz * USB device board specific events handled via callbacks 111790fccb52SAndrzej Pietrasiewicz * 111890fccb52SAndrzej Pietrasiewicz */ 111990fccb52SAndrzej Pietrasiewicz /* Connection change event - notify board function of change */ 112090fccb52SAndrzej Pietrasiewicz static void uda_power_event(struct lpc32xx_udc *udc, u32 conn) 112190fccb52SAndrzej Pietrasiewicz { 112290fccb52SAndrzej Pietrasiewicz /* Just notify of a connection change event (optional) */ 112390fccb52SAndrzej Pietrasiewicz if (udc->board->conn_chgb != NULL) 112490fccb52SAndrzej Pietrasiewicz udc->board->conn_chgb(conn); 112590fccb52SAndrzej Pietrasiewicz } 112690fccb52SAndrzej Pietrasiewicz 112790fccb52SAndrzej Pietrasiewicz /* Suspend/resume event - notify board function of change */ 112890fccb52SAndrzej Pietrasiewicz static void uda_resm_susp_event(struct lpc32xx_udc *udc, u32 conn) 112990fccb52SAndrzej Pietrasiewicz { 113090fccb52SAndrzej Pietrasiewicz /* Just notify of a Suspend/resume change event (optional) */ 113190fccb52SAndrzej Pietrasiewicz if (udc->board->susp_chgb != NULL) 113290fccb52SAndrzej Pietrasiewicz udc->board->susp_chgb(conn); 113390fccb52SAndrzej Pietrasiewicz 113490fccb52SAndrzej Pietrasiewicz if (conn) 113590fccb52SAndrzej Pietrasiewicz udc->suspended = 0; 113690fccb52SAndrzej Pietrasiewicz else 113790fccb52SAndrzej Pietrasiewicz udc->suspended = 1; 113890fccb52SAndrzej Pietrasiewicz } 113990fccb52SAndrzej Pietrasiewicz 114090fccb52SAndrzej Pietrasiewicz /* Remote wakeup enable/disable - notify board function of change */ 114190fccb52SAndrzej Pietrasiewicz static void uda_remwkp_cgh(struct lpc32xx_udc *udc) 114290fccb52SAndrzej Pietrasiewicz { 114390fccb52SAndrzej Pietrasiewicz if (udc->board->rmwk_chgb != NULL) 114490fccb52SAndrzej Pietrasiewicz udc->board->rmwk_chgb(udc->dev_status & 114590fccb52SAndrzej Pietrasiewicz (1 << USB_DEVICE_REMOTE_WAKEUP)); 114690fccb52SAndrzej Pietrasiewicz } 114790fccb52SAndrzej Pietrasiewicz 114890fccb52SAndrzej Pietrasiewicz /* Reads data from FIFO, adjusts for alignment and data size */ 114990fccb52SAndrzej Pietrasiewicz static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes) 115090fccb52SAndrzej Pietrasiewicz { 115190fccb52SAndrzej Pietrasiewicz int n, i, bl; 115290fccb52SAndrzej Pietrasiewicz u16 *p16; 115390fccb52SAndrzej Pietrasiewicz u32 *p32, tmp, cbytes; 115490fccb52SAndrzej Pietrasiewicz 115590fccb52SAndrzej Pietrasiewicz /* Use optimal data transfer method based on source address and size */ 115690fccb52SAndrzej Pietrasiewicz switch (((u32) data) & 0x3) { 115790fccb52SAndrzej Pietrasiewicz case 0: /* 32-bit aligned */ 115890fccb52SAndrzej Pietrasiewicz p32 = (u32 *) data; 115990fccb52SAndrzej Pietrasiewicz cbytes = (bytes & ~0x3); 116090fccb52SAndrzej Pietrasiewicz 116190fccb52SAndrzej Pietrasiewicz /* Copy 32-bit aligned data first */ 116290fccb52SAndrzej Pietrasiewicz for (n = 0; n < cbytes; n += 4) 116390fccb52SAndrzej Pietrasiewicz *p32++ = readl(USBD_RXDATA(udc->udp_baseaddr)); 116490fccb52SAndrzej Pietrasiewicz 116590fccb52SAndrzej Pietrasiewicz /* Handle any remaining bytes */ 116690fccb52SAndrzej Pietrasiewicz bl = bytes - cbytes; 116790fccb52SAndrzej Pietrasiewicz if (bl) { 116890fccb52SAndrzej Pietrasiewicz tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); 116990fccb52SAndrzej Pietrasiewicz for (n = 0; n < bl; n++) 117090fccb52SAndrzej Pietrasiewicz data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF); 117190fccb52SAndrzej Pietrasiewicz 117290fccb52SAndrzej Pietrasiewicz } 117390fccb52SAndrzej Pietrasiewicz break; 117490fccb52SAndrzej Pietrasiewicz 117590fccb52SAndrzej Pietrasiewicz case 1: /* 8-bit aligned */ 117690fccb52SAndrzej Pietrasiewicz case 3: 117790fccb52SAndrzej Pietrasiewicz /* Each byte has to be handled independently */ 117890fccb52SAndrzej Pietrasiewicz for (n = 0; n < bytes; n += 4) { 117990fccb52SAndrzej Pietrasiewicz tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); 118090fccb52SAndrzej Pietrasiewicz 118190fccb52SAndrzej Pietrasiewicz bl = bytes - n; 118290fccb52SAndrzej Pietrasiewicz if (bl > 3) 118390fccb52SAndrzej Pietrasiewicz bl = 3; 118490fccb52SAndrzej Pietrasiewicz 118590fccb52SAndrzej Pietrasiewicz for (i = 0; i < bl; i++) 118690fccb52SAndrzej Pietrasiewicz data[n + i] = (u8) ((tmp >> (n * 8)) & 0xFF); 118790fccb52SAndrzej Pietrasiewicz } 118890fccb52SAndrzej Pietrasiewicz break; 118990fccb52SAndrzej Pietrasiewicz 119090fccb52SAndrzej Pietrasiewicz case 2: /* 16-bit aligned */ 119190fccb52SAndrzej Pietrasiewicz p16 = (u16 *) data; 119290fccb52SAndrzej Pietrasiewicz cbytes = (bytes & ~0x3); 119390fccb52SAndrzej Pietrasiewicz 119490fccb52SAndrzej Pietrasiewicz /* Copy 32-bit sized objects first with 16-bit alignment */ 119590fccb52SAndrzej Pietrasiewicz for (n = 0; n < cbytes; n += 4) { 119690fccb52SAndrzej Pietrasiewicz tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); 119790fccb52SAndrzej Pietrasiewicz *p16++ = (u16)(tmp & 0xFFFF); 119890fccb52SAndrzej Pietrasiewicz *p16++ = (u16)((tmp >> 16) & 0xFFFF); 119990fccb52SAndrzej Pietrasiewicz } 120090fccb52SAndrzej Pietrasiewicz 120190fccb52SAndrzej Pietrasiewicz /* Handle any remaining bytes */ 120290fccb52SAndrzej Pietrasiewicz bl = bytes - cbytes; 120390fccb52SAndrzej Pietrasiewicz if (bl) { 120490fccb52SAndrzej Pietrasiewicz tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); 120590fccb52SAndrzej Pietrasiewicz for (n = 0; n < bl; n++) 120690fccb52SAndrzej Pietrasiewicz data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF); 120790fccb52SAndrzej Pietrasiewicz } 120890fccb52SAndrzej Pietrasiewicz break; 120990fccb52SAndrzej Pietrasiewicz } 121090fccb52SAndrzej Pietrasiewicz } 121190fccb52SAndrzej Pietrasiewicz 121290fccb52SAndrzej Pietrasiewicz /* Read data from the FIFO for an endpoint. This function is for endpoints (such 121390fccb52SAndrzej Pietrasiewicz * as EP0) that don't use DMA. This function should only be called if a packet 121490fccb52SAndrzej Pietrasiewicz * is known to be ready to read for the endpoint. Note that the endpoint must 121590fccb52SAndrzej Pietrasiewicz * be selected in the protocol engine prior to this call. */ 121690fccb52SAndrzej Pietrasiewicz static u32 udc_read_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data, 121790fccb52SAndrzej Pietrasiewicz u32 bytes) 121890fccb52SAndrzej Pietrasiewicz { 121990fccb52SAndrzej Pietrasiewicz u32 tmpv; 122090fccb52SAndrzej Pietrasiewicz int to = 1000; 122190fccb52SAndrzej Pietrasiewicz u32 tmp, hwrep = ((hwep & 0x1E) << 1) | CTRL_RD_EN; 122290fccb52SAndrzej Pietrasiewicz 122390fccb52SAndrzej Pietrasiewicz /* Setup read of endpoint */ 122490fccb52SAndrzej Pietrasiewicz writel(hwrep, USBD_CTRL(udc->udp_baseaddr)); 122590fccb52SAndrzej Pietrasiewicz 122690fccb52SAndrzej Pietrasiewicz /* Wait until packet is ready */ 122790fccb52SAndrzej Pietrasiewicz while ((((tmpv = readl(USBD_RXPLEN(udc->udp_baseaddr))) & 122890fccb52SAndrzej Pietrasiewicz PKT_RDY) == 0) && (to > 0)) 122990fccb52SAndrzej Pietrasiewicz to--; 123090fccb52SAndrzej Pietrasiewicz if (!to) 123190fccb52SAndrzej Pietrasiewicz dev_dbg(udc->dev, "No packet ready on FIFO EP read\n"); 123290fccb52SAndrzej Pietrasiewicz 123390fccb52SAndrzej Pietrasiewicz /* Mask out count */ 123490fccb52SAndrzej Pietrasiewicz tmp = tmpv & PKT_LNGTH_MASK; 123590fccb52SAndrzej Pietrasiewicz if (bytes < tmp) 123690fccb52SAndrzej Pietrasiewicz tmp = bytes; 123790fccb52SAndrzej Pietrasiewicz 123890fccb52SAndrzej Pietrasiewicz if ((tmp > 0) && (data != NULL)) 123990fccb52SAndrzej Pietrasiewicz udc_pop_fifo(udc, (u8 *) data, tmp); 124090fccb52SAndrzej Pietrasiewicz 124190fccb52SAndrzej Pietrasiewicz writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr)); 124290fccb52SAndrzej Pietrasiewicz 124390fccb52SAndrzej Pietrasiewicz /* Clear the buffer */ 124490fccb52SAndrzej Pietrasiewicz udc_clr_buffer_hwep(udc, hwep); 124590fccb52SAndrzej Pietrasiewicz 124690fccb52SAndrzej Pietrasiewicz return tmp; 124790fccb52SAndrzej Pietrasiewicz } 124890fccb52SAndrzej Pietrasiewicz 124990fccb52SAndrzej Pietrasiewicz /* Stuffs data into the FIFO, adjusts for alignment and data size */ 125090fccb52SAndrzej Pietrasiewicz static void udc_stuff_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes) 125190fccb52SAndrzej Pietrasiewicz { 125290fccb52SAndrzej Pietrasiewicz int n, i, bl; 125390fccb52SAndrzej Pietrasiewicz u16 *p16; 125490fccb52SAndrzej Pietrasiewicz u32 *p32, tmp, cbytes; 125590fccb52SAndrzej Pietrasiewicz 125690fccb52SAndrzej Pietrasiewicz /* Use optimal data transfer method based on source address and size */ 125790fccb52SAndrzej Pietrasiewicz switch (((u32) data) & 0x3) { 125890fccb52SAndrzej Pietrasiewicz case 0: /* 32-bit aligned */ 125990fccb52SAndrzej Pietrasiewicz p32 = (u32 *) data; 126090fccb52SAndrzej Pietrasiewicz cbytes = (bytes & ~0x3); 126190fccb52SAndrzej Pietrasiewicz 126290fccb52SAndrzej Pietrasiewicz /* Copy 32-bit aligned data first */ 126390fccb52SAndrzej Pietrasiewicz for (n = 0; n < cbytes; n += 4) 126490fccb52SAndrzej Pietrasiewicz writel(*p32++, USBD_TXDATA(udc->udp_baseaddr)); 126590fccb52SAndrzej Pietrasiewicz 126690fccb52SAndrzej Pietrasiewicz /* Handle any remaining bytes */ 126790fccb52SAndrzej Pietrasiewicz bl = bytes - cbytes; 126890fccb52SAndrzej Pietrasiewicz if (bl) { 126990fccb52SAndrzej Pietrasiewicz tmp = 0; 127090fccb52SAndrzej Pietrasiewicz for (n = 0; n < bl; n++) 127190fccb52SAndrzej Pietrasiewicz tmp |= data[cbytes + n] << (n * 8); 127290fccb52SAndrzej Pietrasiewicz 127390fccb52SAndrzej Pietrasiewicz writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); 127490fccb52SAndrzej Pietrasiewicz } 127590fccb52SAndrzej Pietrasiewicz break; 127690fccb52SAndrzej Pietrasiewicz 127790fccb52SAndrzej Pietrasiewicz case 1: /* 8-bit aligned */ 127890fccb52SAndrzej Pietrasiewicz case 3: 127990fccb52SAndrzej Pietrasiewicz /* Each byte has to be handled independently */ 128090fccb52SAndrzej Pietrasiewicz for (n = 0; n < bytes; n += 4) { 128190fccb52SAndrzej Pietrasiewicz bl = bytes - n; 128290fccb52SAndrzej Pietrasiewicz if (bl > 4) 128390fccb52SAndrzej Pietrasiewicz bl = 4; 128490fccb52SAndrzej Pietrasiewicz 128590fccb52SAndrzej Pietrasiewicz tmp = 0; 128690fccb52SAndrzej Pietrasiewicz for (i = 0; i < bl; i++) 128790fccb52SAndrzej Pietrasiewicz tmp |= data[n + i] << (i * 8); 128890fccb52SAndrzej Pietrasiewicz 128990fccb52SAndrzej Pietrasiewicz writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); 129090fccb52SAndrzej Pietrasiewicz } 129190fccb52SAndrzej Pietrasiewicz break; 129290fccb52SAndrzej Pietrasiewicz 129390fccb52SAndrzej Pietrasiewicz case 2: /* 16-bit aligned */ 129490fccb52SAndrzej Pietrasiewicz p16 = (u16 *) data; 129590fccb52SAndrzej Pietrasiewicz cbytes = (bytes & ~0x3); 129690fccb52SAndrzej Pietrasiewicz 129790fccb52SAndrzej Pietrasiewicz /* Copy 32-bit aligned data first */ 129890fccb52SAndrzej Pietrasiewicz for (n = 0; n < cbytes; n += 4) { 129990fccb52SAndrzej Pietrasiewicz tmp = *p16++ & 0xFFFF; 130090fccb52SAndrzej Pietrasiewicz tmp |= (*p16++ & 0xFFFF) << 16; 130190fccb52SAndrzej Pietrasiewicz writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); 130290fccb52SAndrzej Pietrasiewicz } 130390fccb52SAndrzej Pietrasiewicz 130490fccb52SAndrzej Pietrasiewicz /* Handle any remaining bytes */ 130590fccb52SAndrzej Pietrasiewicz bl = bytes - cbytes; 130690fccb52SAndrzej Pietrasiewicz if (bl) { 130790fccb52SAndrzej Pietrasiewicz tmp = 0; 130890fccb52SAndrzej Pietrasiewicz for (n = 0; n < bl; n++) 130990fccb52SAndrzej Pietrasiewicz tmp |= data[cbytes + n] << (n * 8); 131090fccb52SAndrzej Pietrasiewicz 131190fccb52SAndrzej Pietrasiewicz writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); 131290fccb52SAndrzej Pietrasiewicz } 131390fccb52SAndrzej Pietrasiewicz break; 131490fccb52SAndrzej Pietrasiewicz } 131590fccb52SAndrzej Pietrasiewicz } 131690fccb52SAndrzej Pietrasiewicz 131790fccb52SAndrzej Pietrasiewicz /* Write data to the FIFO for an endpoint. This function is for endpoints (such 131890fccb52SAndrzej Pietrasiewicz * as EP0) that don't use DMA. Note that the endpoint must be selected in the 131990fccb52SAndrzej Pietrasiewicz * protocol engine prior to this call. */ 132090fccb52SAndrzej Pietrasiewicz static void udc_write_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data, 132190fccb52SAndrzej Pietrasiewicz u32 bytes) 132290fccb52SAndrzej Pietrasiewicz { 132390fccb52SAndrzej Pietrasiewicz u32 hwwep = ((hwep & 0x1E) << 1) | CTRL_WR_EN; 132490fccb52SAndrzej Pietrasiewicz 132590fccb52SAndrzej Pietrasiewicz if ((bytes > 0) && (data == NULL)) 132690fccb52SAndrzej Pietrasiewicz return; 132790fccb52SAndrzej Pietrasiewicz 132890fccb52SAndrzej Pietrasiewicz /* Setup write of endpoint */ 132990fccb52SAndrzej Pietrasiewicz writel(hwwep, USBD_CTRL(udc->udp_baseaddr)); 133090fccb52SAndrzej Pietrasiewicz 133190fccb52SAndrzej Pietrasiewicz writel(bytes, USBD_TXPLEN(udc->udp_baseaddr)); 133290fccb52SAndrzej Pietrasiewicz 133390fccb52SAndrzej Pietrasiewicz /* Need at least 1 byte to trigger TX */ 133490fccb52SAndrzej Pietrasiewicz if (bytes == 0) 133590fccb52SAndrzej Pietrasiewicz writel(0, USBD_TXDATA(udc->udp_baseaddr)); 133690fccb52SAndrzej Pietrasiewicz else 133790fccb52SAndrzej Pietrasiewicz udc_stuff_fifo(udc, (u8 *) data, bytes); 133890fccb52SAndrzej Pietrasiewicz 133990fccb52SAndrzej Pietrasiewicz writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr)); 134090fccb52SAndrzej Pietrasiewicz 134190fccb52SAndrzej Pietrasiewicz udc_val_buffer_hwep(udc, hwep); 134290fccb52SAndrzej Pietrasiewicz } 134390fccb52SAndrzej Pietrasiewicz 134490fccb52SAndrzej Pietrasiewicz /* USB device reset - resets USB to a default state with just EP0 134590fccb52SAndrzej Pietrasiewicz enabled */ 134690fccb52SAndrzej Pietrasiewicz static void uda_usb_reset(struct lpc32xx_udc *udc) 134790fccb52SAndrzej Pietrasiewicz { 134890fccb52SAndrzej Pietrasiewicz u32 i = 0; 134990fccb52SAndrzej Pietrasiewicz /* Re-init device controller and EP0 */ 135090fccb52SAndrzej Pietrasiewicz udc_enable(udc); 135190fccb52SAndrzej Pietrasiewicz udc->gadget.speed = USB_SPEED_FULL; 135290fccb52SAndrzej Pietrasiewicz 135390fccb52SAndrzej Pietrasiewicz for (i = 1; i < NUM_ENDPOINTS; i++) { 135490fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep = &udc->ep[i]; 135590fccb52SAndrzej Pietrasiewicz ep->req_pending = 0; 135690fccb52SAndrzej Pietrasiewicz } 135790fccb52SAndrzej Pietrasiewicz } 135890fccb52SAndrzej Pietrasiewicz 135990fccb52SAndrzej Pietrasiewicz /* Send a ZLP on EP0 */ 136090fccb52SAndrzej Pietrasiewicz static void udc_ep0_send_zlp(struct lpc32xx_udc *udc) 136190fccb52SAndrzej Pietrasiewicz { 136290fccb52SAndrzej Pietrasiewicz udc_write_hwep(udc, EP_IN, NULL, 0); 136390fccb52SAndrzej Pietrasiewicz } 136490fccb52SAndrzej Pietrasiewicz 136590fccb52SAndrzej Pietrasiewicz /* Get current frame number */ 136690fccb52SAndrzej Pietrasiewicz static u16 udc_get_current_frame(struct lpc32xx_udc *udc) 136790fccb52SAndrzej Pietrasiewicz { 136890fccb52SAndrzej Pietrasiewicz u16 flo, fhi; 136990fccb52SAndrzej Pietrasiewicz 137090fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_w(udc, CMD_RD_FRAME); 137190fccb52SAndrzej Pietrasiewicz flo = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME); 137290fccb52SAndrzej Pietrasiewicz fhi = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME); 137390fccb52SAndrzej Pietrasiewicz 137490fccb52SAndrzej Pietrasiewicz return (fhi << 8) | flo; 137590fccb52SAndrzej Pietrasiewicz } 137690fccb52SAndrzej Pietrasiewicz 137790fccb52SAndrzej Pietrasiewicz /* Set the device as configured - enables all endpoints */ 137890fccb52SAndrzej Pietrasiewicz static inline void udc_set_device_configured(struct lpc32xx_udc *udc) 137990fccb52SAndrzej Pietrasiewicz { 138090fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(CONF_DVICE)); 138190fccb52SAndrzej Pietrasiewicz } 138290fccb52SAndrzej Pietrasiewicz 138390fccb52SAndrzej Pietrasiewicz /* Set the device as unconfigured - disables all endpoints */ 138490fccb52SAndrzej Pietrasiewicz static inline void udc_set_device_unconfigured(struct lpc32xx_udc *udc) 138590fccb52SAndrzej Pietrasiewicz { 138690fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0)); 138790fccb52SAndrzej Pietrasiewicz } 138890fccb52SAndrzej Pietrasiewicz 138990fccb52SAndrzej Pietrasiewicz /* reinit == restore initial software state */ 139090fccb52SAndrzej Pietrasiewicz static void udc_reinit(struct lpc32xx_udc *udc) 139190fccb52SAndrzej Pietrasiewicz { 139290fccb52SAndrzej Pietrasiewicz u32 i; 139390fccb52SAndrzej Pietrasiewicz 139490fccb52SAndrzej Pietrasiewicz INIT_LIST_HEAD(&udc->gadget.ep_list); 139590fccb52SAndrzej Pietrasiewicz INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); 139690fccb52SAndrzej Pietrasiewicz 139790fccb52SAndrzej Pietrasiewicz for (i = 0; i < NUM_ENDPOINTS; i++) { 139890fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep = &udc->ep[i]; 139990fccb52SAndrzej Pietrasiewicz 140090fccb52SAndrzej Pietrasiewicz if (i != 0) 140190fccb52SAndrzej Pietrasiewicz list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); 140290fccb52SAndrzej Pietrasiewicz usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket); 140390fccb52SAndrzej Pietrasiewicz INIT_LIST_HEAD(&ep->queue); 140490fccb52SAndrzej Pietrasiewicz ep->req_pending = 0; 140590fccb52SAndrzej Pietrasiewicz } 140690fccb52SAndrzej Pietrasiewicz 140790fccb52SAndrzej Pietrasiewicz udc->ep0state = WAIT_FOR_SETUP; 140890fccb52SAndrzej Pietrasiewicz } 140990fccb52SAndrzej Pietrasiewicz 141090fccb52SAndrzej Pietrasiewicz /* Must be called with lock */ 141190fccb52SAndrzej Pietrasiewicz static void done(struct lpc32xx_ep *ep, struct lpc32xx_request *req, int status) 141290fccb52SAndrzej Pietrasiewicz { 141390fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = ep->udc; 141490fccb52SAndrzej Pietrasiewicz 141590fccb52SAndrzej Pietrasiewicz list_del_init(&req->queue); 141690fccb52SAndrzej Pietrasiewicz if (req->req.status == -EINPROGRESS) 141790fccb52SAndrzej Pietrasiewicz req->req.status = status; 141890fccb52SAndrzej Pietrasiewicz else 141990fccb52SAndrzej Pietrasiewicz status = req->req.status; 142090fccb52SAndrzej Pietrasiewicz 142190fccb52SAndrzej Pietrasiewicz if (ep->lep) { 142290fccb52SAndrzej Pietrasiewicz usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in); 142390fccb52SAndrzej Pietrasiewicz 142490fccb52SAndrzej Pietrasiewicz /* Free DDs */ 142590fccb52SAndrzej Pietrasiewicz udc_dd_free(udc, req->dd_desc_ptr); 142690fccb52SAndrzej Pietrasiewicz } 142790fccb52SAndrzej Pietrasiewicz 142890fccb52SAndrzej Pietrasiewicz if (status && status != -ESHUTDOWN) 142990fccb52SAndrzej Pietrasiewicz ep_dbg(ep, "%s done %p, status %d\n", ep->ep.name, req, status); 143090fccb52SAndrzej Pietrasiewicz 143190fccb52SAndrzej Pietrasiewicz ep->req_pending = 0; 143290fccb52SAndrzej Pietrasiewicz spin_unlock(&udc->lock); 1433304f7e5eSMichal Sojka usb_gadget_giveback_request(&ep->ep, &req->req); 143490fccb52SAndrzej Pietrasiewicz spin_lock(&udc->lock); 143590fccb52SAndrzej Pietrasiewicz } 143690fccb52SAndrzej Pietrasiewicz 143790fccb52SAndrzej Pietrasiewicz /* Must be called with lock */ 143890fccb52SAndrzej Pietrasiewicz static void nuke(struct lpc32xx_ep *ep, int status) 143990fccb52SAndrzej Pietrasiewicz { 144090fccb52SAndrzej Pietrasiewicz struct lpc32xx_request *req; 144190fccb52SAndrzej Pietrasiewicz 144290fccb52SAndrzej Pietrasiewicz while (!list_empty(&ep->queue)) { 144390fccb52SAndrzej Pietrasiewicz req = list_entry(ep->queue.next, struct lpc32xx_request, queue); 144490fccb52SAndrzej Pietrasiewicz done(ep, req, status); 144590fccb52SAndrzej Pietrasiewicz } 144690fccb52SAndrzej Pietrasiewicz 144790fccb52SAndrzej Pietrasiewicz if (status == -ESHUTDOWN) { 144890fccb52SAndrzej Pietrasiewicz uda_disable_hwepint(ep->udc, ep->hwep_num); 144990fccb52SAndrzej Pietrasiewicz udc_disable_hwep(ep->udc, ep->hwep_num); 145090fccb52SAndrzej Pietrasiewicz } 145190fccb52SAndrzej Pietrasiewicz } 145290fccb52SAndrzej Pietrasiewicz 145390fccb52SAndrzej Pietrasiewicz /* IN endpoint 0 transfer */ 145490fccb52SAndrzej Pietrasiewicz static int udc_ep0_in_req(struct lpc32xx_udc *udc) 145590fccb52SAndrzej Pietrasiewicz { 145690fccb52SAndrzej Pietrasiewicz struct lpc32xx_request *req; 145790fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep0 = &udc->ep[0]; 145890fccb52SAndrzej Pietrasiewicz u32 tsend, ts = 0; 145990fccb52SAndrzej Pietrasiewicz 146090fccb52SAndrzej Pietrasiewicz if (list_empty(&ep0->queue)) 146190fccb52SAndrzej Pietrasiewicz /* Nothing to send */ 146290fccb52SAndrzej Pietrasiewicz return 0; 146390fccb52SAndrzej Pietrasiewicz else 146490fccb52SAndrzej Pietrasiewicz req = list_entry(ep0->queue.next, struct lpc32xx_request, 146590fccb52SAndrzej Pietrasiewicz queue); 146690fccb52SAndrzej Pietrasiewicz 146790fccb52SAndrzej Pietrasiewicz tsend = ts = req->req.length - req->req.actual; 146890fccb52SAndrzej Pietrasiewicz if (ts == 0) { 146990fccb52SAndrzej Pietrasiewicz /* Send a ZLP */ 147090fccb52SAndrzej Pietrasiewicz udc_ep0_send_zlp(udc); 147190fccb52SAndrzej Pietrasiewicz done(ep0, req, 0); 147290fccb52SAndrzej Pietrasiewicz return 1; 147390fccb52SAndrzej Pietrasiewicz } else if (ts > ep0->ep.maxpacket) 147490fccb52SAndrzej Pietrasiewicz ts = ep0->ep.maxpacket; /* Just send what we can */ 147590fccb52SAndrzej Pietrasiewicz 147690fccb52SAndrzej Pietrasiewicz /* Write data to the EP0 FIFO and start transfer */ 147790fccb52SAndrzej Pietrasiewicz udc_write_hwep(udc, EP_IN, (req->req.buf + req->req.actual), ts); 147890fccb52SAndrzej Pietrasiewicz 147990fccb52SAndrzej Pietrasiewicz /* Increment data pointer */ 148090fccb52SAndrzej Pietrasiewicz req->req.actual += ts; 148190fccb52SAndrzej Pietrasiewicz 148290fccb52SAndrzej Pietrasiewicz if (tsend >= ep0->ep.maxpacket) 148390fccb52SAndrzej Pietrasiewicz return 0; /* Stay in data transfer state */ 148490fccb52SAndrzej Pietrasiewicz 148590fccb52SAndrzej Pietrasiewicz /* Transfer request is complete */ 148690fccb52SAndrzej Pietrasiewicz udc->ep0state = WAIT_FOR_SETUP; 148790fccb52SAndrzej Pietrasiewicz done(ep0, req, 0); 148890fccb52SAndrzej Pietrasiewicz return 1; 148990fccb52SAndrzej Pietrasiewicz } 149090fccb52SAndrzej Pietrasiewicz 149190fccb52SAndrzej Pietrasiewicz /* OUT endpoint 0 transfer */ 149290fccb52SAndrzej Pietrasiewicz static int udc_ep0_out_req(struct lpc32xx_udc *udc) 149390fccb52SAndrzej Pietrasiewicz { 149490fccb52SAndrzej Pietrasiewicz struct lpc32xx_request *req; 149590fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep0 = &udc->ep[0]; 149690fccb52SAndrzej Pietrasiewicz u32 tr, bufferspace; 149790fccb52SAndrzej Pietrasiewicz 149890fccb52SAndrzej Pietrasiewicz if (list_empty(&ep0->queue)) 149990fccb52SAndrzej Pietrasiewicz return 0; 150090fccb52SAndrzej Pietrasiewicz else 150190fccb52SAndrzej Pietrasiewicz req = list_entry(ep0->queue.next, struct lpc32xx_request, 150290fccb52SAndrzej Pietrasiewicz queue); 150390fccb52SAndrzej Pietrasiewicz 150490fccb52SAndrzej Pietrasiewicz if (req) { 150590fccb52SAndrzej Pietrasiewicz if (req->req.length == 0) { 150690fccb52SAndrzej Pietrasiewicz /* Just dequeue request */ 150790fccb52SAndrzej Pietrasiewicz done(ep0, req, 0); 150890fccb52SAndrzej Pietrasiewicz udc->ep0state = WAIT_FOR_SETUP; 150990fccb52SAndrzej Pietrasiewicz return 1; 151090fccb52SAndrzej Pietrasiewicz } 151190fccb52SAndrzej Pietrasiewicz 151290fccb52SAndrzej Pietrasiewicz /* Get data from FIFO */ 151390fccb52SAndrzej Pietrasiewicz bufferspace = req->req.length - req->req.actual; 151490fccb52SAndrzej Pietrasiewicz if (bufferspace > ep0->ep.maxpacket) 151590fccb52SAndrzej Pietrasiewicz bufferspace = ep0->ep.maxpacket; 151690fccb52SAndrzej Pietrasiewicz 151790fccb52SAndrzej Pietrasiewicz /* Copy data to buffer */ 151890fccb52SAndrzej Pietrasiewicz prefetchw(req->req.buf + req->req.actual); 151990fccb52SAndrzej Pietrasiewicz tr = udc_read_hwep(udc, EP_OUT, req->req.buf + req->req.actual, 152090fccb52SAndrzej Pietrasiewicz bufferspace); 152190fccb52SAndrzej Pietrasiewicz req->req.actual += bufferspace; 152290fccb52SAndrzej Pietrasiewicz 152390fccb52SAndrzej Pietrasiewicz if (tr < ep0->ep.maxpacket) { 152490fccb52SAndrzej Pietrasiewicz /* This is the last packet */ 152590fccb52SAndrzej Pietrasiewicz done(ep0, req, 0); 152690fccb52SAndrzej Pietrasiewicz udc->ep0state = WAIT_FOR_SETUP; 152790fccb52SAndrzej Pietrasiewicz return 1; 152890fccb52SAndrzej Pietrasiewicz } 152990fccb52SAndrzej Pietrasiewicz } 153090fccb52SAndrzej Pietrasiewicz 153190fccb52SAndrzej Pietrasiewicz return 0; 153290fccb52SAndrzej Pietrasiewicz } 153390fccb52SAndrzej Pietrasiewicz 153490fccb52SAndrzej Pietrasiewicz /* Must be called with lock */ 153590fccb52SAndrzej Pietrasiewicz static void stop_activity(struct lpc32xx_udc *udc) 153690fccb52SAndrzej Pietrasiewicz { 153790fccb52SAndrzej Pietrasiewicz struct usb_gadget_driver *driver = udc->driver; 153890fccb52SAndrzej Pietrasiewicz int i; 153990fccb52SAndrzej Pietrasiewicz 154090fccb52SAndrzej Pietrasiewicz if (udc->gadget.speed == USB_SPEED_UNKNOWN) 154190fccb52SAndrzej Pietrasiewicz driver = NULL; 154290fccb52SAndrzej Pietrasiewicz 154390fccb52SAndrzej Pietrasiewicz udc->gadget.speed = USB_SPEED_UNKNOWN; 154490fccb52SAndrzej Pietrasiewicz udc->suspended = 0; 154590fccb52SAndrzej Pietrasiewicz 154690fccb52SAndrzej Pietrasiewicz for (i = 0; i < NUM_ENDPOINTS; i++) { 154790fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep = &udc->ep[i]; 154890fccb52SAndrzej Pietrasiewicz nuke(ep, -ESHUTDOWN); 154990fccb52SAndrzej Pietrasiewicz } 155090fccb52SAndrzej Pietrasiewicz if (driver) { 155190fccb52SAndrzej Pietrasiewicz spin_unlock(&udc->lock); 155290fccb52SAndrzej Pietrasiewicz driver->disconnect(&udc->gadget); 155390fccb52SAndrzej Pietrasiewicz spin_lock(&udc->lock); 155490fccb52SAndrzej Pietrasiewicz } 155590fccb52SAndrzej Pietrasiewicz 155690fccb52SAndrzej Pietrasiewicz isp1301_pullup_enable(udc, 0, 0); 155790fccb52SAndrzej Pietrasiewicz udc_disable(udc); 155890fccb52SAndrzej Pietrasiewicz udc_reinit(udc); 155990fccb52SAndrzej Pietrasiewicz } 156090fccb52SAndrzej Pietrasiewicz 156190fccb52SAndrzej Pietrasiewicz /* 156290fccb52SAndrzej Pietrasiewicz * Activate or kill host pullup 156390fccb52SAndrzej Pietrasiewicz * Can be called with or without lock 156490fccb52SAndrzej Pietrasiewicz */ 156590fccb52SAndrzej Pietrasiewicz static void pullup(struct lpc32xx_udc *udc, int is_on) 156690fccb52SAndrzej Pietrasiewicz { 156790fccb52SAndrzej Pietrasiewicz if (!udc->clocked) 156890fccb52SAndrzej Pietrasiewicz return; 156990fccb52SAndrzej Pietrasiewicz 157090fccb52SAndrzej Pietrasiewicz if (!udc->enabled || !udc->vbus) 157190fccb52SAndrzej Pietrasiewicz is_on = 0; 157290fccb52SAndrzej Pietrasiewicz 157390fccb52SAndrzej Pietrasiewicz if (is_on != udc->pullup) 157490fccb52SAndrzej Pietrasiewicz isp1301_pullup_enable(udc, is_on, 0); 157590fccb52SAndrzej Pietrasiewicz } 157690fccb52SAndrzej Pietrasiewicz 157790fccb52SAndrzej Pietrasiewicz /* Must be called without lock */ 157890fccb52SAndrzej Pietrasiewicz static int lpc32xx_ep_disable(struct usb_ep *_ep) 157990fccb52SAndrzej Pietrasiewicz { 158090fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); 158190fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = ep->udc; 158290fccb52SAndrzej Pietrasiewicz unsigned long flags; 158390fccb52SAndrzej Pietrasiewicz 158490fccb52SAndrzej Pietrasiewicz if ((ep->hwep_num_base == 0) || (ep->hwep_num == 0)) 158590fccb52SAndrzej Pietrasiewicz return -EINVAL; 158690fccb52SAndrzej Pietrasiewicz spin_lock_irqsave(&udc->lock, flags); 158790fccb52SAndrzej Pietrasiewicz 158890fccb52SAndrzej Pietrasiewicz nuke(ep, -ESHUTDOWN); 158990fccb52SAndrzej Pietrasiewicz 159090fccb52SAndrzej Pietrasiewicz /* Clear all DMA statuses for this EP */ 159190fccb52SAndrzej Pietrasiewicz udc_ep_dma_disable(udc, ep->hwep_num); 159290fccb52SAndrzej Pietrasiewicz writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr)); 159390fccb52SAndrzej Pietrasiewicz writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr)); 159490fccb52SAndrzej Pietrasiewicz writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr)); 159590fccb52SAndrzej Pietrasiewicz writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr)); 159690fccb52SAndrzej Pietrasiewicz 159790fccb52SAndrzej Pietrasiewicz /* Remove the DD pointer in the UDCA */ 159890fccb52SAndrzej Pietrasiewicz udc->udca_v_base[ep->hwep_num] = 0; 159990fccb52SAndrzej Pietrasiewicz 160090fccb52SAndrzej Pietrasiewicz /* Disable and reset endpoint and interrupt */ 160190fccb52SAndrzej Pietrasiewicz uda_clear_hwepint(udc, ep->hwep_num); 160290fccb52SAndrzej Pietrasiewicz udc_unrealize_hwep(udc, ep->hwep_num); 160390fccb52SAndrzej Pietrasiewicz 160490fccb52SAndrzej Pietrasiewicz ep->hwep_num = 0; 160590fccb52SAndrzej Pietrasiewicz 160690fccb52SAndrzej Pietrasiewicz spin_unlock_irqrestore(&udc->lock, flags); 160790fccb52SAndrzej Pietrasiewicz 160890fccb52SAndrzej Pietrasiewicz atomic_dec(&udc->enabled_ep_cnt); 160990fccb52SAndrzej Pietrasiewicz wake_up(&udc->ep_disable_wait_queue); 161090fccb52SAndrzej Pietrasiewicz 161190fccb52SAndrzej Pietrasiewicz return 0; 161290fccb52SAndrzej Pietrasiewicz } 161390fccb52SAndrzej Pietrasiewicz 161490fccb52SAndrzej Pietrasiewicz /* Must be called without lock */ 161590fccb52SAndrzej Pietrasiewicz static int lpc32xx_ep_enable(struct usb_ep *_ep, 161690fccb52SAndrzej Pietrasiewicz const struct usb_endpoint_descriptor *desc) 161790fccb52SAndrzej Pietrasiewicz { 161890fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); 161990fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = ep->udc; 162090fccb52SAndrzej Pietrasiewicz u16 maxpacket; 162190fccb52SAndrzej Pietrasiewicz u32 tmp; 162290fccb52SAndrzej Pietrasiewicz unsigned long flags; 162390fccb52SAndrzej Pietrasiewicz 162490fccb52SAndrzej Pietrasiewicz /* Verify EP data */ 162590fccb52SAndrzej Pietrasiewicz if ((!_ep) || (!ep) || (!desc) || 162690fccb52SAndrzej Pietrasiewicz (desc->bDescriptorType != USB_DT_ENDPOINT)) { 162790fccb52SAndrzej Pietrasiewicz dev_dbg(udc->dev, "bad ep or descriptor\n"); 162890fccb52SAndrzej Pietrasiewicz return -EINVAL; 162990fccb52SAndrzej Pietrasiewicz } 163090fccb52SAndrzej Pietrasiewicz maxpacket = usb_endpoint_maxp(desc); 163190fccb52SAndrzej Pietrasiewicz if ((maxpacket == 0) || (maxpacket > ep->maxpacket)) { 163290fccb52SAndrzej Pietrasiewicz dev_dbg(udc->dev, "bad ep descriptor's packet size\n"); 163390fccb52SAndrzej Pietrasiewicz return -EINVAL; 163490fccb52SAndrzej Pietrasiewicz } 163590fccb52SAndrzej Pietrasiewicz 163690fccb52SAndrzej Pietrasiewicz /* Don't touch EP0 */ 163790fccb52SAndrzej Pietrasiewicz if (ep->hwep_num_base == 0) { 163890fccb52SAndrzej Pietrasiewicz dev_dbg(udc->dev, "Can't re-enable EP0!!!\n"); 163990fccb52SAndrzej Pietrasiewicz return -EINVAL; 164090fccb52SAndrzej Pietrasiewicz } 164190fccb52SAndrzej Pietrasiewicz 164290fccb52SAndrzej Pietrasiewicz /* Is driver ready? */ 164390fccb52SAndrzej Pietrasiewicz if ((!udc->driver) || (udc->gadget.speed == USB_SPEED_UNKNOWN)) { 164490fccb52SAndrzej Pietrasiewicz dev_dbg(udc->dev, "bogus device state\n"); 164590fccb52SAndrzej Pietrasiewicz return -ESHUTDOWN; 164690fccb52SAndrzej Pietrasiewicz } 164790fccb52SAndrzej Pietrasiewicz 164890fccb52SAndrzej Pietrasiewicz tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; 164990fccb52SAndrzej Pietrasiewicz switch (tmp) { 165090fccb52SAndrzej Pietrasiewicz case USB_ENDPOINT_XFER_CONTROL: 165190fccb52SAndrzej Pietrasiewicz return -EINVAL; 165290fccb52SAndrzej Pietrasiewicz 165390fccb52SAndrzej Pietrasiewicz case USB_ENDPOINT_XFER_INT: 165490fccb52SAndrzej Pietrasiewicz if (maxpacket > ep->maxpacket) { 165590fccb52SAndrzej Pietrasiewicz dev_dbg(udc->dev, 165690fccb52SAndrzej Pietrasiewicz "Bad INT endpoint maxpacket %d\n", maxpacket); 165790fccb52SAndrzej Pietrasiewicz return -EINVAL; 165890fccb52SAndrzej Pietrasiewicz } 165990fccb52SAndrzej Pietrasiewicz break; 166090fccb52SAndrzej Pietrasiewicz 166190fccb52SAndrzej Pietrasiewicz case USB_ENDPOINT_XFER_BULK: 166290fccb52SAndrzej Pietrasiewicz switch (maxpacket) { 166390fccb52SAndrzej Pietrasiewicz case 8: 166490fccb52SAndrzej Pietrasiewicz case 16: 166590fccb52SAndrzej Pietrasiewicz case 32: 166690fccb52SAndrzej Pietrasiewicz case 64: 166790fccb52SAndrzej Pietrasiewicz break; 166890fccb52SAndrzej Pietrasiewicz 166990fccb52SAndrzej Pietrasiewicz default: 167090fccb52SAndrzej Pietrasiewicz dev_dbg(udc->dev, 167190fccb52SAndrzej Pietrasiewicz "Bad BULK endpoint maxpacket %d\n", maxpacket); 167290fccb52SAndrzej Pietrasiewicz return -EINVAL; 167390fccb52SAndrzej Pietrasiewicz } 167490fccb52SAndrzej Pietrasiewicz break; 167590fccb52SAndrzej Pietrasiewicz 167690fccb52SAndrzej Pietrasiewicz case USB_ENDPOINT_XFER_ISOC: 167790fccb52SAndrzej Pietrasiewicz break; 167890fccb52SAndrzej Pietrasiewicz } 167990fccb52SAndrzej Pietrasiewicz spin_lock_irqsave(&udc->lock, flags); 168090fccb52SAndrzej Pietrasiewicz 168190fccb52SAndrzej Pietrasiewicz /* Initialize endpoint to match the selected descriptor */ 168290fccb52SAndrzej Pietrasiewicz ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0; 168390fccb52SAndrzej Pietrasiewicz ep->ep.maxpacket = maxpacket; 168490fccb52SAndrzej Pietrasiewicz 168590fccb52SAndrzej Pietrasiewicz /* Map hardware endpoint from base and direction */ 168690fccb52SAndrzej Pietrasiewicz if (ep->is_in) 168790fccb52SAndrzej Pietrasiewicz /* IN endpoints are offset 1 from the OUT endpoint */ 168890fccb52SAndrzej Pietrasiewicz ep->hwep_num = ep->hwep_num_base + EP_IN; 168990fccb52SAndrzej Pietrasiewicz else 169090fccb52SAndrzej Pietrasiewicz ep->hwep_num = ep->hwep_num_base; 169190fccb52SAndrzej Pietrasiewicz 169290fccb52SAndrzej Pietrasiewicz ep_dbg(ep, "EP enabled: %s, HW:%d, MP:%d IN:%d\n", ep->ep.name, 169390fccb52SAndrzej Pietrasiewicz ep->hwep_num, maxpacket, (ep->is_in == 1)); 169490fccb52SAndrzej Pietrasiewicz 169590fccb52SAndrzej Pietrasiewicz /* Realize the endpoint, interrupt is enabled later when 169690fccb52SAndrzej Pietrasiewicz * buffers are queued, IN EPs will NAK until buffers are ready */ 169790fccb52SAndrzej Pietrasiewicz udc_realize_hwep(udc, ep->hwep_num, ep->ep.maxpacket); 169890fccb52SAndrzej Pietrasiewicz udc_clr_buffer_hwep(udc, ep->hwep_num); 169990fccb52SAndrzej Pietrasiewicz uda_disable_hwepint(udc, ep->hwep_num); 170090fccb52SAndrzej Pietrasiewicz udc_clrstall_hwep(udc, ep->hwep_num); 170190fccb52SAndrzej Pietrasiewicz 170290fccb52SAndrzej Pietrasiewicz /* Clear all DMA statuses for this EP */ 170390fccb52SAndrzej Pietrasiewicz udc_ep_dma_disable(udc, ep->hwep_num); 170490fccb52SAndrzej Pietrasiewicz writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr)); 170590fccb52SAndrzej Pietrasiewicz writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr)); 170690fccb52SAndrzej Pietrasiewicz writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr)); 170790fccb52SAndrzej Pietrasiewicz writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr)); 170890fccb52SAndrzej Pietrasiewicz 170990fccb52SAndrzej Pietrasiewicz spin_unlock_irqrestore(&udc->lock, flags); 171090fccb52SAndrzej Pietrasiewicz 171190fccb52SAndrzej Pietrasiewicz atomic_inc(&udc->enabled_ep_cnt); 171290fccb52SAndrzej Pietrasiewicz return 0; 171390fccb52SAndrzej Pietrasiewicz } 171490fccb52SAndrzej Pietrasiewicz 171590fccb52SAndrzej Pietrasiewicz /* 171690fccb52SAndrzej Pietrasiewicz * Allocate a USB request list 171790fccb52SAndrzej Pietrasiewicz * Can be called with or without lock 171890fccb52SAndrzej Pietrasiewicz */ 171990fccb52SAndrzej Pietrasiewicz static struct usb_request *lpc32xx_ep_alloc_request(struct usb_ep *_ep, 172090fccb52SAndrzej Pietrasiewicz gfp_t gfp_flags) 172190fccb52SAndrzej Pietrasiewicz { 172290fccb52SAndrzej Pietrasiewicz struct lpc32xx_request *req; 172390fccb52SAndrzej Pietrasiewicz 172490fccb52SAndrzej Pietrasiewicz req = kzalloc(sizeof(struct lpc32xx_request), gfp_flags); 172590fccb52SAndrzej Pietrasiewicz if (!req) 172690fccb52SAndrzej Pietrasiewicz return NULL; 172790fccb52SAndrzej Pietrasiewicz 172890fccb52SAndrzej Pietrasiewicz INIT_LIST_HEAD(&req->queue); 172990fccb52SAndrzej Pietrasiewicz return &req->req; 173090fccb52SAndrzej Pietrasiewicz } 173190fccb52SAndrzej Pietrasiewicz 173290fccb52SAndrzej Pietrasiewicz /* 173390fccb52SAndrzej Pietrasiewicz * De-allocate a USB request list 173490fccb52SAndrzej Pietrasiewicz * Can be called with or without lock 173590fccb52SAndrzej Pietrasiewicz */ 173690fccb52SAndrzej Pietrasiewicz static void lpc32xx_ep_free_request(struct usb_ep *_ep, 173790fccb52SAndrzej Pietrasiewicz struct usb_request *_req) 173890fccb52SAndrzej Pietrasiewicz { 173990fccb52SAndrzej Pietrasiewicz struct lpc32xx_request *req; 174090fccb52SAndrzej Pietrasiewicz 174190fccb52SAndrzej Pietrasiewicz req = container_of(_req, struct lpc32xx_request, req); 174290fccb52SAndrzej Pietrasiewicz BUG_ON(!list_empty(&req->queue)); 174390fccb52SAndrzej Pietrasiewicz kfree(req); 174490fccb52SAndrzej Pietrasiewicz } 174590fccb52SAndrzej Pietrasiewicz 174690fccb52SAndrzej Pietrasiewicz /* Must be called without lock */ 174790fccb52SAndrzej Pietrasiewicz static int lpc32xx_ep_queue(struct usb_ep *_ep, 174890fccb52SAndrzej Pietrasiewicz struct usb_request *_req, gfp_t gfp_flags) 174990fccb52SAndrzej Pietrasiewicz { 175090fccb52SAndrzej Pietrasiewicz struct lpc32xx_request *req; 175190fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep; 175290fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc; 175390fccb52SAndrzej Pietrasiewicz unsigned long flags; 175490fccb52SAndrzej Pietrasiewicz int status = 0; 175590fccb52SAndrzej Pietrasiewicz 175690fccb52SAndrzej Pietrasiewicz req = container_of(_req, struct lpc32xx_request, req); 175790fccb52SAndrzej Pietrasiewicz ep = container_of(_ep, struct lpc32xx_ep, ep); 175890fccb52SAndrzej Pietrasiewicz 1759005a6430SPeter Chen if (!_ep || !_req || !_req->complete || !_req->buf || 176090fccb52SAndrzej Pietrasiewicz !list_empty(&req->queue)) 176190fccb52SAndrzej Pietrasiewicz return -EINVAL; 176290fccb52SAndrzej Pietrasiewicz 176390fccb52SAndrzej Pietrasiewicz udc = ep->udc; 176490fccb52SAndrzej Pietrasiewicz 1765005a6430SPeter Chen if (udc->gadget.speed == USB_SPEED_UNKNOWN) 1766005a6430SPeter Chen return -EPIPE; 176790fccb52SAndrzej Pietrasiewicz 176890fccb52SAndrzej Pietrasiewicz if (ep->lep) { 176990fccb52SAndrzej Pietrasiewicz struct lpc32xx_usbd_dd_gad *dd; 177090fccb52SAndrzej Pietrasiewicz 177190fccb52SAndrzej Pietrasiewicz status = usb_gadget_map_request(&udc->gadget, _req, ep->is_in); 177290fccb52SAndrzej Pietrasiewicz if (status) 177390fccb52SAndrzej Pietrasiewicz return status; 177490fccb52SAndrzej Pietrasiewicz 177590fccb52SAndrzej Pietrasiewicz /* For the request, build a list of DDs */ 177690fccb52SAndrzej Pietrasiewicz dd = udc_dd_alloc(udc); 177790fccb52SAndrzej Pietrasiewicz if (!dd) { 177890fccb52SAndrzej Pietrasiewicz /* Error allocating DD */ 177990fccb52SAndrzej Pietrasiewicz return -ENOMEM; 178090fccb52SAndrzej Pietrasiewicz } 178190fccb52SAndrzej Pietrasiewicz req->dd_desc_ptr = dd; 178290fccb52SAndrzej Pietrasiewicz 178390fccb52SAndrzej Pietrasiewicz /* Setup the DMA descriptor */ 178490fccb52SAndrzej Pietrasiewicz dd->dd_next_phy = dd->dd_next_v = 0; 178590fccb52SAndrzej Pietrasiewicz dd->dd_buffer_addr = req->req.dma; 178690fccb52SAndrzej Pietrasiewicz dd->dd_status = 0; 178790fccb52SAndrzej Pietrasiewicz 178890fccb52SAndrzej Pietrasiewicz /* Special handling for ISO EPs */ 178990fccb52SAndrzej Pietrasiewicz if (ep->eptype == EP_ISO_TYPE) { 179090fccb52SAndrzej Pietrasiewicz dd->dd_setup = DD_SETUP_ISO_EP | 179190fccb52SAndrzej Pietrasiewicz DD_SETUP_PACKETLEN(0) | 179290fccb52SAndrzej Pietrasiewicz DD_SETUP_DMALENBYTES(1); 179390fccb52SAndrzej Pietrasiewicz dd->dd_iso_ps_mem_addr = dd->this_dma + 24; 179490fccb52SAndrzej Pietrasiewicz if (ep->is_in) 179590fccb52SAndrzej Pietrasiewicz dd->iso_status[0] = req->req.length; 179690fccb52SAndrzej Pietrasiewicz else 179790fccb52SAndrzej Pietrasiewicz dd->iso_status[0] = 0; 179890fccb52SAndrzej Pietrasiewicz } else 179990fccb52SAndrzej Pietrasiewicz dd->dd_setup = DD_SETUP_PACKETLEN(ep->ep.maxpacket) | 180090fccb52SAndrzej Pietrasiewicz DD_SETUP_DMALENBYTES(req->req.length); 180190fccb52SAndrzej Pietrasiewicz } 180290fccb52SAndrzej Pietrasiewicz 180390fccb52SAndrzej Pietrasiewicz ep_dbg(ep, "%s queue req %p len %d buf %p (in=%d) z=%d\n", _ep->name, 180490fccb52SAndrzej Pietrasiewicz _req, _req->length, _req->buf, ep->is_in, _req->zero); 180590fccb52SAndrzej Pietrasiewicz 180690fccb52SAndrzej Pietrasiewicz spin_lock_irqsave(&udc->lock, flags); 180790fccb52SAndrzej Pietrasiewicz 180890fccb52SAndrzej Pietrasiewicz _req->status = -EINPROGRESS; 180990fccb52SAndrzej Pietrasiewicz _req->actual = 0; 181090fccb52SAndrzej Pietrasiewicz req->send_zlp = _req->zero; 181190fccb52SAndrzej Pietrasiewicz 181290fccb52SAndrzej Pietrasiewicz /* Kickstart empty queues */ 181390fccb52SAndrzej Pietrasiewicz if (list_empty(&ep->queue)) { 181490fccb52SAndrzej Pietrasiewicz list_add_tail(&req->queue, &ep->queue); 181590fccb52SAndrzej Pietrasiewicz 181690fccb52SAndrzej Pietrasiewicz if (ep->hwep_num_base == 0) { 181790fccb52SAndrzej Pietrasiewicz /* Handle expected data direction */ 181890fccb52SAndrzej Pietrasiewicz if (ep->is_in) { 181990fccb52SAndrzej Pietrasiewicz /* IN packet to host */ 182090fccb52SAndrzej Pietrasiewicz udc->ep0state = DATA_IN; 182190fccb52SAndrzej Pietrasiewicz status = udc_ep0_in_req(udc); 182290fccb52SAndrzej Pietrasiewicz } else { 182390fccb52SAndrzej Pietrasiewicz /* OUT packet from host */ 182490fccb52SAndrzej Pietrasiewicz udc->ep0state = DATA_OUT; 182590fccb52SAndrzej Pietrasiewicz status = udc_ep0_out_req(udc); 182690fccb52SAndrzej Pietrasiewicz } 182790fccb52SAndrzej Pietrasiewicz } else if (ep->is_in) { 182890fccb52SAndrzej Pietrasiewicz /* IN packet to host and kick off transfer */ 182990fccb52SAndrzej Pietrasiewicz if (!ep->req_pending) 183090fccb52SAndrzej Pietrasiewicz udc_ep_in_req_dma(udc, ep); 183190fccb52SAndrzej Pietrasiewicz } else 183290fccb52SAndrzej Pietrasiewicz /* OUT packet from host and kick off list */ 183390fccb52SAndrzej Pietrasiewicz if (!ep->req_pending) 183490fccb52SAndrzej Pietrasiewicz udc_ep_out_req_dma(udc, ep); 183590fccb52SAndrzej Pietrasiewicz } else 183690fccb52SAndrzej Pietrasiewicz list_add_tail(&req->queue, &ep->queue); 183790fccb52SAndrzej Pietrasiewicz 183890fccb52SAndrzej Pietrasiewicz spin_unlock_irqrestore(&udc->lock, flags); 183990fccb52SAndrzej Pietrasiewicz 184090fccb52SAndrzej Pietrasiewicz return (status < 0) ? status : 0; 184190fccb52SAndrzej Pietrasiewicz } 184290fccb52SAndrzej Pietrasiewicz 184390fccb52SAndrzej Pietrasiewicz /* Must be called without lock */ 184490fccb52SAndrzej Pietrasiewicz static int lpc32xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) 184590fccb52SAndrzej Pietrasiewicz { 184690fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep; 184790fccb52SAndrzej Pietrasiewicz struct lpc32xx_request *req; 184890fccb52SAndrzej Pietrasiewicz unsigned long flags; 184990fccb52SAndrzej Pietrasiewicz 185090fccb52SAndrzej Pietrasiewicz ep = container_of(_ep, struct lpc32xx_ep, ep); 185190fccb52SAndrzej Pietrasiewicz if (!_ep || ep->hwep_num_base == 0) 185290fccb52SAndrzej Pietrasiewicz return -EINVAL; 185390fccb52SAndrzej Pietrasiewicz 185490fccb52SAndrzej Pietrasiewicz spin_lock_irqsave(&ep->udc->lock, flags); 185590fccb52SAndrzej Pietrasiewicz 185690fccb52SAndrzej Pietrasiewicz /* make sure it's actually queued on this endpoint */ 185790fccb52SAndrzej Pietrasiewicz list_for_each_entry(req, &ep->queue, queue) { 185890fccb52SAndrzej Pietrasiewicz if (&req->req == _req) 185990fccb52SAndrzej Pietrasiewicz break; 186090fccb52SAndrzej Pietrasiewicz } 186190fccb52SAndrzej Pietrasiewicz if (&req->req != _req) { 186290fccb52SAndrzej Pietrasiewicz spin_unlock_irqrestore(&ep->udc->lock, flags); 186390fccb52SAndrzej Pietrasiewicz return -EINVAL; 186490fccb52SAndrzej Pietrasiewicz } 186590fccb52SAndrzej Pietrasiewicz 186690fccb52SAndrzej Pietrasiewicz done(ep, req, -ECONNRESET); 186790fccb52SAndrzej Pietrasiewicz 186890fccb52SAndrzej Pietrasiewicz spin_unlock_irqrestore(&ep->udc->lock, flags); 186990fccb52SAndrzej Pietrasiewicz 187090fccb52SAndrzej Pietrasiewicz return 0; 187190fccb52SAndrzej Pietrasiewicz } 187290fccb52SAndrzej Pietrasiewicz 187390fccb52SAndrzej Pietrasiewicz /* Must be called without lock */ 187490fccb52SAndrzej Pietrasiewicz static int lpc32xx_ep_set_halt(struct usb_ep *_ep, int value) 187590fccb52SAndrzej Pietrasiewicz { 187690fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); 187790fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = ep->udc; 187890fccb52SAndrzej Pietrasiewicz unsigned long flags; 187990fccb52SAndrzej Pietrasiewicz 188090fccb52SAndrzej Pietrasiewicz if ((!ep) || (ep->hwep_num <= 1)) 188190fccb52SAndrzej Pietrasiewicz return -EINVAL; 188290fccb52SAndrzej Pietrasiewicz 188390fccb52SAndrzej Pietrasiewicz /* Don't halt an IN EP */ 188490fccb52SAndrzej Pietrasiewicz if (ep->is_in) 188590fccb52SAndrzej Pietrasiewicz return -EAGAIN; 188690fccb52SAndrzej Pietrasiewicz 188790fccb52SAndrzej Pietrasiewicz spin_lock_irqsave(&udc->lock, flags); 188890fccb52SAndrzej Pietrasiewicz 188990fccb52SAndrzej Pietrasiewicz if (value == 1) { 189090fccb52SAndrzej Pietrasiewicz /* stall */ 189190fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num), 189290fccb52SAndrzej Pietrasiewicz DAT_WR_BYTE(EP_STAT_ST)); 189390fccb52SAndrzej Pietrasiewicz } else { 189490fccb52SAndrzej Pietrasiewicz /* End stall */ 189590fccb52SAndrzej Pietrasiewicz ep->wedge = 0; 189690fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num), 189790fccb52SAndrzej Pietrasiewicz DAT_WR_BYTE(0)); 189890fccb52SAndrzej Pietrasiewicz } 189990fccb52SAndrzej Pietrasiewicz 190090fccb52SAndrzej Pietrasiewicz spin_unlock_irqrestore(&udc->lock, flags); 190190fccb52SAndrzej Pietrasiewicz 190290fccb52SAndrzej Pietrasiewicz return 0; 190390fccb52SAndrzej Pietrasiewicz } 190490fccb52SAndrzej Pietrasiewicz 190590fccb52SAndrzej Pietrasiewicz /* set the halt feature and ignores clear requests */ 190690fccb52SAndrzej Pietrasiewicz static int lpc32xx_ep_set_wedge(struct usb_ep *_ep) 190790fccb52SAndrzej Pietrasiewicz { 190890fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); 190990fccb52SAndrzej Pietrasiewicz 191090fccb52SAndrzej Pietrasiewicz if (!_ep || !ep->udc) 191190fccb52SAndrzej Pietrasiewicz return -EINVAL; 191290fccb52SAndrzej Pietrasiewicz 191390fccb52SAndrzej Pietrasiewicz ep->wedge = 1; 191490fccb52SAndrzej Pietrasiewicz 191590fccb52SAndrzej Pietrasiewicz return usb_ep_set_halt(_ep); 191690fccb52SAndrzej Pietrasiewicz } 191790fccb52SAndrzej Pietrasiewicz 191890fccb52SAndrzej Pietrasiewicz static const struct usb_ep_ops lpc32xx_ep_ops = { 191990fccb52SAndrzej Pietrasiewicz .enable = lpc32xx_ep_enable, 192090fccb52SAndrzej Pietrasiewicz .disable = lpc32xx_ep_disable, 192190fccb52SAndrzej Pietrasiewicz .alloc_request = lpc32xx_ep_alloc_request, 192290fccb52SAndrzej Pietrasiewicz .free_request = lpc32xx_ep_free_request, 192390fccb52SAndrzej Pietrasiewicz .queue = lpc32xx_ep_queue, 192490fccb52SAndrzej Pietrasiewicz .dequeue = lpc32xx_ep_dequeue, 192590fccb52SAndrzej Pietrasiewicz .set_halt = lpc32xx_ep_set_halt, 192690fccb52SAndrzej Pietrasiewicz .set_wedge = lpc32xx_ep_set_wedge, 192790fccb52SAndrzej Pietrasiewicz }; 192890fccb52SAndrzej Pietrasiewicz 192990fccb52SAndrzej Pietrasiewicz /* Send a ZLP on a non-0 IN EP */ 193090fccb52SAndrzej Pietrasiewicz void udc_send_in_zlp(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) 193190fccb52SAndrzej Pietrasiewicz { 193290fccb52SAndrzej Pietrasiewicz /* Clear EP status */ 193390fccb52SAndrzej Pietrasiewicz udc_clearep_getsts(udc, ep->hwep_num); 193490fccb52SAndrzej Pietrasiewicz 193590fccb52SAndrzej Pietrasiewicz /* Send ZLP via FIFO mechanism */ 193690fccb52SAndrzej Pietrasiewicz udc_write_hwep(udc, ep->hwep_num, NULL, 0); 193790fccb52SAndrzej Pietrasiewicz } 193890fccb52SAndrzej Pietrasiewicz 193990fccb52SAndrzej Pietrasiewicz /* 194090fccb52SAndrzej Pietrasiewicz * Handle EP completion for ZLP 194190fccb52SAndrzej Pietrasiewicz * This function will only be called when a delayed ZLP needs to be sent out 194290fccb52SAndrzej Pietrasiewicz * after a DMA transfer has filled both buffers. 194390fccb52SAndrzej Pietrasiewicz */ 194490fccb52SAndrzej Pietrasiewicz void udc_handle_eps(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) 194590fccb52SAndrzej Pietrasiewicz { 194690fccb52SAndrzej Pietrasiewicz u32 epstatus; 194790fccb52SAndrzej Pietrasiewicz struct lpc32xx_request *req; 194890fccb52SAndrzej Pietrasiewicz 194990fccb52SAndrzej Pietrasiewicz if (ep->hwep_num <= 0) 195090fccb52SAndrzej Pietrasiewicz return; 195190fccb52SAndrzej Pietrasiewicz 195290fccb52SAndrzej Pietrasiewicz uda_clear_hwepint(udc, ep->hwep_num); 195390fccb52SAndrzej Pietrasiewicz 195490fccb52SAndrzej Pietrasiewicz /* If this interrupt isn't enabled, return now */ 195590fccb52SAndrzej Pietrasiewicz if (!(udc->enabled_hwepints & (1 << ep->hwep_num))) 195690fccb52SAndrzej Pietrasiewicz return; 195790fccb52SAndrzej Pietrasiewicz 195890fccb52SAndrzej Pietrasiewicz /* Get endpoint status */ 195990fccb52SAndrzej Pietrasiewicz epstatus = udc_clearep_getsts(udc, ep->hwep_num); 196090fccb52SAndrzej Pietrasiewicz 196190fccb52SAndrzej Pietrasiewicz /* 196290fccb52SAndrzej Pietrasiewicz * This should never happen, but protect against writing to the 196390fccb52SAndrzej Pietrasiewicz * buffer when full. 196490fccb52SAndrzej Pietrasiewicz */ 196590fccb52SAndrzej Pietrasiewicz if (epstatus & EP_SEL_F) 196690fccb52SAndrzej Pietrasiewicz return; 196790fccb52SAndrzej Pietrasiewicz 196890fccb52SAndrzej Pietrasiewicz if (ep->is_in) { 196990fccb52SAndrzej Pietrasiewicz udc_send_in_zlp(udc, ep); 197090fccb52SAndrzej Pietrasiewicz uda_disable_hwepint(udc, ep->hwep_num); 197190fccb52SAndrzej Pietrasiewicz } else 197290fccb52SAndrzej Pietrasiewicz return; 197390fccb52SAndrzej Pietrasiewicz 197490fccb52SAndrzej Pietrasiewicz /* If there isn't a request waiting, something went wrong */ 197590fccb52SAndrzej Pietrasiewicz req = list_entry(ep->queue.next, struct lpc32xx_request, queue); 197690fccb52SAndrzej Pietrasiewicz if (req) { 197790fccb52SAndrzej Pietrasiewicz done(ep, req, 0); 197890fccb52SAndrzej Pietrasiewicz 197990fccb52SAndrzej Pietrasiewicz /* Start another request if ready */ 198090fccb52SAndrzej Pietrasiewicz if (!list_empty(&ep->queue)) { 198190fccb52SAndrzej Pietrasiewicz if (ep->is_in) 198290fccb52SAndrzej Pietrasiewicz udc_ep_in_req_dma(udc, ep); 198390fccb52SAndrzej Pietrasiewicz else 198490fccb52SAndrzej Pietrasiewicz udc_ep_out_req_dma(udc, ep); 198590fccb52SAndrzej Pietrasiewicz } else 198690fccb52SAndrzej Pietrasiewicz ep->req_pending = 0; 198790fccb52SAndrzej Pietrasiewicz } 198890fccb52SAndrzej Pietrasiewicz } 198990fccb52SAndrzej Pietrasiewicz 199090fccb52SAndrzej Pietrasiewicz 199190fccb52SAndrzej Pietrasiewicz /* DMA end of transfer completion */ 199290fccb52SAndrzej Pietrasiewicz static void udc_handle_dma_ep(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) 199390fccb52SAndrzej Pietrasiewicz { 199490fccb52SAndrzej Pietrasiewicz u32 status, epstatus; 199590fccb52SAndrzej Pietrasiewicz struct lpc32xx_request *req; 199690fccb52SAndrzej Pietrasiewicz struct lpc32xx_usbd_dd_gad *dd; 199790fccb52SAndrzej Pietrasiewicz 199890fccb52SAndrzej Pietrasiewicz #ifdef CONFIG_USB_GADGET_DEBUG_FILES 199990fccb52SAndrzej Pietrasiewicz ep->totalints++; 200090fccb52SAndrzej Pietrasiewicz #endif 200190fccb52SAndrzej Pietrasiewicz 200290fccb52SAndrzej Pietrasiewicz req = list_entry(ep->queue.next, struct lpc32xx_request, queue); 200390fccb52SAndrzej Pietrasiewicz if (!req) { 200490fccb52SAndrzej Pietrasiewicz ep_err(ep, "DMA interrupt on no req!\n"); 200590fccb52SAndrzej Pietrasiewicz return; 200690fccb52SAndrzej Pietrasiewicz } 200790fccb52SAndrzej Pietrasiewicz dd = req->dd_desc_ptr; 200890fccb52SAndrzej Pietrasiewicz 200990fccb52SAndrzej Pietrasiewicz /* DMA descriptor should always be retired for this call */ 201090fccb52SAndrzej Pietrasiewicz if (!(dd->dd_status & DD_STATUS_DD_RETIRED)) 201190fccb52SAndrzej Pietrasiewicz ep_warn(ep, "DMA descriptor did not retire\n"); 201290fccb52SAndrzej Pietrasiewicz 201390fccb52SAndrzej Pietrasiewicz /* Disable DMA */ 201490fccb52SAndrzej Pietrasiewicz udc_ep_dma_disable(udc, ep->hwep_num); 201590fccb52SAndrzej Pietrasiewicz writel((1 << ep->hwep_num), USBD_EOTINTCLR(udc->udp_baseaddr)); 201690fccb52SAndrzej Pietrasiewicz writel((1 << ep->hwep_num), USBD_NDDRTINTCLR(udc->udp_baseaddr)); 201790fccb52SAndrzej Pietrasiewicz 201890fccb52SAndrzej Pietrasiewicz /* System error? */ 201990fccb52SAndrzej Pietrasiewicz if (readl(USBD_SYSERRTINTST(udc->udp_baseaddr)) & 202090fccb52SAndrzej Pietrasiewicz (1 << ep->hwep_num)) { 202190fccb52SAndrzej Pietrasiewicz writel((1 << ep->hwep_num), 202290fccb52SAndrzej Pietrasiewicz USBD_SYSERRTINTCLR(udc->udp_baseaddr)); 202390fccb52SAndrzej Pietrasiewicz ep_err(ep, "AHB critical error!\n"); 202490fccb52SAndrzej Pietrasiewicz ep->req_pending = 0; 202590fccb52SAndrzej Pietrasiewicz 202690fccb52SAndrzej Pietrasiewicz /* The error could have occurred on a packet of a multipacket 202790fccb52SAndrzej Pietrasiewicz * transfer, so recovering the transfer is not possible. Close 202890fccb52SAndrzej Pietrasiewicz * the request with an error */ 202990fccb52SAndrzej Pietrasiewicz done(ep, req, -ECONNABORTED); 203090fccb52SAndrzej Pietrasiewicz return; 203190fccb52SAndrzej Pietrasiewicz } 203290fccb52SAndrzej Pietrasiewicz 203390fccb52SAndrzej Pietrasiewicz /* Handle the current DD's status */ 203490fccb52SAndrzej Pietrasiewicz status = dd->dd_status; 203590fccb52SAndrzej Pietrasiewicz switch (status & DD_STATUS_STS_MASK) { 203690fccb52SAndrzej Pietrasiewicz case DD_STATUS_STS_NS: 203790fccb52SAndrzej Pietrasiewicz /* DD not serviced? This shouldn't happen! */ 203890fccb52SAndrzej Pietrasiewicz ep->req_pending = 0; 203990fccb52SAndrzej Pietrasiewicz ep_err(ep, "DMA critical EP error: DD not serviced (0x%x)!\n", 204090fccb52SAndrzej Pietrasiewicz status); 204190fccb52SAndrzej Pietrasiewicz 204290fccb52SAndrzej Pietrasiewicz done(ep, req, -ECONNABORTED); 204390fccb52SAndrzej Pietrasiewicz return; 204490fccb52SAndrzej Pietrasiewicz 204590fccb52SAndrzej Pietrasiewicz case DD_STATUS_STS_BS: 204690fccb52SAndrzej Pietrasiewicz /* Interrupt only fires on EOT - This shouldn't happen! */ 204790fccb52SAndrzej Pietrasiewicz ep->req_pending = 0; 204890fccb52SAndrzej Pietrasiewicz ep_err(ep, "DMA critical EP error: EOT prior to service completion (0x%x)!\n", 204990fccb52SAndrzej Pietrasiewicz status); 205090fccb52SAndrzej Pietrasiewicz done(ep, req, -ECONNABORTED); 205190fccb52SAndrzej Pietrasiewicz return; 205290fccb52SAndrzej Pietrasiewicz 205390fccb52SAndrzej Pietrasiewicz case DD_STATUS_STS_NC: 205490fccb52SAndrzej Pietrasiewicz case DD_STATUS_STS_DUR: 205590fccb52SAndrzej Pietrasiewicz /* Really just a short packet, not an underrun */ 205690fccb52SAndrzej Pietrasiewicz /* This is a good status and what we expect */ 205790fccb52SAndrzej Pietrasiewicz break; 205890fccb52SAndrzej Pietrasiewicz 205990fccb52SAndrzej Pietrasiewicz default: 206090fccb52SAndrzej Pietrasiewicz /* Data overrun, system error, or unknown */ 206190fccb52SAndrzej Pietrasiewicz ep->req_pending = 0; 206290fccb52SAndrzej Pietrasiewicz ep_err(ep, "DMA critical EP error: System error (0x%x)!\n", 206390fccb52SAndrzej Pietrasiewicz status); 206490fccb52SAndrzej Pietrasiewicz done(ep, req, -ECONNABORTED); 206590fccb52SAndrzej Pietrasiewicz return; 206690fccb52SAndrzej Pietrasiewicz } 206790fccb52SAndrzej Pietrasiewicz 206890fccb52SAndrzej Pietrasiewicz /* ISO endpoints are handled differently */ 206990fccb52SAndrzej Pietrasiewicz if (ep->eptype == EP_ISO_TYPE) { 207090fccb52SAndrzej Pietrasiewicz if (ep->is_in) 207190fccb52SAndrzej Pietrasiewicz req->req.actual = req->req.length; 207290fccb52SAndrzej Pietrasiewicz else 207390fccb52SAndrzej Pietrasiewicz req->req.actual = dd->iso_status[0] & 0xFFFF; 207490fccb52SAndrzej Pietrasiewicz } else 207590fccb52SAndrzej Pietrasiewicz req->req.actual += DD_STATUS_CURDMACNT(status); 207690fccb52SAndrzej Pietrasiewicz 207790fccb52SAndrzej Pietrasiewicz /* Send a ZLP if necessary. This will be done for non-int 207890fccb52SAndrzej Pietrasiewicz * packets which have a size that is a divisor of MAXP */ 207990fccb52SAndrzej Pietrasiewicz if (req->send_zlp) { 208090fccb52SAndrzej Pietrasiewicz /* 208190fccb52SAndrzej Pietrasiewicz * If at least 1 buffer is available, send the ZLP now. 208290fccb52SAndrzej Pietrasiewicz * Otherwise, the ZLP send needs to be deferred until a 208390fccb52SAndrzej Pietrasiewicz * buffer is available. 208490fccb52SAndrzej Pietrasiewicz */ 208590fccb52SAndrzej Pietrasiewicz if (udc_clearep_getsts(udc, ep->hwep_num) & EP_SEL_F) { 208690fccb52SAndrzej Pietrasiewicz udc_clearep_getsts(udc, ep->hwep_num); 208790fccb52SAndrzej Pietrasiewicz uda_enable_hwepint(udc, ep->hwep_num); 208890fccb52SAndrzej Pietrasiewicz epstatus = udc_clearep_getsts(udc, ep->hwep_num); 208990fccb52SAndrzej Pietrasiewicz 209090fccb52SAndrzej Pietrasiewicz /* Let the EP interrupt handle the ZLP */ 209190fccb52SAndrzej Pietrasiewicz return; 209290fccb52SAndrzej Pietrasiewicz } else 209390fccb52SAndrzej Pietrasiewicz udc_send_in_zlp(udc, ep); 209490fccb52SAndrzej Pietrasiewicz } 209590fccb52SAndrzej Pietrasiewicz 209690fccb52SAndrzej Pietrasiewicz /* Transfer request is complete */ 209790fccb52SAndrzej Pietrasiewicz done(ep, req, 0); 209890fccb52SAndrzej Pietrasiewicz 209990fccb52SAndrzej Pietrasiewicz /* Start another request if ready */ 210090fccb52SAndrzej Pietrasiewicz udc_clearep_getsts(udc, ep->hwep_num); 210190fccb52SAndrzej Pietrasiewicz if (!list_empty((&ep->queue))) { 210290fccb52SAndrzej Pietrasiewicz if (ep->is_in) 210390fccb52SAndrzej Pietrasiewicz udc_ep_in_req_dma(udc, ep); 210490fccb52SAndrzej Pietrasiewicz else 210590fccb52SAndrzej Pietrasiewicz udc_ep_out_req_dma(udc, ep); 210690fccb52SAndrzej Pietrasiewicz } else 210790fccb52SAndrzej Pietrasiewicz ep->req_pending = 0; 210890fccb52SAndrzej Pietrasiewicz 210990fccb52SAndrzej Pietrasiewicz } 211090fccb52SAndrzej Pietrasiewicz 211190fccb52SAndrzej Pietrasiewicz /* 211290fccb52SAndrzej Pietrasiewicz * 211390fccb52SAndrzej Pietrasiewicz * Endpoint 0 functions 211490fccb52SAndrzej Pietrasiewicz * 211590fccb52SAndrzej Pietrasiewicz */ 211690fccb52SAndrzej Pietrasiewicz static void udc_handle_dev(struct lpc32xx_udc *udc) 211790fccb52SAndrzej Pietrasiewicz { 211890fccb52SAndrzej Pietrasiewicz u32 tmp; 211990fccb52SAndrzej Pietrasiewicz 212090fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_w(udc, CMD_GET_DEV_STAT); 212190fccb52SAndrzej Pietrasiewicz tmp = udc_protocol_cmd_r(udc, DAT_GET_DEV_STAT); 212290fccb52SAndrzej Pietrasiewicz 212390fccb52SAndrzej Pietrasiewicz if (tmp & DEV_RST) 212490fccb52SAndrzej Pietrasiewicz uda_usb_reset(udc); 212590fccb52SAndrzej Pietrasiewicz else if (tmp & DEV_CON_CH) 212690fccb52SAndrzej Pietrasiewicz uda_power_event(udc, (tmp & DEV_CON)); 212790fccb52SAndrzej Pietrasiewicz else if (tmp & DEV_SUS_CH) { 212890fccb52SAndrzej Pietrasiewicz if (tmp & DEV_SUS) { 212990fccb52SAndrzej Pietrasiewicz if (udc->vbus == 0) 213090fccb52SAndrzej Pietrasiewicz stop_activity(udc); 213190fccb52SAndrzej Pietrasiewicz else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) && 213290fccb52SAndrzej Pietrasiewicz udc->driver) { 213390fccb52SAndrzej Pietrasiewicz /* Power down transceiver */ 213490fccb52SAndrzej Pietrasiewicz udc->poweron = 0; 213590fccb52SAndrzej Pietrasiewicz schedule_work(&udc->pullup_job); 213690fccb52SAndrzej Pietrasiewicz uda_resm_susp_event(udc, 1); 213790fccb52SAndrzej Pietrasiewicz } 213890fccb52SAndrzej Pietrasiewicz } else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) && 213990fccb52SAndrzej Pietrasiewicz udc->driver && udc->vbus) { 214090fccb52SAndrzej Pietrasiewicz uda_resm_susp_event(udc, 0); 214190fccb52SAndrzej Pietrasiewicz /* Power up transceiver */ 214290fccb52SAndrzej Pietrasiewicz udc->poweron = 1; 214390fccb52SAndrzej Pietrasiewicz schedule_work(&udc->pullup_job); 214490fccb52SAndrzej Pietrasiewicz } 214590fccb52SAndrzej Pietrasiewicz } 214690fccb52SAndrzej Pietrasiewicz } 214790fccb52SAndrzej Pietrasiewicz 214890fccb52SAndrzej Pietrasiewicz static int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex) 214990fccb52SAndrzej Pietrasiewicz { 215090fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep; 215190fccb52SAndrzej Pietrasiewicz u32 ep0buff = 0, tmp; 215290fccb52SAndrzej Pietrasiewicz 215390fccb52SAndrzej Pietrasiewicz switch (reqtype & USB_RECIP_MASK) { 215490fccb52SAndrzej Pietrasiewicz case USB_RECIP_INTERFACE: 215590fccb52SAndrzej Pietrasiewicz break; /* Not supported */ 215690fccb52SAndrzej Pietrasiewicz 215790fccb52SAndrzej Pietrasiewicz case USB_RECIP_DEVICE: 2158d60d9392SPeter Chen ep0buff = udc->gadget.is_selfpowered; 215990fccb52SAndrzej Pietrasiewicz if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP)) 216090fccb52SAndrzej Pietrasiewicz ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP); 216190fccb52SAndrzej Pietrasiewicz break; 216290fccb52SAndrzej Pietrasiewicz 216390fccb52SAndrzej Pietrasiewicz case USB_RECIP_ENDPOINT: 216490fccb52SAndrzej Pietrasiewicz tmp = wIndex & USB_ENDPOINT_NUMBER_MASK; 216590fccb52SAndrzej Pietrasiewicz ep = &udc->ep[tmp]; 216690fccb52SAndrzej Pietrasiewicz if ((tmp == 0) || (tmp >= NUM_ENDPOINTS)) 216790fccb52SAndrzej Pietrasiewicz return -EOPNOTSUPP; 216890fccb52SAndrzej Pietrasiewicz 216990fccb52SAndrzej Pietrasiewicz if (wIndex & USB_DIR_IN) { 217090fccb52SAndrzej Pietrasiewicz if (!ep->is_in) 217190fccb52SAndrzej Pietrasiewicz return -EOPNOTSUPP; /* Something's wrong */ 217290fccb52SAndrzej Pietrasiewicz } else if (ep->is_in) 217390fccb52SAndrzej Pietrasiewicz return -EOPNOTSUPP; /* Not an IN endpoint */ 217490fccb52SAndrzej Pietrasiewicz 217590fccb52SAndrzej Pietrasiewicz /* Get status of the endpoint */ 217690fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_w(udc, CMD_SEL_EP(ep->hwep_num)); 217790fccb52SAndrzej Pietrasiewicz tmp = udc_protocol_cmd_r(udc, DAT_SEL_EP(ep->hwep_num)); 217890fccb52SAndrzej Pietrasiewicz 217990fccb52SAndrzej Pietrasiewicz if (tmp & EP_SEL_ST) 218090fccb52SAndrzej Pietrasiewicz ep0buff = (1 << USB_ENDPOINT_HALT); 218190fccb52SAndrzej Pietrasiewicz else 218290fccb52SAndrzej Pietrasiewicz ep0buff = 0; 218390fccb52SAndrzej Pietrasiewicz break; 218490fccb52SAndrzej Pietrasiewicz 218590fccb52SAndrzej Pietrasiewicz default: 218690fccb52SAndrzej Pietrasiewicz break; 218790fccb52SAndrzej Pietrasiewicz } 218890fccb52SAndrzej Pietrasiewicz 218990fccb52SAndrzej Pietrasiewicz /* Return data */ 219090fccb52SAndrzej Pietrasiewicz udc_write_hwep(udc, EP_IN, &ep0buff, 2); 219190fccb52SAndrzej Pietrasiewicz 219290fccb52SAndrzej Pietrasiewicz return 0; 219390fccb52SAndrzej Pietrasiewicz } 219490fccb52SAndrzej Pietrasiewicz 219590fccb52SAndrzej Pietrasiewicz static void udc_handle_ep0_setup(struct lpc32xx_udc *udc) 219690fccb52SAndrzej Pietrasiewicz { 219790fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep, *ep0 = &udc->ep[0]; 219890fccb52SAndrzej Pietrasiewicz struct usb_ctrlrequest ctrlpkt; 219990fccb52SAndrzej Pietrasiewicz int i, bytes; 220090fccb52SAndrzej Pietrasiewicz u16 wIndex, wValue, wLength, reqtype, req, tmp; 220190fccb52SAndrzej Pietrasiewicz 220290fccb52SAndrzej Pietrasiewicz /* Nuke previous transfers */ 220390fccb52SAndrzej Pietrasiewicz nuke(ep0, -EPROTO); 220490fccb52SAndrzej Pietrasiewicz 220590fccb52SAndrzej Pietrasiewicz /* Get setup packet */ 220690fccb52SAndrzej Pietrasiewicz bytes = udc_read_hwep(udc, EP_OUT, (u32 *) &ctrlpkt, 8); 220790fccb52SAndrzej Pietrasiewicz if (bytes != 8) { 220890fccb52SAndrzej Pietrasiewicz ep_warn(ep0, "Incorrectly sized setup packet (s/b 8, is %d)!\n", 220990fccb52SAndrzej Pietrasiewicz bytes); 221090fccb52SAndrzej Pietrasiewicz return; 221190fccb52SAndrzej Pietrasiewicz } 221290fccb52SAndrzej Pietrasiewicz 221390fccb52SAndrzej Pietrasiewicz /* Native endianness */ 221490fccb52SAndrzej Pietrasiewicz wIndex = le16_to_cpu(ctrlpkt.wIndex); 221590fccb52SAndrzej Pietrasiewicz wValue = le16_to_cpu(ctrlpkt.wValue); 221690fccb52SAndrzej Pietrasiewicz wLength = le16_to_cpu(ctrlpkt.wLength); 221790fccb52SAndrzej Pietrasiewicz reqtype = le16_to_cpu(ctrlpkt.bRequestType); 221890fccb52SAndrzej Pietrasiewicz 221990fccb52SAndrzej Pietrasiewicz /* Set direction of EP0 */ 222090fccb52SAndrzej Pietrasiewicz if (likely(reqtype & USB_DIR_IN)) 222190fccb52SAndrzej Pietrasiewicz ep0->is_in = 1; 222290fccb52SAndrzej Pietrasiewicz else 222390fccb52SAndrzej Pietrasiewicz ep0->is_in = 0; 222490fccb52SAndrzej Pietrasiewicz 222590fccb52SAndrzej Pietrasiewicz /* Handle SETUP packet */ 222690fccb52SAndrzej Pietrasiewicz req = le16_to_cpu(ctrlpkt.bRequest); 222790fccb52SAndrzej Pietrasiewicz switch (req) { 222890fccb52SAndrzej Pietrasiewicz case USB_REQ_CLEAR_FEATURE: 222990fccb52SAndrzej Pietrasiewicz case USB_REQ_SET_FEATURE: 223090fccb52SAndrzej Pietrasiewicz switch (reqtype) { 223190fccb52SAndrzej Pietrasiewicz case (USB_TYPE_STANDARD | USB_RECIP_DEVICE): 223290fccb52SAndrzej Pietrasiewicz if (wValue != USB_DEVICE_REMOTE_WAKEUP) 223390fccb52SAndrzej Pietrasiewicz goto stall; /* Nothing else handled */ 223490fccb52SAndrzej Pietrasiewicz 223590fccb52SAndrzej Pietrasiewicz /* Tell board about event */ 223690fccb52SAndrzej Pietrasiewicz if (req == USB_REQ_CLEAR_FEATURE) 223790fccb52SAndrzej Pietrasiewicz udc->dev_status &= 223890fccb52SAndrzej Pietrasiewicz ~(1 << USB_DEVICE_REMOTE_WAKEUP); 223990fccb52SAndrzej Pietrasiewicz else 224090fccb52SAndrzej Pietrasiewicz udc->dev_status |= 224190fccb52SAndrzej Pietrasiewicz (1 << USB_DEVICE_REMOTE_WAKEUP); 224290fccb52SAndrzej Pietrasiewicz uda_remwkp_cgh(udc); 224390fccb52SAndrzej Pietrasiewicz goto zlp_send; 224490fccb52SAndrzej Pietrasiewicz 224590fccb52SAndrzej Pietrasiewicz case (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT): 224690fccb52SAndrzej Pietrasiewicz tmp = wIndex & USB_ENDPOINT_NUMBER_MASK; 224790fccb52SAndrzej Pietrasiewicz if ((wValue != USB_ENDPOINT_HALT) || 224890fccb52SAndrzej Pietrasiewicz (tmp >= NUM_ENDPOINTS)) 224990fccb52SAndrzej Pietrasiewicz break; 225090fccb52SAndrzej Pietrasiewicz 225190fccb52SAndrzej Pietrasiewicz /* Find hardware endpoint from logical endpoint */ 225290fccb52SAndrzej Pietrasiewicz ep = &udc->ep[tmp]; 225390fccb52SAndrzej Pietrasiewicz tmp = ep->hwep_num; 225490fccb52SAndrzej Pietrasiewicz if (tmp == 0) 225590fccb52SAndrzej Pietrasiewicz break; 225690fccb52SAndrzej Pietrasiewicz 225790fccb52SAndrzej Pietrasiewicz if (req == USB_REQ_SET_FEATURE) 225890fccb52SAndrzej Pietrasiewicz udc_stall_hwep(udc, tmp); 225990fccb52SAndrzej Pietrasiewicz else if (!ep->wedge) 226090fccb52SAndrzej Pietrasiewicz udc_clrstall_hwep(udc, tmp); 226190fccb52SAndrzej Pietrasiewicz 226290fccb52SAndrzej Pietrasiewicz goto zlp_send; 226390fccb52SAndrzej Pietrasiewicz 226490fccb52SAndrzej Pietrasiewicz default: 226590fccb52SAndrzej Pietrasiewicz break; 226690fccb52SAndrzej Pietrasiewicz } 226790fccb52SAndrzej Pietrasiewicz 226890fccb52SAndrzej Pietrasiewicz 226990fccb52SAndrzej Pietrasiewicz case USB_REQ_SET_ADDRESS: 227090fccb52SAndrzej Pietrasiewicz if (reqtype == (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) { 227190fccb52SAndrzej Pietrasiewicz udc_set_address(udc, wValue); 227290fccb52SAndrzej Pietrasiewicz goto zlp_send; 227390fccb52SAndrzej Pietrasiewicz } 227490fccb52SAndrzej Pietrasiewicz break; 227590fccb52SAndrzej Pietrasiewicz 227690fccb52SAndrzej Pietrasiewicz case USB_REQ_GET_STATUS: 227790fccb52SAndrzej Pietrasiewicz udc_get_status(udc, reqtype, wIndex); 227890fccb52SAndrzej Pietrasiewicz return; 227990fccb52SAndrzej Pietrasiewicz 228090fccb52SAndrzej Pietrasiewicz default: 228190fccb52SAndrzej Pietrasiewicz break; /* Let GadgetFS handle the descriptor instead */ 228290fccb52SAndrzej Pietrasiewicz } 228390fccb52SAndrzej Pietrasiewicz 228490fccb52SAndrzej Pietrasiewicz if (likely(udc->driver)) { 228590fccb52SAndrzej Pietrasiewicz /* device-2-host (IN) or no data setup command, process 228690fccb52SAndrzej Pietrasiewicz * immediately */ 228790fccb52SAndrzej Pietrasiewicz spin_unlock(&udc->lock); 228890fccb52SAndrzej Pietrasiewicz i = udc->driver->setup(&udc->gadget, &ctrlpkt); 228990fccb52SAndrzej Pietrasiewicz 229090fccb52SAndrzej Pietrasiewicz spin_lock(&udc->lock); 229190fccb52SAndrzej Pietrasiewicz if (req == USB_REQ_SET_CONFIGURATION) { 229290fccb52SAndrzej Pietrasiewicz /* Configuration is set after endpoints are realized */ 229390fccb52SAndrzej Pietrasiewicz if (wValue) { 229490fccb52SAndrzej Pietrasiewicz /* Set configuration */ 229590fccb52SAndrzej Pietrasiewicz udc_set_device_configured(udc); 229690fccb52SAndrzej Pietrasiewicz 229790fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_data_w(udc, CMD_SET_MODE, 229890fccb52SAndrzej Pietrasiewicz DAT_WR_BYTE(AP_CLK | 229990fccb52SAndrzej Pietrasiewicz INAK_BI | INAK_II)); 230090fccb52SAndrzej Pietrasiewicz } else { 230190fccb52SAndrzej Pietrasiewicz /* Clear configuration */ 230290fccb52SAndrzej Pietrasiewicz udc_set_device_unconfigured(udc); 230390fccb52SAndrzej Pietrasiewicz 230490fccb52SAndrzej Pietrasiewicz /* Disable NAK interrupts */ 230590fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_data_w(udc, CMD_SET_MODE, 230690fccb52SAndrzej Pietrasiewicz DAT_WR_BYTE(AP_CLK)); 230790fccb52SAndrzej Pietrasiewicz } 230890fccb52SAndrzej Pietrasiewicz } 230990fccb52SAndrzej Pietrasiewicz 231090fccb52SAndrzej Pietrasiewicz if (i < 0) { 231190fccb52SAndrzej Pietrasiewicz /* setup processing failed, force stall */ 231290fccb52SAndrzej Pietrasiewicz dev_dbg(udc->dev, 231390fccb52SAndrzej Pietrasiewicz "req %02x.%02x protocol STALL; stat %d\n", 231490fccb52SAndrzej Pietrasiewicz reqtype, req, i); 231590fccb52SAndrzej Pietrasiewicz udc->ep0state = WAIT_FOR_SETUP; 231690fccb52SAndrzej Pietrasiewicz goto stall; 231790fccb52SAndrzej Pietrasiewicz } 231890fccb52SAndrzej Pietrasiewicz } 231990fccb52SAndrzej Pietrasiewicz 232090fccb52SAndrzej Pietrasiewicz if (!ep0->is_in) 232190fccb52SAndrzej Pietrasiewicz udc_ep0_send_zlp(udc); /* ZLP IN packet on data phase */ 232290fccb52SAndrzej Pietrasiewicz 232390fccb52SAndrzej Pietrasiewicz return; 232490fccb52SAndrzej Pietrasiewicz 232590fccb52SAndrzej Pietrasiewicz stall: 232690fccb52SAndrzej Pietrasiewicz udc_stall_hwep(udc, EP_IN); 232790fccb52SAndrzej Pietrasiewicz return; 232890fccb52SAndrzej Pietrasiewicz 232990fccb52SAndrzej Pietrasiewicz zlp_send: 233090fccb52SAndrzej Pietrasiewicz udc_ep0_send_zlp(udc); 233190fccb52SAndrzej Pietrasiewicz return; 233290fccb52SAndrzej Pietrasiewicz } 233390fccb52SAndrzej Pietrasiewicz 233490fccb52SAndrzej Pietrasiewicz /* IN endpoint 0 transfer */ 233590fccb52SAndrzej Pietrasiewicz static void udc_handle_ep0_in(struct lpc32xx_udc *udc) 233690fccb52SAndrzej Pietrasiewicz { 233790fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep0 = &udc->ep[0]; 233890fccb52SAndrzej Pietrasiewicz u32 epstatus; 233990fccb52SAndrzej Pietrasiewicz 234090fccb52SAndrzej Pietrasiewicz /* Clear EP interrupt */ 234190fccb52SAndrzej Pietrasiewicz epstatus = udc_clearep_getsts(udc, EP_IN); 234290fccb52SAndrzej Pietrasiewicz 234390fccb52SAndrzej Pietrasiewicz #ifdef CONFIG_USB_GADGET_DEBUG_FILES 234490fccb52SAndrzej Pietrasiewicz ep0->totalints++; 234590fccb52SAndrzej Pietrasiewicz #endif 234690fccb52SAndrzej Pietrasiewicz 234790fccb52SAndrzej Pietrasiewicz /* Stalled? Clear stall and reset buffers */ 234890fccb52SAndrzej Pietrasiewicz if (epstatus & EP_SEL_ST) { 234990fccb52SAndrzej Pietrasiewicz udc_clrstall_hwep(udc, EP_IN); 235090fccb52SAndrzej Pietrasiewicz nuke(ep0, -ECONNABORTED); 235190fccb52SAndrzej Pietrasiewicz udc->ep0state = WAIT_FOR_SETUP; 235290fccb52SAndrzej Pietrasiewicz return; 235390fccb52SAndrzej Pietrasiewicz } 235490fccb52SAndrzej Pietrasiewicz 235590fccb52SAndrzej Pietrasiewicz /* Is a buffer available? */ 235690fccb52SAndrzej Pietrasiewicz if (!(epstatus & EP_SEL_F)) { 235790fccb52SAndrzej Pietrasiewicz /* Handle based on current state */ 235890fccb52SAndrzej Pietrasiewicz if (udc->ep0state == DATA_IN) 235990fccb52SAndrzej Pietrasiewicz udc_ep0_in_req(udc); 236090fccb52SAndrzej Pietrasiewicz else { 236190fccb52SAndrzej Pietrasiewicz /* Unknown state for EP0 oe end of DATA IN phase */ 236290fccb52SAndrzej Pietrasiewicz nuke(ep0, -ECONNABORTED); 236390fccb52SAndrzej Pietrasiewicz udc->ep0state = WAIT_FOR_SETUP; 236490fccb52SAndrzej Pietrasiewicz } 236590fccb52SAndrzej Pietrasiewicz } 236690fccb52SAndrzej Pietrasiewicz } 236790fccb52SAndrzej Pietrasiewicz 236890fccb52SAndrzej Pietrasiewicz /* OUT endpoint 0 transfer */ 236990fccb52SAndrzej Pietrasiewicz static void udc_handle_ep0_out(struct lpc32xx_udc *udc) 237090fccb52SAndrzej Pietrasiewicz { 237190fccb52SAndrzej Pietrasiewicz struct lpc32xx_ep *ep0 = &udc->ep[0]; 237290fccb52SAndrzej Pietrasiewicz u32 epstatus; 237390fccb52SAndrzej Pietrasiewicz 237490fccb52SAndrzej Pietrasiewicz /* Clear EP interrupt */ 237590fccb52SAndrzej Pietrasiewicz epstatus = udc_clearep_getsts(udc, EP_OUT); 237690fccb52SAndrzej Pietrasiewicz 237790fccb52SAndrzej Pietrasiewicz 237890fccb52SAndrzej Pietrasiewicz #ifdef CONFIG_USB_GADGET_DEBUG_FILES 237990fccb52SAndrzej Pietrasiewicz ep0->totalints++; 238090fccb52SAndrzej Pietrasiewicz #endif 238190fccb52SAndrzej Pietrasiewicz 238290fccb52SAndrzej Pietrasiewicz /* Stalled? */ 238390fccb52SAndrzej Pietrasiewicz if (epstatus & EP_SEL_ST) { 238490fccb52SAndrzej Pietrasiewicz udc_clrstall_hwep(udc, EP_OUT); 238590fccb52SAndrzej Pietrasiewicz nuke(ep0, -ECONNABORTED); 238690fccb52SAndrzej Pietrasiewicz udc->ep0state = WAIT_FOR_SETUP; 238790fccb52SAndrzej Pietrasiewicz return; 238890fccb52SAndrzej Pietrasiewicz } 238990fccb52SAndrzej Pietrasiewicz 239090fccb52SAndrzej Pietrasiewicz /* A NAK may occur if a packet couldn't be received yet */ 239190fccb52SAndrzej Pietrasiewicz if (epstatus & EP_SEL_EPN) 239290fccb52SAndrzej Pietrasiewicz return; 239390fccb52SAndrzej Pietrasiewicz /* Setup packet incoming? */ 239490fccb52SAndrzej Pietrasiewicz if (epstatus & EP_SEL_STP) { 239590fccb52SAndrzej Pietrasiewicz nuke(ep0, 0); 239690fccb52SAndrzej Pietrasiewicz udc->ep0state = WAIT_FOR_SETUP; 239790fccb52SAndrzej Pietrasiewicz } 239890fccb52SAndrzej Pietrasiewicz 239990fccb52SAndrzej Pietrasiewicz /* Data available? */ 240090fccb52SAndrzej Pietrasiewicz if (epstatus & EP_SEL_F) 240190fccb52SAndrzej Pietrasiewicz /* Handle based on current state */ 240290fccb52SAndrzej Pietrasiewicz switch (udc->ep0state) { 240390fccb52SAndrzej Pietrasiewicz case WAIT_FOR_SETUP: 240490fccb52SAndrzej Pietrasiewicz udc_handle_ep0_setup(udc); 240590fccb52SAndrzej Pietrasiewicz break; 240690fccb52SAndrzej Pietrasiewicz 240790fccb52SAndrzej Pietrasiewicz case DATA_OUT: 240890fccb52SAndrzej Pietrasiewicz udc_ep0_out_req(udc); 240990fccb52SAndrzej Pietrasiewicz break; 241090fccb52SAndrzej Pietrasiewicz 241190fccb52SAndrzej Pietrasiewicz default: 241290fccb52SAndrzej Pietrasiewicz /* Unknown state for EP0 */ 241390fccb52SAndrzej Pietrasiewicz nuke(ep0, -ECONNABORTED); 241490fccb52SAndrzej Pietrasiewicz udc->ep0state = WAIT_FOR_SETUP; 241590fccb52SAndrzej Pietrasiewicz } 241690fccb52SAndrzej Pietrasiewicz } 241790fccb52SAndrzej Pietrasiewicz 241890fccb52SAndrzej Pietrasiewicz /* Must be called without lock */ 241990fccb52SAndrzej Pietrasiewicz static int lpc32xx_get_frame(struct usb_gadget *gadget) 242090fccb52SAndrzej Pietrasiewicz { 242190fccb52SAndrzej Pietrasiewicz int frame; 242290fccb52SAndrzej Pietrasiewicz unsigned long flags; 242390fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = to_udc(gadget); 242490fccb52SAndrzej Pietrasiewicz 242590fccb52SAndrzej Pietrasiewicz if (!udc->clocked) 242690fccb52SAndrzej Pietrasiewicz return -EINVAL; 242790fccb52SAndrzej Pietrasiewicz 242890fccb52SAndrzej Pietrasiewicz spin_lock_irqsave(&udc->lock, flags); 242990fccb52SAndrzej Pietrasiewicz 243090fccb52SAndrzej Pietrasiewicz frame = (int) udc_get_current_frame(udc); 243190fccb52SAndrzej Pietrasiewicz 243290fccb52SAndrzej Pietrasiewicz spin_unlock_irqrestore(&udc->lock, flags); 243390fccb52SAndrzej Pietrasiewicz 243490fccb52SAndrzej Pietrasiewicz return frame; 243590fccb52SAndrzej Pietrasiewicz } 243690fccb52SAndrzej Pietrasiewicz 243790fccb52SAndrzej Pietrasiewicz static int lpc32xx_wakeup(struct usb_gadget *gadget) 243890fccb52SAndrzej Pietrasiewicz { 243990fccb52SAndrzej Pietrasiewicz return -ENOTSUPP; 244090fccb52SAndrzej Pietrasiewicz } 244190fccb52SAndrzej Pietrasiewicz 244290fccb52SAndrzej Pietrasiewicz static int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on) 244390fccb52SAndrzej Pietrasiewicz { 2444d60d9392SPeter Chen gadget->is_selfpowered = (is_on != 0); 244590fccb52SAndrzej Pietrasiewicz 244690fccb52SAndrzej Pietrasiewicz return 0; 244790fccb52SAndrzej Pietrasiewicz } 244890fccb52SAndrzej Pietrasiewicz 244990fccb52SAndrzej Pietrasiewicz /* 245090fccb52SAndrzej Pietrasiewicz * vbus is here! turn everything on that's ready 245190fccb52SAndrzej Pietrasiewicz * Must be called without lock 245290fccb52SAndrzej Pietrasiewicz */ 245390fccb52SAndrzej Pietrasiewicz static int lpc32xx_vbus_session(struct usb_gadget *gadget, int is_active) 245490fccb52SAndrzej Pietrasiewicz { 245590fccb52SAndrzej Pietrasiewicz unsigned long flags; 245690fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = to_udc(gadget); 245790fccb52SAndrzej Pietrasiewicz 245890fccb52SAndrzej Pietrasiewicz spin_lock_irqsave(&udc->lock, flags); 245990fccb52SAndrzej Pietrasiewicz 246090fccb52SAndrzej Pietrasiewicz /* Doesn't need lock */ 246190fccb52SAndrzej Pietrasiewicz if (udc->driver) { 246290fccb52SAndrzej Pietrasiewicz udc_clk_set(udc, 1); 246390fccb52SAndrzej Pietrasiewicz udc_enable(udc); 246490fccb52SAndrzej Pietrasiewicz pullup(udc, is_active); 246590fccb52SAndrzej Pietrasiewicz } else { 246690fccb52SAndrzej Pietrasiewicz stop_activity(udc); 246790fccb52SAndrzej Pietrasiewicz pullup(udc, 0); 246890fccb52SAndrzej Pietrasiewicz 246990fccb52SAndrzej Pietrasiewicz spin_unlock_irqrestore(&udc->lock, flags); 247090fccb52SAndrzej Pietrasiewicz /* 247190fccb52SAndrzej Pietrasiewicz * Wait for all the endpoints to disable, 247290fccb52SAndrzej Pietrasiewicz * before disabling clocks. Don't wait if 247390fccb52SAndrzej Pietrasiewicz * endpoints are not enabled. 247490fccb52SAndrzej Pietrasiewicz */ 247590fccb52SAndrzej Pietrasiewicz if (atomic_read(&udc->enabled_ep_cnt)) 247690fccb52SAndrzej Pietrasiewicz wait_event_interruptible(udc->ep_disable_wait_queue, 247790fccb52SAndrzej Pietrasiewicz (atomic_read(&udc->enabled_ep_cnt) == 0)); 247890fccb52SAndrzej Pietrasiewicz 247990fccb52SAndrzej Pietrasiewicz spin_lock_irqsave(&udc->lock, flags); 248090fccb52SAndrzej Pietrasiewicz 248190fccb52SAndrzej Pietrasiewicz udc_clk_set(udc, 0); 248290fccb52SAndrzej Pietrasiewicz } 248390fccb52SAndrzej Pietrasiewicz 248490fccb52SAndrzej Pietrasiewicz spin_unlock_irqrestore(&udc->lock, flags); 248590fccb52SAndrzej Pietrasiewicz 248690fccb52SAndrzej Pietrasiewicz return 0; 248790fccb52SAndrzej Pietrasiewicz } 248890fccb52SAndrzej Pietrasiewicz 248990fccb52SAndrzej Pietrasiewicz /* Can be called with or without lock */ 249090fccb52SAndrzej Pietrasiewicz static int lpc32xx_pullup(struct usb_gadget *gadget, int is_on) 249190fccb52SAndrzej Pietrasiewicz { 249290fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = to_udc(gadget); 249390fccb52SAndrzej Pietrasiewicz 249490fccb52SAndrzej Pietrasiewicz /* Doesn't need lock */ 249590fccb52SAndrzej Pietrasiewicz pullup(udc, is_on); 249690fccb52SAndrzej Pietrasiewicz 249790fccb52SAndrzej Pietrasiewicz return 0; 249890fccb52SAndrzej Pietrasiewicz } 249990fccb52SAndrzej Pietrasiewicz 250090fccb52SAndrzej Pietrasiewicz static int lpc32xx_start(struct usb_gadget *, struct usb_gadget_driver *); 250122835b80SFelipe Balbi static int lpc32xx_stop(struct usb_gadget *); 250290fccb52SAndrzej Pietrasiewicz 250390fccb52SAndrzej Pietrasiewicz static const struct usb_gadget_ops lpc32xx_udc_ops = { 250490fccb52SAndrzej Pietrasiewicz .get_frame = lpc32xx_get_frame, 250590fccb52SAndrzej Pietrasiewicz .wakeup = lpc32xx_wakeup, 250690fccb52SAndrzej Pietrasiewicz .set_selfpowered = lpc32xx_set_selfpowered, 250790fccb52SAndrzej Pietrasiewicz .vbus_session = lpc32xx_vbus_session, 250890fccb52SAndrzej Pietrasiewicz .pullup = lpc32xx_pullup, 250990fccb52SAndrzej Pietrasiewicz .udc_start = lpc32xx_start, 251090fccb52SAndrzej Pietrasiewicz .udc_stop = lpc32xx_stop, 251190fccb52SAndrzej Pietrasiewicz }; 251290fccb52SAndrzej Pietrasiewicz 251390fccb52SAndrzej Pietrasiewicz static void nop_release(struct device *dev) 251490fccb52SAndrzej Pietrasiewicz { 251590fccb52SAndrzej Pietrasiewicz /* nothing to free */ 251690fccb52SAndrzej Pietrasiewicz } 251790fccb52SAndrzej Pietrasiewicz 251890fccb52SAndrzej Pietrasiewicz static const struct lpc32xx_udc controller_template = { 251990fccb52SAndrzej Pietrasiewicz .gadget = { 252090fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_udc_ops, 252190fccb52SAndrzej Pietrasiewicz .name = driver_name, 252290fccb52SAndrzej Pietrasiewicz .dev = { 252390fccb52SAndrzej Pietrasiewicz .init_name = "gadget", 252490fccb52SAndrzej Pietrasiewicz .release = nop_release, 252590fccb52SAndrzej Pietrasiewicz } 252690fccb52SAndrzej Pietrasiewicz }, 252790fccb52SAndrzej Pietrasiewicz .ep[0] = { 252890fccb52SAndrzej Pietrasiewicz .ep = { 252990fccb52SAndrzej Pietrasiewicz .name = "ep0", 253090fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 25314d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, 25324d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 253390fccb52SAndrzej Pietrasiewicz }, 253490fccb52SAndrzej Pietrasiewicz .maxpacket = 64, 253590fccb52SAndrzej Pietrasiewicz .hwep_num_base = 0, 253690fccb52SAndrzej Pietrasiewicz .hwep_num = 0, /* Can be 0 or 1, has special handling */ 253790fccb52SAndrzej Pietrasiewicz .lep = 0, 253890fccb52SAndrzej Pietrasiewicz .eptype = EP_CTL_TYPE, 253990fccb52SAndrzej Pietrasiewicz }, 254090fccb52SAndrzej Pietrasiewicz .ep[1] = { 254190fccb52SAndrzej Pietrasiewicz .ep = { 254290fccb52SAndrzej Pietrasiewicz .name = "ep1-int", 254390fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 25444d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, 25454d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 254690fccb52SAndrzej Pietrasiewicz }, 254790fccb52SAndrzej Pietrasiewicz .maxpacket = 64, 254890fccb52SAndrzej Pietrasiewicz .hwep_num_base = 2, 254990fccb52SAndrzej Pietrasiewicz .hwep_num = 0, /* 2 or 3, will be set later */ 255090fccb52SAndrzej Pietrasiewicz .lep = 1, 255190fccb52SAndrzej Pietrasiewicz .eptype = EP_INT_TYPE, 255290fccb52SAndrzej Pietrasiewicz }, 255390fccb52SAndrzej Pietrasiewicz .ep[2] = { 255490fccb52SAndrzej Pietrasiewicz .ep = { 255590fccb52SAndrzej Pietrasiewicz .name = "ep2-bulk", 255690fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 25574d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 25584d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 255990fccb52SAndrzej Pietrasiewicz }, 256090fccb52SAndrzej Pietrasiewicz .maxpacket = 64, 256190fccb52SAndrzej Pietrasiewicz .hwep_num_base = 4, 256290fccb52SAndrzej Pietrasiewicz .hwep_num = 0, /* 4 or 5, will be set later */ 256390fccb52SAndrzej Pietrasiewicz .lep = 2, 256490fccb52SAndrzej Pietrasiewicz .eptype = EP_BLK_TYPE, 256590fccb52SAndrzej Pietrasiewicz }, 256690fccb52SAndrzej Pietrasiewicz .ep[3] = { 256790fccb52SAndrzej Pietrasiewicz .ep = { 256890fccb52SAndrzej Pietrasiewicz .name = "ep3-iso", 256990fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 25704d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 25714d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 257290fccb52SAndrzej Pietrasiewicz }, 257390fccb52SAndrzej Pietrasiewicz .maxpacket = 1023, 257490fccb52SAndrzej Pietrasiewicz .hwep_num_base = 6, 257590fccb52SAndrzej Pietrasiewicz .hwep_num = 0, /* 6 or 7, will be set later */ 257690fccb52SAndrzej Pietrasiewicz .lep = 3, 257790fccb52SAndrzej Pietrasiewicz .eptype = EP_ISO_TYPE, 257890fccb52SAndrzej Pietrasiewicz }, 257990fccb52SAndrzej Pietrasiewicz .ep[4] = { 258090fccb52SAndrzej Pietrasiewicz .ep = { 258190fccb52SAndrzej Pietrasiewicz .name = "ep4-int", 258290fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 25834d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, 25844d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 258590fccb52SAndrzej Pietrasiewicz }, 258690fccb52SAndrzej Pietrasiewicz .maxpacket = 64, 258790fccb52SAndrzej Pietrasiewicz .hwep_num_base = 8, 258890fccb52SAndrzej Pietrasiewicz .hwep_num = 0, /* 8 or 9, will be set later */ 258990fccb52SAndrzej Pietrasiewicz .lep = 4, 259090fccb52SAndrzej Pietrasiewicz .eptype = EP_INT_TYPE, 259190fccb52SAndrzej Pietrasiewicz }, 259290fccb52SAndrzej Pietrasiewicz .ep[5] = { 259390fccb52SAndrzej Pietrasiewicz .ep = { 259490fccb52SAndrzej Pietrasiewicz .name = "ep5-bulk", 259590fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 25964d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 25974d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 259890fccb52SAndrzej Pietrasiewicz }, 259990fccb52SAndrzej Pietrasiewicz .maxpacket = 64, 260090fccb52SAndrzej Pietrasiewicz .hwep_num_base = 10, 260190fccb52SAndrzej Pietrasiewicz .hwep_num = 0, /* 10 or 11, will be set later */ 260290fccb52SAndrzej Pietrasiewicz .lep = 5, 260390fccb52SAndrzej Pietrasiewicz .eptype = EP_BLK_TYPE, 260490fccb52SAndrzej Pietrasiewicz }, 260590fccb52SAndrzej Pietrasiewicz .ep[6] = { 260690fccb52SAndrzej Pietrasiewicz .ep = { 260790fccb52SAndrzej Pietrasiewicz .name = "ep6-iso", 260890fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 26094d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 26104d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 261190fccb52SAndrzej Pietrasiewicz }, 261290fccb52SAndrzej Pietrasiewicz .maxpacket = 1023, 261390fccb52SAndrzej Pietrasiewicz .hwep_num_base = 12, 261490fccb52SAndrzej Pietrasiewicz .hwep_num = 0, /* 12 or 13, will be set later */ 261590fccb52SAndrzej Pietrasiewicz .lep = 6, 261690fccb52SAndrzej Pietrasiewicz .eptype = EP_ISO_TYPE, 261790fccb52SAndrzej Pietrasiewicz }, 261890fccb52SAndrzej Pietrasiewicz .ep[7] = { 261990fccb52SAndrzej Pietrasiewicz .ep = { 262090fccb52SAndrzej Pietrasiewicz .name = "ep7-int", 262190fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 26224d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, 26234d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 262490fccb52SAndrzej Pietrasiewicz }, 262590fccb52SAndrzej Pietrasiewicz .maxpacket = 64, 262690fccb52SAndrzej Pietrasiewicz .hwep_num_base = 14, 262790fccb52SAndrzej Pietrasiewicz .hwep_num = 0, 262890fccb52SAndrzej Pietrasiewicz .lep = 7, 262990fccb52SAndrzej Pietrasiewicz .eptype = EP_INT_TYPE, 263090fccb52SAndrzej Pietrasiewicz }, 263190fccb52SAndrzej Pietrasiewicz .ep[8] = { 263290fccb52SAndrzej Pietrasiewicz .ep = { 263390fccb52SAndrzej Pietrasiewicz .name = "ep8-bulk", 263490fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 26354d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 26364d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 263790fccb52SAndrzej Pietrasiewicz }, 263890fccb52SAndrzej Pietrasiewicz .maxpacket = 64, 263990fccb52SAndrzej Pietrasiewicz .hwep_num_base = 16, 264090fccb52SAndrzej Pietrasiewicz .hwep_num = 0, 264190fccb52SAndrzej Pietrasiewicz .lep = 8, 264290fccb52SAndrzej Pietrasiewicz .eptype = EP_BLK_TYPE, 264390fccb52SAndrzej Pietrasiewicz }, 264490fccb52SAndrzej Pietrasiewicz .ep[9] = { 264590fccb52SAndrzej Pietrasiewicz .ep = { 264690fccb52SAndrzej Pietrasiewicz .name = "ep9-iso", 264790fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 26484d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 26494d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 265090fccb52SAndrzej Pietrasiewicz }, 265190fccb52SAndrzej Pietrasiewicz .maxpacket = 1023, 265290fccb52SAndrzej Pietrasiewicz .hwep_num_base = 18, 265390fccb52SAndrzej Pietrasiewicz .hwep_num = 0, 265490fccb52SAndrzej Pietrasiewicz .lep = 9, 265590fccb52SAndrzej Pietrasiewicz .eptype = EP_ISO_TYPE, 265690fccb52SAndrzej Pietrasiewicz }, 265790fccb52SAndrzej Pietrasiewicz .ep[10] = { 265890fccb52SAndrzej Pietrasiewicz .ep = { 265990fccb52SAndrzej Pietrasiewicz .name = "ep10-int", 266090fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 26614d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, 26624d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 266390fccb52SAndrzej Pietrasiewicz }, 266490fccb52SAndrzej Pietrasiewicz .maxpacket = 64, 266590fccb52SAndrzej Pietrasiewicz .hwep_num_base = 20, 266690fccb52SAndrzej Pietrasiewicz .hwep_num = 0, 266790fccb52SAndrzej Pietrasiewicz .lep = 10, 266890fccb52SAndrzej Pietrasiewicz .eptype = EP_INT_TYPE, 266990fccb52SAndrzej Pietrasiewicz }, 267090fccb52SAndrzej Pietrasiewicz .ep[11] = { 267190fccb52SAndrzej Pietrasiewicz .ep = { 267290fccb52SAndrzej Pietrasiewicz .name = "ep11-bulk", 267390fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 26744d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 26754d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 267690fccb52SAndrzej Pietrasiewicz }, 267790fccb52SAndrzej Pietrasiewicz .maxpacket = 64, 267890fccb52SAndrzej Pietrasiewicz .hwep_num_base = 22, 267990fccb52SAndrzej Pietrasiewicz .hwep_num = 0, 268090fccb52SAndrzej Pietrasiewicz .lep = 11, 268190fccb52SAndrzej Pietrasiewicz .eptype = EP_BLK_TYPE, 268290fccb52SAndrzej Pietrasiewicz }, 268390fccb52SAndrzej Pietrasiewicz .ep[12] = { 268490fccb52SAndrzej Pietrasiewicz .ep = { 268590fccb52SAndrzej Pietrasiewicz .name = "ep12-iso", 268690fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 26874d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 26884d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 268990fccb52SAndrzej Pietrasiewicz }, 269090fccb52SAndrzej Pietrasiewicz .maxpacket = 1023, 269190fccb52SAndrzej Pietrasiewicz .hwep_num_base = 24, 269290fccb52SAndrzej Pietrasiewicz .hwep_num = 0, 269390fccb52SAndrzej Pietrasiewicz .lep = 12, 269490fccb52SAndrzej Pietrasiewicz .eptype = EP_ISO_TYPE, 269590fccb52SAndrzej Pietrasiewicz }, 269690fccb52SAndrzej Pietrasiewicz .ep[13] = { 269790fccb52SAndrzej Pietrasiewicz .ep = { 269890fccb52SAndrzej Pietrasiewicz .name = "ep13-int", 269990fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 27004d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, 27014d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 270290fccb52SAndrzej Pietrasiewicz }, 270390fccb52SAndrzej Pietrasiewicz .maxpacket = 64, 270490fccb52SAndrzej Pietrasiewicz .hwep_num_base = 26, 270590fccb52SAndrzej Pietrasiewicz .hwep_num = 0, 270690fccb52SAndrzej Pietrasiewicz .lep = 13, 270790fccb52SAndrzej Pietrasiewicz .eptype = EP_INT_TYPE, 270890fccb52SAndrzej Pietrasiewicz }, 270990fccb52SAndrzej Pietrasiewicz .ep[14] = { 271090fccb52SAndrzej Pietrasiewicz .ep = { 271190fccb52SAndrzej Pietrasiewicz .name = "ep14-bulk", 271290fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 27134d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 27144d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 271590fccb52SAndrzej Pietrasiewicz }, 271690fccb52SAndrzej Pietrasiewicz .maxpacket = 64, 271790fccb52SAndrzej Pietrasiewicz .hwep_num_base = 28, 271890fccb52SAndrzej Pietrasiewicz .hwep_num = 0, 271990fccb52SAndrzej Pietrasiewicz .lep = 14, 272090fccb52SAndrzej Pietrasiewicz .eptype = EP_BLK_TYPE, 272190fccb52SAndrzej Pietrasiewicz }, 272290fccb52SAndrzej Pietrasiewicz .ep[15] = { 272390fccb52SAndrzej Pietrasiewicz .ep = { 272490fccb52SAndrzej Pietrasiewicz .name = "ep15-bulk", 272590fccb52SAndrzej Pietrasiewicz .ops = &lpc32xx_ep_ops, 27264d75c8bdSRobert Baldyga .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 27274d75c8bdSRobert Baldyga USB_EP_CAPS_DIR_ALL), 272890fccb52SAndrzej Pietrasiewicz }, 272990fccb52SAndrzej Pietrasiewicz .maxpacket = 1023, 273090fccb52SAndrzej Pietrasiewicz .hwep_num_base = 30, 273190fccb52SAndrzej Pietrasiewicz .hwep_num = 0, 273290fccb52SAndrzej Pietrasiewicz .lep = 15, 273390fccb52SAndrzej Pietrasiewicz .eptype = EP_BLK_TYPE, 273490fccb52SAndrzej Pietrasiewicz }, 273590fccb52SAndrzej Pietrasiewicz }; 273690fccb52SAndrzej Pietrasiewicz 273790fccb52SAndrzej Pietrasiewicz /* ISO and status interrupts */ 273890fccb52SAndrzej Pietrasiewicz static irqreturn_t lpc32xx_usb_lp_irq(int irq, void *_udc) 273990fccb52SAndrzej Pietrasiewicz { 274090fccb52SAndrzej Pietrasiewicz u32 tmp, devstat; 274190fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = _udc; 274290fccb52SAndrzej Pietrasiewicz 274390fccb52SAndrzej Pietrasiewicz spin_lock(&udc->lock); 274490fccb52SAndrzej Pietrasiewicz 274590fccb52SAndrzej Pietrasiewicz /* Read the device status register */ 274690fccb52SAndrzej Pietrasiewicz devstat = readl(USBD_DEVINTST(udc->udp_baseaddr)); 274790fccb52SAndrzej Pietrasiewicz 274890fccb52SAndrzej Pietrasiewicz devstat &= ~USBD_EP_FAST; 274990fccb52SAndrzej Pietrasiewicz writel(devstat, USBD_DEVINTCLR(udc->udp_baseaddr)); 275090fccb52SAndrzej Pietrasiewicz devstat = devstat & udc->enabled_devints; 275190fccb52SAndrzej Pietrasiewicz 275290fccb52SAndrzej Pietrasiewicz /* Device specific handling needed? */ 275390fccb52SAndrzej Pietrasiewicz if (devstat & USBD_DEV_STAT) 275490fccb52SAndrzej Pietrasiewicz udc_handle_dev(udc); 275590fccb52SAndrzej Pietrasiewicz 275690fccb52SAndrzej Pietrasiewicz /* Start of frame? (devstat & FRAME_INT): 275790fccb52SAndrzej Pietrasiewicz * The frame interrupt isn't really needed for ISO support, 275890fccb52SAndrzej Pietrasiewicz * as the driver will queue the necessary packets */ 275990fccb52SAndrzej Pietrasiewicz 276090fccb52SAndrzej Pietrasiewicz /* Error? */ 276190fccb52SAndrzej Pietrasiewicz if (devstat & ERR_INT) { 276290fccb52SAndrzej Pietrasiewicz /* All types of errors, from cable removal during transfer to 276390fccb52SAndrzej Pietrasiewicz * misc protocol and bit errors. These are mostly for just info, 276490fccb52SAndrzej Pietrasiewicz * as the USB hardware will work around these. If these errors 276590fccb52SAndrzej Pietrasiewicz * happen alot, something is wrong. */ 276690fccb52SAndrzej Pietrasiewicz udc_protocol_cmd_w(udc, CMD_RD_ERR_STAT); 276790fccb52SAndrzej Pietrasiewicz tmp = udc_protocol_cmd_r(udc, DAT_RD_ERR_STAT); 276890fccb52SAndrzej Pietrasiewicz dev_dbg(udc->dev, "Device error (0x%x)!\n", tmp); 276990fccb52SAndrzej Pietrasiewicz } 277090fccb52SAndrzej Pietrasiewicz 277190fccb52SAndrzej Pietrasiewicz spin_unlock(&udc->lock); 277290fccb52SAndrzej Pietrasiewicz 277390fccb52SAndrzej Pietrasiewicz return IRQ_HANDLED; 277490fccb52SAndrzej Pietrasiewicz } 277590fccb52SAndrzej Pietrasiewicz 277690fccb52SAndrzej Pietrasiewicz /* EP interrupts */ 277790fccb52SAndrzej Pietrasiewicz static irqreturn_t lpc32xx_usb_hp_irq(int irq, void *_udc) 277890fccb52SAndrzej Pietrasiewicz { 277990fccb52SAndrzej Pietrasiewicz u32 tmp; 278090fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = _udc; 278190fccb52SAndrzej Pietrasiewicz 278290fccb52SAndrzej Pietrasiewicz spin_lock(&udc->lock); 278390fccb52SAndrzej Pietrasiewicz 278490fccb52SAndrzej Pietrasiewicz /* Read the device status register */ 278590fccb52SAndrzej Pietrasiewicz writel(USBD_EP_FAST, USBD_DEVINTCLR(udc->udp_baseaddr)); 278690fccb52SAndrzej Pietrasiewicz 278790fccb52SAndrzej Pietrasiewicz /* Endpoints */ 278890fccb52SAndrzej Pietrasiewicz tmp = readl(USBD_EPINTST(udc->udp_baseaddr)); 278990fccb52SAndrzej Pietrasiewicz 279090fccb52SAndrzej Pietrasiewicz /* Special handling for EP0 */ 279190fccb52SAndrzej Pietrasiewicz if (tmp & (EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) { 279290fccb52SAndrzej Pietrasiewicz /* Handle EP0 IN */ 279390fccb52SAndrzej Pietrasiewicz if (tmp & (EP_MASK_SEL(0, EP_IN))) 279490fccb52SAndrzej Pietrasiewicz udc_handle_ep0_in(udc); 279590fccb52SAndrzej Pietrasiewicz 279690fccb52SAndrzej Pietrasiewicz /* Handle EP0 OUT */ 279790fccb52SAndrzej Pietrasiewicz if (tmp & (EP_MASK_SEL(0, EP_OUT))) 279890fccb52SAndrzej Pietrasiewicz udc_handle_ep0_out(udc); 279990fccb52SAndrzej Pietrasiewicz } 280090fccb52SAndrzej Pietrasiewicz 280190fccb52SAndrzej Pietrasiewicz /* All other EPs */ 280290fccb52SAndrzej Pietrasiewicz if (tmp & ~(EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) { 280390fccb52SAndrzej Pietrasiewicz int i; 280490fccb52SAndrzej Pietrasiewicz 280590fccb52SAndrzej Pietrasiewicz /* Handle other EP interrupts */ 280690fccb52SAndrzej Pietrasiewicz for (i = 1; i < NUM_ENDPOINTS; i++) { 280790fccb52SAndrzej Pietrasiewicz if (tmp & (1 << udc->ep[i].hwep_num)) 280890fccb52SAndrzej Pietrasiewicz udc_handle_eps(udc, &udc->ep[i]); 280990fccb52SAndrzej Pietrasiewicz } 281090fccb52SAndrzej Pietrasiewicz } 281190fccb52SAndrzej Pietrasiewicz 281290fccb52SAndrzej Pietrasiewicz spin_unlock(&udc->lock); 281390fccb52SAndrzej Pietrasiewicz 281490fccb52SAndrzej Pietrasiewicz return IRQ_HANDLED; 281590fccb52SAndrzej Pietrasiewicz } 281690fccb52SAndrzej Pietrasiewicz 281790fccb52SAndrzej Pietrasiewicz static irqreturn_t lpc32xx_usb_devdma_irq(int irq, void *_udc) 281890fccb52SAndrzej Pietrasiewicz { 281990fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = _udc; 282090fccb52SAndrzej Pietrasiewicz 282190fccb52SAndrzej Pietrasiewicz int i; 282290fccb52SAndrzej Pietrasiewicz u32 tmp; 282390fccb52SAndrzej Pietrasiewicz 282490fccb52SAndrzej Pietrasiewicz spin_lock(&udc->lock); 282590fccb52SAndrzej Pietrasiewicz 282690fccb52SAndrzej Pietrasiewicz /* Handle EP DMA EOT interrupts */ 282790fccb52SAndrzej Pietrasiewicz tmp = readl(USBD_EOTINTST(udc->udp_baseaddr)) | 282890fccb52SAndrzej Pietrasiewicz (readl(USBD_EPDMAST(udc->udp_baseaddr)) & 282990fccb52SAndrzej Pietrasiewicz readl(USBD_NDDRTINTST(udc->udp_baseaddr))) | 283090fccb52SAndrzej Pietrasiewicz readl(USBD_SYSERRTINTST(udc->udp_baseaddr)); 283190fccb52SAndrzej Pietrasiewicz for (i = 1; i < NUM_ENDPOINTS; i++) { 283290fccb52SAndrzej Pietrasiewicz if (tmp & (1 << udc->ep[i].hwep_num)) 283390fccb52SAndrzej Pietrasiewicz udc_handle_dma_ep(udc, &udc->ep[i]); 283490fccb52SAndrzej Pietrasiewicz } 283590fccb52SAndrzej Pietrasiewicz 283690fccb52SAndrzej Pietrasiewicz spin_unlock(&udc->lock); 283790fccb52SAndrzej Pietrasiewicz 283890fccb52SAndrzej Pietrasiewicz return IRQ_HANDLED; 283990fccb52SAndrzej Pietrasiewicz } 284090fccb52SAndrzej Pietrasiewicz 284190fccb52SAndrzej Pietrasiewicz /* 284290fccb52SAndrzej Pietrasiewicz * 284390fccb52SAndrzej Pietrasiewicz * VBUS detection, pullup handler, and Gadget cable state notification 284490fccb52SAndrzej Pietrasiewicz * 284590fccb52SAndrzej Pietrasiewicz */ 284690fccb52SAndrzej Pietrasiewicz static void vbus_work(struct work_struct *work) 284790fccb52SAndrzej Pietrasiewicz { 284890fccb52SAndrzej Pietrasiewicz u8 value; 284990fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = container_of(work, struct lpc32xx_udc, 285090fccb52SAndrzej Pietrasiewicz vbus_job); 285190fccb52SAndrzej Pietrasiewicz 285290fccb52SAndrzej Pietrasiewicz if (udc->enabled != 0) { 285390fccb52SAndrzej Pietrasiewicz /* Discharge VBUS real quick */ 285490fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 285590fccb52SAndrzej Pietrasiewicz ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG); 285690fccb52SAndrzej Pietrasiewicz 285790fccb52SAndrzej Pietrasiewicz /* Give VBUS some time (100mS) to discharge */ 285890fccb52SAndrzej Pietrasiewicz msleep(100); 285990fccb52SAndrzej Pietrasiewicz 286090fccb52SAndrzej Pietrasiewicz /* Disable VBUS discharge resistor */ 286190fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 286290fccb52SAndrzej Pietrasiewicz ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, 286390fccb52SAndrzej Pietrasiewicz OTG1_VBUS_DISCHRG); 286490fccb52SAndrzej Pietrasiewicz 286590fccb52SAndrzej Pietrasiewicz /* Clear interrupt */ 286690fccb52SAndrzej Pietrasiewicz i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 286790fccb52SAndrzej Pietrasiewicz ISP1301_I2C_INTERRUPT_LATCH | 286890fccb52SAndrzej Pietrasiewicz ISP1301_I2C_REG_CLEAR_ADDR, ~0); 286990fccb52SAndrzej Pietrasiewicz 287090fccb52SAndrzej Pietrasiewicz /* Get the VBUS status from the transceiver */ 287190fccb52SAndrzej Pietrasiewicz value = i2c_smbus_read_byte_data(udc->isp1301_i2c_client, 287290fccb52SAndrzej Pietrasiewicz ISP1301_I2C_INTERRUPT_SOURCE); 287390fccb52SAndrzej Pietrasiewicz 287490fccb52SAndrzej Pietrasiewicz /* VBUS on or off? */ 287590fccb52SAndrzej Pietrasiewicz if (value & INT_SESS_VLD) 287690fccb52SAndrzej Pietrasiewicz udc->vbus = 1; 287790fccb52SAndrzej Pietrasiewicz else 287890fccb52SAndrzej Pietrasiewicz udc->vbus = 0; 287990fccb52SAndrzej Pietrasiewicz 288090fccb52SAndrzej Pietrasiewicz /* VBUS changed? */ 288190fccb52SAndrzej Pietrasiewicz if (udc->last_vbus != udc->vbus) { 288290fccb52SAndrzej Pietrasiewicz udc->last_vbus = udc->vbus; 288390fccb52SAndrzej Pietrasiewicz lpc32xx_vbus_session(&udc->gadget, udc->vbus); 288490fccb52SAndrzej Pietrasiewicz } 288590fccb52SAndrzej Pietrasiewicz } 288690fccb52SAndrzej Pietrasiewicz 288790fccb52SAndrzej Pietrasiewicz /* Re-enable after completion */ 288890fccb52SAndrzej Pietrasiewicz enable_irq(udc->udp_irq[IRQ_USB_ATX]); 288990fccb52SAndrzej Pietrasiewicz } 289090fccb52SAndrzej Pietrasiewicz 289190fccb52SAndrzej Pietrasiewicz static irqreturn_t lpc32xx_usb_vbus_irq(int irq, void *_udc) 289290fccb52SAndrzej Pietrasiewicz { 289390fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = _udc; 289490fccb52SAndrzej Pietrasiewicz 289590fccb52SAndrzej Pietrasiewicz /* Defer handling of VBUS IRQ to work queue */ 289690fccb52SAndrzej Pietrasiewicz disable_irq_nosync(udc->udp_irq[IRQ_USB_ATX]); 289790fccb52SAndrzej Pietrasiewicz schedule_work(&udc->vbus_job); 289890fccb52SAndrzej Pietrasiewicz 289990fccb52SAndrzej Pietrasiewicz return IRQ_HANDLED; 290090fccb52SAndrzej Pietrasiewicz } 290190fccb52SAndrzej Pietrasiewicz 290290fccb52SAndrzej Pietrasiewicz static int lpc32xx_start(struct usb_gadget *gadget, 290390fccb52SAndrzej Pietrasiewicz struct usb_gadget_driver *driver) 290490fccb52SAndrzej Pietrasiewicz { 290590fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = to_udc(gadget); 290690fccb52SAndrzej Pietrasiewicz int i; 290790fccb52SAndrzej Pietrasiewicz 290890fccb52SAndrzej Pietrasiewicz if (!driver || driver->max_speed < USB_SPEED_FULL || !driver->setup) { 290990fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, "bad parameter.\n"); 291090fccb52SAndrzej Pietrasiewicz return -EINVAL; 291190fccb52SAndrzej Pietrasiewicz } 291290fccb52SAndrzej Pietrasiewicz 291390fccb52SAndrzej Pietrasiewicz if (udc->driver) { 291490fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, "UDC already has a gadget driver\n"); 291590fccb52SAndrzej Pietrasiewicz return -EBUSY; 291690fccb52SAndrzej Pietrasiewicz } 291790fccb52SAndrzej Pietrasiewicz 291890fccb52SAndrzej Pietrasiewicz udc->driver = driver; 291990fccb52SAndrzej Pietrasiewicz udc->gadget.dev.of_node = udc->dev->of_node; 292090fccb52SAndrzej Pietrasiewicz udc->enabled = 1; 2921d60d9392SPeter Chen udc->gadget.is_selfpowered = 1; 292290fccb52SAndrzej Pietrasiewicz udc->vbus = 0; 292390fccb52SAndrzej Pietrasiewicz 292490fccb52SAndrzej Pietrasiewicz /* Force VBUS process once to check for cable insertion */ 292590fccb52SAndrzej Pietrasiewicz udc->last_vbus = udc->vbus = 0; 292690fccb52SAndrzej Pietrasiewicz schedule_work(&udc->vbus_job); 292790fccb52SAndrzej Pietrasiewicz 292890fccb52SAndrzej Pietrasiewicz /* Do not re-enable ATX IRQ (3) */ 292990fccb52SAndrzej Pietrasiewicz for (i = IRQ_USB_LP; i < IRQ_USB_ATX; i++) 293090fccb52SAndrzej Pietrasiewicz enable_irq(udc->udp_irq[i]); 293190fccb52SAndrzej Pietrasiewicz 293290fccb52SAndrzej Pietrasiewicz return 0; 293390fccb52SAndrzej Pietrasiewicz } 293490fccb52SAndrzej Pietrasiewicz 293522835b80SFelipe Balbi static int lpc32xx_stop(struct usb_gadget *gadget) 293690fccb52SAndrzej Pietrasiewicz { 293790fccb52SAndrzej Pietrasiewicz int i; 293890fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = to_udc(gadget); 293990fccb52SAndrzej Pietrasiewicz 294090fccb52SAndrzej Pietrasiewicz for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++) 294190fccb52SAndrzej Pietrasiewicz disable_irq(udc->udp_irq[i]); 294290fccb52SAndrzej Pietrasiewicz 294390fccb52SAndrzej Pietrasiewicz if (udc->clocked) { 294490fccb52SAndrzej Pietrasiewicz spin_lock(&udc->lock); 294590fccb52SAndrzej Pietrasiewicz stop_activity(udc); 294690fccb52SAndrzej Pietrasiewicz spin_unlock(&udc->lock); 294790fccb52SAndrzej Pietrasiewicz 294890fccb52SAndrzej Pietrasiewicz /* 294990fccb52SAndrzej Pietrasiewicz * Wait for all the endpoints to disable, 295090fccb52SAndrzej Pietrasiewicz * before disabling clocks. Don't wait if 295190fccb52SAndrzej Pietrasiewicz * endpoints are not enabled. 295290fccb52SAndrzej Pietrasiewicz */ 295390fccb52SAndrzej Pietrasiewicz if (atomic_read(&udc->enabled_ep_cnt)) 295490fccb52SAndrzej Pietrasiewicz wait_event_interruptible(udc->ep_disable_wait_queue, 295590fccb52SAndrzej Pietrasiewicz (atomic_read(&udc->enabled_ep_cnt) == 0)); 295690fccb52SAndrzej Pietrasiewicz 295790fccb52SAndrzej Pietrasiewicz spin_lock(&udc->lock); 295890fccb52SAndrzej Pietrasiewicz udc_clk_set(udc, 0); 295990fccb52SAndrzej Pietrasiewicz spin_unlock(&udc->lock); 296090fccb52SAndrzej Pietrasiewicz } 296190fccb52SAndrzej Pietrasiewicz 296290fccb52SAndrzej Pietrasiewicz udc->enabled = 0; 296390fccb52SAndrzej Pietrasiewicz udc->driver = NULL; 296490fccb52SAndrzej Pietrasiewicz 296590fccb52SAndrzej Pietrasiewicz return 0; 296690fccb52SAndrzej Pietrasiewicz } 296790fccb52SAndrzej Pietrasiewicz 296890fccb52SAndrzej Pietrasiewicz static void lpc32xx_udc_shutdown(struct platform_device *dev) 296990fccb52SAndrzej Pietrasiewicz { 297090fccb52SAndrzej Pietrasiewicz /* Force disconnect on reboot */ 297190fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = platform_get_drvdata(dev); 297290fccb52SAndrzej Pietrasiewicz 297390fccb52SAndrzej Pietrasiewicz pullup(udc, 0); 297490fccb52SAndrzej Pietrasiewicz } 297590fccb52SAndrzej Pietrasiewicz 297690fccb52SAndrzej Pietrasiewicz /* 297790fccb52SAndrzej Pietrasiewicz * Callbacks to be overridden by options passed via OF (TODO) 297890fccb52SAndrzej Pietrasiewicz */ 297990fccb52SAndrzej Pietrasiewicz 298090fccb52SAndrzej Pietrasiewicz static void lpc32xx_usbd_conn_chg(int conn) 298190fccb52SAndrzej Pietrasiewicz { 298290fccb52SAndrzej Pietrasiewicz /* Do nothing, it might be nice to enable an LED 298390fccb52SAndrzej Pietrasiewicz * based on conn state being !0 */ 298490fccb52SAndrzej Pietrasiewicz } 298590fccb52SAndrzej Pietrasiewicz 298690fccb52SAndrzej Pietrasiewicz static void lpc32xx_usbd_susp_chg(int susp) 298790fccb52SAndrzej Pietrasiewicz { 298890fccb52SAndrzej Pietrasiewicz /* Device suspend if susp != 0 */ 298990fccb52SAndrzej Pietrasiewicz } 299090fccb52SAndrzej Pietrasiewicz 299190fccb52SAndrzej Pietrasiewicz static void lpc32xx_rmwkup_chg(int remote_wakup_enable) 299290fccb52SAndrzej Pietrasiewicz { 299390fccb52SAndrzej Pietrasiewicz /* Enable or disable USB remote wakeup */ 299490fccb52SAndrzej Pietrasiewicz } 299590fccb52SAndrzej Pietrasiewicz 299690fccb52SAndrzej Pietrasiewicz struct lpc32xx_usbd_cfg lpc32xx_usbddata = { 299790fccb52SAndrzej Pietrasiewicz .vbus_drv_pol = 0, 299890fccb52SAndrzej Pietrasiewicz .conn_chgb = &lpc32xx_usbd_conn_chg, 299990fccb52SAndrzej Pietrasiewicz .susp_chgb = &lpc32xx_usbd_susp_chg, 300090fccb52SAndrzej Pietrasiewicz .rmwk_chgb = &lpc32xx_rmwkup_chg, 300190fccb52SAndrzej Pietrasiewicz }; 300290fccb52SAndrzej Pietrasiewicz 300390fccb52SAndrzej Pietrasiewicz 300490fccb52SAndrzej Pietrasiewicz static u64 lpc32xx_usbd_dmamask = ~(u32) 0x7F; 300590fccb52SAndrzej Pietrasiewicz 300690fccb52SAndrzej Pietrasiewicz static int lpc32xx_udc_probe(struct platform_device *pdev) 300790fccb52SAndrzej Pietrasiewicz { 300890fccb52SAndrzej Pietrasiewicz struct device *dev = &pdev->dev; 300990fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc; 301090fccb52SAndrzej Pietrasiewicz int retval, i; 301190fccb52SAndrzej Pietrasiewicz struct resource *res; 301290fccb52SAndrzej Pietrasiewicz dma_addr_t dma_handle; 301390fccb52SAndrzej Pietrasiewicz struct device_node *isp1301_node; 301490fccb52SAndrzej Pietrasiewicz 301590fccb52SAndrzej Pietrasiewicz udc = kmemdup(&controller_template, sizeof(*udc), GFP_KERNEL); 301690fccb52SAndrzej Pietrasiewicz if (!udc) 301790fccb52SAndrzej Pietrasiewicz return -ENOMEM; 301890fccb52SAndrzej Pietrasiewicz 301990fccb52SAndrzej Pietrasiewicz for (i = 0; i <= 15; i++) 302090fccb52SAndrzej Pietrasiewicz udc->ep[i].udc = udc; 302190fccb52SAndrzej Pietrasiewicz udc->gadget.ep0 = &udc->ep[0].ep; 302290fccb52SAndrzej Pietrasiewicz 302390fccb52SAndrzej Pietrasiewicz /* init software state */ 302490fccb52SAndrzej Pietrasiewicz udc->gadget.dev.parent = dev; 302590fccb52SAndrzej Pietrasiewicz udc->pdev = pdev; 302690fccb52SAndrzej Pietrasiewicz udc->dev = &pdev->dev; 302790fccb52SAndrzej Pietrasiewicz udc->enabled = 0; 302890fccb52SAndrzej Pietrasiewicz 302990fccb52SAndrzej Pietrasiewicz if (pdev->dev.of_node) { 303090fccb52SAndrzej Pietrasiewicz isp1301_node = of_parse_phandle(pdev->dev.of_node, 303190fccb52SAndrzej Pietrasiewicz "transceiver", 0); 303290fccb52SAndrzej Pietrasiewicz } else { 303390fccb52SAndrzej Pietrasiewicz isp1301_node = NULL; 303490fccb52SAndrzej Pietrasiewicz } 303590fccb52SAndrzej Pietrasiewicz 303690fccb52SAndrzej Pietrasiewicz udc->isp1301_i2c_client = isp1301_get_client(isp1301_node); 303790fccb52SAndrzej Pietrasiewicz if (!udc->isp1301_i2c_client) { 303890fccb52SAndrzej Pietrasiewicz retval = -EPROBE_DEFER; 303990fccb52SAndrzej Pietrasiewicz goto phy_fail; 304090fccb52SAndrzej Pietrasiewicz } 304190fccb52SAndrzej Pietrasiewicz 304290fccb52SAndrzej Pietrasiewicz dev_info(udc->dev, "ISP1301 I2C device at address 0x%x\n", 304390fccb52SAndrzej Pietrasiewicz udc->isp1301_i2c_client->addr); 304490fccb52SAndrzej Pietrasiewicz 304590fccb52SAndrzej Pietrasiewicz pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; 304690fccb52SAndrzej Pietrasiewicz retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); 304790fccb52SAndrzej Pietrasiewicz if (retval) 304890fccb52SAndrzej Pietrasiewicz goto resource_fail; 304990fccb52SAndrzej Pietrasiewicz 305090fccb52SAndrzej Pietrasiewicz udc->board = &lpc32xx_usbddata; 305190fccb52SAndrzej Pietrasiewicz 305290fccb52SAndrzej Pietrasiewicz /* 305390fccb52SAndrzej Pietrasiewicz * Resources are mapped as follows: 305490fccb52SAndrzej Pietrasiewicz * IORESOURCE_MEM, base address and size of USB space 305590fccb52SAndrzej Pietrasiewicz * IORESOURCE_IRQ, USB device low priority interrupt number 305690fccb52SAndrzej Pietrasiewicz * IORESOURCE_IRQ, USB device high priority interrupt number 305790fccb52SAndrzej Pietrasiewicz * IORESOURCE_IRQ, USB device interrupt number 305890fccb52SAndrzej Pietrasiewicz * IORESOURCE_IRQ, USB transceiver interrupt number 305990fccb52SAndrzej Pietrasiewicz */ 306090fccb52SAndrzej Pietrasiewicz res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 306190fccb52SAndrzej Pietrasiewicz if (!res) { 306290fccb52SAndrzej Pietrasiewicz retval = -ENXIO; 306390fccb52SAndrzej Pietrasiewicz goto resource_fail; 306490fccb52SAndrzej Pietrasiewicz } 306590fccb52SAndrzej Pietrasiewicz 306690fccb52SAndrzej Pietrasiewicz spin_lock_init(&udc->lock); 306790fccb52SAndrzej Pietrasiewicz 306890fccb52SAndrzej Pietrasiewicz /* Get IRQs */ 306990fccb52SAndrzej Pietrasiewicz for (i = 0; i < 4; i++) { 307090fccb52SAndrzej Pietrasiewicz udc->udp_irq[i] = platform_get_irq(pdev, i); 307190fccb52SAndrzej Pietrasiewicz if (udc->udp_irq[i] < 0) { 307290fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, 307390fccb52SAndrzej Pietrasiewicz "irq resource %d not available!\n", i); 307490fccb52SAndrzej Pietrasiewicz retval = udc->udp_irq[i]; 307590fccb52SAndrzej Pietrasiewicz goto irq_fail; 307690fccb52SAndrzej Pietrasiewicz } 307790fccb52SAndrzej Pietrasiewicz } 307890fccb52SAndrzej Pietrasiewicz 307990fccb52SAndrzej Pietrasiewicz udc->io_p_start = res->start; 308090fccb52SAndrzej Pietrasiewicz udc->io_p_size = resource_size(res); 308190fccb52SAndrzej Pietrasiewicz if (!request_mem_region(udc->io_p_start, udc->io_p_size, driver_name)) { 308290fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, "someone's using UDC memory\n"); 308390fccb52SAndrzej Pietrasiewicz retval = -EBUSY; 308490fccb52SAndrzej Pietrasiewicz goto request_mem_region_fail; 308590fccb52SAndrzej Pietrasiewicz } 308690fccb52SAndrzej Pietrasiewicz 308790fccb52SAndrzej Pietrasiewicz udc->udp_baseaddr = ioremap(udc->io_p_start, udc->io_p_size); 308890fccb52SAndrzej Pietrasiewicz if (!udc->udp_baseaddr) { 308990fccb52SAndrzej Pietrasiewicz retval = -ENOMEM; 309090fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, "IO map failure\n"); 309190fccb52SAndrzej Pietrasiewicz goto io_map_fail; 309290fccb52SAndrzej Pietrasiewicz } 309390fccb52SAndrzej Pietrasiewicz 309459e05272SVladimir Zapolskiy /* Get USB device clock */ 309559e05272SVladimir Zapolskiy udc->usb_slv_clk = clk_get(&pdev->dev, NULL); 309690fccb52SAndrzej Pietrasiewicz if (IS_ERR(udc->usb_slv_clk)) { 309790fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, "failed to acquire USB device clock\n"); 309890fccb52SAndrzej Pietrasiewicz retval = PTR_ERR(udc->usb_slv_clk); 309990fccb52SAndrzej Pietrasiewicz goto usb_clk_get_fail; 310090fccb52SAndrzej Pietrasiewicz } 310190fccb52SAndrzej Pietrasiewicz 310290fccb52SAndrzej Pietrasiewicz /* Enable USB device clock */ 310368726e77SVladimir Zapolskiy retval = clk_prepare_enable(udc->usb_slv_clk); 310490fccb52SAndrzej Pietrasiewicz if (retval < 0) { 310590fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, "failed to start USB device clock\n"); 310690fccb52SAndrzej Pietrasiewicz goto usb_clk_enable_fail; 310790fccb52SAndrzej Pietrasiewicz } 310890fccb52SAndrzej Pietrasiewicz 310990fccb52SAndrzej Pietrasiewicz /* Setup deferred workqueue data */ 311090fccb52SAndrzej Pietrasiewicz udc->poweron = udc->pullup = 0; 311190fccb52SAndrzej Pietrasiewicz INIT_WORK(&udc->pullup_job, pullup_work); 311290fccb52SAndrzej Pietrasiewicz INIT_WORK(&udc->vbus_job, vbus_work); 311390fccb52SAndrzej Pietrasiewicz #ifdef CONFIG_PM 311490fccb52SAndrzej Pietrasiewicz INIT_WORK(&udc->power_job, power_work); 311590fccb52SAndrzej Pietrasiewicz #endif 311690fccb52SAndrzej Pietrasiewicz 311790fccb52SAndrzej Pietrasiewicz /* All clocks are now on */ 311890fccb52SAndrzej Pietrasiewicz udc->clocked = 1; 311990fccb52SAndrzej Pietrasiewicz 312090fccb52SAndrzej Pietrasiewicz isp1301_udc_configure(udc); 312190fccb52SAndrzej Pietrasiewicz /* Allocate memory for the UDCA */ 312290fccb52SAndrzej Pietrasiewicz udc->udca_v_base = dma_alloc_coherent(&pdev->dev, UDCA_BUFF_SIZE, 312390fccb52SAndrzej Pietrasiewicz &dma_handle, 312490fccb52SAndrzej Pietrasiewicz (GFP_KERNEL | GFP_DMA)); 312590fccb52SAndrzej Pietrasiewicz if (!udc->udca_v_base) { 312690fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, "error getting UDCA region\n"); 312790fccb52SAndrzej Pietrasiewicz retval = -ENOMEM; 312890fccb52SAndrzej Pietrasiewicz goto i2c_fail; 312990fccb52SAndrzej Pietrasiewicz } 313090fccb52SAndrzej Pietrasiewicz udc->udca_p_base = dma_handle; 313190fccb52SAndrzej Pietrasiewicz dev_dbg(udc->dev, "DMA buffer(0x%x bytes), P:0x%08x, V:0x%p\n", 313290fccb52SAndrzej Pietrasiewicz UDCA_BUFF_SIZE, udc->udca_p_base, udc->udca_v_base); 313390fccb52SAndrzej Pietrasiewicz 313490fccb52SAndrzej Pietrasiewicz /* Setup the DD DMA memory pool */ 313590fccb52SAndrzej Pietrasiewicz udc->dd_cache = dma_pool_create("udc_dd", udc->dev, 313690fccb52SAndrzej Pietrasiewicz sizeof(struct lpc32xx_usbd_dd_gad), 313790fccb52SAndrzej Pietrasiewicz sizeof(u32), 0); 313890fccb52SAndrzej Pietrasiewicz if (!udc->dd_cache) { 313990fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, "error getting DD DMA region\n"); 314090fccb52SAndrzej Pietrasiewicz retval = -ENOMEM; 314190fccb52SAndrzej Pietrasiewicz goto dma_alloc_fail; 314290fccb52SAndrzej Pietrasiewicz } 314390fccb52SAndrzej Pietrasiewicz 314490fccb52SAndrzej Pietrasiewicz /* Clear USB peripheral and initialize gadget endpoints */ 314590fccb52SAndrzej Pietrasiewicz udc_disable(udc); 314690fccb52SAndrzej Pietrasiewicz udc_reinit(udc); 314790fccb52SAndrzej Pietrasiewicz 314890fccb52SAndrzej Pietrasiewicz /* Request IRQs - low and high priority USB device IRQs are routed to 314990fccb52SAndrzej Pietrasiewicz * the same handler, while the DMA interrupt is routed elsewhere */ 315090fccb52SAndrzej Pietrasiewicz retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq, 315190fccb52SAndrzej Pietrasiewicz 0, "udc_lp", udc); 315290fccb52SAndrzej Pietrasiewicz if (retval < 0) { 315390fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, "LP request irq %d failed\n", 315490fccb52SAndrzej Pietrasiewicz udc->udp_irq[IRQ_USB_LP]); 315590fccb52SAndrzej Pietrasiewicz goto irq_lp_fail; 315690fccb52SAndrzej Pietrasiewicz } 315790fccb52SAndrzej Pietrasiewicz retval = request_irq(udc->udp_irq[IRQ_USB_HP], lpc32xx_usb_hp_irq, 315890fccb52SAndrzej Pietrasiewicz 0, "udc_hp", udc); 315990fccb52SAndrzej Pietrasiewicz if (retval < 0) { 316090fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, "HP request irq %d failed\n", 316190fccb52SAndrzej Pietrasiewicz udc->udp_irq[IRQ_USB_HP]); 316290fccb52SAndrzej Pietrasiewicz goto irq_hp_fail; 316390fccb52SAndrzej Pietrasiewicz } 316490fccb52SAndrzej Pietrasiewicz 316590fccb52SAndrzej Pietrasiewicz retval = request_irq(udc->udp_irq[IRQ_USB_DEVDMA], 316690fccb52SAndrzej Pietrasiewicz lpc32xx_usb_devdma_irq, 0, "udc_dma", udc); 316790fccb52SAndrzej Pietrasiewicz if (retval < 0) { 316890fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, "DEV request irq %d failed\n", 316990fccb52SAndrzej Pietrasiewicz udc->udp_irq[IRQ_USB_DEVDMA]); 317090fccb52SAndrzej Pietrasiewicz goto irq_dev_fail; 317190fccb52SAndrzej Pietrasiewicz } 317290fccb52SAndrzej Pietrasiewicz 317390fccb52SAndrzej Pietrasiewicz /* The transceiver interrupt is used for VBUS detection and will 317490fccb52SAndrzej Pietrasiewicz kick off the VBUS handler function */ 317590fccb52SAndrzej Pietrasiewicz retval = request_irq(udc->udp_irq[IRQ_USB_ATX], lpc32xx_usb_vbus_irq, 317690fccb52SAndrzej Pietrasiewicz 0, "udc_otg", udc); 317790fccb52SAndrzej Pietrasiewicz if (retval < 0) { 317890fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, "VBUS request irq %d failed\n", 317990fccb52SAndrzej Pietrasiewicz udc->udp_irq[IRQ_USB_ATX]); 318090fccb52SAndrzej Pietrasiewicz goto irq_xcvr_fail; 318190fccb52SAndrzej Pietrasiewicz } 318290fccb52SAndrzej Pietrasiewicz 318390fccb52SAndrzej Pietrasiewicz /* Initialize wait queue */ 318490fccb52SAndrzej Pietrasiewicz init_waitqueue_head(&udc->ep_disable_wait_queue); 318590fccb52SAndrzej Pietrasiewicz atomic_set(&udc->enabled_ep_cnt, 0); 318690fccb52SAndrzej Pietrasiewicz 318790fccb52SAndrzej Pietrasiewicz /* Keep all IRQs disabled until GadgetFS starts up */ 318890fccb52SAndrzej Pietrasiewicz for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++) 318990fccb52SAndrzej Pietrasiewicz disable_irq(udc->udp_irq[i]); 319090fccb52SAndrzej Pietrasiewicz 319190fccb52SAndrzej Pietrasiewicz retval = usb_add_gadget_udc(dev, &udc->gadget); 319290fccb52SAndrzej Pietrasiewicz if (retval < 0) 319390fccb52SAndrzej Pietrasiewicz goto add_gadget_fail; 319490fccb52SAndrzej Pietrasiewicz 319590fccb52SAndrzej Pietrasiewicz dev_set_drvdata(dev, udc); 319690fccb52SAndrzej Pietrasiewicz device_init_wakeup(dev, 1); 319790fccb52SAndrzej Pietrasiewicz create_debug_file(udc); 319890fccb52SAndrzej Pietrasiewicz 319990fccb52SAndrzej Pietrasiewicz /* Disable clocks for now */ 320090fccb52SAndrzej Pietrasiewicz udc_clk_set(udc, 0); 320190fccb52SAndrzej Pietrasiewicz 320290fccb52SAndrzej Pietrasiewicz dev_info(udc->dev, "%s version %s\n", driver_name, DRIVER_VERSION); 320390fccb52SAndrzej Pietrasiewicz return 0; 320490fccb52SAndrzej Pietrasiewicz 320590fccb52SAndrzej Pietrasiewicz add_gadget_fail: 320690fccb52SAndrzej Pietrasiewicz free_irq(udc->udp_irq[IRQ_USB_ATX], udc); 320790fccb52SAndrzej Pietrasiewicz irq_xcvr_fail: 320890fccb52SAndrzej Pietrasiewicz free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc); 320990fccb52SAndrzej Pietrasiewicz irq_dev_fail: 321090fccb52SAndrzej Pietrasiewicz free_irq(udc->udp_irq[IRQ_USB_HP], udc); 321190fccb52SAndrzej Pietrasiewicz irq_hp_fail: 321290fccb52SAndrzej Pietrasiewicz free_irq(udc->udp_irq[IRQ_USB_LP], udc); 321390fccb52SAndrzej Pietrasiewicz irq_lp_fail: 321490fccb52SAndrzej Pietrasiewicz dma_pool_destroy(udc->dd_cache); 321590fccb52SAndrzej Pietrasiewicz dma_alloc_fail: 321690fccb52SAndrzej Pietrasiewicz dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, 321790fccb52SAndrzej Pietrasiewicz udc->udca_v_base, udc->udca_p_base); 321890fccb52SAndrzej Pietrasiewicz i2c_fail: 321968726e77SVladimir Zapolskiy clk_disable_unprepare(udc->usb_slv_clk); 322090fccb52SAndrzej Pietrasiewicz usb_clk_enable_fail: 322190fccb52SAndrzej Pietrasiewicz clk_put(udc->usb_slv_clk); 322290fccb52SAndrzej Pietrasiewicz usb_clk_get_fail: 322390fccb52SAndrzej Pietrasiewicz iounmap(udc->udp_baseaddr); 322490fccb52SAndrzej Pietrasiewicz io_map_fail: 322590fccb52SAndrzej Pietrasiewicz release_mem_region(udc->io_p_start, udc->io_p_size); 322690fccb52SAndrzej Pietrasiewicz dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval); 322790fccb52SAndrzej Pietrasiewicz request_mem_region_fail: 322890fccb52SAndrzej Pietrasiewicz irq_fail: 322990fccb52SAndrzej Pietrasiewicz resource_fail: 323090fccb52SAndrzej Pietrasiewicz phy_fail: 323190fccb52SAndrzej Pietrasiewicz kfree(udc); 323290fccb52SAndrzej Pietrasiewicz return retval; 323390fccb52SAndrzej Pietrasiewicz } 323490fccb52SAndrzej Pietrasiewicz 323590fccb52SAndrzej Pietrasiewicz static int lpc32xx_udc_remove(struct platform_device *pdev) 323690fccb52SAndrzej Pietrasiewicz { 323790fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = platform_get_drvdata(pdev); 323890fccb52SAndrzej Pietrasiewicz 323990fccb52SAndrzej Pietrasiewicz usb_del_gadget_udc(&udc->gadget); 324090fccb52SAndrzej Pietrasiewicz if (udc->driver) 324190fccb52SAndrzej Pietrasiewicz return -EBUSY; 324290fccb52SAndrzej Pietrasiewicz 324390fccb52SAndrzej Pietrasiewicz udc_clk_set(udc, 1); 324490fccb52SAndrzej Pietrasiewicz udc_disable(udc); 324590fccb52SAndrzej Pietrasiewicz pullup(udc, 0); 324690fccb52SAndrzej Pietrasiewicz 324790fccb52SAndrzej Pietrasiewicz free_irq(udc->udp_irq[IRQ_USB_ATX], udc); 324890fccb52SAndrzej Pietrasiewicz 324990fccb52SAndrzej Pietrasiewicz device_init_wakeup(&pdev->dev, 0); 325090fccb52SAndrzej Pietrasiewicz remove_debug_file(udc); 325190fccb52SAndrzej Pietrasiewicz 325290fccb52SAndrzej Pietrasiewicz dma_pool_destroy(udc->dd_cache); 325390fccb52SAndrzej Pietrasiewicz dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, 325490fccb52SAndrzej Pietrasiewicz udc->udca_v_base, udc->udca_p_base); 325590fccb52SAndrzej Pietrasiewicz free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc); 325690fccb52SAndrzej Pietrasiewicz free_irq(udc->udp_irq[IRQ_USB_HP], udc); 325790fccb52SAndrzej Pietrasiewicz free_irq(udc->udp_irq[IRQ_USB_LP], udc); 325890fccb52SAndrzej Pietrasiewicz 325968726e77SVladimir Zapolskiy clk_disable_unprepare(udc->usb_slv_clk); 326090fccb52SAndrzej Pietrasiewicz clk_put(udc->usb_slv_clk); 326159e05272SVladimir Zapolskiy 326290fccb52SAndrzej Pietrasiewicz iounmap(udc->udp_baseaddr); 326390fccb52SAndrzej Pietrasiewicz release_mem_region(udc->io_p_start, udc->io_p_size); 326490fccb52SAndrzej Pietrasiewicz kfree(udc); 326590fccb52SAndrzej Pietrasiewicz 326690fccb52SAndrzej Pietrasiewicz return 0; 326790fccb52SAndrzej Pietrasiewicz } 326890fccb52SAndrzej Pietrasiewicz 326990fccb52SAndrzej Pietrasiewicz #ifdef CONFIG_PM 327090fccb52SAndrzej Pietrasiewicz static int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg) 327190fccb52SAndrzej Pietrasiewicz { 327290fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = platform_get_drvdata(pdev); 327390fccb52SAndrzej Pietrasiewicz 327490fccb52SAndrzej Pietrasiewicz if (udc->clocked) { 327590fccb52SAndrzej Pietrasiewicz /* Power down ISP */ 327690fccb52SAndrzej Pietrasiewicz udc->poweron = 0; 327790fccb52SAndrzej Pietrasiewicz isp1301_set_powerstate(udc, 0); 327890fccb52SAndrzej Pietrasiewicz 327990fccb52SAndrzej Pietrasiewicz /* Disable clocking */ 328090fccb52SAndrzej Pietrasiewicz udc_clk_set(udc, 0); 328190fccb52SAndrzej Pietrasiewicz 328290fccb52SAndrzej Pietrasiewicz /* Keep clock flag on, so we know to re-enable clocks 328390fccb52SAndrzej Pietrasiewicz on resume */ 328490fccb52SAndrzej Pietrasiewicz udc->clocked = 1; 328590fccb52SAndrzej Pietrasiewicz 328690fccb52SAndrzej Pietrasiewicz /* Kill global USB clock */ 328768726e77SVladimir Zapolskiy clk_disable_unprepare(udc->usb_slv_clk); 328890fccb52SAndrzej Pietrasiewicz } 328990fccb52SAndrzej Pietrasiewicz 329090fccb52SAndrzej Pietrasiewicz return 0; 329190fccb52SAndrzej Pietrasiewicz } 329290fccb52SAndrzej Pietrasiewicz 329390fccb52SAndrzej Pietrasiewicz static int lpc32xx_udc_resume(struct platform_device *pdev) 329490fccb52SAndrzej Pietrasiewicz { 329590fccb52SAndrzej Pietrasiewicz struct lpc32xx_udc *udc = platform_get_drvdata(pdev); 329690fccb52SAndrzej Pietrasiewicz 329790fccb52SAndrzej Pietrasiewicz if (udc->clocked) { 329890fccb52SAndrzej Pietrasiewicz /* Enable global USB clock */ 329968726e77SVladimir Zapolskiy clk_prepare_enable(udc->usb_slv_clk); 330090fccb52SAndrzej Pietrasiewicz 330190fccb52SAndrzej Pietrasiewicz /* Enable clocking */ 330290fccb52SAndrzej Pietrasiewicz udc_clk_set(udc, 1); 330390fccb52SAndrzej Pietrasiewicz 330490fccb52SAndrzej Pietrasiewicz /* ISP back to normal power mode */ 330590fccb52SAndrzej Pietrasiewicz udc->poweron = 1; 330690fccb52SAndrzej Pietrasiewicz isp1301_set_powerstate(udc, 1); 330790fccb52SAndrzej Pietrasiewicz } 330890fccb52SAndrzej Pietrasiewicz 330990fccb52SAndrzej Pietrasiewicz return 0; 331090fccb52SAndrzej Pietrasiewicz } 331190fccb52SAndrzej Pietrasiewicz #else 331290fccb52SAndrzej Pietrasiewicz #define lpc32xx_udc_suspend NULL 331390fccb52SAndrzej Pietrasiewicz #define lpc32xx_udc_resume NULL 331490fccb52SAndrzej Pietrasiewicz #endif 331590fccb52SAndrzej Pietrasiewicz 331690fccb52SAndrzej Pietrasiewicz #ifdef CONFIG_OF 331790fccb52SAndrzej Pietrasiewicz static const struct of_device_id lpc32xx_udc_of_match[] = { 331890fccb52SAndrzej Pietrasiewicz { .compatible = "nxp,lpc3220-udc", }, 331990fccb52SAndrzej Pietrasiewicz { }, 332090fccb52SAndrzej Pietrasiewicz }; 332190fccb52SAndrzej Pietrasiewicz MODULE_DEVICE_TABLE(of, lpc32xx_udc_of_match); 332290fccb52SAndrzej Pietrasiewicz #endif 332390fccb52SAndrzej Pietrasiewicz 332490fccb52SAndrzej Pietrasiewicz static struct platform_driver lpc32xx_udc_driver = { 332590fccb52SAndrzej Pietrasiewicz .remove = lpc32xx_udc_remove, 332690fccb52SAndrzej Pietrasiewicz .shutdown = lpc32xx_udc_shutdown, 332790fccb52SAndrzej Pietrasiewicz .suspend = lpc32xx_udc_suspend, 332890fccb52SAndrzej Pietrasiewicz .resume = lpc32xx_udc_resume, 332990fccb52SAndrzej Pietrasiewicz .driver = { 333090fccb52SAndrzej Pietrasiewicz .name = (char *) driver_name, 333190fccb52SAndrzej Pietrasiewicz .of_match_table = of_match_ptr(lpc32xx_udc_of_match), 333290fccb52SAndrzej Pietrasiewicz }, 333390fccb52SAndrzej Pietrasiewicz }; 333490fccb52SAndrzej Pietrasiewicz 333590fccb52SAndrzej Pietrasiewicz module_platform_driver_probe(lpc32xx_udc_driver, lpc32xx_udc_probe); 333690fccb52SAndrzej Pietrasiewicz 333790fccb52SAndrzej Pietrasiewicz MODULE_DESCRIPTION("LPC32XX udc driver"); 333890fccb52SAndrzej Pietrasiewicz MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>"); 333990fccb52SAndrzej Pietrasiewicz MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); 334090fccb52SAndrzej Pietrasiewicz MODULE_LICENSE("GPL"); 334190fccb52SAndrzej Pietrasiewicz MODULE_ALIAS("platform:lpc32xx_udc"); 3342