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