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