162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * USB Gadget driver for LPC32xx 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: 662306a36Sopenharmony_ci * Kevin Wells <kevin.wells@nxp.com> 762306a36Sopenharmony_ci * Mike James 862306a36Sopenharmony_ci * Roland Stigge <stigge@antcom.de> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright (C) 2006 Philips Semiconductors 1162306a36Sopenharmony_ci * Copyright (C) 2009 NXP Semiconductors 1262306a36Sopenharmony_ci * Copyright (C) 2012 Roland Stigge 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Note: This driver is based on original work done by Mike James for 1562306a36Sopenharmony_ci * the LPC3180. 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/clk.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2162306a36Sopenharmony_ci#include <linux/dmapool.h> 2262306a36Sopenharmony_ci#include <linux/i2c.h> 2362306a36Sopenharmony_ci#include <linux/interrupt.h> 2462306a36Sopenharmony_ci#include <linux/module.h> 2562306a36Sopenharmony_ci#include <linux/of.h> 2662306a36Sopenharmony_ci#include <linux/platform_device.h> 2762306a36Sopenharmony_ci#include <linux/prefetch.h> 2862306a36Sopenharmony_ci#include <linux/proc_fs.h> 2962306a36Sopenharmony_ci#include <linux/slab.h> 3062306a36Sopenharmony_ci#include <linux/usb/ch9.h> 3162306a36Sopenharmony_ci#include <linux/usb/gadget.h> 3262306a36Sopenharmony_ci#include <linux/usb/isp1301.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#ifdef CONFIG_USB_GADGET_DEBUG_FILES 3562306a36Sopenharmony_ci#include <linux/debugfs.h> 3662306a36Sopenharmony_ci#include <linux/seq_file.h> 3762306a36Sopenharmony_ci#endif 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * USB device configuration structure 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_citypedef void (*usc_chg_event)(int); 4362306a36Sopenharmony_cistruct lpc32xx_usbd_cfg { 4462306a36Sopenharmony_ci int vbus_drv_pol; /* 0=active low drive for VBUS via ISP1301 */ 4562306a36Sopenharmony_ci usc_chg_event conn_chgb; /* Connection change event (optional) */ 4662306a36Sopenharmony_ci usc_chg_event susp_chgb; /* Suspend/resume event (optional) */ 4762306a36Sopenharmony_ci usc_chg_event rmwk_chgb; /* Enable/disable remote wakeup */ 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* 5162306a36Sopenharmony_ci * controller driver data structures 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* 16 endpoints (not to be confused with 32 hardware endpoints) */ 5562306a36Sopenharmony_ci#define NUM_ENDPOINTS 16 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * IRQ indices make reading the code a little easier 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci#define IRQ_USB_LP 0 6162306a36Sopenharmony_ci#define IRQ_USB_HP 1 6262306a36Sopenharmony_ci#define IRQ_USB_DEVDMA 2 6362306a36Sopenharmony_ci#define IRQ_USB_ATX 3 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define EP_OUT 0 /* RX (from host) */ 6662306a36Sopenharmony_ci#define EP_IN 1 /* TX (to host) */ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* Returns the interrupt mask for the selected hardware endpoint */ 6962306a36Sopenharmony_ci#define EP_MASK_SEL(ep, dir) (1 << (((ep) * 2) + dir)) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define EP_INT_TYPE 0 7262306a36Sopenharmony_ci#define EP_ISO_TYPE 1 7362306a36Sopenharmony_ci#define EP_BLK_TYPE 2 7462306a36Sopenharmony_ci#define EP_CTL_TYPE 3 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* EP0 states */ 7762306a36Sopenharmony_ci#define WAIT_FOR_SETUP 0 /* Wait for setup packet */ 7862306a36Sopenharmony_ci#define DATA_IN 1 /* Expect dev->host transfer */ 7962306a36Sopenharmony_ci#define DATA_OUT 2 /* Expect host->dev transfer */ 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* DD (DMA Descriptor) structure, requires word alignment, this is already 8262306a36Sopenharmony_ci * defined in the LPC32XX USB device header file, but this version is slightly 8362306a36Sopenharmony_ci * modified to tag some work data with each DMA descriptor. */ 8462306a36Sopenharmony_cistruct lpc32xx_usbd_dd_gad { 8562306a36Sopenharmony_ci u32 dd_next_phy; 8662306a36Sopenharmony_ci u32 dd_setup; 8762306a36Sopenharmony_ci u32 dd_buffer_addr; 8862306a36Sopenharmony_ci u32 dd_status; 8962306a36Sopenharmony_ci u32 dd_iso_ps_mem_addr; 9062306a36Sopenharmony_ci u32 this_dma; 9162306a36Sopenharmony_ci u32 iso_status[6]; /* 5 spare */ 9262306a36Sopenharmony_ci u32 dd_next_v; 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* 9662306a36Sopenharmony_ci * Logical endpoint structure 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_cistruct lpc32xx_ep { 9962306a36Sopenharmony_ci struct usb_ep ep; 10062306a36Sopenharmony_ci struct list_head queue; 10162306a36Sopenharmony_ci struct lpc32xx_udc *udc; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci u32 hwep_num_base; /* Physical hardware EP */ 10462306a36Sopenharmony_ci u32 hwep_num; /* Maps to hardware endpoint */ 10562306a36Sopenharmony_ci u32 maxpacket; 10662306a36Sopenharmony_ci u32 lep; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci bool is_in; 10962306a36Sopenharmony_ci bool req_pending; 11062306a36Sopenharmony_ci u32 eptype; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci u32 totalints; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci bool wedge; 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cienum atx_type { 11862306a36Sopenharmony_ci ISP1301, 11962306a36Sopenharmony_ci STOTG04, 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* 12362306a36Sopenharmony_ci * Common UDC structure 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_cistruct lpc32xx_udc { 12662306a36Sopenharmony_ci struct usb_gadget gadget; 12762306a36Sopenharmony_ci struct usb_gadget_driver *driver; 12862306a36Sopenharmony_ci struct platform_device *pdev; 12962306a36Sopenharmony_ci struct device *dev; 13062306a36Sopenharmony_ci spinlock_t lock; 13162306a36Sopenharmony_ci struct i2c_client *isp1301_i2c_client; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* Board and device specific */ 13462306a36Sopenharmony_ci struct lpc32xx_usbd_cfg *board; 13562306a36Sopenharmony_ci void __iomem *udp_baseaddr; 13662306a36Sopenharmony_ci int udp_irq[4]; 13762306a36Sopenharmony_ci struct clk *usb_slv_clk; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* DMA support */ 14062306a36Sopenharmony_ci u32 *udca_v_base; 14162306a36Sopenharmony_ci u32 udca_p_base; 14262306a36Sopenharmony_ci struct dma_pool *dd_cache; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* Common EP and control data */ 14562306a36Sopenharmony_ci u32 enabled_devints; 14662306a36Sopenharmony_ci u32 enabled_hwepints; 14762306a36Sopenharmony_ci u32 dev_status; 14862306a36Sopenharmony_ci u32 realized_eps; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* VBUS detection, pullup, and power flags */ 15162306a36Sopenharmony_ci u8 vbus; 15262306a36Sopenharmony_ci u8 last_vbus; 15362306a36Sopenharmony_ci int pullup; 15462306a36Sopenharmony_ci int poweron; 15562306a36Sopenharmony_ci enum atx_type atx; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* Work queues related to I2C support */ 15862306a36Sopenharmony_ci struct work_struct pullup_job; 15962306a36Sopenharmony_ci struct work_struct power_job; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* USB device peripheral - various */ 16262306a36Sopenharmony_ci struct lpc32xx_ep ep[NUM_ENDPOINTS]; 16362306a36Sopenharmony_ci bool enabled; 16462306a36Sopenharmony_ci bool clocked; 16562306a36Sopenharmony_ci bool suspended; 16662306a36Sopenharmony_ci int ep0state; 16762306a36Sopenharmony_ci atomic_t enabled_ep_cnt; 16862306a36Sopenharmony_ci wait_queue_head_t ep_disable_wait_queue; 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* 17262306a36Sopenharmony_ci * Endpoint request 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_cistruct lpc32xx_request { 17562306a36Sopenharmony_ci struct usb_request req; 17662306a36Sopenharmony_ci struct list_head queue; 17762306a36Sopenharmony_ci struct lpc32xx_usbd_dd_gad *dd_desc_ptr; 17862306a36Sopenharmony_ci bool mapped; 17962306a36Sopenharmony_ci bool send_zlp; 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic inline struct lpc32xx_udc *to_udc(struct usb_gadget *g) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci return container_of(g, struct lpc32xx_udc, gadget); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci#define ep_dbg(epp, fmt, arg...) \ 18862306a36Sopenharmony_ci dev_dbg(epp->udc->dev, "%s: " fmt, __func__, ## arg) 18962306a36Sopenharmony_ci#define ep_err(epp, fmt, arg...) \ 19062306a36Sopenharmony_ci dev_err(epp->udc->dev, "%s: " fmt, __func__, ## arg) 19162306a36Sopenharmony_ci#define ep_info(epp, fmt, arg...) \ 19262306a36Sopenharmony_ci dev_info(epp->udc->dev, "%s: " fmt, __func__, ## arg) 19362306a36Sopenharmony_ci#define ep_warn(epp, fmt, arg...) \ 19462306a36Sopenharmony_ci dev_warn(epp->udc->dev, "%s:" fmt, __func__, ## arg) 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci#define UDCA_BUFF_SIZE (128) 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci/********************************************************************** 19962306a36Sopenharmony_ci * USB device controller register offsets 20062306a36Sopenharmony_ci **********************************************************************/ 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci#define USBD_DEVINTST(x) ((x) + 0x200) 20362306a36Sopenharmony_ci#define USBD_DEVINTEN(x) ((x) + 0x204) 20462306a36Sopenharmony_ci#define USBD_DEVINTCLR(x) ((x) + 0x208) 20562306a36Sopenharmony_ci#define USBD_DEVINTSET(x) ((x) + 0x20C) 20662306a36Sopenharmony_ci#define USBD_CMDCODE(x) ((x) + 0x210) 20762306a36Sopenharmony_ci#define USBD_CMDDATA(x) ((x) + 0x214) 20862306a36Sopenharmony_ci#define USBD_RXDATA(x) ((x) + 0x218) 20962306a36Sopenharmony_ci#define USBD_TXDATA(x) ((x) + 0x21C) 21062306a36Sopenharmony_ci#define USBD_RXPLEN(x) ((x) + 0x220) 21162306a36Sopenharmony_ci#define USBD_TXPLEN(x) ((x) + 0x224) 21262306a36Sopenharmony_ci#define USBD_CTRL(x) ((x) + 0x228) 21362306a36Sopenharmony_ci#define USBD_DEVINTPRI(x) ((x) + 0x22C) 21462306a36Sopenharmony_ci#define USBD_EPINTST(x) ((x) + 0x230) 21562306a36Sopenharmony_ci#define USBD_EPINTEN(x) ((x) + 0x234) 21662306a36Sopenharmony_ci#define USBD_EPINTCLR(x) ((x) + 0x238) 21762306a36Sopenharmony_ci#define USBD_EPINTSET(x) ((x) + 0x23C) 21862306a36Sopenharmony_ci#define USBD_EPINTPRI(x) ((x) + 0x240) 21962306a36Sopenharmony_ci#define USBD_REEP(x) ((x) + 0x244) 22062306a36Sopenharmony_ci#define USBD_EPIND(x) ((x) + 0x248) 22162306a36Sopenharmony_ci#define USBD_EPMAXPSIZE(x) ((x) + 0x24C) 22262306a36Sopenharmony_ci/* DMA support registers only below */ 22362306a36Sopenharmony_ci/* Set, clear, or get enabled state of the DMA request status. If 22462306a36Sopenharmony_ci * enabled, an IN or OUT token will start a DMA transfer for the EP */ 22562306a36Sopenharmony_ci#define USBD_DMARST(x) ((x) + 0x250) 22662306a36Sopenharmony_ci#define USBD_DMARCLR(x) ((x) + 0x254) 22762306a36Sopenharmony_ci#define USBD_DMARSET(x) ((x) + 0x258) 22862306a36Sopenharmony_ci/* DMA UDCA head pointer */ 22962306a36Sopenharmony_ci#define USBD_UDCAH(x) ((x) + 0x280) 23062306a36Sopenharmony_ci/* EP DMA status, enable, and disable. This is used to specifically 23162306a36Sopenharmony_ci * enabled or disable DMA for a specific EP */ 23262306a36Sopenharmony_ci#define USBD_EPDMAST(x) ((x) + 0x284) 23362306a36Sopenharmony_ci#define USBD_EPDMAEN(x) ((x) + 0x288) 23462306a36Sopenharmony_ci#define USBD_EPDMADIS(x) ((x) + 0x28C) 23562306a36Sopenharmony_ci/* DMA master interrupts enable and pending interrupts */ 23662306a36Sopenharmony_ci#define USBD_DMAINTST(x) ((x) + 0x290) 23762306a36Sopenharmony_ci#define USBD_DMAINTEN(x) ((x) + 0x294) 23862306a36Sopenharmony_ci/* DMA end of transfer interrupt enable, disable, status */ 23962306a36Sopenharmony_ci#define USBD_EOTINTST(x) ((x) + 0x2A0) 24062306a36Sopenharmony_ci#define USBD_EOTINTCLR(x) ((x) + 0x2A4) 24162306a36Sopenharmony_ci#define USBD_EOTINTSET(x) ((x) + 0x2A8) 24262306a36Sopenharmony_ci/* New DD request interrupt enable, disable, status */ 24362306a36Sopenharmony_ci#define USBD_NDDRTINTST(x) ((x) + 0x2AC) 24462306a36Sopenharmony_ci#define USBD_NDDRTINTCLR(x) ((x) + 0x2B0) 24562306a36Sopenharmony_ci#define USBD_NDDRTINTSET(x) ((x) + 0x2B4) 24662306a36Sopenharmony_ci/* DMA error interrupt enable, disable, status */ 24762306a36Sopenharmony_ci#define USBD_SYSERRTINTST(x) ((x) + 0x2B8) 24862306a36Sopenharmony_ci#define USBD_SYSERRTINTCLR(x) ((x) + 0x2BC) 24962306a36Sopenharmony_ci#define USBD_SYSERRTINTSET(x) ((x) + 0x2C0) 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/********************************************************************** 25262306a36Sopenharmony_ci * USBD_DEVINTST/USBD_DEVINTEN/USBD_DEVINTCLR/USBD_DEVINTSET/ 25362306a36Sopenharmony_ci * USBD_DEVINTPRI register definitions 25462306a36Sopenharmony_ci **********************************************************************/ 25562306a36Sopenharmony_ci#define USBD_ERR_INT (1 << 9) 25662306a36Sopenharmony_ci#define USBD_EP_RLZED (1 << 8) 25762306a36Sopenharmony_ci#define USBD_TXENDPKT (1 << 7) 25862306a36Sopenharmony_ci#define USBD_RXENDPKT (1 << 6) 25962306a36Sopenharmony_ci#define USBD_CDFULL (1 << 5) 26062306a36Sopenharmony_ci#define USBD_CCEMPTY (1 << 4) 26162306a36Sopenharmony_ci#define USBD_DEV_STAT (1 << 3) 26262306a36Sopenharmony_ci#define USBD_EP_SLOW (1 << 2) 26362306a36Sopenharmony_ci#define USBD_EP_FAST (1 << 1) 26462306a36Sopenharmony_ci#define USBD_FRAME (1 << 0) 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/********************************************************************** 26762306a36Sopenharmony_ci * USBD_EPINTST/USBD_EPINTEN/USBD_EPINTCLR/USBD_EPINTSET/ 26862306a36Sopenharmony_ci * USBD_EPINTPRI register definitions 26962306a36Sopenharmony_ci **********************************************************************/ 27062306a36Sopenharmony_ci/* End point selection macro (RX) */ 27162306a36Sopenharmony_ci#define USBD_RX_EP_SEL(e) (1 << ((e) << 1)) 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/* End point selection macro (TX) */ 27462306a36Sopenharmony_ci#define USBD_TX_EP_SEL(e) (1 << (((e) << 1) + 1)) 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci/********************************************************************** 27762306a36Sopenharmony_ci * USBD_REEP/USBD_DMARST/USBD_DMARCLR/USBD_DMARSET/USBD_EPDMAST/ 27862306a36Sopenharmony_ci * USBD_EPDMAEN/USBD_EPDMADIS/ 27962306a36Sopenharmony_ci * USBD_NDDRTINTST/USBD_NDDRTINTCLR/USBD_NDDRTINTSET/ 28062306a36Sopenharmony_ci * USBD_EOTINTST/USBD_EOTINTCLR/USBD_EOTINTSET/ 28162306a36Sopenharmony_ci * USBD_SYSERRTINTST/USBD_SYSERRTINTCLR/USBD_SYSERRTINTSET 28262306a36Sopenharmony_ci * register definitions 28362306a36Sopenharmony_ci **********************************************************************/ 28462306a36Sopenharmony_ci/* Endpoint selection macro */ 28562306a36Sopenharmony_ci#define USBD_EP_SEL(e) (1 << (e)) 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/********************************************************************** 28862306a36Sopenharmony_ci * SBD_DMAINTST/USBD_DMAINTEN 28962306a36Sopenharmony_ci **********************************************************************/ 29062306a36Sopenharmony_ci#define USBD_SYS_ERR_INT (1 << 2) 29162306a36Sopenharmony_ci#define USBD_NEW_DD_INT (1 << 1) 29262306a36Sopenharmony_ci#define USBD_EOT_INT (1 << 0) 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/********************************************************************** 29562306a36Sopenharmony_ci * USBD_RXPLEN register definitions 29662306a36Sopenharmony_ci **********************************************************************/ 29762306a36Sopenharmony_ci#define USBD_PKT_RDY (1 << 11) 29862306a36Sopenharmony_ci#define USBD_DV (1 << 10) 29962306a36Sopenharmony_ci#define USBD_PK_LEN_MASK 0x3FF 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/********************************************************************** 30262306a36Sopenharmony_ci * USBD_CTRL register definitions 30362306a36Sopenharmony_ci **********************************************************************/ 30462306a36Sopenharmony_ci#define USBD_LOG_ENDPOINT(e) ((e) << 2) 30562306a36Sopenharmony_ci#define USBD_WR_EN (1 << 1) 30662306a36Sopenharmony_ci#define USBD_RD_EN (1 << 0) 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/********************************************************************** 30962306a36Sopenharmony_ci * USBD_CMDCODE register definitions 31062306a36Sopenharmony_ci **********************************************************************/ 31162306a36Sopenharmony_ci#define USBD_CMD_CODE(c) ((c) << 16) 31262306a36Sopenharmony_ci#define USBD_CMD_PHASE(p) ((p) << 8) 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci/********************************************************************** 31562306a36Sopenharmony_ci * USBD_DMARST/USBD_DMARCLR/USBD_DMARSET register definitions 31662306a36Sopenharmony_ci **********************************************************************/ 31762306a36Sopenharmony_ci#define USBD_DMAEP(e) (1 << (e)) 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci/* DD (DMA Descriptor) structure, requires word alignment */ 32062306a36Sopenharmony_cistruct lpc32xx_usbd_dd { 32162306a36Sopenharmony_ci u32 *dd_next; 32262306a36Sopenharmony_ci u32 dd_setup; 32362306a36Sopenharmony_ci u32 dd_buffer_addr; 32462306a36Sopenharmony_ci u32 dd_status; 32562306a36Sopenharmony_ci u32 dd_iso_ps_mem_addr; 32662306a36Sopenharmony_ci}; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/* dd_setup bit defines */ 32962306a36Sopenharmony_ci#define DD_SETUP_ATLE_DMA_MODE 0x01 33062306a36Sopenharmony_ci#define DD_SETUP_NEXT_DD_VALID 0x04 33162306a36Sopenharmony_ci#define DD_SETUP_ISO_EP 0x10 33262306a36Sopenharmony_ci#define DD_SETUP_PACKETLEN(n) (((n) & 0x7FF) << 5) 33362306a36Sopenharmony_ci#define DD_SETUP_DMALENBYTES(n) (((n) & 0xFFFF) << 16) 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci/* dd_status bit defines */ 33662306a36Sopenharmony_ci#define DD_STATUS_DD_RETIRED 0x01 33762306a36Sopenharmony_ci#define DD_STATUS_STS_MASK 0x1E 33862306a36Sopenharmony_ci#define DD_STATUS_STS_NS 0x00 /* Not serviced */ 33962306a36Sopenharmony_ci#define DD_STATUS_STS_BS 0x02 /* Being serviced */ 34062306a36Sopenharmony_ci#define DD_STATUS_STS_NC 0x04 /* Normal completion */ 34162306a36Sopenharmony_ci#define DD_STATUS_STS_DUR 0x06 /* Data underrun (short packet) */ 34262306a36Sopenharmony_ci#define DD_STATUS_STS_DOR 0x08 /* Data overrun */ 34362306a36Sopenharmony_ci#define DD_STATUS_STS_SE 0x12 /* System error */ 34462306a36Sopenharmony_ci#define DD_STATUS_PKT_VAL 0x20 /* Packet valid */ 34562306a36Sopenharmony_ci#define DD_STATUS_LSB_EX 0x40 /* LS byte extracted (ATLE) */ 34662306a36Sopenharmony_ci#define DD_STATUS_MSB_EX 0x80 /* MS byte extracted (ATLE) */ 34762306a36Sopenharmony_ci#define DD_STATUS_MLEN(n) (((n) >> 8) & 0x3F) 34862306a36Sopenharmony_ci#define DD_STATUS_CURDMACNT(n) (((n) >> 16) & 0xFFFF) 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/* 35162306a36Sopenharmony_ci * 35262306a36Sopenharmony_ci * Protocol engine bits below 35362306a36Sopenharmony_ci * 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_ci/* Device Interrupt Bit Definitions */ 35662306a36Sopenharmony_ci#define FRAME_INT 0x00000001 35762306a36Sopenharmony_ci#define EP_FAST_INT 0x00000002 35862306a36Sopenharmony_ci#define EP_SLOW_INT 0x00000004 35962306a36Sopenharmony_ci#define DEV_STAT_INT 0x00000008 36062306a36Sopenharmony_ci#define CCEMTY_INT 0x00000010 36162306a36Sopenharmony_ci#define CDFULL_INT 0x00000020 36262306a36Sopenharmony_ci#define RxENDPKT_INT 0x00000040 36362306a36Sopenharmony_ci#define TxENDPKT_INT 0x00000080 36462306a36Sopenharmony_ci#define EP_RLZED_INT 0x00000100 36562306a36Sopenharmony_ci#define ERR_INT 0x00000200 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/* Rx & Tx Packet Length Definitions */ 36862306a36Sopenharmony_ci#define PKT_LNGTH_MASK 0x000003FF 36962306a36Sopenharmony_ci#define PKT_DV 0x00000400 37062306a36Sopenharmony_ci#define PKT_RDY 0x00000800 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci/* USB Control Definitions */ 37362306a36Sopenharmony_ci#define CTRL_RD_EN 0x00000001 37462306a36Sopenharmony_ci#define CTRL_WR_EN 0x00000002 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci/* Command Codes */ 37762306a36Sopenharmony_ci#define CMD_SET_ADDR 0x00D00500 37862306a36Sopenharmony_ci#define CMD_CFG_DEV 0x00D80500 37962306a36Sopenharmony_ci#define CMD_SET_MODE 0x00F30500 38062306a36Sopenharmony_ci#define CMD_RD_FRAME 0x00F50500 38162306a36Sopenharmony_ci#define DAT_RD_FRAME 0x00F50200 38262306a36Sopenharmony_ci#define CMD_RD_TEST 0x00FD0500 38362306a36Sopenharmony_ci#define DAT_RD_TEST 0x00FD0200 38462306a36Sopenharmony_ci#define CMD_SET_DEV_STAT 0x00FE0500 38562306a36Sopenharmony_ci#define CMD_GET_DEV_STAT 0x00FE0500 38662306a36Sopenharmony_ci#define DAT_GET_DEV_STAT 0x00FE0200 38762306a36Sopenharmony_ci#define CMD_GET_ERR_CODE 0x00FF0500 38862306a36Sopenharmony_ci#define DAT_GET_ERR_CODE 0x00FF0200 38962306a36Sopenharmony_ci#define CMD_RD_ERR_STAT 0x00FB0500 39062306a36Sopenharmony_ci#define DAT_RD_ERR_STAT 0x00FB0200 39162306a36Sopenharmony_ci#define DAT_WR_BYTE(x) (0x00000100 | ((x) << 16)) 39262306a36Sopenharmony_ci#define CMD_SEL_EP(x) (0x00000500 | ((x) << 16)) 39362306a36Sopenharmony_ci#define DAT_SEL_EP(x) (0x00000200 | ((x) << 16)) 39462306a36Sopenharmony_ci#define CMD_SEL_EP_CLRI(x) (0x00400500 | ((x) << 16)) 39562306a36Sopenharmony_ci#define DAT_SEL_EP_CLRI(x) (0x00400200 | ((x) << 16)) 39662306a36Sopenharmony_ci#define CMD_SET_EP_STAT(x) (0x00400500 | ((x) << 16)) 39762306a36Sopenharmony_ci#define CMD_CLR_BUF 0x00F20500 39862306a36Sopenharmony_ci#define DAT_CLR_BUF 0x00F20200 39962306a36Sopenharmony_ci#define CMD_VALID_BUF 0x00FA0500 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci/* Device Address Register Definitions */ 40262306a36Sopenharmony_ci#define DEV_ADDR_MASK 0x7F 40362306a36Sopenharmony_ci#define DEV_EN 0x80 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/* Device Configure Register Definitions */ 40662306a36Sopenharmony_ci#define CONF_DVICE 0x01 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci/* Device Mode Register Definitions */ 40962306a36Sopenharmony_ci#define AP_CLK 0x01 41062306a36Sopenharmony_ci#define INAK_CI 0x02 41162306a36Sopenharmony_ci#define INAK_CO 0x04 41262306a36Sopenharmony_ci#define INAK_II 0x08 41362306a36Sopenharmony_ci#define INAK_IO 0x10 41462306a36Sopenharmony_ci#define INAK_BI 0x20 41562306a36Sopenharmony_ci#define INAK_BO 0x40 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* Device Status Register Definitions */ 41862306a36Sopenharmony_ci#define DEV_CON 0x01 41962306a36Sopenharmony_ci#define DEV_CON_CH 0x02 42062306a36Sopenharmony_ci#define DEV_SUS 0x04 42162306a36Sopenharmony_ci#define DEV_SUS_CH 0x08 42262306a36Sopenharmony_ci#define DEV_RST 0x10 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci/* Error Code Register Definitions */ 42562306a36Sopenharmony_ci#define ERR_EC_MASK 0x0F 42662306a36Sopenharmony_ci#define ERR_EA 0x10 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci/* Error Status Register Definitions */ 42962306a36Sopenharmony_ci#define ERR_PID 0x01 43062306a36Sopenharmony_ci#define ERR_UEPKT 0x02 43162306a36Sopenharmony_ci#define ERR_DCRC 0x04 43262306a36Sopenharmony_ci#define ERR_TIMOUT 0x08 43362306a36Sopenharmony_ci#define ERR_EOP 0x10 43462306a36Sopenharmony_ci#define ERR_B_OVRN 0x20 43562306a36Sopenharmony_ci#define ERR_BTSTF 0x40 43662306a36Sopenharmony_ci#define ERR_TGL 0x80 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci/* Endpoint Select Register Definitions */ 43962306a36Sopenharmony_ci#define EP_SEL_F 0x01 44062306a36Sopenharmony_ci#define EP_SEL_ST 0x02 44162306a36Sopenharmony_ci#define EP_SEL_STP 0x04 44262306a36Sopenharmony_ci#define EP_SEL_PO 0x08 44362306a36Sopenharmony_ci#define EP_SEL_EPN 0x10 44462306a36Sopenharmony_ci#define EP_SEL_B_1_FULL 0x20 44562306a36Sopenharmony_ci#define EP_SEL_B_2_FULL 0x40 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci/* Endpoint Status Register Definitions */ 44862306a36Sopenharmony_ci#define EP_STAT_ST 0x01 44962306a36Sopenharmony_ci#define EP_STAT_DA 0x20 45062306a36Sopenharmony_ci#define EP_STAT_RF_MO 0x40 45162306a36Sopenharmony_ci#define EP_STAT_CND_ST 0x80 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci/* Clear Buffer Register Definitions */ 45462306a36Sopenharmony_ci#define CLR_BUF_PO 0x01 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci/* DMA Interrupt Bit Definitions */ 45762306a36Sopenharmony_ci#define EOT_INT 0x01 45862306a36Sopenharmony_ci#define NDD_REQ_INT 0x02 45962306a36Sopenharmony_ci#define SYS_ERR_INT 0x04 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci#define DRIVER_VERSION "1.03" 46262306a36Sopenharmony_cistatic const char driver_name[] = "lpc32xx_udc"; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci/* 46562306a36Sopenharmony_ci * 46662306a36Sopenharmony_ci * proc interface support 46762306a36Sopenharmony_ci * 46862306a36Sopenharmony_ci */ 46962306a36Sopenharmony_ci#ifdef CONFIG_USB_GADGET_DEBUG_FILES 47062306a36Sopenharmony_cistatic char *epnames[] = {"INT", "ISO", "BULK", "CTRL"}; 47162306a36Sopenharmony_cistatic const char debug_filename[] = "driver/udc"; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic void proc_ep_show(struct seq_file *s, struct lpc32xx_ep *ep) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct lpc32xx_request *req; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci seq_printf(s, "\n"); 47862306a36Sopenharmony_ci seq_printf(s, "%12s, maxpacket %4d %3s", 47962306a36Sopenharmony_ci ep->ep.name, ep->ep.maxpacket, 48062306a36Sopenharmony_ci ep->is_in ? "in" : "out"); 48162306a36Sopenharmony_ci seq_printf(s, " type %4s", epnames[ep->eptype]); 48262306a36Sopenharmony_ci seq_printf(s, " ints: %12d", ep->totalints); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (list_empty(&ep->queue)) 48562306a36Sopenharmony_ci seq_printf(s, "\t(queue empty)\n"); 48662306a36Sopenharmony_ci else { 48762306a36Sopenharmony_ci list_for_each_entry(req, &ep->queue, queue) { 48862306a36Sopenharmony_ci u32 length = req->req.actual; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci seq_printf(s, "\treq %p len %d/%d buf %p\n", 49162306a36Sopenharmony_ci &req->req, length, 49262306a36Sopenharmony_ci req->req.length, req->req.buf); 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic int udc_show(struct seq_file *s, void *unused) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci struct lpc32xx_udc *udc = s->private; 50062306a36Sopenharmony_ci struct lpc32xx_ep *ep; 50162306a36Sopenharmony_ci unsigned long flags; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci seq_printf(s, "%s: version %s\n", driver_name, DRIVER_VERSION); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci seq_printf(s, "vbus %s, pullup %s, %s powered%s, gadget %s\n\n", 50862306a36Sopenharmony_ci udc->vbus ? "present" : "off", 50962306a36Sopenharmony_ci udc->enabled ? (udc->vbus ? "active" : "enabled") : 51062306a36Sopenharmony_ci "disabled", 51162306a36Sopenharmony_ci udc->gadget.is_selfpowered ? "self" : "VBUS", 51262306a36Sopenharmony_ci udc->suspended ? ", suspended" : "", 51362306a36Sopenharmony_ci udc->driver ? udc->driver->driver.name : "(none)"); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (udc->enabled && udc->vbus) { 51662306a36Sopenharmony_ci proc_ep_show(s, &udc->ep[0]); 51762306a36Sopenharmony_ci list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) 51862306a36Sopenharmony_ci proc_ep_show(s, ep); 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci return 0; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(udc); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic void create_debug_file(struct lpc32xx_udc *udc) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci debugfs_create_file(debug_filename, 0, NULL, udc, &udc_fops); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic void remove_debug_file(struct lpc32xx_udc *udc) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci debugfs_lookup_and_remove(debug_filename, NULL); 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci#else 53962306a36Sopenharmony_cistatic inline void create_debug_file(struct lpc32xx_udc *udc) {} 54062306a36Sopenharmony_cistatic inline void remove_debug_file(struct lpc32xx_udc *udc) {} 54162306a36Sopenharmony_ci#endif 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci/* Primary initialization sequence for the ISP1301 transceiver */ 54462306a36Sopenharmony_cistatic void isp1301_udc_configure(struct lpc32xx_udc *udc) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci u8 value; 54762306a36Sopenharmony_ci s32 vendor, product; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci vendor = i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00); 55062306a36Sopenharmony_ci product = i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x02); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (vendor == 0x0483 && product == 0xa0c4) 55362306a36Sopenharmony_ci udc->atx = STOTG04; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* LPC32XX only supports DAT_SE0 USB mode */ 55662306a36Sopenharmony_ci /* This sequence is important */ 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* Disable transparent UART mode first */ 55962306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 56062306a36Sopenharmony_ci (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), 56162306a36Sopenharmony_ci MC1_UART_EN); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* Set full speed and SE0 mode */ 56462306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 56562306a36Sopenharmony_ci (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); 56662306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 56762306a36Sopenharmony_ci ISP1301_I2C_MODE_CONTROL_1, (MC1_SPEED_REG | MC1_DAT_SE0)); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* 57062306a36Sopenharmony_ci * The PSW_OE enable bit state is reversed in the ISP1301 User's Guide 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 57362306a36Sopenharmony_ci (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci value = MC2_BI_DI; 57662306a36Sopenharmony_ci if (udc->atx != STOTG04) 57762306a36Sopenharmony_ci value |= MC2_SPD_SUSP_CTRL; 57862306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 57962306a36Sopenharmony_ci ISP1301_I2C_MODE_CONTROL_2, value); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* Driver VBUS_DRV high or low depending on board setup */ 58262306a36Sopenharmony_ci if (udc->board->vbus_drv_pol != 0) 58362306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 58462306a36Sopenharmony_ci ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV); 58562306a36Sopenharmony_ci else 58662306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 58762306a36Sopenharmony_ci ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, 58862306a36Sopenharmony_ci OTG1_VBUS_DRV); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci /* Bi-directional mode with suspend control 59162306a36Sopenharmony_ci * Enable both pulldowns for now - the pullup will be enable when VBUS 59262306a36Sopenharmony_ci * is detected */ 59362306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 59462306a36Sopenharmony_ci (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); 59562306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 59662306a36Sopenharmony_ci ISP1301_I2C_OTG_CONTROL_1, 59762306a36Sopenharmony_ci (0 | OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN)); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci /* Discharge VBUS (just in case) */ 60062306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 60162306a36Sopenharmony_ci ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG); 60262306a36Sopenharmony_ci msleep(1); 60362306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 60462306a36Sopenharmony_ci (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), 60562306a36Sopenharmony_ci OTG1_VBUS_DISCHRG); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 60862306a36Sopenharmony_ci ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, ~0); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 61162306a36Sopenharmony_ci ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); 61262306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 61362306a36Sopenharmony_ci ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci dev_info(udc->dev, "ISP1301 Vendor ID : 0x%04x\n", vendor); 61662306a36Sopenharmony_ci dev_info(udc->dev, "ISP1301 Product ID : 0x%04x\n", product); 61762306a36Sopenharmony_ci dev_info(udc->dev, "ISP1301 Version ID : 0x%04x\n", 61862306a36Sopenharmony_ci i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x14)); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci/* Enables or disables the USB device pullup via the ISP1301 transceiver */ 62362306a36Sopenharmony_cistatic void isp1301_pullup_set(struct lpc32xx_udc *udc) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci if (udc->pullup) 62662306a36Sopenharmony_ci /* Enable pullup for bus signalling */ 62762306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 62862306a36Sopenharmony_ci ISP1301_I2C_OTG_CONTROL_1, OTG1_DP_PULLUP); 62962306a36Sopenharmony_ci else 63062306a36Sopenharmony_ci /* Enable pullup for bus signalling */ 63162306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 63262306a36Sopenharmony_ci ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, 63362306a36Sopenharmony_ci OTG1_DP_PULLUP); 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic void pullup_work(struct work_struct *work) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct lpc32xx_udc *udc = 63962306a36Sopenharmony_ci container_of(work, struct lpc32xx_udc, pullup_job); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci isp1301_pullup_set(udc); 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic void isp1301_pullup_enable(struct lpc32xx_udc *udc, int en_pullup, 64562306a36Sopenharmony_ci int block) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci if (en_pullup == udc->pullup) 64862306a36Sopenharmony_ci return; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci udc->pullup = en_pullup; 65162306a36Sopenharmony_ci if (block) 65262306a36Sopenharmony_ci isp1301_pullup_set(udc); 65362306a36Sopenharmony_ci else 65462306a36Sopenharmony_ci /* defer slow i2c pull up setting */ 65562306a36Sopenharmony_ci schedule_work(&udc->pullup_job); 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci#ifdef CONFIG_PM 65962306a36Sopenharmony_ci/* Powers up or down the ISP1301 transceiver */ 66062306a36Sopenharmony_cistatic void isp1301_set_powerstate(struct lpc32xx_udc *udc, int enable) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci /* There is no "global power down" register for stotg04 */ 66362306a36Sopenharmony_ci if (udc->atx == STOTG04) 66462306a36Sopenharmony_ci return; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (enable != 0) 66762306a36Sopenharmony_ci /* Power up ISP1301 - this ISP1301 will automatically wakeup 66862306a36Sopenharmony_ci when VBUS is detected */ 66962306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 67062306a36Sopenharmony_ci ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR, 67162306a36Sopenharmony_ci MC2_GLOBAL_PWR_DN); 67262306a36Sopenharmony_ci else 67362306a36Sopenharmony_ci /* Power down ISP1301 */ 67462306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 67562306a36Sopenharmony_ci ISP1301_I2C_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic void power_work(struct work_struct *work) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci struct lpc32xx_udc *udc = 68162306a36Sopenharmony_ci container_of(work, struct lpc32xx_udc, power_job); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci isp1301_set_powerstate(udc, udc->poweron); 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci#endif 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci/* 68862306a36Sopenharmony_ci * 68962306a36Sopenharmony_ci * USB protocol engine command/data read/write helper functions 69062306a36Sopenharmony_ci * 69162306a36Sopenharmony_ci */ 69262306a36Sopenharmony_ci/* Issues a single command to the USB device state machine */ 69362306a36Sopenharmony_cistatic void udc_protocol_cmd_w(struct lpc32xx_udc *udc, u32 cmd) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci u32 pass = 0; 69662306a36Sopenharmony_ci int to; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* EP may lock on CLRI if this read isn't done */ 69962306a36Sopenharmony_ci u32 tmp = readl(USBD_DEVINTST(udc->udp_baseaddr)); 70062306a36Sopenharmony_ci (void) tmp; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci while (pass == 0) { 70362306a36Sopenharmony_ci writel(USBD_CCEMPTY, USBD_DEVINTCLR(udc->udp_baseaddr)); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* Write command code */ 70662306a36Sopenharmony_ci writel(cmd, USBD_CMDCODE(udc->udp_baseaddr)); 70762306a36Sopenharmony_ci to = 10000; 70862306a36Sopenharmony_ci while (((readl(USBD_DEVINTST(udc->udp_baseaddr)) & 70962306a36Sopenharmony_ci USBD_CCEMPTY) == 0) && (to > 0)) { 71062306a36Sopenharmony_ci to--; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (to > 0) 71462306a36Sopenharmony_ci pass = 1; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci cpu_relax(); 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci/* Issues 2 commands (or command and data) to the USB device state machine */ 72162306a36Sopenharmony_cistatic inline void udc_protocol_cmd_data_w(struct lpc32xx_udc *udc, u32 cmd, 72262306a36Sopenharmony_ci u32 data) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci udc_protocol_cmd_w(udc, cmd); 72562306a36Sopenharmony_ci udc_protocol_cmd_w(udc, data); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci/* Issues a single command to the USB device state machine and reads 72962306a36Sopenharmony_ci * response data */ 73062306a36Sopenharmony_cistatic u32 udc_protocol_cmd_r(struct lpc32xx_udc *udc, u32 cmd) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci int to = 1000; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci /* Write a command and read data from the protocol engine */ 73562306a36Sopenharmony_ci writel((USBD_CDFULL | USBD_CCEMPTY), 73662306a36Sopenharmony_ci USBD_DEVINTCLR(udc->udp_baseaddr)); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci /* Write command code */ 73962306a36Sopenharmony_ci udc_protocol_cmd_w(udc, cmd); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) & USBD_CDFULL)) 74262306a36Sopenharmony_ci && (to > 0)) 74362306a36Sopenharmony_ci to--; 74462306a36Sopenharmony_ci if (!to) 74562306a36Sopenharmony_ci dev_dbg(udc->dev, 74662306a36Sopenharmony_ci "Protocol engine didn't receive response (CDFULL)\n"); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci return readl(USBD_CMDDATA(udc->udp_baseaddr)); 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci/* 75262306a36Sopenharmony_ci * 75362306a36Sopenharmony_ci * USB device interrupt mask support functions 75462306a36Sopenharmony_ci * 75562306a36Sopenharmony_ci */ 75662306a36Sopenharmony_ci/* Enable one or more USB device interrupts */ 75762306a36Sopenharmony_cistatic inline void uda_enable_devint(struct lpc32xx_udc *udc, u32 devmask) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci udc->enabled_devints |= devmask; 76062306a36Sopenharmony_ci writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr)); 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci/* Disable one or more USB device interrupts */ 76462306a36Sopenharmony_cistatic inline void uda_disable_devint(struct lpc32xx_udc *udc, u32 mask) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci udc->enabled_devints &= ~mask; 76762306a36Sopenharmony_ci writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr)); 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci/* Clear one or more USB device interrupts */ 77162306a36Sopenharmony_cistatic inline void uda_clear_devint(struct lpc32xx_udc *udc, u32 mask) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci writel(mask, USBD_DEVINTCLR(udc->udp_baseaddr)); 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci/* 77762306a36Sopenharmony_ci * 77862306a36Sopenharmony_ci * Endpoint interrupt disable/enable functions 77962306a36Sopenharmony_ci * 78062306a36Sopenharmony_ci */ 78162306a36Sopenharmony_ci/* Enable one or more USB endpoint interrupts */ 78262306a36Sopenharmony_cistatic void uda_enable_hwepint(struct lpc32xx_udc *udc, u32 hwep) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci udc->enabled_hwepints |= (1 << hwep); 78562306a36Sopenharmony_ci writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr)); 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci/* Disable one or more USB endpoint interrupts */ 78962306a36Sopenharmony_cistatic void uda_disable_hwepint(struct lpc32xx_udc *udc, u32 hwep) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci udc->enabled_hwepints &= ~(1 << hwep); 79262306a36Sopenharmony_ci writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr)); 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci/* Clear one or more USB endpoint interrupts */ 79662306a36Sopenharmony_cistatic inline void uda_clear_hwepint(struct lpc32xx_udc *udc, u32 hwep) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci writel((1 << hwep), USBD_EPINTCLR(udc->udp_baseaddr)); 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci/* Enable DMA for the HW channel */ 80262306a36Sopenharmony_cistatic inline void udc_ep_dma_enable(struct lpc32xx_udc *udc, u32 hwep) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci writel((1 << hwep), USBD_EPDMAEN(udc->udp_baseaddr)); 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci/* Disable DMA for the HW channel */ 80862306a36Sopenharmony_cistatic inline void udc_ep_dma_disable(struct lpc32xx_udc *udc, u32 hwep) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci writel((1 << hwep), USBD_EPDMADIS(udc->udp_baseaddr)); 81162306a36Sopenharmony_ci} 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci/* 81462306a36Sopenharmony_ci * 81562306a36Sopenharmony_ci * Endpoint realize/unrealize functions 81662306a36Sopenharmony_ci * 81762306a36Sopenharmony_ci */ 81862306a36Sopenharmony_ci/* Before an endpoint can be used, it needs to be realized 81962306a36Sopenharmony_ci * in the USB protocol engine - this realizes the endpoint. 82062306a36Sopenharmony_ci * The interrupt (FIFO or DMA) is not enabled with this function */ 82162306a36Sopenharmony_cistatic void udc_realize_hwep(struct lpc32xx_udc *udc, u32 hwep, 82262306a36Sopenharmony_ci u32 maxpacket) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci int to = 1000; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr)); 82762306a36Sopenharmony_ci writel(hwep, USBD_EPIND(udc->udp_baseaddr)); 82862306a36Sopenharmony_ci udc->realized_eps |= (1 << hwep); 82962306a36Sopenharmony_ci writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr)); 83062306a36Sopenharmony_ci writel(maxpacket, USBD_EPMAXPSIZE(udc->udp_baseaddr)); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci /* Wait until endpoint is realized in hardware */ 83362306a36Sopenharmony_ci while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) & 83462306a36Sopenharmony_ci USBD_EP_RLZED)) && (to > 0)) 83562306a36Sopenharmony_ci to--; 83662306a36Sopenharmony_ci if (!to) 83762306a36Sopenharmony_ci dev_dbg(udc->dev, "EP not correctly realized in hardware\n"); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr)); 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci/* Unrealize an EP */ 84362306a36Sopenharmony_cistatic void udc_unrealize_hwep(struct lpc32xx_udc *udc, u32 hwep) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci udc->realized_eps &= ~(1 << hwep); 84662306a36Sopenharmony_ci writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr)); 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci/* 85062306a36Sopenharmony_ci * 85162306a36Sopenharmony_ci * Endpoint support functions 85262306a36Sopenharmony_ci * 85362306a36Sopenharmony_ci */ 85462306a36Sopenharmony_ci/* Select and clear endpoint interrupt */ 85562306a36Sopenharmony_cistatic u32 udc_selep_clrint(struct lpc32xx_udc *udc, u32 hwep) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci udc_protocol_cmd_w(udc, CMD_SEL_EP_CLRI(hwep)); 85862306a36Sopenharmony_ci return udc_protocol_cmd_r(udc, DAT_SEL_EP_CLRI(hwep)); 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci/* Disables the endpoint in the USB protocol engine */ 86262306a36Sopenharmony_cistatic void udc_disable_hwep(struct lpc32xx_udc *udc, u32 hwep) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep), 86562306a36Sopenharmony_ci DAT_WR_BYTE(EP_STAT_DA)); 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci/* Stalls the endpoint - endpoint will return STALL */ 86962306a36Sopenharmony_cistatic void udc_stall_hwep(struct lpc32xx_udc *udc, u32 hwep) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep), 87262306a36Sopenharmony_ci DAT_WR_BYTE(EP_STAT_ST)); 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci/* Clear stall or reset endpoint */ 87662306a36Sopenharmony_cistatic void udc_clrstall_hwep(struct lpc32xx_udc *udc, u32 hwep) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep), 87962306a36Sopenharmony_ci DAT_WR_BYTE(0)); 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci/* Select an endpoint for endpoint status, clear, validate */ 88362306a36Sopenharmony_cistatic void udc_select_hwep(struct lpc32xx_udc *udc, u32 hwep) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci udc_protocol_cmd_w(udc, CMD_SEL_EP(hwep)); 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci/* 88962306a36Sopenharmony_ci * 89062306a36Sopenharmony_ci * Endpoint buffer management functions 89162306a36Sopenharmony_ci * 89262306a36Sopenharmony_ci */ 89362306a36Sopenharmony_ci/* Clear the current endpoint's buffer */ 89462306a36Sopenharmony_cistatic void udc_clr_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci udc_select_hwep(udc, hwep); 89762306a36Sopenharmony_ci udc_protocol_cmd_w(udc, CMD_CLR_BUF); 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci/* Validate the current endpoint's buffer */ 90162306a36Sopenharmony_cistatic void udc_val_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci udc_select_hwep(udc, hwep); 90462306a36Sopenharmony_ci udc_protocol_cmd_w(udc, CMD_VALID_BUF); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic inline u32 udc_clearep_getsts(struct lpc32xx_udc *udc, u32 hwep) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci /* Clear EP interrupt */ 91062306a36Sopenharmony_ci uda_clear_hwepint(udc, hwep); 91162306a36Sopenharmony_ci return udc_selep_clrint(udc, hwep); 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci/* 91562306a36Sopenharmony_ci * 91662306a36Sopenharmony_ci * USB EP DMA support 91762306a36Sopenharmony_ci * 91862306a36Sopenharmony_ci */ 91962306a36Sopenharmony_ci/* Allocate a DMA Descriptor */ 92062306a36Sopenharmony_cistatic struct lpc32xx_usbd_dd_gad *udc_dd_alloc(struct lpc32xx_udc *udc) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci dma_addr_t dma; 92362306a36Sopenharmony_ci struct lpc32xx_usbd_dd_gad *dd; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci dd = dma_pool_alloc(udc->dd_cache, GFP_ATOMIC | GFP_DMA, &dma); 92662306a36Sopenharmony_ci if (dd) 92762306a36Sopenharmony_ci dd->this_dma = dma; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci return dd; 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci/* Free a DMA Descriptor */ 93362306a36Sopenharmony_cistatic void udc_dd_free(struct lpc32xx_udc *udc, struct lpc32xx_usbd_dd_gad *dd) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci dma_pool_free(udc->dd_cache, dd, dd->this_dma); 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci/* 93962306a36Sopenharmony_ci * 94062306a36Sopenharmony_ci * USB setup and shutdown functions 94162306a36Sopenharmony_ci * 94262306a36Sopenharmony_ci */ 94362306a36Sopenharmony_ci/* Enables or disables most of the USB system clocks when low power mode is 94462306a36Sopenharmony_ci * needed. Clocks are typically started on a connection event, and disabled 94562306a36Sopenharmony_ci * when a cable is disconnected */ 94662306a36Sopenharmony_cistatic void udc_clk_set(struct lpc32xx_udc *udc, int enable) 94762306a36Sopenharmony_ci{ 94862306a36Sopenharmony_ci if (enable != 0) { 94962306a36Sopenharmony_ci if (udc->clocked) 95062306a36Sopenharmony_ci return; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci udc->clocked = 1; 95362306a36Sopenharmony_ci clk_prepare_enable(udc->usb_slv_clk); 95462306a36Sopenharmony_ci } else { 95562306a36Sopenharmony_ci if (!udc->clocked) 95662306a36Sopenharmony_ci return; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci udc->clocked = 0; 95962306a36Sopenharmony_ci clk_disable_unprepare(udc->usb_slv_clk); 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci} 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci/* Set/reset USB device address */ 96462306a36Sopenharmony_cistatic void udc_set_address(struct lpc32xx_udc *udc, u32 addr) 96562306a36Sopenharmony_ci{ 96662306a36Sopenharmony_ci /* Address will be latched at the end of the status phase, or 96762306a36Sopenharmony_ci latched immediately if function is called twice */ 96862306a36Sopenharmony_ci udc_protocol_cmd_data_w(udc, CMD_SET_ADDR, 96962306a36Sopenharmony_ci DAT_WR_BYTE(DEV_EN | addr)); 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci/* Setup up a IN request for DMA transfer - this consists of determining the 97362306a36Sopenharmony_ci * list of DMA addresses for the transfer, allocating DMA Descriptors, 97462306a36Sopenharmony_ci * installing the DD into the UDCA, and then enabling the DMA for that EP */ 97562306a36Sopenharmony_cistatic int udc_ep_in_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) 97662306a36Sopenharmony_ci{ 97762306a36Sopenharmony_ci struct lpc32xx_request *req; 97862306a36Sopenharmony_ci u32 hwep = ep->hwep_num; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci ep->req_pending = 1; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* There will always be a request waiting here */ 98362306a36Sopenharmony_ci req = list_entry(ep->queue.next, struct lpc32xx_request, queue); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* Place the DD Descriptor into the UDCA */ 98662306a36Sopenharmony_ci udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci /* Enable DMA and interrupt for the HW EP */ 98962306a36Sopenharmony_ci udc_ep_dma_enable(udc, hwep); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci /* Clear ZLP if last packet is not of MAXP size */ 99262306a36Sopenharmony_ci if (req->req.length % ep->ep.maxpacket) 99362306a36Sopenharmony_ci req->send_zlp = 0; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci return 0; 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci/* Setup up a OUT request for DMA transfer - this consists of determining the 99962306a36Sopenharmony_ci * list of DMA addresses for the transfer, allocating DMA Descriptors, 100062306a36Sopenharmony_ci * installing the DD into the UDCA, and then enabling the DMA for that EP */ 100162306a36Sopenharmony_cistatic int udc_ep_out_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) 100262306a36Sopenharmony_ci{ 100362306a36Sopenharmony_ci struct lpc32xx_request *req; 100462306a36Sopenharmony_ci u32 hwep = ep->hwep_num; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci ep->req_pending = 1; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci /* There will always be a request waiting here */ 100962306a36Sopenharmony_ci req = list_entry(ep->queue.next, struct lpc32xx_request, queue); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci /* Place the DD Descriptor into the UDCA */ 101262306a36Sopenharmony_ci udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci /* Enable DMA and interrupt for the HW EP */ 101562306a36Sopenharmony_ci udc_ep_dma_enable(udc, hwep); 101662306a36Sopenharmony_ci return 0; 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cistatic void udc_disable(struct lpc32xx_udc *udc) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci u32 i; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci /* Disable device */ 102462306a36Sopenharmony_ci udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0)); 102562306a36Sopenharmony_ci udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(0)); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci /* Disable all device interrupts (including EP0) */ 102862306a36Sopenharmony_ci uda_disable_devint(udc, 0x3FF); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci /* Disable and reset all endpoint interrupts */ 103162306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 103262306a36Sopenharmony_ci uda_disable_hwepint(udc, i); 103362306a36Sopenharmony_ci uda_clear_hwepint(udc, i); 103462306a36Sopenharmony_ci udc_disable_hwep(udc, i); 103562306a36Sopenharmony_ci udc_unrealize_hwep(udc, i); 103662306a36Sopenharmony_ci udc->udca_v_base[i] = 0; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci /* Disable and clear all interrupts and DMA */ 103962306a36Sopenharmony_ci udc_ep_dma_disable(udc, i); 104062306a36Sopenharmony_ci writel((1 << i), USBD_EOTINTCLR(udc->udp_baseaddr)); 104162306a36Sopenharmony_ci writel((1 << i), USBD_NDDRTINTCLR(udc->udp_baseaddr)); 104262306a36Sopenharmony_ci writel((1 << i), USBD_SYSERRTINTCLR(udc->udp_baseaddr)); 104362306a36Sopenharmony_ci writel((1 << i), USBD_DMARCLR(udc->udp_baseaddr)); 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci /* Disable DMA interrupts */ 104762306a36Sopenharmony_ci writel(0, USBD_DMAINTEN(udc->udp_baseaddr)); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci writel(0, USBD_UDCAH(udc->udp_baseaddr)); 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic void udc_enable(struct lpc32xx_udc *udc) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci u32 i; 105562306a36Sopenharmony_ci struct lpc32xx_ep *ep = &udc->ep[0]; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci /* Start with known state */ 105862306a36Sopenharmony_ci udc_disable(udc); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci /* Enable device */ 106162306a36Sopenharmony_ci udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(DEV_CON)); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* EP interrupts on high priority, FRAME interrupt on low priority */ 106462306a36Sopenharmony_ci writel(USBD_EP_FAST, USBD_DEVINTPRI(udc->udp_baseaddr)); 106562306a36Sopenharmony_ci writel(0xFFFF, USBD_EPINTPRI(udc->udp_baseaddr)); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci /* Clear any pending device interrupts */ 106862306a36Sopenharmony_ci writel(0x3FF, USBD_DEVINTCLR(udc->udp_baseaddr)); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci /* Setup UDCA - not yet used (DMA) */ 107162306a36Sopenharmony_ci writel(udc->udca_p_base, USBD_UDCAH(udc->udp_baseaddr)); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* Only enable EP0 in and out for now, EP0 only works in FIFO mode */ 107462306a36Sopenharmony_ci for (i = 0; i <= 1; i++) { 107562306a36Sopenharmony_ci udc_realize_hwep(udc, i, ep->ep.maxpacket); 107662306a36Sopenharmony_ci uda_enable_hwepint(udc, i); 107762306a36Sopenharmony_ci udc_select_hwep(udc, i); 107862306a36Sopenharmony_ci udc_clrstall_hwep(udc, i); 107962306a36Sopenharmony_ci udc_clr_buffer_hwep(udc, i); 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci /* Device interrupt setup */ 108362306a36Sopenharmony_ci uda_clear_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW | 108462306a36Sopenharmony_ci USBD_EP_FAST)); 108562306a36Sopenharmony_ci uda_enable_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW | 108662306a36Sopenharmony_ci USBD_EP_FAST)); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci /* Set device address to 0 - called twice to force a latch in the USB 108962306a36Sopenharmony_ci engine without the need of a setup packet status closure */ 109062306a36Sopenharmony_ci udc_set_address(udc, 0); 109162306a36Sopenharmony_ci udc_set_address(udc, 0); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci /* Enable master DMA interrupts */ 109462306a36Sopenharmony_ci writel((USBD_SYS_ERR_INT | USBD_EOT_INT), 109562306a36Sopenharmony_ci USBD_DMAINTEN(udc->udp_baseaddr)); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci udc->dev_status = 0; 109862306a36Sopenharmony_ci} 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci/* 110162306a36Sopenharmony_ci * 110262306a36Sopenharmony_ci * USB device board specific events handled via callbacks 110362306a36Sopenharmony_ci * 110462306a36Sopenharmony_ci */ 110562306a36Sopenharmony_ci/* Connection change event - notify board function of change */ 110662306a36Sopenharmony_cistatic void uda_power_event(struct lpc32xx_udc *udc, u32 conn) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci /* Just notify of a connection change event (optional) */ 110962306a36Sopenharmony_ci if (udc->board->conn_chgb != NULL) 111062306a36Sopenharmony_ci udc->board->conn_chgb(conn); 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci/* Suspend/resume event - notify board function of change */ 111462306a36Sopenharmony_cistatic void uda_resm_susp_event(struct lpc32xx_udc *udc, u32 conn) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci /* Just notify of a Suspend/resume change event (optional) */ 111762306a36Sopenharmony_ci if (udc->board->susp_chgb != NULL) 111862306a36Sopenharmony_ci udc->board->susp_chgb(conn); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci if (conn) 112162306a36Sopenharmony_ci udc->suspended = 0; 112262306a36Sopenharmony_ci else 112362306a36Sopenharmony_ci udc->suspended = 1; 112462306a36Sopenharmony_ci} 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci/* Remote wakeup enable/disable - notify board function of change */ 112762306a36Sopenharmony_cistatic void uda_remwkp_cgh(struct lpc32xx_udc *udc) 112862306a36Sopenharmony_ci{ 112962306a36Sopenharmony_ci if (udc->board->rmwk_chgb != NULL) 113062306a36Sopenharmony_ci udc->board->rmwk_chgb(udc->dev_status & 113162306a36Sopenharmony_ci (1 << USB_DEVICE_REMOTE_WAKEUP)); 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci/* Reads data from FIFO, adjusts for alignment and data size */ 113562306a36Sopenharmony_cistatic void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci int n, i, bl; 113862306a36Sopenharmony_ci u16 *p16; 113962306a36Sopenharmony_ci u32 *p32, tmp, cbytes; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci /* Use optimal data transfer method based on source address and size */ 114262306a36Sopenharmony_ci switch (((uintptr_t) data) & 0x3) { 114362306a36Sopenharmony_ci case 0: /* 32-bit aligned */ 114462306a36Sopenharmony_ci p32 = (u32 *) data; 114562306a36Sopenharmony_ci cbytes = (bytes & ~0x3); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci /* Copy 32-bit aligned data first */ 114862306a36Sopenharmony_ci for (n = 0; n < cbytes; n += 4) 114962306a36Sopenharmony_ci *p32++ = readl(USBD_RXDATA(udc->udp_baseaddr)); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci /* Handle any remaining bytes */ 115262306a36Sopenharmony_ci bl = bytes - cbytes; 115362306a36Sopenharmony_ci if (bl) { 115462306a36Sopenharmony_ci tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); 115562306a36Sopenharmony_ci for (n = 0; n < bl; n++) 115662306a36Sopenharmony_ci data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF); 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci break; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci case 1: /* 8-bit aligned */ 116262306a36Sopenharmony_ci case 3: 116362306a36Sopenharmony_ci /* Each byte has to be handled independently */ 116462306a36Sopenharmony_ci for (n = 0; n < bytes; n += 4) { 116562306a36Sopenharmony_ci tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci bl = bytes - n; 116862306a36Sopenharmony_ci if (bl > 4) 116962306a36Sopenharmony_ci bl = 4; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci for (i = 0; i < bl; i++) 117262306a36Sopenharmony_ci data[n + i] = (u8) ((tmp >> (i * 8)) & 0xFF); 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci break; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci case 2: /* 16-bit aligned */ 117762306a36Sopenharmony_ci p16 = (u16 *) data; 117862306a36Sopenharmony_ci cbytes = (bytes & ~0x3); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci /* Copy 32-bit sized objects first with 16-bit alignment */ 118162306a36Sopenharmony_ci for (n = 0; n < cbytes; n += 4) { 118262306a36Sopenharmony_ci tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); 118362306a36Sopenharmony_ci *p16++ = (u16)(tmp & 0xFFFF); 118462306a36Sopenharmony_ci *p16++ = (u16)((tmp >> 16) & 0xFFFF); 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci /* Handle any remaining bytes */ 118862306a36Sopenharmony_ci bl = bytes - cbytes; 118962306a36Sopenharmony_ci if (bl) { 119062306a36Sopenharmony_ci tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); 119162306a36Sopenharmony_ci for (n = 0; n < bl; n++) 119262306a36Sopenharmony_ci data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF); 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci break; 119562306a36Sopenharmony_ci } 119662306a36Sopenharmony_ci} 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci/* Read data from the FIFO for an endpoint. This function is for endpoints (such 119962306a36Sopenharmony_ci * as EP0) that don't use DMA. This function should only be called if a packet 120062306a36Sopenharmony_ci * is known to be ready to read for the endpoint. Note that the endpoint must 120162306a36Sopenharmony_ci * be selected in the protocol engine prior to this call. */ 120262306a36Sopenharmony_cistatic u32 udc_read_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data, 120362306a36Sopenharmony_ci u32 bytes) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci u32 tmpv; 120662306a36Sopenharmony_ci int to = 1000; 120762306a36Sopenharmony_ci u32 tmp, hwrep = ((hwep & 0x1E) << 1) | CTRL_RD_EN; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci /* Setup read of endpoint */ 121062306a36Sopenharmony_ci writel(hwrep, USBD_CTRL(udc->udp_baseaddr)); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci /* Wait until packet is ready */ 121362306a36Sopenharmony_ci while ((((tmpv = readl(USBD_RXPLEN(udc->udp_baseaddr))) & 121462306a36Sopenharmony_ci PKT_RDY) == 0) && (to > 0)) 121562306a36Sopenharmony_ci to--; 121662306a36Sopenharmony_ci if (!to) 121762306a36Sopenharmony_ci dev_dbg(udc->dev, "No packet ready on FIFO EP read\n"); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci /* Mask out count */ 122062306a36Sopenharmony_ci tmp = tmpv & PKT_LNGTH_MASK; 122162306a36Sopenharmony_ci if (bytes < tmp) 122262306a36Sopenharmony_ci tmp = bytes; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci if ((tmp > 0) && (data != NULL)) 122562306a36Sopenharmony_ci udc_pop_fifo(udc, (u8 *) data, tmp); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr)); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci /* Clear the buffer */ 123062306a36Sopenharmony_ci udc_clr_buffer_hwep(udc, hwep); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci return tmp; 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci/* Stuffs data into the FIFO, adjusts for alignment and data size */ 123662306a36Sopenharmony_cistatic void udc_stuff_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci int n, i, bl; 123962306a36Sopenharmony_ci u16 *p16; 124062306a36Sopenharmony_ci u32 *p32, tmp, cbytes; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci /* Use optimal data transfer method based on source address and size */ 124362306a36Sopenharmony_ci switch (((uintptr_t) data) & 0x3) { 124462306a36Sopenharmony_ci case 0: /* 32-bit aligned */ 124562306a36Sopenharmony_ci p32 = (u32 *) data; 124662306a36Sopenharmony_ci cbytes = (bytes & ~0x3); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci /* Copy 32-bit aligned data first */ 124962306a36Sopenharmony_ci for (n = 0; n < cbytes; n += 4) 125062306a36Sopenharmony_ci writel(*p32++, USBD_TXDATA(udc->udp_baseaddr)); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* Handle any remaining bytes */ 125362306a36Sopenharmony_ci bl = bytes - cbytes; 125462306a36Sopenharmony_ci if (bl) { 125562306a36Sopenharmony_ci tmp = 0; 125662306a36Sopenharmony_ci for (n = 0; n < bl; n++) 125762306a36Sopenharmony_ci tmp |= data[cbytes + n] << (n * 8); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci break; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci case 1: /* 8-bit aligned */ 126462306a36Sopenharmony_ci case 3: 126562306a36Sopenharmony_ci /* Each byte has to be handled independently */ 126662306a36Sopenharmony_ci for (n = 0; n < bytes; n += 4) { 126762306a36Sopenharmony_ci bl = bytes - n; 126862306a36Sopenharmony_ci if (bl > 4) 126962306a36Sopenharmony_ci bl = 4; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci tmp = 0; 127262306a36Sopenharmony_ci for (i = 0; i < bl; i++) 127362306a36Sopenharmony_ci tmp |= data[n + i] << (i * 8); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci break; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci case 2: /* 16-bit aligned */ 128062306a36Sopenharmony_ci p16 = (u16 *) data; 128162306a36Sopenharmony_ci cbytes = (bytes & ~0x3); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci /* Copy 32-bit aligned data first */ 128462306a36Sopenharmony_ci for (n = 0; n < cbytes; n += 4) { 128562306a36Sopenharmony_ci tmp = *p16++ & 0xFFFF; 128662306a36Sopenharmony_ci tmp |= (*p16++ & 0xFFFF) << 16; 128762306a36Sopenharmony_ci writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci /* Handle any remaining bytes */ 129162306a36Sopenharmony_ci bl = bytes - cbytes; 129262306a36Sopenharmony_ci if (bl) { 129362306a36Sopenharmony_ci tmp = 0; 129462306a36Sopenharmony_ci for (n = 0; n < bl; n++) 129562306a36Sopenharmony_ci tmp |= data[cbytes + n] << (n * 8); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci break; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci} 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci/* Write data to the FIFO for an endpoint. This function is for endpoints (such 130462306a36Sopenharmony_ci * as EP0) that don't use DMA. Note that the endpoint must be selected in the 130562306a36Sopenharmony_ci * protocol engine prior to this call. */ 130662306a36Sopenharmony_cistatic void udc_write_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data, 130762306a36Sopenharmony_ci u32 bytes) 130862306a36Sopenharmony_ci{ 130962306a36Sopenharmony_ci u32 hwwep = ((hwep & 0x1E) << 1) | CTRL_WR_EN; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if ((bytes > 0) && (data == NULL)) 131262306a36Sopenharmony_ci return; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci /* Setup write of endpoint */ 131562306a36Sopenharmony_ci writel(hwwep, USBD_CTRL(udc->udp_baseaddr)); 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci writel(bytes, USBD_TXPLEN(udc->udp_baseaddr)); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci /* Need at least 1 byte to trigger TX */ 132062306a36Sopenharmony_ci if (bytes == 0) 132162306a36Sopenharmony_ci writel(0, USBD_TXDATA(udc->udp_baseaddr)); 132262306a36Sopenharmony_ci else 132362306a36Sopenharmony_ci udc_stuff_fifo(udc, (u8 *) data, bytes); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr)); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci udc_val_buffer_hwep(udc, hwep); 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci/* USB device reset - resets USB to a default state with just EP0 133162306a36Sopenharmony_ci enabled */ 133262306a36Sopenharmony_cistatic void uda_usb_reset(struct lpc32xx_udc *udc) 133362306a36Sopenharmony_ci{ 133462306a36Sopenharmony_ci u32 i = 0; 133562306a36Sopenharmony_ci /* Re-init device controller and EP0 */ 133662306a36Sopenharmony_ci udc_enable(udc); 133762306a36Sopenharmony_ci udc->gadget.speed = USB_SPEED_FULL; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci for (i = 1; i < NUM_ENDPOINTS; i++) { 134062306a36Sopenharmony_ci struct lpc32xx_ep *ep = &udc->ep[i]; 134162306a36Sopenharmony_ci ep->req_pending = 0; 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci} 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci/* Send a ZLP on EP0 */ 134662306a36Sopenharmony_cistatic void udc_ep0_send_zlp(struct lpc32xx_udc *udc) 134762306a36Sopenharmony_ci{ 134862306a36Sopenharmony_ci udc_write_hwep(udc, EP_IN, NULL, 0); 134962306a36Sopenharmony_ci} 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci/* Get current frame number */ 135262306a36Sopenharmony_cistatic u16 udc_get_current_frame(struct lpc32xx_udc *udc) 135362306a36Sopenharmony_ci{ 135462306a36Sopenharmony_ci u16 flo, fhi; 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci udc_protocol_cmd_w(udc, CMD_RD_FRAME); 135762306a36Sopenharmony_ci flo = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME); 135862306a36Sopenharmony_ci fhi = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci return (fhi << 8) | flo; 136162306a36Sopenharmony_ci} 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci/* Set the device as configured - enables all endpoints */ 136462306a36Sopenharmony_cistatic inline void udc_set_device_configured(struct lpc32xx_udc *udc) 136562306a36Sopenharmony_ci{ 136662306a36Sopenharmony_ci udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(CONF_DVICE)); 136762306a36Sopenharmony_ci} 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci/* Set the device as unconfigured - disables all endpoints */ 137062306a36Sopenharmony_cistatic inline void udc_set_device_unconfigured(struct lpc32xx_udc *udc) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0)); 137362306a36Sopenharmony_ci} 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci/* reinit == restore initial software state */ 137662306a36Sopenharmony_cistatic void udc_reinit(struct lpc32xx_udc *udc) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci u32 i; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci INIT_LIST_HEAD(&udc->gadget.ep_list); 138162306a36Sopenharmony_ci INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci for (i = 0; i < NUM_ENDPOINTS; i++) { 138462306a36Sopenharmony_ci struct lpc32xx_ep *ep = &udc->ep[i]; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (i != 0) 138762306a36Sopenharmony_ci list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); 138862306a36Sopenharmony_ci usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket); 138962306a36Sopenharmony_ci INIT_LIST_HEAD(&ep->queue); 139062306a36Sopenharmony_ci ep->req_pending = 0; 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci udc->ep0state = WAIT_FOR_SETUP; 139462306a36Sopenharmony_ci} 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci/* Must be called with lock */ 139762306a36Sopenharmony_cistatic void done(struct lpc32xx_ep *ep, struct lpc32xx_request *req, int status) 139862306a36Sopenharmony_ci{ 139962306a36Sopenharmony_ci struct lpc32xx_udc *udc = ep->udc; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci list_del_init(&req->queue); 140262306a36Sopenharmony_ci if (req->req.status == -EINPROGRESS) 140362306a36Sopenharmony_ci req->req.status = status; 140462306a36Sopenharmony_ci else 140562306a36Sopenharmony_ci status = req->req.status; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci if (ep->lep) { 140862306a36Sopenharmony_ci usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci /* Free DDs */ 141162306a36Sopenharmony_ci udc_dd_free(udc, req->dd_desc_ptr); 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (status && status != -ESHUTDOWN) 141562306a36Sopenharmony_ci ep_dbg(ep, "%s done %p, status %d\n", ep->ep.name, req, status); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci ep->req_pending = 0; 141862306a36Sopenharmony_ci spin_unlock(&udc->lock); 141962306a36Sopenharmony_ci usb_gadget_giveback_request(&ep->ep, &req->req); 142062306a36Sopenharmony_ci spin_lock(&udc->lock); 142162306a36Sopenharmony_ci} 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci/* Must be called with lock */ 142462306a36Sopenharmony_cistatic void nuke(struct lpc32xx_ep *ep, int status) 142562306a36Sopenharmony_ci{ 142662306a36Sopenharmony_ci struct lpc32xx_request *req; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci while (!list_empty(&ep->queue)) { 142962306a36Sopenharmony_ci req = list_entry(ep->queue.next, struct lpc32xx_request, queue); 143062306a36Sopenharmony_ci done(ep, req, status); 143162306a36Sopenharmony_ci } 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (status == -ESHUTDOWN) { 143462306a36Sopenharmony_ci uda_disable_hwepint(ep->udc, ep->hwep_num); 143562306a36Sopenharmony_ci udc_disable_hwep(ep->udc, ep->hwep_num); 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci} 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci/* IN endpoint 0 transfer */ 144062306a36Sopenharmony_cistatic int udc_ep0_in_req(struct lpc32xx_udc *udc) 144162306a36Sopenharmony_ci{ 144262306a36Sopenharmony_ci struct lpc32xx_request *req; 144362306a36Sopenharmony_ci struct lpc32xx_ep *ep0 = &udc->ep[0]; 144462306a36Sopenharmony_ci u32 tsend, ts = 0; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci if (list_empty(&ep0->queue)) 144762306a36Sopenharmony_ci /* Nothing to send */ 144862306a36Sopenharmony_ci return 0; 144962306a36Sopenharmony_ci else 145062306a36Sopenharmony_ci req = list_entry(ep0->queue.next, struct lpc32xx_request, 145162306a36Sopenharmony_ci queue); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci tsend = ts = req->req.length - req->req.actual; 145462306a36Sopenharmony_ci if (ts == 0) { 145562306a36Sopenharmony_ci /* Send a ZLP */ 145662306a36Sopenharmony_ci udc_ep0_send_zlp(udc); 145762306a36Sopenharmony_ci done(ep0, req, 0); 145862306a36Sopenharmony_ci return 1; 145962306a36Sopenharmony_ci } else if (ts > ep0->ep.maxpacket) 146062306a36Sopenharmony_ci ts = ep0->ep.maxpacket; /* Just send what we can */ 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci /* Write data to the EP0 FIFO and start transfer */ 146362306a36Sopenharmony_ci udc_write_hwep(udc, EP_IN, (req->req.buf + req->req.actual), ts); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci /* Increment data pointer */ 146662306a36Sopenharmony_ci req->req.actual += ts; 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci if (tsend >= ep0->ep.maxpacket) 146962306a36Sopenharmony_ci return 0; /* Stay in data transfer state */ 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci /* Transfer request is complete */ 147262306a36Sopenharmony_ci udc->ep0state = WAIT_FOR_SETUP; 147362306a36Sopenharmony_ci done(ep0, req, 0); 147462306a36Sopenharmony_ci return 1; 147562306a36Sopenharmony_ci} 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci/* OUT endpoint 0 transfer */ 147862306a36Sopenharmony_cistatic int udc_ep0_out_req(struct lpc32xx_udc *udc) 147962306a36Sopenharmony_ci{ 148062306a36Sopenharmony_ci struct lpc32xx_request *req; 148162306a36Sopenharmony_ci struct lpc32xx_ep *ep0 = &udc->ep[0]; 148262306a36Sopenharmony_ci u32 tr, bufferspace; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci if (list_empty(&ep0->queue)) 148562306a36Sopenharmony_ci return 0; 148662306a36Sopenharmony_ci else 148762306a36Sopenharmony_ci req = list_entry(ep0->queue.next, struct lpc32xx_request, 148862306a36Sopenharmony_ci queue); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci if (req) { 149162306a36Sopenharmony_ci if (req->req.length == 0) { 149262306a36Sopenharmony_ci /* Just dequeue request */ 149362306a36Sopenharmony_ci done(ep0, req, 0); 149462306a36Sopenharmony_ci udc->ep0state = WAIT_FOR_SETUP; 149562306a36Sopenharmony_ci return 1; 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci /* Get data from FIFO */ 149962306a36Sopenharmony_ci bufferspace = req->req.length - req->req.actual; 150062306a36Sopenharmony_ci if (bufferspace > ep0->ep.maxpacket) 150162306a36Sopenharmony_ci bufferspace = ep0->ep.maxpacket; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci /* Copy data to buffer */ 150462306a36Sopenharmony_ci prefetchw(req->req.buf + req->req.actual); 150562306a36Sopenharmony_ci tr = udc_read_hwep(udc, EP_OUT, req->req.buf + req->req.actual, 150662306a36Sopenharmony_ci bufferspace); 150762306a36Sopenharmony_ci req->req.actual += bufferspace; 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci if (tr < ep0->ep.maxpacket) { 151062306a36Sopenharmony_ci /* This is the last packet */ 151162306a36Sopenharmony_ci done(ep0, req, 0); 151262306a36Sopenharmony_ci udc->ep0state = WAIT_FOR_SETUP; 151362306a36Sopenharmony_ci return 1; 151462306a36Sopenharmony_ci } 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci return 0; 151862306a36Sopenharmony_ci} 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci/* Must be called with lock */ 152162306a36Sopenharmony_cistatic void stop_activity(struct lpc32xx_udc *udc) 152262306a36Sopenharmony_ci{ 152362306a36Sopenharmony_ci struct usb_gadget_driver *driver = udc->driver; 152462306a36Sopenharmony_ci int i; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci if (udc->gadget.speed == USB_SPEED_UNKNOWN) 152762306a36Sopenharmony_ci driver = NULL; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci udc->gadget.speed = USB_SPEED_UNKNOWN; 153062306a36Sopenharmony_ci udc->suspended = 0; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci for (i = 0; i < NUM_ENDPOINTS; i++) { 153362306a36Sopenharmony_ci struct lpc32xx_ep *ep = &udc->ep[i]; 153462306a36Sopenharmony_ci nuke(ep, -ESHUTDOWN); 153562306a36Sopenharmony_ci } 153662306a36Sopenharmony_ci if (driver) { 153762306a36Sopenharmony_ci spin_unlock(&udc->lock); 153862306a36Sopenharmony_ci driver->disconnect(&udc->gadget); 153962306a36Sopenharmony_ci spin_lock(&udc->lock); 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci isp1301_pullup_enable(udc, 0, 0); 154362306a36Sopenharmony_ci udc_disable(udc); 154462306a36Sopenharmony_ci udc_reinit(udc); 154562306a36Sopenharmony_ci} 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci/* 154862306a36Sopenharmony_ci * Activate or kill host pullup 154962306a36Sopenharmony_ci * Can be called with or without lock 155062306a36Sopenharmony_ci */ 155162306a36Sopenharmony_cistatic void pullup(struct lpc32xx_udc *udc, int is_on) 155262306a36Sopenharmony_ci{ 155362306a36Sopenharmony_ci if (!udc->clocked) 155462306a36Sopenharmony_ci return; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci if (!udc->enabled || !udc->vbus) 155762306a36Sopenharmony_ci is_on = 0; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci if (is_on != udc->pullup) 156062306a36Sopenharmony_ci isp1301_pullup_enable(udc, is_on, 0); 156162306a36Sopenharmony_ci} 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci/* Must be called without lock */ 156462306a36Sopenharmony_cistatic int lpc32xx_ep_disable(struct usb_ep *_ep) 156562306a36Sopenharmony_ci{ 156662306a36Sopenharmony_ci struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); 156762306a36Sopenharmony_ci struct lpc32xx_udc *udc = ep->udc; 156862306a36Sopenharmony_ci unsigned long flags; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci if ((ep->hwep_num_base == 0) || (ep->hwep_num == 0)) 157162306a36Sopenharmony_ci return -EINVAL; 157262306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci nuke(ep, -ESHUTDOWN); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci /* Clear all DMA statuses for this EP */ 157762306a36Sopenharmony_ci udc_ep_dma_disable(udc, ep->hwep_num); 157862306a36Sopenharmony_ci writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr)); 157962306a36Sopenharmony_ci writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr)); 158062306a36Sopenharmony_ci writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr)); 158162306a36Sopenharmony_ci writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr)); 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci /* Remove the DD pointer in the UDCA */ 158462306a36Sopenharmony_ci udc->udca_v_base[ep->hwep_num] = 0; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci /* Disable and reset endpoint and interrupt */ 158762306a36Sopenharmony_ci uda_clear_hwepint(udc, ep->hwep_num); 158862306a36Sopenharmony_ci udc_unrealize_hwep(udc, ep->hwep_num); 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci ep->hwep_num = 0; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci atomic_dec(&udc->enabled_ep_cnt); 159562306a36Sopenharmony_ci wake_up(&udc->ep_disable_wait_queue); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci return 0; 159862306a36Sopenharmony_ci} 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci/* Must be called without lock */ 160162306a36Sopenharmony_cistatic int lpc32xx_ep_enable(struct usb_ep *_ep, 160262306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 160362306a36Sopenharmony_ci{ 160462306a36Sopenharmony_ci struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); 160562306a36Sopenharmony_ci struct lpc32xx_udc *udc; 160662306a36Sopenharmony_ci u16 maxpacket; 160762306a36Sopenharmony_ci u32 tmp; 160862306a36Sopenharmony_ci unsigned long flags; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci /* Verify EP data */ 161162306a36Sopenharmony_ci if ((!_ep) || (!ep) || (!desc) || 161262306a36Sopenharmony_ci (desc->bDescriptorType != USB_DT_ENDPOINT)) 161362306a36Sopenharmony_ci return -EINVAL; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci udc = ep->udc; 161662306a36Sopenharmony_ci maxpacket = usb_endpoint_maxp(desc); 161762306a36Sopenharmony_ci if ((maxpacket == 0) || (maxpacket > ep->maxpacket)) { 161862306a36Sopenharmony_ci dev_dbg(udc->dev, "bad ep descriptor's packet size\n"); 161962306a36Sopenharmony_ci return -EINVAL; 162062306a36Sopenharmony_ci } 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci /* Don't touch EP0 */ 162362306a36Sopenharmony_ci if (ep->hwep_num_base == 0) { 162462306a36Sopenharmony_ci dev_dbg(udc->dev, "Can't re-enable EP0!!!\n"); 162562306a36Sopenharmony_ci return -EINVAL; 162662306a36Sopenharmony_ci } 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci /* Is driver ready? */ 162962306a36Sopenharmony_ci if ((!udc->driver) || (udc->gadget.speed == USB_SPEED_UNKNOWN)) { 163062306a36Sopenharmony_ci dev_dbg(udc->dev, "bogus device state\n"); 163162306a36Sopenharmony_ci return -ESHUTDOWN; 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; 163562306a36Sopenharmony_ci switch (tmp) { 163662306a36Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 163762306a36Sopenharmony_ci return -EINVAL; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 164062306a36Sopenharmony_ci if (maxpacket > ep->maxpacket) { 164162306a36Sopenharmony_ci dev_dbg(udc->dev, 164262306a36Sopenharmony_ci "Bad INT endpoint maxpacket %d\n", maxpacket); 164362306a36Sopenharmony_ci return -EINVAL; 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci break; 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 164862306a36Sopenharmony_ci switch (maxpacket) { 164962306a36Sopenharmony_ci case 8: 165062306a36Sopenharmony_ci case 16: 165162306a36Sopenharmony_ci case 32: 165262306a36Sopenharmony_ci case 64: 165362306a36Sopenharmony_ci break; 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci default: 165662306a36Sopenharmony_ci dev_dbg(udc->dev, 165762306a36Sopenharmony_ci "Bad BULK endpoint maxpacket %d\n", maxpacket); 165862306a36Sopenharmony_ci return -EINVAL; 165962306a36Sopenharmony_ci } 166062306a36Sopenharmony_ci break; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 166362306a36Sopenharmony_ci break; 166462306a36Sopenharmony_ci } 166562306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci /* Initialize endpoint to match the selected descriptor */ 166862306a36Sopenharmony_ci ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0; 166962306a36Sopenharmony_ci ep->ep.maxpacket = maxpacket; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci /* Map hardware endpoint from base and direction */ 167262306a36Sopenharmony_ci if (ep->is_in) 167362306a36Sopenharmony_ci /* IN endpoints are offset 1 from the OUT endpoint */ 167462306a36Sopenharmony_ci ep->hwep_num = ep->hwep_num_base + EP_IN; 167562306a36Sopenharmony_ci else 167662306a36Sopenharmony_ci ep->hwep_num = ep->hwep_num_base; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci ep_dbg(ep, "EP enabled: %s, HW:%d, MP:%d IN:%d\n", ep->ep.name, 167962306a36Sopenharmony_ci ep->hwep_num, maxpacket, (ep->is_in == 1)); 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci /* Realize the endpoint, interrupt is enabled later when 168262306a36Sopenharmony_ci * buffers are queued, IN EPs will NAK until buffers are ready */ 168362306a36Sopenharmony_ci udc_realize_hwep(udc, ep->hwep_num, ep->ep.maxpacket); 168462306a36Sopenharmony_ci udc_clr_buffer_hwep(udc, ep->hwep_num); 168562306a36Sopenharmony_ci uda_disable_hwepint(udc, ep->hwep_num); 168662306a36Sopenharmony_ci udc_clrstall_hwep(udc, ep->hwep_num); 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci /* Clear all DMA statuses for this EP */ 168962306a36Sopenharmony_ci udc_ep_dma_disable(udc, ep->hwep_num); 169062306a36Sopenharmony_ci writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr)); 169162306a36Sopenharmony_ci writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr)); 169262306a36Sopenharmony_ci writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr)); 169362306a36Sopenharmony_ci writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr)); 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci atomic_inc(&udc->enabled_ep_cnt); 169862306a36Sopenharmony_ci return 0; 169962306a36Sopenharmony_ci} 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci/* 170262306a36Sopenharmony_ci * Allocate a USB request list 170362306a36Sopenharmony_ci * Can be called with or without lock 170462306a36Sopenharmony_ci */ 170562306a36Sopenharmony_cistatic struct usb_request *lpc32xx_ep_alloc_request(struct usb_ep *_ep, 170662306a36Sopenharmony_ci gfp_t gfp_flags) 170762306a36Sopenharmony_ci{ 170862306a36Sopenharmony_ci struct lpc32xx_request *req; 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci req = kzalloc(sizeof(struct lpc32xx_request), gfp_flags); 171162306a36Sopenharmony_ci if (!req) 171262306a36Sopenharmony_ci return NULL; 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci INIT_LIST_HEAD(&req->queue); 171562306a36Sopenharmony_ci return &req->req; 171662306a36Sopenharmony_ci} 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci/* 171962306a36Sopenharmony_ci * De-allocate a USB request list 172062306a36Sopenharmony_ci * Can be called with or without lock 172162306a36Sopenharmony_ci */ 172262306a36Sopenharmony_cistatic void lpc32xx_ep_free_request(struct usb_ep *_ep, 172362306a36Sopenharmony_ci struct usb_request *_req) 172462306a36Sopenharmony_ci{ 172562306a36Sopenharmony_ci struct lpc32xx_request *req; 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci req = container_of(_req, struct lpc32xx_request, req); 172862306a36Sopenharmony_ci BUG_ON(!list_empty(&req->queue)); 172962306a36Sopenharmony_ci kfree(req); 173062306a36Sopenharmony_ci} 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci/* Must be called without lock */ 173362306a36Sopenharmony_cistatic int lpc32xx_ep_queue(struct usb_ep *_ep, 173462306a36Sopenharmony_ci struct usb_request *_req, gfp_t gfp_flags) 173562306a36Sopenharmony_ci{ 173662306a36Sopenharmony_ci struct lpc32xx_request *req; 173762306a36Sopenharmony_ci struct lpc32xx_ep *ep; 173862306a36Sopenharmony_ci struct lpc32xx_udc *udc; 173962306a36Sopenharmony_ci unsigned long flags; 174062306a36Sopenharmony_ci int status = 0; 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci req = container_of(_req, struct lpc32xx_request, req); 174362306a36Sopenharmony_ci ep = container_of(_ep, struct lpc32xx_ep, ep); 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci if (!_ep || !_req || !_req->complete || !_req->buf || 174662306a36Sopenharmony_ci !list_empty(&req->queue)) 174762306a36Sopenharmony_ci return -EINVAL; 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci udc = ep->udc; 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci if (udc->gadget.speed == USB_SPEED_UNKNOWN) 175262306a36Sopenharmony_ci return -EPIPE; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci if (ep->lep) { 175562306a36Sopenharmony_ci struct lpc32xx_usbd_dd_gad *dd; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci status = usb_gadget_map_request(&udc->gadget, _req, ep->is_in); 175862306a36Sopenharmony_ci if (status) 175962306a36Sopenharmony_ci return status; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci /* For the request, build a list of DDs */ 176262306a36Sopenharmony_ci dd = udc_dd_alloc(udc); 176362306a36Sopenharmony_ci if (!dd) { 176462306a36Sopenharmony_ci /* Error allocating DD */ 176562306a36Sopenharmony_ci return -ENOMEM; 176662306a36Sopenharmony_ci } 176762306a36Sopenharmony_ci req->dd_desc_ptr = dd; 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci /* Setup the DMA descriptor */ 177062306a36Sopenharmony_ci dd->dd_next_phy = dd->dd_next_v = 0; 177162306a36Sopenharmony_ci dd->dd_buffer_addr = req->req.dma; 177262306a36Sopenharmony_ci dd->dd_status = 0; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci /* Special handling for ISO EPs */ 177562306a36Sopenharmony_ci if (ep->eptype == EP_ISO_TYPE) { 177662306a36Sopenharmony_ci dd->dd_setup = DD_SETUP_ISO_EP | 177762306a36Sopenharmony_ci DD_SETUP_PACKETLEN(0) | 177862306a36Sopenharmony_ci DD_SETUP_DMALENBYTES(1); 177962306a36Sopenharmony_ci dd->dd_iso_ps_mem_addr = dd->this_dma + 24; 178062306a36Sopenharmony_ci if (ep->is_in) 178162306a36Sopenharmony_ci dd->iso_status[0] = req->req.length; 178262306a36Sopenharmony_ci else 178362306a36Sopenharmony_ci dd->iso_status[0] = 0; 178462306a36Sopenharmony_ci } else 178562306a36Sopenharmony_ci dd->dd_setup = DD_SETUP_PACKETLEN(ep->ep.maxpacket) | 178662306a36Sopenharmony_ci DD_SETUP_DMALENBYTES(req->req.length); 178762306a36Sopenharmony_ci } 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci ep_dbg(ep, "%s queue req %p len %d buf %p (in=%d) z=%d\n", _ep->name, 179062306a36Sopenharmony_ci _req, _req->length, _req->buf, ep->is_in, _req->zero); 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci _req->status = -EINPROGRESS; 179562306a36Sopenharmony_ci _req->actual = 0; 179662306a36Sopenharmony_ci req->send_zlp = _req->zero; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci /* Kickstart empty queues */ 179962306a36Sopenharmony_ci if (list_empty(&ep->queue)) { 180062306a36Sopenharmony_ci list_add_tail(&req->queue, &ep->queue); 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci if (ep->hwep_num_base == 0) { 180362306a36Sopenharmony_ci /* Handle expected data direction */ 180462306a36Sopenharmony_ci if (ep->is_in) { 180562306a36Sopenharmony_ci /* IN packet to host */ 180662306a36Sopenharmony_ci udc->ep0state = DATA_IN; 180762306a36Sopenharmony_ci status = udc_ep0_in_req(udc); 180862306a36Sopenharmony_ci } else { 180962306a36Sopenharmony_ci /* OUT packet from host */ 181062306a36Sopenharmony_ci udc->ep0state = DATA_OUT; 181162306a36Sopenharmony_ci status = udc_ep0_out_req(udc); 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci } else if (ep->is_in) { 181462306a36Sopenharmony_ci /* IN packet to host and kick off transfer */ 181562306a36Sopenharmony_ci if (!ep->req_pending) 181662306a36Sopenharmony_ci udc_ep_in_req_dma(udc, ep); 181762306a36Sopenharmony_ci } else 181862306a36Sopenharmony_ci /* OUT packet from host and kick off list */ 181962306a36Sopenharmony_ci if (!ep->req_pending) 182062306a36Sopenharmony_ci udc_ep_out_req_dma(udc, ep); 182162306a36Sopenharmony_ci } else 182262306a36Sopenharmony_ci list_add_tail(&req->queue, &ep->queue); 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci return (status < 0) ? status : 0; 182762306a36Sopenharmony_ci} 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci/* Must be called without lock */ 183062306a36Sopenharmony_cistatic int lpc32xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) 183162306a36Sopenharmony_ci{ 183262306a36Sopenharmony_ci struct lpc32xx_ep *ep; 183362306a36Sopenharmony_ci struct lpc32xx_request *req = NULL, *iter; 183462306a36Sopenharmony_ci unsigned long flags; 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci ep = container_of(_ep, struct lpc32xx_ep, ep); 183762306a36Sopenharmony_ci if (!_ep || ep->hwep_num_base == 0) 183862306a36Sopenharmony_ci return -EINVAL; 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci spin_lock_irqsave(&ep->udc->lock, flags); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci /* make sure it's actually queued on this endpoint */ 184362306a36Sopenharmony_ci list_for_each_entry(iter, &ep->queue, queue) { 184462306a36Sopenharmony_ci if (&iter->req != _req) 184562306a36Sopenharmony_ci continue; 184662306a36Sopenharmony_ci req = iter; 184762306a36Sopenharmony_ci break; 184862306a36Sopenharmony_ci } 184962306a36Sopenharmony_ci if (!req) { 185062306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->udc->lock, flags); 185162306a36Sopenharmony_ci return -EINVAL; 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci done(ep, req, -ECONNRESET); 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->udc->lock, flags); 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci return 0; 185962306a36Sopenharmony_ci} 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci/* Must be called without lock */ 186262306a36Sopenharmony_cistatic int lpc32xx_ep_set_halt(struct usb_ep *_ep, int value) 186362306a36Sopenharmony_ci{ 186462306a36Sopenharmony_ci struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); 186562306a36Sopenharmony_ci struct lpc32xx_udc *udc; 186662306a36Sopenharmony_ci unsigned long flags; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci if ((!ep) || (ep->hwep_num <= 1)) 186962306a36Sopenharmony_ci return -EINVAL; 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci /* Don't halt an IN EP */ 187262306a36Sopenharmony_ci if (ep->is_in) 187362306a36Sopenharmony_ci return -EAGAIN; 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci udc = ep->udc; 187662306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci if (value == 1) { 187962306a36Sopenharmony_ci /* stall */ 188062306a36Sopenharmony_ci udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num), 188162306a36Sopenharmony_ci DAT_WR_BYTE(EP_STAT_ST)); 188262306a36Sopenharmony_ci } else { 188362306a36Sopenharmony_ci /* End stall */ 188462306a36Sopenharmony_ci ep->wedge = 0; 188562306a36Sopenharmony_ci udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num), 188662306a36Sopenharmony_ci DAT_WR_BYTE(0)); 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci return 0; 189262306a36Sopenharmony_ci} 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci/* set the halt feature and ignores clear requests */ 189562306a36Sopenharmony_cistatic int lpc32xx_ep_set_wedge(struct usb_ep *_ep) 189662306a36Sopenharmony_ci{ 189762306a36Sopenharmony_ci struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci if (!_ep || !ep->udc) 190062306a36Sopenharmony_ci return -EINVAL; 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci ep->wedge = 1; 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci return usb_ep_set_halt(_ep); 190562306a36Sopenharmony_ci} 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_cistatic const struct usb_ep_ops lpc32xx_ep_ops = { 190862306a36Sopenharmony_ci .enable = lpc32xx_ep_enable, 190962306a36Sopenharmony_ci .disable = lpc32xx_ep_disable, 191062306a36Sopenharmony_ci .alloc_request = lpc32xx_ep_alloc_request, 191162306a36Sopenharmony_ci .free_request = lpc32xx_ep_free_request, 191262306a36Sopenharmony_ci .queue = lpc32xx_ep_queue, 191362306a36Sopenharmony_ci .dequeue = lpc32xx_ep_dequeue, 191462306a36Sopenharmony_ci .set_halt = lpc32xx_ep_set_halt, 191562306a36Sopenharmony_ci .set_wedge = lpc32xx_ep_set_wedge, 191662306a36Sopenharmony_ci}; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci/* Send a ZLP on a non-0 IN EP */ 191962306a36Sopenharmony_cistatic void udc_send_in_zlp(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) 192062306a36Sopenharmony_ci{ 192162306a36Sopenharmony_ci /* Clear EP status */ 192262306a36Sopenharmony_ci udc_clearep_getsts(udc, ep->hwep_num); 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci /* Send ZLP via FIFO mechanism */ 192562306a36Sopenharmony_ci udc_write_hwep(udc, ep->hwep_num, NULL, 0); 192662306a36Sopenharmony_ci} 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci/* 192962306a36Sopenharmony_ci * Handle EP completion for ZLP 193062306a36Sopenharmony_ci * This function will only be called when a delayed ZLP needs to be sent out 193162306a36Sopenharmony_ci * after a DMA transfer has filled both buffers. 193262306a36Sopenharmony_ci */ 193362306a36Sopenharmony_cistatic void udc_handle_eps(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) 193462306a36Sopenharmony_ci{ 193562306a36Sopenharmony_ci u32 epstatus; 193662306a36Sopenharmony_ci struct lpc32xx_request *req; 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci if (ep->hwep_num <= 0) 193962306a36Sopenharmony_ci return; 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci uda_clear_hwepint(udc, ep->hwep_num); 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci /* If this interrupt isn't enabled, return now */ 194462306a36Sopenharmony_ci if (!(udc->enabled_hwepints & (1 << ep->hwep_num))) 194562306a36Sopenharmony_ci return; 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci /* Get endpoint status */ 194862306a36Sopenharmony_ci epstatus = udc_clearep_getsts(udc, ep->hwep_num); 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci /* 195162306a36Sopenharmony_ci * This should never happen, but protect against writing to the 195262306a36Sopenharmony_ci * buffer when full. 195362306a36Sopenharmony_ci */ 195462306a36Sopenharmony_ci if (epstatus & EP_SEL_F) 195562306a36Sopenharmony_ci return; 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci if (ep->is_in) { 195862306a36Sopenharmony_ci udc_send_in_zlp(udc, ep); 195962306a36Sopenharmony_ci uda_disable_hwepint(udc, ep->hwep_num); 196062306a36Sopenharmony_ci } else 196162306a36Sopenharmony_ci return; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci /* If there isn't a request waiting, something went wrong */ 196462306a36Sopenharmony_ci req = list_entry(ep->queue.next, struct lpc32xx_request, queue); 196562306a36Sopenharmony_ci if (req) { 196662306a36Sopenharmony_ci done(ep, req, 0); 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci /* Start another request if ready */ 196962306a36Sopenharmony_ci if (!list_empty(&ep->queue)) { 197062306a36Sopenharmony_ci if (ep->is_in) 197162306a36Sopenharmony_ci udc_ep_in_req_dma(udc, ep); 197262306a36Sopenharmony_ci else 197362306a36Sopenharmony_ci udc_ep_out_req_dma(udc, ep); 197462306a36Sopenharmony_ci } else 197562306a36Sopenharmony_ci ep->req_pending = 0; 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci} 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci/* DMA end of transfer completion */ 198162306a36Sopenharmony_cistatic void udc_handle_dma_ep(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) 198262306a36Sopenharmony_ci{ 198362306a36Sopenharmony_ci u32 status; 198462306a36Sopenharmony_ci struct lpc32xx_request *req; 198562306a36Sopenharmony_ci struct lpc32xx_usbd_dd_gad *dd; 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci#ifdef CONFIG_USB_GADGET_DEBUG_FILES 198862306a36Sopenharmony_ci ep->totalints++; 198962306a36Sopenharmony_ci#endif 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci req = list_entry(ep->queue.next, struct lpc32xx_request, queue); 199262306a36Sopenharmony_ci if (!req) { 199362306a36Sopenharmony_ci ep_err(ep, "DMA interrupt on no req!\n"); 199462306a36Sopenharmony_ci return; 199562306a36Sopenharmony_ci } 199662306a36Sopenharmony_ci dd = req->dd_desc_ptr; 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci /* DMA descriptor should always be retired for this call */ 199962306a36Sopenharmony_ci if (!(dd->dd_status & DD_STATUS_DD_RETIRED)) 200062306a36Sopenharmony_ci ep_warn(ep, "DMA descriptor did not retire\n"); 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci /* Disable DMA */ 200362306a36Sopenharmony_ci udc_ep_dma_disable(udc, ep->hwep_num); 200462306a36Sopenharmony_ci writel((1 << ep->hwep_num), USBD_EOTINTCLR(udc->udp_baseaddr)); 200562306a36Sopenharmony_ci writel((1 << ep->hwep_num), USBD_NDDRTINTCLR(udc->udp_baseaddr)); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci /* System error? */ 200862306a36Sopenharmony_ci if (readl(USBD_SYSERRTINTST(udc->udp_baseaddr)) & 200962306a36Sopenharmony_ci (1 << ep->hwep_num)) { 201062306a36Sopenharmony_ci writel((1 << ep->hwep_num), 201162306a36Sopenharmony_ci USBD_SYSERRTINTCLR(udc->udp_baseaddr)); 201262306a36Sopenharmony_ci ep_err(ep, "AHB critical error!\n"); 201362306a36Sopenharmony_ci ep->req_pending = 0; 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci /* The error could have occurred on a packet of a multipacket 201662306a36Sopenharmony_ci * transfer, so recovering the transfer is not possible. Close 201762306a36Sopenharmony_ci * the request with an error */ 201862306a36Sopenharmony_ci done(ep, req, -ECONNABORTED); 201962306a36Sopenharmony_ci return; 202062306a36Sopenharmony_ci } 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci /* Handle the current DD's status */ 202362306a36Sopenharmony_ci status = dd->dd_status; 202462306a36Sopenharmony_ci switch (status & DD_STATUS_STS_MASK) { 202562306a36Sopenharmony_ci case DD_STATUS_STS_NS: 202662306a36Sopenharmony_ci /* DD not serviced? This shouldn't happen! */ 202762306a36Sopenharmony_ci ep->req_pending = 0; 202862306a36Sopenharmony_ci ep_err(ep, "DMA critical EP error: DD not serviced (0x%x)!\n", 202962306a36Sopenharmony_ci status); 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci done(ep, req, -ECONNABORTED); 203262306a36Sopenharmony_ci return; 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci case DD_STATUS_STS_BS: 203562306a36Sopenharmony_ci /* Interrupt only fires on EOT - This shouldn't happen! */ 203662306a36Sopenharmony_ci ep->req_pending = 0; 203762306a36Sopenharmony_ci ep_err(ep, "DMA critical EP error: EOT prior to service completion (0x%x)!\n", 203862306a36Sopenharmony_ci status); 203962306a36Sopenharmony_ci done(ep, req, -ECONNABORTED); 204062306a36Sopenharmony_ci return; 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci case DD_STATUS_STS_NC: 204362306a36Sopenharmony_ci case DD_STATUS_STS_DUR: 204462306a36Sopenharmony_ci /* Really just a short packet, not an underrun */ 204562306a36Sopenharmony_ci /* This is a good status and what we expect */ 204662306a36Sopenharmony_ci break; 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci default: 204962306a36Sopenharmony_ci /* Data overrun, system error, or unknown */ 205062306a36Sopenharmony_ci ep->req_pending = 0; 205162306a36Sopenharmony_ci ep_err(ep, "DMA critical EP error: System error (0x%x)!\n", 205262306a36Sopenharmony_ci status); 205362306a36Sopenharmony_ci done(ep, req, -ECONNABORTED); 205462306a36Sopenharmony_ci return; 205562306a36Sopenharmony_ci } 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci /* ISO endpoints are handled differently */ 205862306a36Sopenharmony_ci if (ep->eptype == EP_ISO_TYPE) { 205962306a36Sopenharmony_ci if (ep->is_in) 206062306a36Sopenharmony_ci req->req.actual = req->req.length; 206162306a36Sopenharmony_ci else 206262306a36Sopenharmony_ci req->req.actual = dd->iso_status[0] & 0xFFFF; 206362306a36Sopenharmony_ci } else 206462306a36Sopenharmony_ci req->req.actual += DD_STATUS_CURDMACNT(status); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci /* Send a ZLP if necessary. This will be done for non-int 206762306a36Sopenharmony_ci * packets which have a size that is a divisor of MAXP */ 206862306a36Sopenharmony_ci if (req->send_zlp) { 206962306a36Sopenharmony_ci /* 207062306a36Sopenharmony_ci * If at least 1 buffer is available, send the ZLP now. 207162306a36Sopenharmony_ci * Otherwise, the ZLP send needs to be deferred until a 207262306a36Sopenharmony_ci * buffer is available. 207362306a36Sopenharmony_ci */ 207462306a36Sopenharmony_ci if (udc_clearep_getsts(udc, ep->hwep_num) & EP_SEL_F) { 207562306a36Sopenharmony_ci udc_clearep_getsts(udc, ep->hwep_num); 207662306a36Sopenharmony_ci uda_enable_hwepint(udc, ep->hwep_num); 207762306a36Sopenharmony_ci udc_clearep_getsts(udc, ep->hwep_num); 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci /* Let the EP interrupt handle the ZLP */ 208062306a36Sopenharmony_ci return; 208162306a36Sopenharmony_ci } else 208262306a36Sopenharmony_ci udc_send_in_zlp(udc, ep); 208362306a36Sopenharmony_ci } 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci /* Transfer request is complete */ 208662306a36Sopenharmony_ci done(ep, req, 0); 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci /* Start another request if ready */ 208962306a36Sopenharmony_ci udc_clearep_getsts(udc, ep->hwep_num); 209062306a36Sopenharmony_ci if (!list_empty((&ep->queue))) { 209162306a36Sopenharmony_ci if (ep->is_in) 209262306a36Sopenharmony_ci udc_ep_in_req_dma(udc, ep); 209362306a36Sopenharmony_ci else 209462306a36Sopenharmony_ci udc_ep_out_req_dma(udc, ep); 209562306a36Sopenharmony_ci } else 209662306a36Sopenharmony_ci ep->req_pending = 0; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci} 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci/* 210162306a36Sopenharmony_ci * 210262306a36Sopenharmony_ci * Endpoint 0 functions 210362306a36Sopenharmony_ci * 210462306a36Sopenharmony_ci */ 210562306a36Sopenharmony_cistatic void udc_handle_dev(struct lpc32xx_udc *udc) 210662306a36Sopenharmony_ci{ 210762306a36Sopenharmony_ci u32 tmp; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci udc_protocol_cmd_w(udc, CMD_GET_DEV_STAT); 211062306a36Sopenharmony_ci tmp = udc_protocol_cmd_r(udc, DAT_GET_DEV_STAT); 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci if (tmp & DEV_RST) 211362306a36Sopenharmony_ci uda_usb_reset(udc); 211462306a36Sopenharmony_ci else if (tmp & DEV_CON_CH) 211562306a36Sopenharmony_ci uda_power_event(udc, (tmp & DEV_CON)); 211662306a36Sopenharmony_ci else if (tmp & DEV_SUS_CH) { 211762306a36Sopenharmony_ci if (tmp & DEV_SUS) { 211862306a36Sopenharmony_ci if (udc->vbus == 0) 211962306a36Sopenharmony_ci stop_activity(udc); 212062306a36Sopenharmony_ci else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) && 212162306a36Sopenharmony_ci udc->driver) { 212262306a36Sopenharmony_ci /* Power down transceiver */ 212362306a36Sopenharmony_ci udc->poweron = 0; 212462306a36Sopenharmony_ci schedule_work(&udc->pullup_job); 212562306a36Sopenharmony_ci uda_resm_susp_event(udc, 1); 212662306a36Sopenharmony_ci } 212762306a36Sopenharmony_ci } else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) && 212862306a36Sopenharmony_ci udc->driver && udc->vbus) { 212962306a36Sopenharmony_ci uda_resm_susp_event(udc, 0); 213062306a36Sopenharmony_ci /* Power up transceiver */ 213162306a36Sopenharmony_ci udc->poweron = 1; 213262306a36Sopenharmony_ci schedule_work(&udc->pullup_job); 213362306a36Sopenharmony_ci } 213462306a36Sopenharmony_ci } 213562306a36Sopenharmony_ci} 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_cistatic int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex) 213862306a36Sopenharmony_ci{ 213962306a36Sopenharmony_ci struct lpc32xx_ep *ep; 214062306a36Sopenharmony_ci u32 ep0buff = 0, tmp; 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci switch (reqtype & USB_RECIP_MASK) { 214362306a36Sopenharmony_ci case USB_RECIP_INTERFACE: 214462306a36Sopenharmony_ci break; /* Not supported */ 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci case USB_RECIP_DEVICE: 214762306a36Sopenharmony_ci ep0buff = udc->gadget.is_selfpowered; 214862306a36Sopenharmony_ci if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP)) 214962306a36Sopenharmony_ci ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP); 215062306a36Sopenharmony_ci break; 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci case USB_RECIP_ENDPOINT: 215362306a36Sopenharmony_ci tmp = wIndex & USB_ENDPOINT_NUMBER_MASK; 215462306a36Sopenharmony_ci ep = &udc->ep[tmp]; 215562306a36Sopenharmony_ci if ((tmp == 0) || (tmp >= NUM_ENDPOINTS)) 215662306a36Sopenharmony_ci return -EOPNOTSUPP; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci if (wIndex & USB_DIR_IN) { 215962306a36Sopenharmony_ci if (!ep->is_in) 216062306a36Sopenharmony_ci return -EOPNOTSUPP; /* Something's wrong */ 216162306a36Sopenharmony_ci } else if (ep->is_in) 216262306a36Sopenharmony_ci return -EOPNOTSUPP; /* Not an IN endpoint */ 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci /* Get status of the endpoint */ 216562306a36Sopenharmony_ci udc_protocol_cmd_w(udc, CMD_SEL_EP(ep->hwep_num)); 216662306a36Sopenharmony_ci tmp = udc_protocol_cmd_r(udc, DAT_SEL_EP(ep->hwep_num)); 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci if (tmp & EP_SEL_ST) 216962306a36Sopenharmony_ci ep0buff = (1 << USB_ENDPOINT_HALT); 217062306a36Sopenharmony_ci else 217162306a36Sopenharmony_ci ep0buff = 0; 217262306a36Sopenharmony_ci break; 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci default: 217562306a36Sopenharmony_ci break; 217662306a36Sopenharmony_ci } 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci /* Return data */ 217962306a36Sopenharmony_ci udc_write_hwep(udc, EP_IN, &ep0buff, 2); 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci return 0; 218262306a36Sopenharmony_ci} 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_cistatic void udc_handle_ep0_setup(struct lpc32xx_udc *udc) 218562306a36Sopenharmony_ci{ 218662306a36Sopenharmony_ci struct lpc32xx_ep *ep, *ep0 = &udc->ep[0]; 218762306a36Sopenharmony_ci struct usb_ctrlrequest ctrlpkt; 218862306a36Sopenharmony_ci int i, bytes; 218962306a36Sopenharmony_ci u16 wIndex, wValue, reqtype, req, tmp; 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci /* Nuke previous transfers */ 219262306a36Sopenharmony_ci nuke(ep0, -EPROTO); 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci /* Get setup packet */ 219562306a36Sopenharmony_ci bytes = udc_read_hwep(udc, EP_OUT, (u32 *) &ctrlpkt, 8); 219662306a36Sopenharmony_ci if (bytes != 8) { 219762306a36Sopenharmony_ci ep_warn(ep0, "Incorrectly sized setup packet (s/b 8, is %d)!\n", 219862306a36Sopenharmony_ci bytes); 219962306a36Sopenharmony_ci return; 220062306a36Sopenharmony_ci } 220162306a36Sopenharmony_ci 220262306a36Sopenharmony_ci /* Native endianness */ 220362306a36Sopenharmony_ci wIndex = le16_to_cpu(ctrlpkt.wIndex); 220462306a36Sopenharmony_ci wValue = le16_to_cpu(ctrlpkt.wValue); 220562306a36Sopenharmony_ci reqtype = le16_to_cpu(ctrlpkt.bRequestType); 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci /* Set direction of EP0 */ 220862306a36Sopenharmony_ci if (likely(reqtype & USB_DIR_IN)) 220962306a36Sopenharmony_ci ep0->is_in = 1; 221062306a36Sopenharmony_ci else 221162306a36Sopenharmony_ci ep0->is_in = 0; 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci /* Handle SETUP packet */ 221462306a36Sopenharmony_ci req = le16_to_cpu(ctrlpkt.bRequest); 221562306a36Sopenharmony_ci switch (req) { 221662306a36Sopenharmony_ci case USB_REQ_CLEAR_FEATURE: 221762306a36Sopenharmony_ci case USB_REQ_SET_FEATURE: 221862306a36Sopenharmony_ci switch (reqtype) { 221962306a36Sopenharmony_ci case (USB_TYPE_STANDARD | USB_RECIP_DEVICE): 222062306a36Sopenharmony_ci if (wValue != USB_DEVICE_REMOTE_WAKEUP) 222162306a36Sopenharmony_ci goto stall; /* Nothing else handled */ 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci /* Tell board about event */ 222462306a36Sopenharmony_ci if (req == USB_REQ_CLEAR_FEATURE) 222562306a36Sopenharmony_ci udc->dev_status &= 222662306a36Sopenharmony_ci ~(1 << USB_DEVICE_REMOTE_WAKEUP); 222762306a36Sopenharmony_ci else 222862306a36Sopenharmony_ci udc->dev_status |= 222962306a36Sopenharmony_ci (1 << USB_DEVICE_REMOTE_WAKEUP); 223062306a36Sopenharmony_ci uda_remwkp_cgh(udc); 223162306a36Sopenharmony_ci goto zlp_send; 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci case (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT): 223462306a36Sopenharmony_ci tmp = wIndex & USB_ENDPOINT_NUMBER_MASK; 223562306a36Sopenharmony_ci if ((wValue != USB_ENDPOINT_HALT) || 223662306a36Sopenharmony_ci (tmp >= NUM_ENDPOINTS)) 223762306a36Sopenharmony_ci break; 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci /* Find hardware endpoint from logical endpoint */ 224062306a36Sopenharmony_ci ep = &udc->ep[tmp]; 224162306a36Sopenharmony_ci tmp = ep->hwep_num; 224262306a36Sopenharmony_ci if (tmp == 0) 224362306a36Sopenharmony_ci break; 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci if (req == USB_REQ_SET_FEATURE) 224662306a36Sopenharmony_ci udc_stall_hwep(udc, tmp); 224762306a36Sopenharmony_ci else if (!ep->wedge) 224862306a36Sopenharmony_ci udc_clrstall_hwep(udc, tmp); 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci goto zlp_send; 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci default: 225362306a36Sopenharmony_ci break; 225462306a36Sopenharmony_ci } 225562306a36Sopenharmony_ci break; 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci case USB_REQ_SET_ADDRESS: 225862306a36Sopenharmony_ci if (reqtype == (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) { 225962306a36Sopenharmony_ci udc_set_address(udc, wValue); 226062306a36Sopenharmony_ci goto zlp_send; 226162306a36Sopenharmony_ci } 226262306a36Sopenharmony_ci break; 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci case USB_REQ_GET_STATUS: 226562306a36Sopenharmony_ci udc_get_status(udc, reqtype, wIndex); 226662306a36Sopenharmony_ci return; 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci default: 226962306a36Sopenharmony_ci break; /* Let GadgetFS handle the descriptor instead */ 227062306a36Sopenharmony_ci } 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci if (likely(udc->driver)) { 227362306a36Sopenharmony_ci /* device-2-host (IN) or no data setup command, process 227462306a36Sopenharmony_ci * immediately */ 227562306a36Sopenharmony_ci spin_unlock(&udc->lock); 227662306a36Sopenharmony_ci i = udc->driver->setup(&udc->gadget, &ctrlpkt); 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci spin_lock(&udc->lock); 227962306a36Sopenharmony_ci if (req == USB_REQ_SET_CONFIGURATION) { 228062306a36Sopenharmony_ci /* Configuration is set after endpoints are realized */ 228162306a36Sopenharmony_ci if (wValue) { 228262306a36Sopenharmony_ci /* Set configuration */ 228362306a36Sopenharmony_ci udc_set_device_configured(udc); 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci udc_protocol_cmd_data_w(udc, CMD_SET_MODE, 228662306a36Sopenharmony_ci DAT_WR_BYTE(AP_CLK | 228762306a36Sopenharmony_ci INAK_BI | INAK_II)); 228862306a36Sopenharmony_ci } else { 228962306a36Sopenharmony_ci /* Clear configuration */ 229062306a36Sopenharmony_ci udc_set_device_unconfigured(udc); 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci /* Disable NAK interrupts */ 229362306a36Sopenharmony_ci udc_protocol_cmd_data_w(udc, CMD_SET_MODE, 229462306a36Sopenharmony_ci DAT_WR_BYTE(AP_CLK)); 229562306a36Sopenharmony_ci } 229662306a36Sopenharmony_ci } 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci if (i < 0) { 229962306a36Sopenharmony_ci /* setup processing failed, force stall */ 230062306a36Sopenharmony_ci dev_dbg(udc->dev, 230162306a36Sopenharmony_ci "req %02x.%02x protocol STALL; stat %d\n", 230262306a36Sopenharmony_ci reqtype, req, i); 230362306a36Sopenharmony_ci udc->ep0state = WAIT_FOR_SETUP; 230462306a36Sopenharmony_ci goto stall; 230562306a36Sopenharmony_ci } 230662306a36Sopenharmony_ci } 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci if (!ep0->is_in) 230962306a36Sopenharmony_ci udc_ep0_send_zlp(udc); /* ZLP IN packet on data phase */ 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci return; 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_cistall: 231462306a36Sopenharmony_ci udc_stall_hwep(udc, EP_IN); 231562306a36Sopenharmony_ci return; 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_cizlp_send: 231862306a36Sopenharmony_ci udc_ep0_send_zlp(udc); 231962306a36Sopenharmony_ci return; 232062306a36Sopenharmony_ci} 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci/* IN endpoint 0 transfer */ 232362306a36Sopenharmony_cistatic void udc_handle_ep0_in(struct lpc32xx_udc *udc) 232462306a36Sopenharmony_ci{ 232562306a36Sopenharmony_ci struct lpc32xx_ep *ep0 = &udc->ep[0]; 232662306a36Sopenharmony_ci u32 epstatus; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci /* Clear EP interrupt */ 232962306a36Sopenharmony_ci epstatus = udc_clearep_getsts(udc, EP_IN); 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci#ifdef CONFIG_USB_GADGET_DEBUG_FILES 233262306a36Sopenharmony_ci ep0->totalints++; 233362306a36Sopenharmony_ci#endif 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci /* Stalled? Clear stall and reset buffers */ 233662306a36Sopenharmony_ci if (epstatus & EP_SEL_ST) { 233762306a36Sopenharmony_ci udc_clrstall_hwep(udc, EP_IN); 233862306a36Sopenharmony_ci nuke(ep0, -ECONNABORTED); 233962306a36Sopenharmony_ci udc->ep0state = WAIT_FOR_SETUP; 234062306a36Sopenharmony_ci return; 234162306a36Sopenharmony_ci } 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci /* Is a buffer available? */ 234462306a36Sopenharmony_ci if (!(epstatus & EP_SEL_F)) { 234562306a36Sopenharmony_ci /* Handle based on current state */ 234662306a36Sopenharmony_ci if (udc->ep0state == DATA_IN) 234762306a36Sopenharmony_ci udc_ep0_in_req(udc); 234862306a36Sopenharmony_ci else { 234962306a36Sopenharmony_ci /* Unknown state for EP0 oe end of DATA IN phase */ 235062306a36Sopenharmony_ci nuke(ep0, -ECONNABORTED); 235162306a36Sopenharmony_ci udc->ep0state = WAIT_FOR_SETUP; 235262306a36Sopenharmony_ci } 235362306a36Sopenharmony_ci } 235462306a36Sopenharmony_ci} 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci/* OUT endpoint 0 transfer */ 235762306a36Sopenharmony_cistatic void udc_handle_ep0_out(struct lpc32xx_udc *udc) 235862306a36Sopenharmony_ci{ 235962306a36Sopenharmony_ci struct lpc32xx_ep *ep0 = &udc->ep[0]; 236062306a36Sopenharmony_ci u32 epstatus; 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci /* Clear EP interrupt */ 236362306a36Sopenharmony_ci epstatus = udc_clearep_getsts(udc, EP_OUT); 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci#ifdef CONFIG_USB_GADGET_DEBUG_FILES 236762306a36Sopenharmony_ci ep0->totalints++; 236862306a36Sopenharmony_ci#endif 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci /* Stalled? */ 237162306a36Sopenharmony_ci if (epstatus & EP_SEL_ST) { 237262306a36Sopenharmony_ci udc_clrstall_hwep(udc, EP_OUT); 237362306a36Sopenharmony_ci nuke(ep0, -ECONNABORTED); 237462306a36Sopenharmony_ci udc->ep0state = WAIT_FOR_SETUP; 237562306a36Sopenharmony_ci return; 237662306a36Sopenharmony_ci } 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci /* A NAK may occur if a packet couldn't be received yet */ 237962306a36Sopenharmony_ci if (epstatus & EP_SEL_EPN) 238062306a36Sopenharmony_ci return; 238162306a36Sopenharmony_ci /* Setup packet incoming? */ 238262306a36Sopenharmony_ci if (epstatus & EP_SEL_STP) { 238362306a36Sopenharmony_ci nuke(ep0, 0); 238462306a36Sopenharmony_ci udc->ep0state = WAIT_FOR_SETUP; 238562306a36Sopenharmony_ci } 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci /* Data available? */ 238862306a36Sopenharmony_ci if (epstatus & EP_SEL_F) 238962306a36Sopenharmony_ci /* Handle based on current state */ 239062306a36Sopenharmony_ci switch (udc->ep0state) { 239162306a36Sopenharmony_ci case WAIT_FOR_SETUP: 239262306a36Sopenharmony_ci udc_handle_ep0_setup(udc); 239362306a36Sopenharmony_ci break; 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci case DATA_OUT: 239662306a36Sopenharmony_ci udc_ep0_out_req(udc); 239762306a36Sopenharmony_ci break; 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci default: 240062306a36Sopenharmony_ci /* Unknown state for EP0 */ 240162306a36Sopenharmony_ci nuke(ep0, -ECONNABORTED); 240262306a36Sopenharmony_ci udc->ep0state = WAIT_FOR_SETUP; 240362306a36Sopenharmony_ci } 240462306a36Sopenharmony_ci} 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci/* Must be called without lock */ 240762306a36Sopenharmony_cistatic int lpc32xx_get_frame(struct usb_gadget *gadget) 240862306a36Sopenharmony_ci{ 240962306a36Sopenharmony_ci int frame; 241062306a36Sopenharmony_ci unsigned long flags; 241162306a36Sopenharmony_ci struct lpc32xx_udc *udc = to_udc(gadget); 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci if (!udc->clocked) 241462306a36Sopenharmony_ci return -EINVAL; 241562306a36Sopenharmony_ci 241662306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci frame = (int) udc_get_current_frame(udc); 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci return frame; 242362306a36Sopenharmony_ci} 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_cistatic int lpc32xx_wakeup(struct usb_gadget *gadget) 242662306a36Sopenharmony_ci{ 242762306a36Sopenharmony_ci return -ENOTSUPP; 242862306a36Sopenharmony_ci} 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_cistatic int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on) 243162306a36Sopenharmony_ci{ 243262306a36Sopenharmony_ci gadget->is_selfpowered = (is_on != 0); 243362306a36Sopenharmony_ci 243462306a36Sopenharmony_ci return 0; 243562306a36Sopenharmony_ci} 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci/* 243862306a36Sopenharmony_ci * vbus is here! turn everything on that's ready 243962306a36Sopenharmony_ci * Must be called without lock 244062306a36Sopenharmony_ci */ 244162306a36Sopenharmony_cistatic int lpc32xx_vbus_session(struct usb_gadget *gadget, int is_active) 244262306a36Sopenharmony_ci{ 244362306a36Sopenharmony_ci unsigned long flags; 244462306a36Sopenharmony_ci struct lpc32xx_udc *udc = to_udc(gadget); 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci /* Doesn't need lock */ 244962306a36Sopenharmony_ci if (udc->driver) { 245062306a36Sopenharmony_ci udc_clk_set(udc, 1); 245162306a36Sopenharmony_ci udc_enable(udc); 245262306a36Sopenharmony_ci pullup(udc, is_active); 245362306a36Sopenharmony_ci } else { 245462306a36Sopenharmony_ci stop_activity(udc); 245562306a36Sopenharmony_ci pullup(udc, 0); 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 245862306a36Sopenharmony_ci /* 245962306a36Sopenharmony_ci * Wait for all the endpoints to disable, 246062306a36Sopenharmony_ci * before disabling clocks. Don't wait if 246162306a36Sopenharmony_ci * endpoints are not enabled. 246262306a36Sopenharmony_ci */ 246362306a36Sopenharmony_ci if (atomic_read(&udc->enabled_ep_cnt)) 246462306a36Sopenharmony_ci wait_event_interruptible(udc->ep_disable_wait_queue, 246562306a36Sopenharmony_ci (atomic_read(&udc->enabled_ep_cnt) == 0)); 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci udc_clk_set(udc, 0); 247062306a36Sopenharmony_ci } 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci return 0; 247562306a36Sopenharmony_ci} 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci/* Can be called with or without lock */ 247862306a36Sopenharmony_cistatic int lpc32xx_pullup(struct usb_gadget *gadget, int is_on) 247962306a36Sopenharmony_ci{ 248062306a36Sopenharmony_ci struct lpc32xx_udc *udc = to_udc(gadget); 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci /* Doesn't need lock */ 248362306a36Sopenharmony_ci pullup(udc, is_on); 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci return 0; 248662306a36Sopenharmony_ci} 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_cistatic int lpc32xx_start(struct usb_gadget *, struct usb_gadget_driver *); 248962306a36Sopenharmony_cistatic int lpc32xx_stop(struct usb_gadget *); 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_cistatic const struct usb_gadget_ops lpc32xx_udc_ops = { 249262306a36Sopenharmony_ci .get_frame = lpc32xx_get_frame, 249362306a36Sopenharmony_ci .wakeup = lpc32xx_wakeup, 249462306a36Sopenharmony_ci .set_selfpowered = lpc32xx_set_selfpowered, 249562306a36Sopenharmony_ci .vbus_session = lpc32xx_vbus_session, 249662306a36Sopenharmony_ci .pullup = lpc32xx_pullup, 249762306a36Sopenharmony_ci .udc_start = lpc32xx_start, 249862306a36Sopenharmony_ci .udc_stop = lpc32xx_stop, 249962306a36Sopenharmony_ci}; 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_cistatic void nop_release(struct device *dev) 250262306a36Sopenharmony_ci{ 250362306a36Sopenharmony_ci /* nothing to free */ 250462306a36Sopenharmony_ci} 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_cistatic const struct lpc32xx_udc controller_template = { 250762306a36Sopenharmony_ci .gadget = { 250862306a36Sopenharmony_ci .ops = &lpc32xx_udc_ops, 250962306a36Sopenharmony_ci .name = driver_name, 251062306a36Sopenharmony_ci .dev = { 251162306a36Sopenharmony_ci .init_name = "gadget", 251262306a36Sopenharmony_ci .release = nop_release, 251362306a36Sopenharmony_ci } 251462306a36Sopenharmony_ci }, 251562306a36Sopenharmony_ci .ep[0] = { 251662306a36Sopenharmony_ci .ep = { 251762306a36Sopenharmony_ci .name = "ep0", 251862306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 251962306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, 252062306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 252162306a36Sopenharmony_ci }, 252262306a36Sopenharmony_ci .maxpacket = 64, 252362306a36Sopenharmony_ci .hwep_num_base = 0, 252462306a36Sopenharmony_ci .hwep_num = 0, /* Can be 0 or 1, has special handling */ 252562306a36Sopenharmony_ci .lep = 0, 252662306a36Sopenharmony_ci .eptype = EP_CTL_TYPE, 252762306a36Sopenharmony_ci }, 252862306a36Sopenharmony_ci .ep[1] = { 252962306a36Sopenharmony_ci .ep = { 253062306a36Sopenharmony_ci .name = "ep1-int", 253162306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 253262306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, 253362306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 253462306a36Sopenharmony_ci }, 253562306a36Sopenharmony_ci .maxpacket = 64, 253662306a36Sopenharmony_ci .hwep_num_base = 2, 253762306a36Sopenharmony_ci .hwep_num = 0, /* 2 or 3, will be set later */ 253862306a36Sopenharmony_ci .lep = 1, 253962306a36Sopenharmony_ci .eptype = EP_INT_TYPE, 254062306a36Sopenharmony_ci }, 254162306a36Sopenharmony_ci .ep[2] = { 254262306a36Sopenharmony_ci .ep = { 254362306a36Sopenharmony_ci .name = "ep2-bulk", 254462306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 254562306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 254662306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 254762306a36Sopenharmony_ci }, 254862306a36Sopenharmony_ci .maxpacket = 64, 254962306a36Sopenharmony_ci .hwep_num_base = 4, 255062306a36Sopenharmony_ci .hwep_num = 0, /* 4 or 5, will be set later */ 255162306a36Sopenharmony_ci .lep = 2, 255262306a36Sopenharmony_ci .eptype = EP_BLK_TYPE, 255362306a36Sopenharmony_ci }, 255462306a36Sopenharmony_ci .ep[3] = { 255562306a36Sopenharmony_ci .ep = { 255662306a36Sopenharmony_ci .name = "ep3-iso", 255762306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 255862306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 255962306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 256062306a36Sopenharmony_ci }, 256162306a36Sopenharmony_ci .maxpacket = 1023, 256262306a36Sopenharmony_ci .hwep_num_base = 6, 256362306a36Sopenharmony_ci .hwep_num = 0, /* 6 or 7, will be set later */ 256462306a36Sopenharmony_ci .lep = 3, 256562306a36Sopenharmony_ci .eptype = EP_ISO_TYPE, 256662306a36Sopenharmony_ci }, 256762306a36Sopenharmony_ci .ep[4] = { 256862306a36Sopenharmony_ci .ep = { 256962306a36Sopenharmony_ci .name = "ep4-int", 257062306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 257162306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, 257262306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 257362306a36Sopenharmony_ci }, 257462306a36Sopenharmony_ci .maxpacket = 64, 257562306a36Sopenharmony_ci .hwep_num_base = 8, 257662306a36Sopenharmony_ci .hwep_num = 0, /* 8 or 9, will be set later */ 257762306a36Sopenharmony_ci .lep = 4, 257862306a36Sopenharmony_ci .eptype = EP_INT_TYPE, 257962306a36Sopenharmony_ci }, 258062306a36Sopenharmony_ci .ep[5] = { 258162306a36Sopenharmony_ci .ep = { 258262306a36Sopenharmony_ci .name = "ep5-bulk", 258362306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 258462306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 258562306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 258662306a36Sopenharmony_ci }, 258762306a36Sopenharmony_ci .maxpacket = 64, 258862306a36Sopenharmony_ci .hwep_num_base = 10, 258962306a36Sopenharmony_ci .hwep_num = 0, /* 10 or 11, will be set later */ 259062306a36Sopenharmony_ci .lep = 5, 259162306a36Sopenharmony_ci .eptype = EP_BLK_TYPE, 259262306a36Sopenharmony_ci }, 259362306a36Sopenharmony_ci .ep[6] = { 259462306a36Sopenharmony_ci .ep = { 259562306a36Sopenharmony_ci .name = "ep6-iso", 259662306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 259762306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 259862306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 259962306a36Sopenharmony_ci }, 260062306a36Sopenharmony_ci .maxpacket = 1023, 260162306a36Sopenharmony_ci .hwep_num_base = 12, 260262306a36Sopenharmony_ci .hwep_num = 0, /* 12 or 13, will be set later */ 260362306a36Sopenharmony_ci .lep = 6, 260462306a36Sopenharmony_ci .eptype = EP_ISO_TYPE, 260562306a36Sopenharmony_ci }, 260662306a36Sopenharmony_ci .ep[7] = { 260762306a36Sopenharmony_ci .ep = { 260862306a36Sopenharmony_ci .name = "ep7-int", 260962306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 261062306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, 261162306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 261262306a36Sopenharmony_ci }, 261362306a36Sopenharmony_ci .maxpacket = 64, 261462306a36Sopenharmony_ci .hwep_num_base = 14, 261562306a36Sopenharmony_ci .hwep_num = 0, 261662306a36Sopenharmony_ci .lep = 7, 261762306a36Sopenharmony_ci .eptype = EP_INT_TYPE, 261862306a36Sopenharmony_ci }, 261962306a36Sopenharmony_ci .ep[8] = { 262062306a36Sopenharmony_ci .ep = { 262162306a36Sopenharmony_ci .name = "ep8-bulk", 262262306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 262362306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 262462306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 262562306a36Sopenharmony_ci }, 262662306a36Sopenharmony_ci .maxpacket = 64, 262762306a36Sopenharmony_ci .hwep_num_base = 16, 262862306a36Sopenharmony_ci .hwep_num = 0, 262962306a36Sopenharmony_ci .lep = 8, 263062306a36Sopenharmony_ci .eptype = EP_BLK_TYPE, 263162306a36Sopenharmony_ci }, 263262306a36Sopenharmony_ci .ep[9] = { 263362306a36Sopenharmony_ci .ep = { 263462306a36Sopenharmony_ci .name = "ep9-iso", 263562306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 263662306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 263762306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 263862306a36Sopenharmony_ci }, 263962306a36Sopenharmony_ci .maxpacket = 1023, 264062306a36Sopenharmony_ci .hwep_num_base = 18, 264162306a36Sopenharmony_ci .hwep_num = 0, 264262306a36Sopenharmony_ci .lep = 9, 264362306a36Sopenharmony_ci .eptype = EP_ISO_TYPE, 264462306a36Sopenharmony_ci }, 264562306a36Sopenharmony_ci .ep[10] = { 264662306a36Sopenharmony_ci .ep = { 264762306a36Sopenharmony_ci .name = "ep10-int", 264862306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 264962306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, 265062306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 265162306a36Sopenharmony_ci }, 265262306a36Sopenharmony_ci .maxpacket = 64, 265362306a36Sopenharmony_ci .hwep_num_base = 20, 265462306a36Sopenharmony_ci .hwep_num = 0, 265562306a36Sopenharmony_ci .lep = 10, 265662306a36Sopenharmony_ci .eptype = EP_INT_TYPE, 265762306a36Sopenharmony_ci }, 265862306a36Sopenharmony_ci .ep[11] = { 265962306a36Sopenharmony_ci .ep = { 266062306a36Sopenharmony_ci .name = "ep11-bulk", 266162306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 266262306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 266362306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 266462306a36Sopenharmony_ci }, 266562306a36Sopenharmony_ci .maxpacket = 64, 266662306a36Sopenharmony_ci .hwep_num_base = 22, 266762306a36Sopenharmony_ci .hwep_num = 0, 266862306a36Sopenharmony_ci .lep = 11, 266962306a36Sopenharmony_ci .eptype = EP_BLK_TYPE, 267062306a36Sopenharmony_ci }, 267162306a36Sopenharmony_ci .ep[12] = { 267262306a36Sopenharmony_ci .ep = { 267362306a36Sopenharmony_ci .name = "ep12-iso", 267462306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 267562306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 267662306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 267762306a36Sopenharmony_ci }, 267862306a36Sopenharmony_ci .maxpacket = 1023, 267962306a36Sopenharmony_ci .hwep_num_base = 24, 268062306a36Sopenharmony_ci .hwep_num = 0, 268162306a36Sopenharmony_ci .lep = 12, 268262306a36Sopenharmony_ci .eptype = EP_ISO_TYPE, 268362306a36Sopenharmony_ci }, 268462306a36Sopenharmony_ci .ep[13] = { 268562306a36Sopenharmony_ci .ep = { 268662306a36Sopenharmony_ci .name = "ep13-int", 268762306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 268862306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, 268962306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 269062306a36Sopenharmony_ci }, 269162306a36Sopenharmony_ci .maxpacket = 64, 269262306a36Sopenharmony_ci .hwep_num_base = 26, 269362306a36Sopenharmony_ci .hwep_num = 0, 269462306a36Sopenharmony_ci .lep = 13, 269562306a36Sopenharmony_ci .eptype = EP_INT_TYPE, 269662306a36Sopenharmony_ci }, 269762306a36Sopenharmony_ci .ep[14] = { 269862306a36Sopenharmony_ci .ep = { 269962306a36Sopenharmony_ci .name = "ep14-bulk", 270062306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 270162306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 270262306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 270362306a36Sopenharmony_ci }, 270462306a36Sopenharmony_ci .maxpacket = 64, 270562306a36Sopenharmony_ci .hwep_num_base = 28, 270662306a36Sopenharmony_ci .hwep_num = 0, 270762306a36Sopenharmony_ci .lep = 14, 270862306a36Sopenharmony_ci .eptype = EP_BLK_TYPE, 270962306a36Sopenharmony_ci }, 271062306a36Sopenharmony_ci .ep[15] = { 271162306a36Sopenharmony_ci .ep = { 271262306a36Sopenharmony_ci .name = "ep15-bulk", 271362306a36Sopenharmony_ci .ops = &lpc32xx_ep_ops, 271462306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 271562306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 271662306a36Sopenharmony_ci }, 271762306a36Sopenharmony_ci .maxpacket = 1023, 271862306a36Sopenharmony_ci .hwep_num_base = 30, 271962306a36Sopenharmony_ci .hwep_num = 0, 272062306a36Sopenharmony_ci .lep = 15, 272162306a36Sopenharmony_ci .eptype = EP_BLK_TYPE, 272262306a36Sopenharmony_ci }, 272362306a36Sopenharmony_ci}; 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_ci/* ISO and status interrupts */ 272662306a36Sopenharmony_cistatic irqreturn_t lpc32xx_usb_lp_irq(int irq, void *_udc) 272762306a36Sopenharmony_ci{ 272862306a36Sopenharmony_ci u32 tmp, devstat; 272962306a36Sopenharmony_ci struct lpc32xx_udc *udc = _udc; 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci spin_lock(&udc->lock); 273262306a36Sopenharmony_ci 273362306a36Sopenharmony_ci /* Read the device status register */ 273462306a36Sopenharmony_ci devstat = readl(USBD_DEVINTST(udc->udp_baseaddr)); 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci devstat &= ~USBD_EP_FAST; 273762306a36Sopenharmony_ci writel(devstat, USBD_DEVINTCLR(udc->udp_baseaddr)); 273862306a36Sopenharmony_ci devstat = devstat & udc->enabled_devints; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci /* Device specific handling needed? */ 274162306a36Sopenharmony_ci if (devstat & USBD_DEV_STAT) 274262306a36Sopenharmony_ci udc_handle_dev(udc); 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci /* Start of frame? (devstat & FRAME_INT): 274562306a36Sopenharmony_ci * The frame interrupt isn't really needed for ISO support, 274662306a36Sopenharmony_ci * as the driver will queue the necessary packets */ 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci /* Error? */ 274962306a36Sopenharmony_ci if (devstat & ERR_INT) { 275062306a36Sopenharmony_ci /* All types of errors, from cable removal during transfer to 275162306a36Sopenharmony_ci * misc protocol and bit errors. These are mostly for just info, 275262306a36Sopenharmony_ci * as the USB hardware will work around these. If these errors 275362306a36Sopenharmony_ci * happen alot, something is wrong. */ 275462306a36Sopenharmony_ci udc_protocol_cmd_w(udc, CMD_RD_ERR_STAT); 275562306a36Sopenharmony_ci tmp = udc_protocol_cmd_r(udc, DAT_RD_ERR_STAT); 275662306a36Sopenharmony_ci dev_dbg(udc->dev, "Device error (0x%x)!\n", tmp); 275762306a36Sopenharmony_ci } 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci spin_unlock(&udc->lock); 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci return IRQ_HANDLED; 276262306a36Sopenharmony_ci} 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ci/* EP interrupts */ 276562306a36Sopenharmony_cistatic irqreturn_t lpc32xx_usb_hp_irq(int irq, void *_udc) 276662306a36Sopenharmony_ci{ 276762306a36Sopenharmony_ci u32 tmp; 276862306a36Sopenharmony_ci struct lpc32xx_udc *udc = _udc; 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci spin_lock(&udc->lock); 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci /* Read the device status register */ 277362306a36Sopenharmony_ci writel(USBD_EP_FAST, USBD_DEVINTCLR(udc->udp_baseaddr)); 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci /* Endpoints */ 277662306a36Sopenharmony_ci tmp = readl(USBD_EPINTST(udc->udp_baseaddr)); 277762306a36Sopenharmony_ci 277862306a36Sopenharmony_ci /* Special handling for EP0 */ 277962306a36Sopenharmony_ci if (tmp & (EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) { 278062306a36Sopenharmony_ci /* Handle EP0 IN */ 278162306a36Sopenharmony_ci if (tmp & (EP_MASK_SEL(0, EP_IN))) 278262306a36Sopenharmony_ci udc_handle_ep0_in(udc); 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_ci /* Handle EP0 OUT */ 278562306a36Sopenharmony_ci if (tmp & (EP_MASK_SEL(0, EP_OUT))) 278662306a36Sopenharmony_ci udc_handle_ep0_out(udc); 278762306a36Sopenharmony_ci } 278862306a36Sopenharmony_ci 278962306a36Sopenharmony_ci /* All other EPs */ 279062306a36Sopenharmony_ci if (tmp & ~(EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) { 279162306a36Sopenharmony_ci int i; 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_ci /* Handle other EP interrupts */ 279462306a36Sopenharmony_ci for (i = 1; i < NUM_ENDPOINTS; i++) { 279562306a36Sopenharmony_ci if (tmp & (1 << udc->ep[i].hwep_num)) 279662306a36Sopenharmony_ci udc_handle_eps(udc, &udc->ep[i]); 279762306a36Sopenharmony_ci } 279862306a36Sopenharmony_ci } 279962306a36Sopenharmony_ci 280062306a36Sopenharmony_ci spin_unlock(&udc->lock); 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci return IRQ_HANDLED; 280362306a36Sopenharmony_ci} 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_cistatic irqreturn_t lpc32xx_usb_devdma_irq(int irq, void *_udc) 280662306a36Sopenharmony_ci{ 280762306a36Sopenharmony_ci struct lpc32xx_udc *udc = _udc; 280862306a36Sopenharmony_ci 280962306a36Sopenharmony_ci int i; 281062306a36Sopenharmony_ci u32 tmp; 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci spin_lock(&udc->lock); 281362306a36Sopenharmony_ci 281462306a36Sopenharmony_ci /* Handle EP DMA EOT interrupts */ 281562306a36Sopenharmony_ci tmp = readl(USBD_EOTINTST(udc->udp_baseaddr)) | 281662306a36Sopenharmony_ci (readl(USBD_EPDMAST(udc->udp_baseaddr)) & 281762306a36Sopenharmony_ci readl(USBD_NDDRTINTST(udc->udp_baseaddr))) | 281862306a36Sopenharmony_ci readl(USBD_SYSERRTINTST(udc->udp_baseaddr)); 281962306a36Sopenharmony_ci for (i = 1; i < NUM_ENDPOINTS; i++) { 282062306a36Sopenharmony_ci if (tmp & (1 << udc->ep[i].hwep_num)) 282162306a36Sopenharmony_ci udc_handle_dma_ep(udc, &udc->ep[i]); 282262306a36Sopenharmony_ci } 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci spin_unlock(&udc->lock); 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci return IRQ_HANDLED; 282762306a36Sopenharmony_ci} 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci/* 283062306a36Sopenharmony_ci * 283162306a36Sopenharmony_ci * VBUS detection, pullup handler, and Gadget cable state notification 283262306a36Sopenharmony_ci * 283362306a36Sopenharmony_ci */ 283462306a36Sopenharmony_cistatic void vbus_work(struct lpc32xx_udc *udc) 283562306a36Sopenharmony_ci{ 283662306a36Sopenharmony_ci u8 value; 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci if (udc->enabled != 0) { 283962306a36Sopenharmony_ci /* Discharge VBUS real quick */ 284062306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 284162306a36Sopenharmony_ci ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG); 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_ci /* Give VBUS some time (100mS) to discharge */ 284462306a36Sopenharmony_ci msleep(100); 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci /* Disable VBUS discharge resistor */ 284762306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 284862306a36Sopenharmony_ci ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, 284962306a36Sopenharmony_ci OTG1_VBUS_DISCHRG); 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_ci /* Clear interrupt */ 285262306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 285362306a36Sopenharmony_ci ISP1301_I2C_INTERRUPT_LATCH | 285462306a36Sopenharmony_ci ISP1301_I2C_REG_CLEAR_ADDR, ~0); 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci /* Get the VBUS status from the transceiver */ 285762306a36Sopenharmony_ci value = i2c_smbus_read_byte_data(udc->isp1301_i2c_client, 285862306a36Sopenharmony_ci ISP1301_I2C_INTERRUPT_SOURCE); 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_ci /* VBUS on or off? */ 286162306a36Sopenharmony_ci if (value & INT_SESS_VLD) 286262306a36Sopenharmony_ci udc->vbus = 1; 286362306a36Sopenharmony_ci else 286462306a36Sopenharmony_ci udc->vbus = 0; 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci /* VBUS changed? */ 286762306a36Sopenharmony_ci if (udc->last_vbus != udc->vbus) { 286862306a36Sopenharmony_ci udc->last_vbus = udc->vbus; 286962306a36Sopenharmony_ci lpc32xx_vbus_session(&udc->gadget, udc->vbus); 287062306a36Sopenharmony_ci } 287162306a36Sopenharmony_ci } 287262306a36Sopenharmony_ci} 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_cistatic irqreturn_t lpc32xx_usb_vbus_irq(int irq, void *_udc) 287562306a36Sopenharmony_ci{ 287662306a36Sopenharmony_ci struct lpc32xx_udc *udc = _udc; 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci vbus_work(udc); 287962306a36Sopenharmony_ci 288062306a36Sopenharmony_ci return IRQ_HANDLED; 288162306a36Sopenharmony_ci} 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_cistatic int lpc32xx_start(struct usb_gadget *gadget, 288462306a36Sopenharmony_ci struct usb_gadget_driver *driver) 288562306a36Sopenharmony_ci{ 288662306a36Sopenharmony_ci struct lpc32xx_udc *udc = to_udc(gadget); 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci if (!driver || driver->max_speed < USB_SPEED_FULL || !driver->setup) { 288962306a36Sopenharmony_ci dev_err(udc->dev, "bad parameter.\n"); 289062306a36Sopenharmony_ci return -EINVAL; 289162306a36Sopenharmony_ci } 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_ci if (udc->driver) { 289462306a36Sopenharmony_ci dev_err(udc->dev, "UDC already has a gadget driver\n"); 289562306a36Sopenharmony_ci return -EBUSY; 289662306a36Sopenharmony_ci } 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci udc->driver = driver; 289962306a36Sopenharmony_ci udc->gadget.dev.of_node = udc->dev->of_node; 290062306a36Sopenharmony_ci udc->enabled = 1; 290162306a36Sopenharmony_ci udc->gadget.is_selfpowered = 1; 290262306a36Sopenharmony_ci udc->vbus = 0; 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_ci /* Force VBUS process once to check for cable insertion */ 290562306a36Sopenharmony_ci udc->last_vbus = udc->vbus = 0; 290662306a36Sopenharmony_ci vbus_work(udc); 290762306a36Sopenharmony_ci 290862306a36Sopenharmony_ci /* enable interrupts */ 290962306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 291062306a36Sopenharmony_ci ISP1301_I2C_INTERRUPT_FALLING, INT_SESS_VLD | INT_VBUS_VLD); 291162306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 291262306a36Sopenharmony_ci ISP1301_I2C_INTERRUPT_RISING, INT_SESS_VLD | INT_VBUS_VLD); 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ci return 0; 291562306a36Sopenharmony_ci} 291662306a36Sopenharmony_ci 291762306a36Sopenharmony_cistatic int lpc32xx_stop(struct usb_gadget *gadget) 291862306a36Sopenharmony_ci{ 291962306a36Sopenharmony_ci struct lpc32xx_udc *udc = to_udc(gadget); 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 292262306a36Sopenharmony_ci ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); 292362306a36Sopenharmony_ci i2c_smbus_write_byte_data(udc->isp1301_i2c_client, 292462306a36Sopenharmony_ci ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci if (udc->clocked) { 292762306a36Sopenharmony_ci spin_lock(&udc->lock); 292862306a36Sopenharmony_ci stop_activity(udc); 292962306a36Sopenharmony_ci spin_unlock(&udc->lock); 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci /* 293262306a36Sopenharmony_ci * Wait for all the endpoints to disable, 293362306a36Sopenharmony_ci * before disabling clocks. Don't wait if 293462306a36Sopenharmony_ci * endpoints are not enabled. 293562306a36Sopenharmony_ci */ 293662306a36Sopenharmony_ci if (atomic_read(&udc->enabled_ep_cnt)) 293762306a36Sopenharmony_ci wait_event_interruptible(udc->ep_disable_wait_queue, 293862306a36Sopenharmony_ci (atomic_read(&udc->enabled_ep_cnt) == 0)); 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci spin_lock(&udc->lock); 294162306a36Sopenharmony_ci udc_clk_set(udc, 0); 294262306a36Sopenharmony_ci spin_unlock(&udc->lock); 294362306a36Sopenharmony_ci } 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci udc->enabled = 0; 294662306a36Sopenharmony_ci udc->driver = NULL; 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_ci return 0; 294962306a36Sopenharmony_ci} 295062306a36Sopenharmony_ci 295162306a36Sopenharmony_cistatic void lpc32xx_udc_shutdown(struct platform_device *dev) 295262306a36Sopenharmony_ci{ 295362306a36Sopenharmony_ci /* Force disconnect on reboot */ 295462306a36Sopenharmony_ci struct lpc32xx_udc *udc = platform_get_drvdata(dev); 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci pullup(udc, 0); 295762306a36Sopenharmony_ci} 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci/* 296062306a36Sopenharmony_ci * Callbacks to be overridden by options passed via OF (TODO) 296162306a36Sopenharmony_ci */ 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_cistatic void lpc32xx_usbd_conn_chg(int conn) 296462306a36Sopenharmony_ci{ 296562306a36Sopenharmony_ci /* Do nothing, it might be nice to enable an LED 296662306a36Sopenharmony_ci * based on conn state being !0 */ 296762306a36Sopenharmony_ci} 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_cistatic void lpc32xx_usbd_susp_chg(int susp) 297062306a36Sopenharmony_ci{ 297162306a36Sopenharmony_ci /* Device suspend if susp != 0 */ 297262306a36Sopenharmony_ci} 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_cistatic void lpc32xx_rmwkup_chg(int remote_wakup_enable) 297562306a36Sopenharmony_ci{ 297662306a36Sopenharmony_ci /* Enable or disable USB remote wakeup */ 297762306a36Sopenharmony_ci} 297862306a36Sopenharmony_ci 297962306a36Sopenharmony_cistatic struct lpc32xx_usbd_cfg lpc32xx_usbddata = { 298062306a36Sopenharmony_ci .vbus_drv_pol = 0, 298162306a36Sopenharmony_ci .conn_chgb = &lpc32xx_usbd_conn_chg, 298262306a36Sopenharmony_ci .susp_chgb = &lpc32xx_usbd_susp_chg, 298362306a36Sopenharmony_ci .rmwk_chgb = &lpc32xx_rmwkup_chg, 298462306a36Sopenharmony_ci}; 298562306a36Sopenharmony_ci 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_cistatic u64 lpc32xx_usbd_dmamask = ~(u32) 0x7F; 298862306a36Sopenharmony_ci 298962306a36Sopenharmony_cistatic int lpc32xx_udc_probe(struct platform_device *pdev) 299062306a36Sopenharmony_ci{ 299162306a36Sopenharmony_ci struct device *dev = &pdev->dev; 299262306a36Sopenharmony_ci struct lpc32xx_udc *udc; 299362306a36Sopenharmony_ci int retval, i; 299462306a36Sopenharmony_ci dma_addr_t dma_handle; 299562306a36Sopenharmony_ci struct device_node *isp1301_node; 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci udc = devm_kmemdup(dev, &controller_template, sizeof(*udc), GFP_KERNEL); 299862306a36Sopenharmony_ci if (!udc) 299962306a36Sopenharmony_ci return -ENOMEM; 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci for (i = 0; i <= 15; i++) 300262306a36Sopenharmony_ci udc->ep[i].udc = udc; 300362306a36Sopenharmony_ci udc->gadget.ep0 = &udc->ep[0].ep; 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_ci /* init software state */ 300662306a36Sopenharmony_ci udc->gadget.dev.parent = dev; 300762306a36Sopenharmony_ci udc->pdev = pdev; 300862306a36Sopenharmony_ci udc->dev = &pdev->dev; 300962306a36Sopenharmony_ci udc->enabled = 0; 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_ci if (pdev->dev.of_node) { 301262306a36Sopenharmony_ci isp1301_node = of_parse_phandle(pdev->dev.of_node, 301362306a36Sopenharmony_ci "transceiver", 0); 301462306a36Sopenharmony_ci } else { 301562306a36Sopenharmony_ci isp1301_node = NULL; 301662306a36Sopenharmony_ci } 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci udc->isp1301_i2c_client = isp1301_get_client(isp1301_node); 301962306a36Sopenharmony_ci of_node_put(isp1301_node); 302062306a36Sopenharmony_ci if (!udc->isp1301_i2c_client) { 302162306a36Sopenharmony_ci return -EPROBE_DEFER; 302262306a36Sopenharmony_ci } 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_ci dev_info(udc->dev, "ISP1301 I2C device at address 0x%x\n", 302562306a36Sopenharmony_ci udc->isp1301_i2c_client->addr); 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; 302862306a36Sopenharmony_ci retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); 302962306a36Sopenharmony_ci if (retval) 303062306a36Sopenharmony_ci return retval; 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci udc->board = &lpc32xx_usbddata; 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci /* 303562306a36Sopenharmony_ci * Resources are mapped as follows: 303662306a36Sopenharmony_ci * IORESOURCE_MEM, base address and size of USB space 303762306a36Sopenharmony_ci * IORESOURCE_IRQ, USB device low priority interrupt number 303862306a36Sopenharmony_ci * IORESOURCE_IRQ, USB device high priority interrupt number 303962306a36Sopenharmony_ci * IORESOURCE_IRQ, USB device interrupt number 304062306a36Sopenharmony_ci * IORESOURCE_IRQ, USB transceiver interrupt number 304162306a36Sopenharmony_ci */ 304262306a36Sopenharmony_ci 304362306a36Sopenharmony_ci spin_lock_init(&udc->lock); 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci /* Get IRQs */ 304662306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 304762306a36Sopenharmony_ci udc->udp_irq[i] = platform_get_irq(pdev, i); 304862306a36Sopenharmony_ci if (udc->udp_irq[i] < 0) 304962306a36Sopenharmony_ci return udc->udp_irq[i]; 305062306a36Sopenharmony_ci } 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_ci udc->udp_baseaddr = devm_platform_ioremap_resource(pdev, 0); 305362306a36Sopenharmony_ci if (IS_ERR(udc->udp_baseaddr)) { 305462306a36Sopenharmony_ci dev_err(udc->dev, "IO map failure\n"); 305562306a36Sopenharmony_ci return PTR_ERR(udc->udp_baseaddr); 305662306a36Sopenharmony_ci } 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci /* Get USB device clock */ 305962306a36Sopenharmony_ci udc->usb_slv_clk = devm_clk_get(&pdev->dev, NULL); 306062306a36Sopenharmony_ci if (IS_ERR(udc->usb_slv_clk)) { 306162306a36Sopenharmony_ci dev_err(udc->dev, "failed to acquire USB device clock\n"); 306262306a36Sopenharmony_ci return PTR_ERR(udc->usb_slv_clk); 306362306a36Sopenharmony_ci } 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_ci /* Enable USB device clock */ 306662306a36Sopenharmony_ci retval = clk_prepare_enable(udc->usb_slv_clk); 306762306a36Sopenharmony_ci if (retval < 0) { 306862306a36Sopenharmony_ci dev_err(udc->dev, "failed to start USB device clock\n"); 306962306a36Sopenharmony_ci return retval; 307062306a36Sopenharmony_ci } 307162306a36Sopenharmony_ci 307262306a36Sopenharmony_ci /* Setup deferred workqueue data */ 307362306a36Sopenharmony_ci udc->poweron = udc->pullup = 0; 307462306a36Sopenharmony_ci INIT_WORK(&udc->pullup_job, pullup_work); 307562306a36Sopenharmony_ci#ifdef CONFIG_PM 307662306a36Sopenharmony_ci INIT_WORK(&udc->power_job, power_work); 307762306a36Sopenharmony_ci#endif 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_ci /* All clocks are now on */ 308062306a36Sopenharmony_ci udc->clocked = 1; 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci isp1301_udc_configure(udc); 308362306a36Sopenharmony_ci /* Allocate memory for the UDCA */ 308462306a36Sopenharmony_ci udc->udca_v_base = dma_alloc_coherent(&pdev->dev, UDCA_BUFF_SIZE, 308562306a36Sopenharmony_ci &dma_handle, 308662306a36Sopenharmony_ci (GFP_KERNEL | GFP_DMA)); 308762306a36Sopenharmony_ci if (!udc->udca_v_base) { 308862306a36Sopenharmony_ci dev_err(udc->dev, "error getting UDCA region\n"); 308962306a36Sopenharmony_ci retval = -ENOMEM; 309062306a36Sopenharmony_ci goto i2c_fail; 309162306a36Sopenharmony_ci } 309262306a36Sopenharmony_ci udc->udca_p_base = dma_handle; 309362306a36Sopenharmony_ci dev_dbg(udc->dev, "DMA buffer(0x%x bytes), P:0x%08x, V:0x%p\n", 309462306a36Sopenharmony_ci UDCA_BUFF_SIZE, udc->udca_p_base, udc->udca_v_base); 309562306a36Sopenharmony_ci 309662306a36Sopenharmony_ci /* Setup the DD DMA memory pool */ 309762306a36Sopenharmony_ci udc->dd_cache = dma_pool_create("udc_dd", udc->dev, 309862306a36Sopenharmony_ci sizeof(struct lpc32xx_usbd_dd_gad), 309962306a36Sopenharmony_ci sizeof(u32), 0); 310062306a36Sopenharmony_ci if (!udc->dd_cache) { 310162306a36Sopenharmony_ci dev_err(udc->dev, "error getting DD DMA region\n"); 310262306a36Sopenharmony_ci retval = -ENOMEM; 310362306a36Sopenharmony_ci goto dma_alloc_fail; 310462306a36Sopenharmony_ci } 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci /* Clear USB peripheral and initialize gadget endpoints */ 310762306a36Sopenharmony_ci udc_disable(udc); 310862306a36Sopenharmony_ci udc_reinit(udc); 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci /* Request IRQs - low and high priority USB device IRQs are routed to 311162306a36Sopenharmony_ci * the same handler, while the DMA interrupt is routed elsewhere */ 311262306a36Sopenharmony_ci retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_LP], 311362306a36Sopenharmony_ci lpc32xx_usb_lp_irq, 0, "udc_lp", udc); 311462306a36Sopenharmony_ci if (retval < 0) { 311562306a36Sopenharmony_ci dev_err(udc->dev, "LP request irq %d failed\n", 311662306a36Sopenharmony_ci udc->udp_irq[IRQ_USB_LP]); 311762306a36Sopenharmony_ci goto irq_req_fail; 311862306a36Sopenharmony_ci } 311962306a36Sopenharmony_ci retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_HP], 312062306a36Sopenharmony_ci lpc32xx_usb_hp_irq, 0, "udc_hp", udc); 312162306a36Sopenharmony_ci if (retval < 0) { 312262306a36Sopenharmony_ci dev_err(udc->dev, "HP request irq %d failed\n", 312362306a36Sopenharmony_ci udc->udp_irq[IRQ_USB_HP]); 312462306a36Sopenharmony_ci goto irq_req_fail; 312562306a36Sopenharmony_ci } 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_ci retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_DEVDMA], 312862306a36Sopenharmony_ci lpc32xx_usb_devdma_irq, 0, "udc_dma", udc); 312962306a36Sopenharmony_ci if (retval < 0) { 313062306a36Sopenharmony_ci dev_err(udc->dev, "DEV request irq %d failed\n", 313162306a36Sopenharmony_ci udc->udp_irq[IRQ_USB_DEVDMA]); 313262306a36Sopenharmony_ci goto irq_req_fail; 313362306a36Sopenharmony_ci } 313462306a36Sopenharmony_ci 313562306a36Sopenharmony_ci /* The transceiver interrupt is used for VBUS detection and will 313662306a36Sopenharmony_ci kick off the VBUS handler function */ 313762306a36Sopenharmony_ci retval = devm_request_threaded_irq(dev, udc->udp_irq[IRQ_USB_ATX], NULL, 313862306a36Sopenharmony_ci lpc32xx_usb_vbus_irq, IRQF_ONESHOT, 313962306a36Sopenharmony_ci "udc_otg", udc); 314062306a36Sopenharmony_ci if (retval < 0) { 314162306a36Sopenharmony_ci dev_err(udc->dev, "VBUS request irq %d failed\n", 314262306a36Sopenharmony_ci udc->udp_irq[IRQ_USB_ATX]); 314362306a36Sopenharmony_ci goto irq_req_fail; 314462306a36Sopenharmony_ci } 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_ci /* Initialize wait queue */ 314762306a36Sopenharmony_ci init_waitqueue_head(&udc->ep_disable_wait_queue); 314862306a36Sopenharmony_ci atomic_set(&udc->enabled_ep_cnt, 0); 314962306a36Sopenharmony_ci 315062306a36Sopenharmony_ci retval = usb_add_gadget_udc(dev, &udc->gadget); 315162306a36Sopenharmony_ci if (retval < 0) 315262306a36Sopenharmony_ci goto add_gadget_fail; 315362306a36Sopenharmony_ci 315462306a36Sopenharmony_ci dev_set_drvdata(dev, udc); 315562306a36Sopenharmony_ci device_init_wakeup(dev, 1); 315662306a36Sopenharmony_ci create_debug_file(udc); 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_ci /* Disable clocks for now */ 315962306a36Sopenharmony_ci udc_clk_set(udc, 0); 316062306a36Sopenharmony_ci 316162306a36Sopenharmony_ci dev_info(udc->dev, "%s version %s\n", driver_name, DRIVER_VERSION); 316262306a36Sopenharmony_ci return 0; 316362306a36Sopenharmony_ci 316462306a36Sopenharmony_ciadd_gadget_fail: 316562306a36Sopenharmony_ciirq_req_fail: 316662306a36Sopenharmony_ci dma_pool_destroy(udc->dd_cache); 316762306a36Sopenharmony_cidma_alloc_fail: 316862306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, 316962306a36Sopenharmony_ci udc->udca_v_base, udc->udca_p_base); 317062306a36Sopenharmony_cii2c_fail: 317162306a36Sopenharmony_ci clk_disable_unprepare(udc->usb_slv_clk); 317262306a36Sopenharmony_ci dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval); 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci return retval; 317562306a36Sopenharmony_ci} 317662306a36Sopenharmony_ci 317762306a36Sopenharmony_cistatic int lpc32xx_udc_remove(struct platform_device *pdev) 317862306a36Sopenharmony_ci{ 317962306a36Sopenharmony_ci struct lpc32xx_udc *udc = platform_get_drvdata(pdev); 318062306a36Sopenharmony_ci 318162306a36Sopenharmony_ci usb_del_gadget_udc(&udc->gadget); 318262306a36Sopenharmony_ci if (udc->driver) 318362306a36Sopenharmony_ci return -EBUSY; 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci udc_clk_set(udc, 1); 318662306a36Sopenharmony_ci udc_disable(udc); 318762306a36Sopenharmony_ci pullup(udc, 0); 318862306a36Sopenharmony_ci 318962306a36Sopenharmony_ci device_init_wakeup(&pdev->dev, 0); 319062306a36Sopenharmony_ci remove_debug_file(udc); 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_ci dma_pool_destroy(udc->dd_cache); 319362306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, 319462306a36Sopenharmony_ci udc->udca_v_base, udc->udca_p_base); 319562306a36Sopenharmony_ci 319662306a36Sopenharmony_ci clk_disable_unprepare(udc->usb_slv_clk); 319762306a36Sopenharmony_ci 319862306a36Sopenharmony_ci return 0; 319962306a36Sopenharmony_ci} 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_ci#ifdef CONFIG_PM 320262306a36Sopenharmony_cistatic int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg) 320362306a36Sopenharmony_ci{ 320462306a36Sopenharmony_ci struct lpc32xx_udc *udc = platform_get_drvdata(pdev); 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci if (udc->clocked) { 320762306a36Sopenharmony_ci /* Power down ISP */ 320862306a36Sopenharmony_ci udc->poweron = 0; 320962306a36Sopenharmony_ci isp1301_set_powerstate(udc, 0); 321062306a36Sopenharmony_ci 321162306a36Sopenharmony_ci /* Disable clocking */ 321262306a36Sopenharmony_ci udc_clk_set(udc, 0); 321362306a36Sopenharmony_ci 321462306a36Sopenharmony_ci /* Keep clock flag on, so we know to re-enable clocks 321562306a36Sopenharmony_ci on resume */ 321662306a36Sopenharmony_ci udc->clocked = 1; 321762306a36Sopenharmony_ci 321862306a36Sopenharmony_ci /* Kill global USB clock */ 321962306a36Sopenharmony_ci clk_disable_unprepare(udc->usb_slv_clk); 322062306a36Sopenharmony_ci } 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci return 0; 322362306a36Sopenharmony_ci} 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_cistatic int lpc32xx_udc_resume(struct platform_device *pdev) 322662306a36Sopenharmony_ci{ 322762306a36Sopenharmony_ci struct lpc32xx_udc *udc = platform_get_drvdata(pdev); 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_ci if (udc->clocked) { 323062306a36Sopenharmony_ci /* Enable global USB clock */ 323162306a36Sopenharmony_ci clk_prepare_enable(udc->usb_slv_clk); 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci /* Enable clocking */ 323462306a36Sopenharmony_ci udc_clk_set(udc, 1); 323562306a36Sopenharmony_ci 323662306a36Sopenharmony_ci /* ISP back to normal power mode */ 323762306a36Sopenharmony_ci udc->poweron = 1; 323862306a36Sopenharmony_ci isp1301_set_powerstate(udc, 1); 323962306a36Sopenharmony_ci } 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ci return 0; 324262306a36Sopenharmony_ci} 324362306a36Sopenharmony_ci#else 324462306a36Sopenharmony_ci#define lpc32xx_udc_suspend NULL 324562306a36Sopenharmony_ci#define lpc32xx_udc_resume NULL 324662306a36Sopenharmony_ci#endif 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci#ifdef CONFIG_OF 324962306a36Sopenharmony_cistatic const struct of_device_id lpc32xx_udc_of_match[] = { 325062306a36Sopenharmony_ci { .compatible = "nxp,lpc3220-udc", }, 325162306a36Sopenharmony_ci { }, 325262306a36Sopenharmony_ci}; 325362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, lpc32xx_udc_of_match); 325462306a36Sopenharmony_ci#endif 325562306a36Sopenharmony_ci 325662306a36Sopenharmony_cistatic struct platform_driver lpc32xx_udc_driver = { 325762306a36Sopenharmony_ci .remove = lpc32xx_udc_remove, 325862306a36Sopenharmony_ci .shutdown = lpc32xx_udc_shutdown, 325962306a36Sopenharmony_ci .suspend = lpc32xx_udc_suspend, 326062306a36Sopenharmony_ci .resume = lpc32xx_udc_resume, 326162306a36Sopenharmony_ci .driver = { 326262306a36Sopenharmony_ci .name = driver_name, 326362306a36Sopenharmony_ci .of_match_table = of_match_ptr(lpc32xx_udc_of_match), 326462306a36Sopenharmony_ci }, 326562306a36Sopenharmony_ci}; 326662306a36Sopenharmony_ci 326762306a36Sopenharmony_cimodule_platform_driver_probe(lpc32xx_udc_driver, lpc32xx_udc_probe); 326862306a36Sopenharmony_ci 326962306a36Sopenharmony_ciMODULE_DESCRIPTION("LPC32XX udc driver"); 327062306a36Sopenharmony_ciMODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>"); 327162306a36Sopenharmony_ciMODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); 327262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 327362306a36Sopenharmony_ciMODULE_ALIAS("platform:lpc32xx_udc"); 3274