1055276c1SNeal Liu // SPDX-License-Identifier: GPL-2.0+ 2055276c1SNeal Liu /* 3055276c1SNeal Liu * Copyright (c) 2021 Aspeed Technology Inc. 4055276c1SNeal Liu */ 5055276c1SNeal Liu 6055276c1SNeal Liu #include <linux/clk.h> 7055276c1SNeal Liu #include <linux/delay.h> 8055276c1SNeal Liu #include <linux/dma-mapping.h> 9055276c1SNeal Liu #include <linux/interrupt.h> 10055276c1SNeal Liu #include <linux/kernel.h> 11055276c1SNeal Liu #include <linux/module.h> 12055276c1SNeal Liu #include <linux/of.h> 13055276c1SNeal Liu #include <linux/platform_device.h> 14055276c1SNeal Liu #include <linux/prefetch.h> 15055276c1SNeal Liu #include <linux/usb/ch9.h> 16055276c1SNeal Liu #include <linux/usb/gadget.h> 17055276c1SNeal Liu #include <linux/slab.h> 18055276c1SNeal Liu 19055276c1SNeal Liu #define AST_UDC_NUM_ENDPOINTS (1 + 4) 20055276c1SNeal Liu #define AST_UDC_EP0_MAX_PACKET 64 /* EP0's max packet size */ 21055276c1SNeal Liu #define AST_UDC_EPn_MAX_PACKET 1024 /* Generic EPs max packet size */ 22055276c1SNeal Liu #define AST_UDC_DESCS_COUNT 256 /* Use 256 stages descriptor mode (32/256) */ 23055276c1SNeal Liu #define AST_UDC_DESC_MODE 1 /* Single/Multiple Stage(s) Descriptor Mode */ 24055276c1SNeal Liu 25055276c1SNeal Liu #define AST_UDC_EP_DMA_SIZE (AST_UDC_EPn_MAX_PACKET + 8 * AST_UDC_DESCS_COUNT) 26055276c1SNeal Liu 27055276c1SNeal Liu /***************************** 28055276c1SNeal Liu * * 29055276c1SNeal Liu * UDC register definitions * 30055276c1SNeal Liu * * 31055276c1SNeal Liu *****************************/ 32055276c1SNeal Liu 33055276c1SNeal Liu #define AST_UDC_FUNC_CTRL 0x00 /* Root Function Control & Status Register */ 34055276c1SNeal Liu #define AST_UDC_CONFIG 0x04 /* Root Configuration Setting Register */ 35055276c1SNeal Liu #define AST_UDC_IER 0x08 /* Interrupt Control Register */ 36055276c1SNeal Liu #define AST_UDC_ISR 0x0C /* Interrupt Status Register */ 37055276c1SNeal Liu #define AST_UDC_EP_ACK_IER 0x10 /* Programmable ep Pool ACK Interrupt Enable Reg */ 38055276c1SNeal Liu #define AST_UDC_EP_NAK_IER 0x14 /* Programmable ep Pool NAK Interrupt Enable Reg */ 39055276c1SNeal Liu #define AST_UDC_EP_ACK_ISR 0x18 /* Programmable ep Pool ACK Interrupt Status Reg */ 40055276c1SNeal Liu #define AST_UDC_EP_NAK_ISR 0x1C /* Programmable ep Pool NAK Interrupt Status Reg */ 41055276c1SNeal Liu #define AST_UDC_DEV_RESET 0x20 /* Device Controller Soft Reset Enable Register */ 42055276c1SNeal Liu #define AST_UDC_STS 0x24 /* USB Status Register */ 43055276c1SNeal Liu #define AST_VHUB_EP_DATA 0x28 /* Programmable ep Pool Data Toggle Value Set */ 44055276c1SNeal Liu #define AST_VHUB_ISO_TX_FAIL 0x2C /* Isochronous Transaction Fail Accumulator */ 45055276c1SNeal Liu #define AST_UDC_EP0_CTRL 0x30 /* Endpoint 0 Control/Status Register */ 46055276c1SNeal Liu #define AST_UDC_EP0_DATA_BUFF 0x34 /* Base Address of ep0 IN/OUT Data Buffer Reg */ 47055276c1SNeal Liu #define AST_UDC_SETUP0 0x80 /* Root Device Setup Data Buffer0 */ 48055276c1SNeal Liu #define AST_UDC_SETUP1 0x84 /* Root Device Setup Data Buffer1 */ 49055276c1SNeal Liu 50055276c1SNeal Liu 51055276c1SNeal Liu /* Main control reg */ 52055276c1SNeal Liu #define USB_PHY_CLK_EN BIT(31) 53055276c1SNeal Liu #define USB_FIFO_DYN_PWRD_EN BIT(19) 54055276c1SNeal Liu #define USB_EP_LONG_DESC BIT(18) 55055276c1SNeal Liu #define USB_BIST_TEST_PASS BIT(13) 56055276c1SNeal Liu #define USB_BIST_TURN_ON BIT(12) 57055276c1SNeal Liu #define USB_PHY_RESET_DIS BIT(11) 58055276c1SNeal Liu #define USB_TEST_MODE(x) ((x) << 8) 59055276c1SNeal Liu #define USB_FORCE_TIMER_HS BIT(7) 60055276c1SNeal Liu #define USB_FORCE_HS BIT(6) 61055276c1SNeal Liu #define USB_REMOTE_WAKEUP_12MS BIT(5) 62055276c1SNeal Liu #define USB_REMOTE_WAKEUP_EN BIT(4) 63055276c1SNeal Liu #define USB_AUTO_REMOTE_WAKEUP_EN BIT(3) 64055276c1SNeal Liu #define USB_STOP_CLK_IN_SUPEND BIT(2) 65055276c1SNeal Liu #define USB_UPSTREAM_FS BIT(1) 66055276c1SNeal Liu #define USB_UPSTREAM_EN BIT(0) 67055276c1SNeal Liu 68055276c1SNeal Liu /* Main config reg */ 69055276c1SNeal Liu #define UDC_CFG_SET_ADDR(x) ((x) & 0x3f) 70055276c1SNeal Liu #define UDC_CFG_ADDR_MASK (0x3f) 71055276c1SNeal Liu 72055276c1SNeal Liu /* Interrupt ctrl & status reg */ 73055276c1SNeal Liu #define UDC_IRQ_EP_POOL_NAK BIT(17) 74055276c1SNeal Liu #define UDC_IRQ_EP_POOL_ACK_STALL BIT(16) 75055276c1SNeal Liu #define UDC_IRQ_BUS_RESUME BIT(8) 76055276c1SNeal Liu #define UDC_IRQ_BUS_SUSPEND BIT(7) 77055276c1SNeal Liu #define UDC_IRQ_BUS_RESET BIT(6) 78055276c1SNeal Liu #define UDC_IRQ_EP0_IN_DATA_NAK BIT(4) 79055276c1SNeal Liu #define UDC_IRQ_EP0_IN_ACK_STALL BIT(3) 80055276c1SNeal Liu #define UDC_IRQ_EP0_OUT_NAK BIT(2) 81055276c1SNeal Liu #define UDC_IRQ_EP0_OUT_ACK_STALL BIT(1) 82055276c1SNeal Liu #define UDC_IRQ_EP0_SETUP BIT(0) 83055276c1SNeal Liu #define UDC_IRQ_ACK_ALL (0x1ff) 84055276c1SNeal Liu 85055276c1SNeal Liu /* EP isr reg */ 86055276c1SNeal Liu #define USB_EP3_ISR BIT(3) 87055276c1SNeal Liu #define USB_EP2_ISR BIT(2) 88055276c1SNeal Liu #define USB_EP1_ISR BIT(1) 89055276c1SNeal Liu #define USB_EP0_ISR BIT(0) 90055276c1SNeal Liu #define UDC_IRQ_EP_ACK_ALL (0xf) 91055276c1SNeal Liu 92055276c1SNeal Liu /*Soft reset reg */ 93055276c1SNeal Liu #define ROOT_UDC_SOFT_RESET BIT(0) 94055276c1SNeal Liu 95055276c1SNeal Liu /* USB status reg */ 96055276c1SNeal Liu #define UDC_STS_HIGHSPEED BIT(27) 97055276c1SNeal Liu 98055276c1SNeal Liu /* Programmable EP data toggle */ 99055276c1SNeal Liu #define EP_TOGGLE_SET_EPNUM(x) ((x) & 0x3) 100055276c1SNeal Liu 101055276c1SNeal Liu /* EP0 ctrl reg */ 102055276c1SNeal Liu #define EP0_GET_RX_LEN(x) ((x >> 16) & 0x7f) 103055276c1SNeal Liu #define EP0_TX_LEN(x) ((x & 0x7f) << 8) 104055276c1SNeal Liu #define EP0_RX_BUFF_RDY BIT(2) 105055276c1SNeal Liu #define EP0_TX_BUFF_RDY BIT(1) 106055276c1SNeal Liu #define EP0_STALL BIT(0) 107055276c1SNeal Liu 108055276c1SNeal Liu /************************************* 109055276c1SNeal Liu * * 110055276c1SNeal Liu * per-endpoint register definitions * 111055276c1SNeal Liu * * 112055276c1SNeal Liu *************************************/ 113055276c1SNeal Liu 114055276c1SNeal Liu #define AST_UDC_EP_CONFIG 0x00 /* Endpoint Configuration Register */ 115055276c1SNeal Liu #define AST_UDC_EP_DMA_CTRL 0x04 /* DMA Descriptor List Control/Status Register */ 116055276c1SNeal Liu #define AST_UDC_EP_DMA_BUFF 0x08 /* DMA Descriptor/Buffer Base Address */ 117055276c1SNeal Liu #define AST_UDC_EP_DMA_STS 0x0C /* DMA Descriptor List R/W Pointer and Status */ 118055276c1SNeal Liu 119055276c1SNeal Liu #define AST_UDC_EP_BASE 0x200 120055276c1SNeal Liu #define AST_UDC_EP_OFFSET 0x10 121055276c1SNeal Liu 122055276c1SNeal Liu /* EP config reg */ 123055276c1SNeal Liu #define EP_SET_MAX_PKT(x) ((x & 0x3ff) << 16) 124055276c1SNeal Liu #define EP_DATA_FETCH_CTRL(x) ((x & 0x3) << 14) 125055276c1SNeal Liu #define EP_AUTO_DATA_DISABLE (0x1 << 13) 126055276c1SNeal Liu #define EP_SET_EP_STALL (0x1 << 12) 127055276c1SNeal Liu #define EP_SET_EP_NUM(x) ((x & 0xf) << 8) 128055276c1SNeal Liu #define EP_SET_TYPE_MASK(x) ((x) << 5) 129055276c1SNeal Liu #define EP_TYPE_BULK (0x1) 130055276c1SNeal Liu #define EP_TYPE_INT (0x2) 131055276c1SNeal Liu #define EP_TYPE_ISO (0x3) 132055276c1SNeal Liu #define EP_DIR_OUT (0x1 << 4) 133055276c1SNeal Liu #define EP_ALLOCATED_MASK (0x7 << 1) 134055276c1SNeal Liu #define EP_ENABLE BIT(0) 135055276c1SNeal Liu 136055276c1SNeal Liu /* EP DMA ctrl reg */ 137055276c1SNeal Liu #define EP_DMA_CTRL_GET_PROC_STS(x) ((x >> 4) & 0xf) 138055276c1SNeal Liu #define EP_DMA_CTRL_STS_RX_IDLE 0x0 139055276c1SNeal Liu #define EP_DMA_CTRL_STS_TX_IDLE 0x8 140055276c1SNeal Liu #define EP_DMA_CTRL_IN_LONG_MODE (0x1 << 3) 141055276c1SNeal Liu #define EP_DMA_CTRL_RESET (0x1 << 2) 142055276c1SNeal Liu #define EP_DMA_SINGLE_STAGE (0x1 << 1) 143055276c1SNeal Liu #define EP_DMA_DESC_MODE (0x1 << 0) 144055276c1SNeal Liu 145055276c1SNeal Liu /* EP DMA status reg */ 146055276c1SNeal Liu #define EP_DMA_SET_TX_SIZE(x) ((x & 0x7ff) << 16) 147055276c1SNeal Liu #define EP_DMA_GET_TX_SIZE(x) (((x) >> 16) & 0x7ff) 148055276c1SNeal Liu #define EP_DMA_GET_RPTR(x) (((x) >> 8) & 0xff) 149055276c1SNeal Liu #define EP_DMA_GET_WPTR(x) ((x) & 0xff) 150055276c1SNeal Liu #define EP_DMA_SINGLE_KICK (1 << 0) /* WPTR = 1 for single mode */ 151055276c1SNeal Liu 152055276c1SNeal Liu /* EP desc reg */ 153055276c1SNeal Liu #define AST_EP_DMA_DESC_INTR_ENABLE BIT(31) 154055276c1SNeal Liu #define AST_EP_DMA_DESC_PID_DATA0 (0 << 14) 155055276c1SNeal Liu #define AST_EP_DMA_DESC_PID_DATA2 BIT(14) 156055276c1SNeal Liu #define AST_EP_DMA_DESC_PID_DATA1 (2 << 14) 157055276c1SNeal Liu #define AST_EP_DMA_DESC_PID_MDATA (3 << 14) 158055276c1SNeal Liu #define EP_DESC1_IN_LEN(x) ((x) & 0x1fff) 159055276c1SNeal Liu #define AST_EP_DMA_DESC_MAX_LEN (7680) /* Max packet length for trasmit in 1 desc */ 160055276c1SNeal Liu 161055276c1SNeal Liu struct ast_udc_request { 162055276c1SNeal Liu struct usb_request req; 163055276c1SNeal Liu struct list_head queue; 164055276c1SNeal Liu unsigned mapped:1; 165055276c1SNeal Liu unsigned int actual_dma_length; 166055276c1SNeal Liu u32 saved_dma_wptr; 167055276c1SNeal Liu }; 168055276c1SNeal Liu 169055276c1SNeal Liu #define to_ast_req(__req) container_of(__req, struct ast_udc_request, req) 170055276c1SNeal Liu 171055276c1SNeal Liu struct ast_dma_desc { 172055276c1SNeal Liu u32 des_0; 173055276c1SNeal Liu u32 des_1; 174055276c1SNeal Liu }; 175055276c1SNeal Liu 176055276c1SNeal Liu struct ast_udc_ep { 177055276c1SNeal Liu struct usb_ep ep; 178055276c1SNeal Liu 179055276c1SNeal Liu /* Request queue */ 180055276c1SNeal Liu struct list_head queue; 181055276c1SNeal Liu 182055276c1SNeal Liu struct ast_udc_dev *udc; 183055276c1SNeal Liu void __iomem *ep_reg; 184055276c1SNeal Liu void *epn_buf; 185055276c1SNeal Liu dma_addr_t epn_buf_dma; 186055276c1SNeal Liu const struct usb_endpoint_descriptor *desc; 187055276c1SNeal Liu 188055276c1SNeal Liu /* DMA Descriptors */ 189055276c1SNeal Liu struct ast_dma_desc *descs; 190055276c1SNeal Liu dma_addr_t descs_dma; 191055276c1SNeal Liu u32 descs_wptr; 192055276c1SNeal Liu u32 chunk_max; 193055276c1SNeal Liu 194055276c1SNeal Liu bool dir_in:1; 195055276c1SNeal Liu unsigned stopped:1; 196055276c1SNeal Liu bool desc_mode:1; 197055276c1SNeal Liu }; 198055276c1SNeal Liu 199055276c1SNeal Liu #define to_ast_ep(__ep) container_of(__ep, struct ast_udc_ep, ep) 200055276c1SNeal Liu 201055276c1SNeal Liu struct ast_udc_dev { 202055276c1SNeal Liu struct platform_device *pdev; 203055276c1SNeal Liu void __iomem *reg; 204055276c1SNeal Liu int irq; 205055276c1SNeal Liu spinlock_t lock; 206055276c1SNeal Liu struct clk *clk; 207055276c1SNeal Liu struct work_struct wake_work; 208055276c1SNeal Liu 209055276c1SNeal Liu /* EP0 DMA buffers allocated in one chunk */ 210055276c1SNeal Liu void *ep0_buf; 211055276c1SNeal Liu dma_addr_t ep0_buf_dma; 212055276c1SNeal Liu struct ast_udc_ep ep[AST_UDC_NUM_ENDPOINTS]; 213055276c1SNeal Liu 214055276c1SNeal Liu struct usb_gadget gadget; 215055276c1SNeal Liu struct usb_gadget_driver *driver; 216055276c1SNeal Liu void __iomem *creq; 217055276c1SNeal Liu enum usb_device_state suspended_from; 218055276c1SNeal Liu int desc_mode; 219055276c1SNeal Liu 220055276c1SNeal Liu /* Force full speed only */ 221055276c1SNeal Liu bool force_usb1:1; 222055276c1SNeal Liu unsigned is_control_tx:1; 223055276c1SNeal Liu bool wakeup_en:1; 224055276c1SNeal Liu }; 225055276c1SNeal Liu 226055276c1SNeal Liu #define to_ast_dev(__g) container_of(__g, struct ast_udc_dev, gadget) 227055276c1SNeal Liu 228055276c1SNeal Liu static const char * const ast_ep_name[] = { 229055276c1SNeal Liu "ep0", "ep1", "ep2", "ep3", "ep4" 230055276c1SNeal Liu }; 231055276c1SNeal Liu 232055276c1SNeal Liu #ifdef AST_UDC_DEBUG_ALL 233055276c1SNeal Liu #define AST_UDC_DEBUG 234055276c1SNeal Liu #define AST_SETUP_DEBUG 235055276c1SNeal Liu #define AST_EP_DEBUG 236055276c1SNeal Liu #define AST_ISR_DEBUG 237055276c1SNeal Liu #endif 238055276c1SNeal Liu 239055276c1SNeal Liu #ifdef AST_SETUP_DEBUG 240055276c1SNeal Liu #define SETUP_DBG(u, fmt, ...) \ 241055276c1SNeal Liu dev_dbg(&(u)->pdev->dev, "%s() " fmt, __func__, ##__VA_ARGS__) 242055276c1SNeal Liu #else 243055276c1SNeal Liu #define SETUP_DBG(u, fmt, ...) 244055276c1SNeal Liu #endif 245055276c1SNeal Liu 246055276c1SNeal Liu #ifdef AST_EP_DEBUG 247055276c1SNeal Liu #define EP_DBG(e, fmt, ...) \ 248055276c1SNeal Liu dev_dbg(&(e)->udc->pdev->dev, "%s():%s " fmt, __func__, \ 249055276c1SNeal Liu (e)->ep.name, ##__VA_ARGS__) 250055276c1SNeal Liu #else 251055276c1SNeal Liu #define EP_DBG(ep, fmt, ...) ((void)(ep)) 252055276c1SNeal Liu #endif 253055276c1SNeal Liu 254055276c1SNeal Liu #ifdef AST_UDC_DEBUG 255055276c1SNeal Liu #define UDC_DBG(u, fmt, ...) \ 256055276c1SNeal Liu dev_dbg(&(u)->pdev->dev, "%s() " fmt, __func__, ##__VA_ARGS__) 257055276c1SNeal Liu #else 258055276c1SNeal Liu #define UDC_DBG(u, fmt, ...) 259055276c1SNeal Liu #endif 260055276c1SNeal Liu 261055276c1SNeal Liu #ifdef AST_ISR_DEBUG 262055276c1SNeal Liu #define ISR_DBG(u, fmt, ...) \ 263055276c1SNeal Liu dev_dbg(&(u)->pdev->dev, "%s() " fmt, __func__, ##__VA_ARGS__) 264055276c1SNeal Liu #else 265055276c1SNeal Liu #define ISR_DBG(u, fmt, ...) 266055276c1SNeal Liu #endif 267055276c1SNeal Liu 268055276c1SNeal Liu /*-------------------------------------------------------------------------*/ 269055276c1SNeal Liu #define ast_udc_read(udc, offset) \ 270055276c1SNeal Liu readl((udc)->reg + (offset)) 271055276c1SNeal Liu #define ast_udc_write(udc, val, offset) \ 272055276c1SNeal Liu writel((val), (udc)->reg + (offset)) 273055276c1SNeal Liu 274055276c1SNeal Liu #define ast_ep_read(ep, reg) \ 275055276c1SNeal Liu readl((ep)->ep_reg + (reg)) 276055276c1SNeal Liu #define ast_ep_write(ep, val, reg) \ 277055276c1SNeal Liu writel((val), (ep)->ep_reg + (reg)) 278055276c1SNeal Liu 279055276c1SNeal Liu /*-------------------------------------------------------------------------*/ 280055276c1SNeal Liu 281055276c1SNeal Liu static void ast_udc_done(struct ast_udc_ep *ep, struct ast_udc_request *req, 282055276c1SNeal Liu int status) 283055276c1SNeal Liu { 284055276c1SNeal Liu struct ast_udc_dev *udc = ep->udc; 285055276c1SNeal Liu 286055276c1SNeal Liu EP_DBG(ep, "req @%p, len (%d/%d), buf:0x%x, dir:0x%x\n", 287055276c1SNeal Liu req, req->req.actual, req->req.length, 288055276c1SNeal Liu (u32)req->req.buf, ep->dir_in); 289055276c1SNeal Liu 290055276c1SNeal Liu list_del(&req->queue); 291055276c1SNeal Liu 292055276c1SNeal Liu if (req->req.status == -EINPROGRESS) 293055276c1SNeal Liu req->req.status = status; 294055276c1SNeal Liu else 295055276c1SNeal Liu status = req->req.status; 296055276c1SNeal Liu 297055276c1SNeal Liu if (status && status != -ESHUTDOWN) 298055276c1SNeal Liu EP_DBG(ep, "done req:%p, status:%d\n", req, status); 299055276c1SNeal Liu 300055276c1SNeal Liu spin_unlock(&udc->lock); 301055276c1SNeal Liu usb_gadget_giveback_request(&ep->ep, &req->req); 302055276c1SNeal Liu spin_lock(&udc->lock); 303055276c1SNeal Liu } 304055276c1SNeal Liu 305055276c1SNeal Liu static void ast_udc_nuke(struct ast_udc_ep *ep, int status) 306055276c1SNeal Liu { 307055276c1SNeal Liu int count = 0; 308055276c1SNeal Liu 309055276c1SNeal Liu while (!list_empty(&ep->queue)) { 310055276c1SNeal Liu struct ast_udc_request *req; 311055276c1SNeal Liu 312055276c1SNeal Liu req = list_entry(ep->queue.next, struct ast_udc_request, 313055276c1SNeal Liu queue); 314055276c1SNeal Liu ast_udc_done(ep, req, status); 315055276c1SNeal Liu count++; 316055276c1SNeal Liu } 317055276c1SNeal Liu 318055276c1SNeal Liu if (count) 319055276c1SNeal Liu EP_DBG(ep, "Nuked %d request(s)\n", count); 320055276c1SNeal Liu } 321055276c1SNeal Liu 322055276c1SNeal Liu /* 323055276c1SNeal Liu * Stop activity on all endpoints. 324055276c1SNeal Liu * Device controller for which EP activity is to be stopped. 325055276c1SNeal Liu * 326055276c1SNeal Liu * All the endpoints are stopped and any pending transfer requests if any on 327055276c1SNeal Liu * the endpoint are terminated. 328055276c1SNeal Liu */ 329055276c1SNeal Liu static void ast_udc_stop_activity(struct ast_udc_dev *udc) 330055276c1SNeal Liu { 331055276c1SNeal Liu struct ast_udc_ep *ep; 332055276c1SNeal Liu int i; 333055276c1SNeal Liu 334055276c1SNeal Liu for (i = 0; i < AST_UDC_NUM_ENDPOINTS; i++) { 335055276c1SNeal Liu ep = &udc->ep[i]; 336055276c1SNeal Liu ep->stopped = 1; 337055276c1SNeal Liu ast_udc_nuke(ep, -ESHUTDOWN); 338055276c1SNeal Liu } 339055276c1SNeal Liu } 340055276c1SNeal Liu 341055276c1SNeal Liu static int ast_udc_ep_enable(struct usb_ep *_ep, 342055276c1SNeal Liu const struct usb_endpoint_descriptor *desc) 343055276c1SNeal Liu { 344055276c1SNeal Liu u16 maxpacket = usb_endpoint_maxp(desc); 345055276c1SNeal Liu struct ast_udc_ep *ep = to_ast_ep(_ep); 346055276c1SNeal Liu struct ast_udc_dev *udc = ep->udc; 347055276c1SNeal Liu u8 epnum = usb_endpoint_num(desc); 348055276c1SNeal Liu unsigned long flags; 349055276c1SNeal Liu u32 ep_conf = 0; 350055276c1SNeal Liu u8 dir_in; 351055276c1SNeal Liu u8 type; 352055276c1SNeal Liu 353055276c1SNeal Liu if (!_ep || !ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT || 354055276c1SNeal Liu maxpacket == 0 || maxpacket > ep->ep.maxpacket) { 355055276c1SNeal Liu EP_DBG(ep, "Failed, invalid EP enable param\n"); 356055276c1SNeal Liu return -EINVAL; 357055276c1SNeal Liu } 358055276c1SNeal Liu 359055276c1SNeal Liu if (!udc->driver) { 360055276c1SNeal Liu EP_DBG(ep, "bogus device state\n"); 361055276c1SNeal Liu return -ESHUTDOWN; 362055276c1SNeal Liu } 363055276c1SNeal Liu 364055276c1SNeal Liu EP_DBG(ep, "maxpacket:0x%x\n", maxpacket); 365055276c1SNeal Liu 366055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 367055276c1SNeal Liu 368055276c1SNeal Liu ep->desc = desc; 369055276c1SNeal Liu ep->stopped = 0; 370055276c1SNeal Liu ep->ep.maxpacket = maxpacket; 371055276c1SNeal Liu ep->chunk_max = AST_EP_DMA_DESC_MAX_LEN; 372055276c1SNeal Liu 373055276c1SNeal Liu if (maxpacket < AST_UDC_EPn_MAX_PACKET) 374055276c1SNeal Liu ep_conf = EP_SET_MAX_PKT(maxpacket); 375055276c1SNeal Liu 376055276c1SNeal Liu ep_conf |= EP_SET_EP_NUM(epnum); 377055276c1SNeal Liu 378055276c1SNeal Liu type = usb_endpoint_type(desc); 379055276c1SNeal Liu dir_in = usb_endpoint_dir_in(desc); 380055276c1SNeal Liu ep->dir_in = dir_in; 381055276c1SNeal Liu if (!ep->dir_in) 382055276c1SNeal Liu ep_conf |= EP_DIR_OUT; 383055276c1SNeal Liu 384055276c1SNeal Liu EP_DBG(ep, "type %d, dir_in %d\n", type, dir_in); 385055276c1SNeal Liu switch (type) { 386055276c1SNeal Liu case USB_ENDPOINT_XFER_ISOC: 387055276c1SNeal Liu ep_conf |= EP_SET_TYPE_MASK(EP_TYPE_ISO); 388055276c1SNeal Liu break; 389055276c1SNeal Liu 390055276c1SNeal Liu case USB_ENDPOINT_XFER_BULK: 391055276c1SNeal Liu ep_conf |= EP_SET_TYPE_MASK(EP_TYPE_BULK); 392055276c1SNeal Liu break; 393055276c1SNeal Liu 394055276c1SNeal Liu case USB_ENDPOINT_XFER_INT: 395055276c1SNeal Liu ep_conf |= EP_SET_TYPE_MASK(EP_TYPE_INT); 396055276c1SNeal Liu break; 397055276c1SNeal Liu } 398055276c1SNeal Liu 399055276c1SNeal Liu ep->desc_mode = udc->desc_mode && ep->descs_dma && ep->dir_in; 400055276c1SNeal Liu if (ep->desc_mode) { 401055276c1SNeal Liu ast_ep_write(ep, EP_DMA_CTRL_RESET, AST_UDC_EP_DMA_CTRL); 402055276c1SNeal Liu ast_ep_write(ep, 0, AST_UDC_EP_DMA_STS); 403055276c1SNeal Liu ast_ep_write(ep, ep->descs_dma, AST_UDC_EP_DMA_BUFF); 404055276c1SNeal Liu 405055276c1SNeal Liu /* Enable Long Descriptor Mode */ 406055276c1SNeal Liu ast_ep_write(ep, EP_DMA_CTRL_IN_LONG_MODE | EP_DMA_DESC_MODE, 407055276c1SNeal Liu AST_UDC_EP_DMA_CTRL); 408055276c1SNeal Liu 409055276c1SNeal Liu ep->descs_wptr = 0; 410055276c1SNeal Liu 411055276c1SNeal Liu } else { 412055276c1SNeal Liu ast_ep_write(ep, EP_DMA_CTRL_RESET, AST_UDC_EP_DMA_CTRL); 413055276c1SNeal Liu ast_ep_write(ep, EP_DMA_SINGLE_STAGE, AST_UDC_EP_DMA_CTRL); 414055276c1SNeal Liu ast_ep_write(ep, 0, AST_UDC_EP_DMA_STS); 415055276c1SNeal Liu } 416055276c1SNeal Liu 417055276c1SNeal Liu /* Cleanup data toggle just in case */ 418055276c1SNeal Liu ast_udc_write(udc, EP_TOGGLE_SET_EPNUM(epnum), AST_VHUB_EP_DATA); 419055276c1SNeal Liu 420055276c1SNeal Liu /* Enable EP */ 421055276c1SNeal Liu ast_ep_write(ep, ep_conf | EP_ENABLE, AST_UDC_EP_CONFIG); 422055276c1SNeal Liu 423055276c1SNeal Liu EP_DBG(ep, "ep_config: 0x%x\n", ast_ep_read(ep, AST_UDC_EP_CONFIG)); 424055276c1SNeal Liu 425055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 426055276c1SNeal Liu 427055276c1SNeal Liu return 0; 428055276c1SNeal Liu } 429055276c1SNeal Liu 430055276c1SNeal Liu static int ast_udc_ep_disable(struct usb_ep *_ep) 431055276c1SNeal Liu { 432055276c1SNeal Liu struct ast_udc_ep *ep = to_ast_ep(_ep); 433055276c1SNeal Liu struct ast_udc_dev *udc = ep->udc; 434055276c1SNeal Liu unsigned long flags; 435055276c1SNeal Liu 436055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 437055276c1SNeal Liu 438055276c1SNeal Liu ep->ep.desc = NULL; 439055276c1SNeal Liu ep->stopped = 1; 440055276c1SNeal Liu 441055276c1SNeal Liu ast_udc_nuke(ep, -ESHUTDOWN); 442055276c1SNeal Liu ast_ep_write(ep, 0, AST_UDC_EP_CONFIG); 443055276c1SNeal Liu 444055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 445055276c1SNeal Liu 446055276c1SNeal Liu return 0; 447055276c1SNeal Liu } 448055276c1SNeal Liu 449055276c1SNeal Liu static struct usb_request *ast_udc_ep_alloc_request(struct usb_ep *_ep, 450055276c1SNeal Liu gfp_t gfp_flags) 451055276c1SNeal Liu { 452055276c1SNeal Liu struct ast_udc_ep *ep = to_ast_ep(_ep); 453055276c1SNeal Liu struct ast_udc_request *req; 454055276c1SNeal Liu 455055276c1SNeal Liu req = kzalloc(sizeof(struct ast_udc_request), gfp_flags); 456055276c1SNeal Liu if (!req) { 457055276c1SNeal Liu EP_DBG(ep, "request allocation failed\n"); 458055276c1SNeal Liu return NULL; 459055276c1SNeal Liu } 460055276c1SNeal Liu 461055276c1SNeal Liu INIT_LIST_HEAD(&req->queue); 462055276c1SNeal Liu 463055276c1SNeal Liu return &req->req; 464055276c1SNeal Liu } 465055276c1SNeal Liu 466055276c1SNeal Liu static void ast_udc_ep_free_request(struct usb_ep *_ep, 467055276c1SNeal Liu struct usb_request *_req) 468055276c1SNeal Liu { 469055276c1SNeal Liu struct ast_udc_request *req = to_ast_req(_req); 470055276c1SNeal Liu 471055276c1SNeal Liu kfree(req); 472055276c1SNeal Liu } 473055276c1SNeal Liu 474055276c1SNeal Liu static int ast_dma_descriptor_setup(struct ast_udc_ep *ep, u32 dma_buf, 475055276c1SNeal Liu u16 tx_len, struct ast_udc_request *req) 476055276c1SNeal Liu { 477055276c1SNeal Liu struct ast_udc_dev *udc = ep->udc; 478055276c1SNeal Liu struct device *dev = &udc->pdev->dev; 479c09b1f37SDan Carpenter int chunk, count; 480c09b1f37SDan Carpenter u32 offset; 481055276c1SNeal Liu 482055276c1SNeal Liu if (!ep->descs) { 483055276c1SNeal Liu dev_warn(dev, "%s: Empty DMA descs list failure\n", 484055276c1SNeal Liu ep->ep.name); 485055276c1SNeal Liu return -EINVAL; 486055276c1SNeal Liu } 487055276c1SNeal Liu 488055276c1SNeal Liu chunk = tx_len; 489c09b1f37SDan Carpenter offset = count = 0; 490055276c1SNeal Liu 491055276c1SNeal Liu EP_DBG(ep, "req @%p, %s:%d, %s:0x%x, %s:0x%x\n", req, 492055276c1SNeal Liu "wptr", ep->descs_wptr, "dma_buf", dma_buf, 493055276c1SNeal Liu "tx_len", tx_len); 494055276c1SNeal Liu 495055276c1SNeal Liu /* Create Descriptor Lists */ 496c09b1f37SDan Carpenter while (chunk > 0 && count < AST_UDC_DESCS_COUNT) { 497055276c1SNeal Liu 498055276c1SNeal Liu ep->descs[ep->descs_wptr].des_0 = dma_buf + offset; 499055276c1SNeal Liu 500c09b1f37SDan Carpenter if (chunk > ep->chunk_max) 501055276c1SNeal Liu ep->descs[ep->descs_wptr].des_1 = ep->chunk_max; 502c09b1f37SDan Carpenter else 503c09b1f37SDan Carpenter ep->descs[ep->descs_wptr].des_1 = chunk; 504055276c1SNeal Liu 505c09b1f37SDan Carpenter chunk -= ep->chunk_max; 506c09b1f37SDan Carpenter 507c09b1f37SDan Carpenter EP_DBG(ep, "descs[%d]: 0x%x 0x%x\n", 508055276c1SNeal Liu ep->descs_wptr, 509055276c1SNeal Liu ep->descs[ep->descs_wptr].des_0, 510c09b1f37SDan Carpenter ep->descs[ep->descs_wptr].des_1); 511055276c1SNeal Liu 512055276c1SNeal Liu if (count == 0) 513055276c1SNeal Liu req->saved_dma_wptr = ep->descs_wptr; 514055276c1SNeal Liu 515055276c1SNeal Liu ep->descs_wptr++; 516055276c1SNeal Liu count++; 517055276c1SNeal Liu 518055276c1SNeal Liu if (ep->descs_wptr >= AST_UDC_DESCS_COUNT) 519055276c1SNeal Liu ep->descs_wptr = 0; 520055276c1SNeal Liu 521055276c1SNeal Liu offset = ep->chunk_max * count; 522055276c1SNeal Liu } 523055276c1SNeal Liu 524055276c1SNeal Liu return 0; 525055276c1SNeal Liu } 526055276c1SNeal Liu 527055276c1SNeal Liu static void ast_udc_epn_kick(struct ast_udc_ep *ep, struct ast_udc_request *req) 528055276c1SNeal Liu { 529055276c1SNeal Liu u32 tx_len; 530055276c1SNeal Liu u32 last; 531055276c1SNeal Liu 532055276c1SNeal Liu last = req->req.length - req->req.actual; 533055276c1SNeal Liu tx_len = last > ep->ep.maxpacket ? ep->ep.maxpacket : last; 534055276c1SNeal Liu 535055276c1SNeal Liu EP_DBG(ep, "kick req @%p, len:%d, dir:%d\n", 536055276c1SNeal Liu req, tx_len, ep->dir_in); 537055276c1SNeal Liu 538055276c1SNeal Liu ast_ep_write(ep, req->req.dma + req->req.actual, AST_UDC_EP_DMA_BUFF); 539055276c1SNeal Liu 540055276c1SNeal Liu /* Start DMA */ 541055276c1SNeal Liu ast_ep_write(ep, EP_DMA_SET_TX_SIZE(tx_len), AST_UDC_EP_DMA_STS); 542055276c1SNeal Liu ast_ep_write(ep, EP_DMA_SET_TX_SIZE(tx_len) | EP_DMA_SINGLE_KICK, 543055276c1SNeal Liu AST_UDC_EP_DMA_STS); 544055276c1SNeal Liu } 545055276c1SNeal Liu 546055276c1SNeal Liu static void ast_udc_epn_kick_desc(struct ast_udc_ep *ep, 547055276c1SNeal Liu struct ast_udc_request *req) 548055276c1SNeal Liu { 549055276c1SNeal Liu u32 descs_max_size; 550055276c1SNeal Liu u32 tx_len; 551055276c1SNeal Liu u32 last; 552055276c1SNeal Liu 553055276c1SNeal Liu descs_max_size = AST_EP_DMA_DESC_MAX_LEN * AST_UDC_DESCS_COUNT; 554055276c1SNeal Liu 555055276c1SNeal Liu last = req->req.length - req->req.actual; 556055276c1SNeal Liu tx_len = last > descs_max_size ? descs_max_size : last; 557055276c1SNeal Liu 558055276c1SNeal Liu EP_DBG(ep, "kick req @%p, %s:%d, %s:0x%x, %s:0x%x (%d/%d), %s:0x%x\n", 559055276c1SNeal Liu req, "tx_len", tx_len, "dir_in", ep->dir_in, 560055276c1SNeal Liu "dma", req->req.dma + req->req.actual, 561055276c1SNeal Liu req->req.actual, req->req.length, 562055276c1SNeal Liu "descs_max_size", descs_max_size); 563055276c1SNeal Liu 564055276c1SNeal Liu if (!ast_dma_descriptor_setup(ep, req->req.dma + req->req.actual, 565055276c1SNeal Liu tx_len, req)) 566055276c1SNeal Liu req->actual_dma_length += tx_len; 567055276c1SNeal Liu 568055276c1SNeal Liu /* make sure CPU done everything before triggering DMA */ 569055276c1SNeal Liu mb(); 570055276c1SNeal Liu 571055276c1SNeal Liu ast_ep_write(ep, ep->descs_wptr, AST_UDC_EP_DMA_STS); 572055276c1SNeal Liu 573055276c1SNeal Liu EP_DBG(ep, "descs_wptr:%d, dstat:0x%x, dctrl:0x%x\n", 574055276c1SNeal Liu ep->descs_wptr, 575055276c1SNeal Liu ast_ep_read(ep, AST_UDC_EP_DMA_STS), 576055276c1SNeal Liu ast_ep_read(ep, AST_UDC_EP_DMA_CTRL)); 577055276c1SNeal Liu } 578055276c1SNeal Liu 579055276c1SNeal Liu static void ast_udc_ep0_queue(struct ast_udc_ep *ep, 580055276c1SNeal Liu struct ast_udc_request *req) 581055276c1SNeal Liu { 582055276c1SNeal Liu struct ast_udc_dev *udc = ep->udc; 583055276c1SNeal Liu u32 tx_len; 584055276c1SNeal Liu u32 last; 585055276c1SNeal Liu 586055276c1SNeal Liu last = req->req.length - req->req.actual; 587055276c1SNeal Liu tx_len = last > ep->ep.maxpacket ? ep->ep.maxpacket : last; 588055276c1SNeal Liu 589055276c1SNeal Liu ast_udc_write(udc, req->req.dma + req->req.actual, 590055276c1SNeal Liu AST_UDC_EP0_DATA_BUFF); 591055276c1SNeal Liu 592055276c1SNeal Liu if (ep->dir_in) { 593055276c1SNeal Liu /* IN requests, send data */ 594055276c1SNeal Liu SETUP_DBG(udc, "IN: %s:0x%x, %s:0x%x, %s:%d (%d/%d), %s:%d\n", 595055276c1SNeal Liu "buf", (u32)req->req.buf, 596055276c1SNeal Liu "dma", req->req.dma + req->req.actual, 597055276c1SNeal Liu "tx_len", tx_len, 598055276c1SNeal Liu req->req.actual, req->req.length, 599055276c1SNeal Liu "dir_in", ep->dir_in); 600055276c1SNeal Liu 601055276c1SNeal Liu req->req.actual += tx_len; 602055276c1SNeal Liu ast_udc_write(udc, EP0_TX_LEN(tx_len), AST_UDC_EP0_CTRL); 603055276c1SNeal Liu ast_udc_write(udc, EP0_TX_LEN(tx_len) | EP0_TX_BUFF_RDY, 604055276c1SNeal Liu AST_UDC_EP0_CTRL); 605055276c1SNeal Liu 606055276c1SNeal Liu } else { 607055276c1SNeal Liu /* OUT requests, receive data */ 608055276c1SNeal Liu SETUP_DBG(udc, "OUT: %s:%x, %s:%x, %s:(%d/%d), %s:%d\n", 609055276c1SNeal Liu "buf", (u32)req->req.buf, 610055276c1SNeal Liu "dma", req->req.dma + req->req.actual, 611055276c1SNeal Liu "len", req->req.actual, req->req.length, 612055276c1SNeal Liu "dir_in", ep->dir_in); 613055276c1SNeal Liu 614055276c1SNeal Liu if (!req->req.length) { 615055276c1SNeal Liu /* 0 len request, send tx as completion */ 616055276c1SNeal Liu ast_udc_write(udc, EP0_TX_BUFF_RDY, AST_UDC_EP0_CTRL); 617055276c1SNeal Liu ep->dir_in = 0x1; 618055276c1SNeal Liu } else 619055276c1SNeal Liu ast_udc_write(udc, EP0_RX_BUFF_RDY, AST_UDC_EP0_CTRL); 620055276c1SNeal Liu } 621055276c1SNeal Liu } 622055276c1SNeal Liu 623055276c1SNeal Liu static int ast_udc_ep_queue(struct usb_ep *_ep, struct usb_request *_req, 624055276c1SNeal Liu gfp_t gfp_flags) 625055276c1SNeal Liu { 626055276c1SNeal Liu struct ast_udc_request *req = to_ast_req(_req); 627055276c1SNeal Liu struct ast_udc_ep *ep = to_ast_ep(_ep); 628055276c1SNeal Liu struct ast_udc_dev *udc = ep->udc; 629055276c1SNeal Liu struct device *dev = &udc->pdev->dev; 630055276c1SNeal Liu unsigned long flags; 631055276c1SNeal Liu int rc; 632055276c1SNeal Liu 633055276c1SNeal Liu if (unlikely(!_req || !_req->complete || !_req->buf || !_ep)) { 634055276c1SNeal Liu dev_warn(dev, "Invalid EP request !\n"); 635055276c1SNeal Liu return -EINVAL; 636055276c1SNeal Liu } 637055276c1SNeal Liu 638055276c1SNeal Liu if (ep->stopped) { 639055276c1SNeal Liu dev_warn(dev, "%s is already stopped !\n", _ep->name); 640055276c1SNeal Liu return -ESHUTDOWN; 641055276c1SNeal Liu } 642055276c1SNeal Liu 643055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 644055276c1SNeal Liu 645055276c1SNeal Liu list_add_tail(&req->queue, &ep->queue); 646055276c1SNeal Liu 647055276c1SNeal Liu req->req.actual = 0; 648055276c1SNeal Liu req->req.status = -EINPROGRESS; 649055276c1SNeal Liu req->actual_dma_length = 0; 650055276c1SNeal Liu 651055276c1SNeal Liu rc = usb_gadget_map_request(&udc->gadget, &req->req, ep->dir_in); 652055276c1SNeal Liu if (rc) { 653055276c1SNeal Liu EP_DBG(ep, "Request mapping failure %d\n", rc); 654055276c1SNeal Liu dev_warn(dev, "Request mapping failure %d\n", rc); 655055276c1SNeal Liu goto end; 656055276c1SNeal Liu } 657055276c1SNeal Liu 658055276c1SNeal Liu EP_DBG(ep, "enqueue req @%p\n", req); 659055276c1SNeal Liu EP_DBG(ep, "l=%d, dma:0x%x, zero:%d, is_in:%d\n", 660055276c1SNeal Liu _req->length, _req->dma, _req->zero, ep->dir_in); 661055276c1SNeal Liu 662055276c1SNeal Liu /* EP0 request enqueue */ 663055276c1SNeal Liu if (ep->ep.desc == NULL) { 664055276c1SNeal Liu if ((req->req.dma % 4) != 0) { 665055276c1SNeal Liu dev_warn(dev, "EP0 req dma alignment error\n"); 6663d393f03SZheng Bin rc = -ESHUTDOWN; 6673d393f03SZheng Bin goto end; 668055276c1SNeal Liu } 669055276c1SNeal Liu 670055276c1SNeal Liu ast_udc_ep0_queue(ep, req); 671055276c1SNeal Liu goto end; 672055276c1SNeal Liu } 673055276c1SNeal Liu 674055276c1SNeal Liu /* EPn request enqueue */ 675055276c1SNeal Liu if (list_is_singular(&ep->queue)) { 676055276c1SNeal Liu if (ep->desc_mode) 677055276c1SNeal Liu ast_udc_epn_kick_desc(ep, req); 678055276c1SNeal Liu else 679055276c1SNeal Liu ast_udc_epn_kick(ep, req); 680055276c1SNeal Liu } 681055276c1SNeal Liu 682055276c1SNeal Liu end: 683055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 684055276c1SNeal Liu 685055276c1SNeal Liu return rc; 686055276c1SNeal Liu } 687055276c1SNeal Liu 688055276c1SNeal Liu static int ast_udc_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) 689055276c1SNeal Liu { 690055276c1SNeal Liu struct ast_udc_ep *ep = to_ast_ep(_ep); 691055276c1SNeal Liu struct ast_udc_dev *udc = ep->udc; 692055276c1SNeal Liu struct ast_udc_request *req; 693055276c1SNeal Liu unsigned long flags; 694055276c1SNeal Liu int rc = 0; 695055276c1SNeal Liu 696055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 697055276c1SNeal Liu 698055276c1SNeal Liu /* make sure it's actually queued on this endpoint */ 699055276c1SNeal Liu list_for_each_entry(req, &ep->queue, queue) { 700055276c1SNeal Liu if (&req->req == _req) { 701055276c1SNeal Liu list_del_init(&req->queue); 702055276c1SNeal Liu ast_udc_done(ep, req, -ESHUTDOWN); 703055276c1SNeal Liu _req->status = -ECONNRESET; 704055276c1SNeal Liu break; 705055276c1SNeal Liu } 706055276c1SNeal Liu } 707055276c1SNeal Liu 708055276c1SNeal Liu /* dequeue request not found */ 709055276c1SNeal Liu if (&req->req != _req) 710055276c1SNeal Liu rc = -EINVAL; 711055276c1SNeal Liu 712055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 713055276c1SNeal Liu 714055276c1SNeal Liu return rc; 715055276c1SNeal Liu } 716055276c1SNeal Liu 717055276c1SNeal Liu static int ast_udc_ep_set_halt(struct usb_ep *_ep, int value) 718055276c1SNeal Liu { 719055276c1SNeal Liu struct ast_udc_ep *ep = to_ast_ep(_ep); 720055276c1SNeal Liu struct ast_udc_dev *udc = ep->udc; 721055276c1SNeal Liu unsigned long flags; 722055276c1SNeal Liu int epnum; 723055276c1SNeal Liu u32 ctrl; 724055276c1SNeal Liu 725055276c1SNeal Liu EP_DBG(ep, "val:%d\n", value); 726055276c1SNeal Liu 727055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 728055276c1SNeal Liu 729055276c1SNeal Liu epnum = usb_endpoint_num(ep->desc); 730055276c1SNeal Liu 731055276c1SNeal Liu /* EP0 */ 732055276c1SNeal Liu if (epnum == 0) { 733055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_EP0_CTRL); 734055276c1SNeal Liu if (value) 735055276c1SNeal Liu ctrl |= EP0_STALL; 736055276c1SNeal Liu else 737055276c1SNeal Liu ctrl &= ~EP0_STALL; 738055276c1SNeal Liu 739055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_EP0_CTRL); 740055276c1SNeal Liu 741055276c1SNeal Liu } else { 742055276c1SNeal Liu /* EPn */ 743055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_EP_CONFIG); 744055276c1SNeal Liu if (value) 745055276c1SNeal Liu ctrl |= EP_SET_EP_STALL; 746055276c1SNeal Liu else 747055276c1SNeal Liu ctrl &= ~EP_SET_EP_STALL; 748055276c1SNeal Liu 749055276c1SNeal Liu ast_ep_write(ep, ctrl, AST_UDC_EP_CONFIG); 750055276c1SNeal Liu 751055276c1SNeal Liu /* only epn is stopped and waits for clear */ 752055276c1SNeal Liu ep->stopped = value ? 1 : 0; 753055276c1SNeal Liu } 754055276c1SNeal Liu 755055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 756055276c1SNeal Liu 757055276c1SNeal Liu return 0; 758055276c1SNeal Liu } 759055276c1SNeal Liu 760055276c1SNeal Liu static const struct usb_ep_ops ast_udc_ep_ops = { 761055276c1SNeal Liu .enable = ast_udc_ep_enable, 762055276c1SNeal Liu .disable = ast_udc_ep_disable, 763055276c1SNeal Liu .alloc_request = ast_udc_ep_alloc_request, 764055276c1SNeal Liu .free_request = ast_udc_ep_free_request, 765055276c1SNeal Liu .queue = ast_udc_ep_queue, 766055276c1SNeal Liu .dequeue = ast_udc_ep_dequeue, 767055276c1SNeal Liu .set_halt = ast_udc_ep_set_halt, 768055276c1SNeal Liu /* there's only imprecise fifo status reporting */ 769055276c1SNeal Liu }; 770055276c1SNeal Liu 771055276c1SNeal Liu static void ast_udc_ep0_rx(struct ast_udc_dev *udc) 772055276c1SNeal Liu { 773055276c1SNeal Liu ast_udc_write(udc, udc->ep0_buf_dma, AST_UDC_EP0_DATA_BUFF); 774055276c1SNeal Liu ast_udc_write(udc, EP0_RX_BUFF_RDY, AST_UDC_EP0_CTRL); 775055276c1SNeal Liu } 776055276c1SNeal Liu 777055276c1SNeal Liu static void ast_udc_ep0_tx(struct ast_udc_dev *udc) 778055276c1SNeal Liu { 779055276c1SNeal Liu ast_udc_write(udc, udc->ep0_buf_dma, AST_UDC_EP0_DATA_BUFF); 780055276c1SNeal Liu ast_udc_write(udc, EP0_TX_BUFF_RDY, AST_UDC_EP0_CTRL); 781055276c1SNeal Liu } 782055276c1SNeal Liu 783055276c1SNeal Liu static void ast_udc_ep0_out(struct ast_udc_dev *udc) 784055276c1SNeal Liu { 785055276c1SNeal Liu struct device *dev = &udc->pdev->dev; 786055276c1SNeal Liu struct ast_udc_ep *ep = &udc->ep[0]; 787055276c1SNeal Liu struct ast_udc_request *req; 788055276c1SNeal Liu u16 rx_len; 789055276c1SNeal Liu 790055276c1SNeal Liu if (list_empty(&ep->queue)) 791055276c1SNeal Liu return; 792055276c1SNeal Liu 793055276c1SNeal Liu req = list_entry(ep->queue.next, struct ast_udc_request, queue); 794055276c1SNeal Liu 795055276c1SNeal Liu rx_len = EP0_GET_RX_LEN(ast_udc_read(udc, AST_UDC_EP0_CTRL)); 796055276c1SNeal Liu req->req.actual += rx_len; 797055276c1SNeal Liu 798055276c1SNeal Liu SETUP_DBG(udc, "req %p (%d/%d)\n", req, 799055276c1SNeal Liu req->req.actual, req->req.length); 800055276c1SNeal Liu 801055276c1SNeal Liu if ((rx_len < ep->ep.maxpacket) || 802055276c1SNeal Liu (req->req.actual == req->req.length)) { 803055276c1SNeal Liu ast_udc_ep0_tx(udc); 804055276c1SNeal Liu if (!ep->dir_in) 805055276c1SNeal Liu ast_udc_done(ep, req, 0); 806055276c1SNeal Liu 807055276c1SNeal Liu } else { 808055276c1SNeal Liu if (rx_len > req->req.length) { 809055276c1SNeal Liu // Issue Fix 810055276c1SNeal Liu dev_warn(dev, "Something wrong (%d/%d)\n", 811055276c1SNeal Liu req->req.actual, req->req.length); 812055276c1SNeal Liu ast_udc_ep0_tx(udc); 813055276c1SNeal Liu ast_udc_done(ep, req, 0); 814055276c1SNeal Liu return; 815055276c1SNeal Liu } 816055276c1SNeal Liu 817055276c1SNeal Liu ep->dir_in = 0; 818055276c1SNeal Liu 819055276c1SNeal Liu /* More works */ 820055276c1SNeal Liu ast_udc_ep0_queue(ep, req); 821055276c1SNeal Liu } 822055276c1SNeal Liu } 823055276c1SNeal Liu 824055276c1SNeal Liu static void ast_udc_ep0_in(struct ast_udc_dev *udc) 825055276c1SNeal Liu { 826055276c1SNeal Liu struct ast_udc_ep *ep = &udc->ep[0]; 827055276c1SNeal Liu struct ast_udc_request *req; 828055276c1SNeal Liu 829055276c1SNeal Liu if (list_empty(&ep->queue)) { 830055276c1SNeal Liu if (udc->is_control_tx) { 831055276c1SNeal Liu ast_udc_ep0_rx(udc); 832055276c1SNeal Liu udc->is_control_tx = 0; 833055276c1SNeal Liu } 834055276c1SNeal Liu 835055276c1SNeal Liu return; 836055276c1SNeal Liu } 837055276c1SNeal Liu 838055276c1SNeal Liu req = list_entry(ep->queue.next, struct ast_udc_request, queue); 839055276c1SNeal Liu 840055276c1SNeal Liu SETUP_DBG(udc, "req %p (%d/%d)\n", req, 841055276c1SNeal Liu req->req.actual, req->req.length); 842055276c1SNeal Liu 843055276c1SNeal Liu if (req->req.length == req->req.actual) { 844055276c1SNeal Liu if (req->req.length) 845055276c1SNeal Liu ast_udc_ep0_rx(udc); 846055276c1SNeal Liu 847055276c1SNeal Liu if (ep->dir_in) 848055276c1SNeal Liu ast_udc_done(ep, req, 0); 849055276c1SNeal Liu 850055276c1SNeal Liu } else { 851055276c1SNeal Liu /* More works */ 852055276c1SNeal Liu ast_udc_ep0_queue(ep, req); 853055276c1SNeal Liu } 854055276c1SNeal Liu } 855055276c1SNeal Liu 856055276c1SNeal Liu static void ast_udc_epn_handle(struct ast_udc_dev *udc, u16 ep_num) 857055276c1SNeal Liu { 858055276c1SNeal Liu struct ast_udc_ep *ep = &udc->ep[ep_num]; 859055276c1SNeal Liu struct ast_udc_request *req; 860055276c1SNeal Liu u16 len = 0; 861055276c1SNeal Liu 862055276c1SNeal Liu if (list_empty(&ep->queue)) 863055276c1SNeal Liu return; 864055276c1SNeal Liu 865055276c1SNeal Liu req = list_first_entry(&ep->queue, struct ast_udc_request, queue); 866055276c1SNeal Liu 867055276c1SNeal Liu len = EP_DMA_GET_TX_SIZE(ast_ep_read(ep, AST_UDC_EP_DMA_STS)); 868055276c1SNeal Liu req->req.actual += len; 869055276c1SNeal Liu 870055276c1SNeal Liu EP_DBG(ep, "req @%p, length:(%d/%d), %s:0x%x\n", req, 871055276c1SNeal Liu req->req.actual, req->req.length, "len", len); 872055276c1SNeal Liu 873055276c1SNeal Liu /* Done this request */ 874055276c1SNeal Liu if (req->req.length == req->req.actual) { 875055276c1SNeal Liu ast_udc_done(ep, req, 0); 876055276c1SNeal Liu req = list_first_entry_or_null(&ep->queue, 877055276c1SNeal Liu struct ast_udc_request, 878055276c1SNeal Liu queue); 879055276c1SNeal Liu 880055276c1SNeal Liu } else { 881055276c1SNeal Liu /* Check for short packet */ 882055276c1SNeal Liu if (len < ep->ep.maxpacket) { 883055276c1SNeal Liu ast_udc_done(ep, req, 0); 884055276c1SNeal Liu req = list_first_entry_or_null(&ep->queue, 885055276c1SNeal Liu struct ast_udc_request, 886055276c1SNeal Liu queue); 887055276c1SNeal Liu } 888055276c1SNeal Liu } 889055276c1SNeal Liu 890055276c1SNeal Liu /* More requests */ 891055276c1SNeal Liu if (req) 892055276c1SNeal Liu ast_udc_epn_kick(ep, req); 893055276c1SNeal Liu } 894055276c1SNeal Liu 895055276c1SNeal Liu static void ast_udc_epn_handle_desc(struct ast_udc_dev *udc, u16 ep_num) 896055276c1SNeal Liu { 897055276c1SNeal Liu struct ast_udc_ep *ep = &udc->ep[ep_num]; 898055276c1SNeal Liu struct device *dev = &udc->pdev->dev; 899055276c1SNeal Liu struct ast_udc_request *req; 900055276c1SNeal Liu u32 proc_sts, wr_ptr, rd_ptr; 901055276c1SNeal Liu u32 len_in_desc, ctrl; 902055276c1SNeal Liu u16 total_len = 0; 903055276c1SNeal Liu int i; 904055276c1SNeal Liu 905055276c1SNeal Liu if (list_empty(&ep->queue)) { 906*e2900f74SColin Ian King dev_warn(dev, "%s request queue empty!\n", ep->ep.name); 907055276c1SNeal Liu return; 908055276c1SNeal Liu } 909055276c1SNeal Liu 910055276c1SNeal Liu req = list_first_entry(&ep->queue, struct ast_udc_request, queue); 911055276c1SNeal Liu 912055276c1SNeal Liu ctrl = ast_ep_read(ep, AST_UDC_EP_DMA_CTRL); 913055276c1SNeal Liu proc_sts = EP_DMA_CTRL_GET_PROC_STS(ctrl); 914055276c1SNeal Liu 915055276c1SNeal Liu /* Check processing status is idle */ 916055276c1SNeal Liu if (proc_sts != EP_DMA_CTRL_STS_RX_IDLE && 917055276c1SNeal Liu proc_sts != EP_DMA_CTRL_STS_TX_IDLE) { 918055276c1SNeal Liu dev_warn(dev, "EP DMA CTRL: 0x%x, PS:0x%x\n", 919055276c1SNeal Liu ast_ep_read(ep, AST_UDC_EP_DMA_CTRL), 920055276c1SNeal Liu proc_sts); 921055276c1SNeal Liu return; 922055276c1SNeal Liu } 923055276c1SNeal Liu 924055276c1SNeal Liu ctrl = ast_ep_read(ep, AST_UDC_EP_DMA_STS); 925055276c1SNeal Liu rd_ptr = EP_DMA_GET_RPTR(ctrl); 926055276c1SNeal Liu wr_ptr = EP_DMA_GET_WPTR(ctrl); 927055276c1SNeal Liu 928055276c1SNeal Liu if (rd_ptr != wr_ptr) { 929055276c1SNeal Liu dev_warn(dev, "desc list is not empty ! %s:%d, %s:%d\n", 930055276c1SNeal Liu "rptr", rd_ptr, "wptr", wr_ptr); 931055276c1SNeal Liu return; 932055276c1SNeal Liu } 933055276c1SNeal Liu 934055276c1SNeal Liu EP_DBG(ep, "rd_ptr:%d, wr_ptr:%d\n", rd_ptr, wr_ptr); 935055276c1SNeal Liu i = req->saved_dma_wptr; 936055276c1SNeal Liu 937055276c1SNeal Liu do { 938055276c1SNeal Liu len_in_desc = EP_DESC1_IN_LEN(ep->descs[i].des_1); 939055276c1SNeal Liu EP_DBG(ep, "desc[%d] len: %d\n", i, len_in_desc); 940055276c1SNeal Liu total_len += len_in_desc; 941055276c1SNeal Liu i++; 942055276c1SNeal Liu if (i >= AST_UDC_DESCS_COUNT) 943055276c1SNeal Liu i = 0; 944055276c1SNeal Liu 945055276c1SNeal Liu } while (i != wr_ptr); 946055276c1SNeal Liu 947055276c1SNeal Liu req->req.actual += total_len; 948055276c1SNeal Liu 949055276c1SNeal Liu EP_DBG(ep, "req @%p, length:(%d/%d), %s:0x%x\n", req, 950055276c1SNeal Liu req->req.actual, req->req.length, "len", total_len); 951055276c1SNeal Liu 952055276c1SNeal Liu /* Done this request */ 953055276c1SNeal Liu if (req->req.length == req->req.actual) { 954055276c1SNeal Liu ast_udc_done(ep, req, 0); 955055276c1SNeal Liu req = list_first_entry_or_null(&ep->queue, 956055276c1SNeal Liu struct ast_udc_request, 957055276c1SNeal Liu queue); 958055276c1SNeal Liu 959055276c1SNeal Liu } else { 960055276c1SNeal Liu /* Check for short packet */ 961055276c1SNeal Liu if (total_len < ep->ep.maxpacket) { 962055276c1SNeal Liu ast_udc_done(ep, req, 0); 963055276c1SNeal Liu req = list_first_entry_or_null(&ep->queue, 964055276c1SNeal Liu struct ast_udc_request, 965055276c1SNeal Liu queue); 966055276c1SNeal Liu } 967055276c1SNeal Liu } 968055276c1SNeal Liu 969055276c1SNeal Liu /* More requests & dma descs not setup yet */ 970055276c1SNeal Liu if (req && (req->actual_dma_length == req->req.actual)) { 971055276c1SNeal Liu EP_DBG(ep, "More requests\n"); 972055276c1SNeal Liu ast_udc_epn_kick_desc(ep, req); 973055276c1SNeal Liu } 974055276c1SNeal Liu } 975055276c1SNeal Liu 976055276c1SNeal Liu static void ast_udc_ep0_data_tx(struct ast_udc_dev *udc, u8 *tx_data, u32 len) 977055276c1SNeal Liu { 978055276c1SNeal Liu if (len) { 979055276c1SNeal Liu memcpy(udc->ep0_buf, tx_data, len); 980055276c1SNeal Liu 981055276c1SNeal Liu ast_udc_write(udc, udc->ep0_buf_dma, AST_UDC_EP0_DATA_BUFF); 982055276c1SNeal Liu ast_udc_write(udc, EP0_TX_LEN(len), AST_UDC_EP0_CTRL); 983055276c1SNeal Liu ast_udc_write(udc, EP0_TX_LEN(len) | EP0_TX_BUFF_RDY, 984055276c1SNeal Liu AST_UDC_EP0_CTRL); 985055276c1SNeal Liu udc->is_control_tx = 1; 986055276c1SNeal Liu 987055276c1SNeal Liu } else 988055276c1SNeal Liu ast_udc_write(udc, EP0_TX_BUFF_RDY, AST_UDC_EP0_CTRL); 989055276c1SNeal Liu } 990055276c1SNeal Liu 991055276c1SNeal Liu static void ast_udc_getstatus(struct ast_udc_dev *udc) 992055276c1SNeal Liu { 993055276c1SNeal Liu struct usb_ctrlrequest crq; 994055276c1SNeal Liu struct ast_udc_ep *ep; 995055276c1SNeal Liu u16 status = 0; 996055276c1SNeal Liu u16 epnum = 0; 997055276c1SNeal Liu 998055276c1SNeal Liu memcpy_fromio(&crq, udc->creq, sizeof(crq)); 999055276c1SNeal Liu 1000055276c1SNeal Liu switch (crq.bRequestType & USB_RECIP_MASK) { 1001055276c1SNeal Liu case USB_RECIP_DEVICE: 1002055276c1SNeal Liu /* Get device status */ 1003055276c1SNeal Liu status = 1 << USB_DEVICE_SELF_POWERED; 1004055276c1SNeal Liu break; 1005055276c1SNeal Liu case USB_RECIP_INTERFACE: 1006055276c1SNeal Liu break; 1007055276c1SNeal Liu case USB_RECIP_ENDPOINT: 1008055276c1SNeal Liu epnum = crq.wIndex & USB_ENDPOINT_NUMBER_MASK; 1009055276c1SNeal Liu status = udc->ep[epnum].stopped; 1010055276c1SNeal Liu break; 1011055276c1SNeal Liu default: 1012055276c1SNeal Liu goto stall; 1013055276c1SNeal Liu } 1014055276c1SNeal Liu 1015055276c1SNeal Liu ep = &udc->ep[epnum]; 1016055276c1SNeal Liu EP_DBG(ep, "status: 0x%x\n", status); 1017055276c1SNeal Liu ast_udc_ep0_data_tx(udc, (u8 *)&status, sizeof(status)); 1018055276c1SNeal Liu 1019055276c1SNeal Liu return; 1020055276c1SNeal Liu 1021055276c1SNeal Liu stall: 1022055276c1SNeal Liu EP_DBG(ep, "Can't respond request\n"); 1023055276c1SNeal Liu ast_udc_write(udc, ast_udc_read(udc, AST_UDC_EP0_CTRL) | EP0_STALL, 1024055276c1SNeal Liu AST_UDC_EP0_CTRL); 1025055276c1SNeal Liu } 1026055276c1SNeal Liu 1027055276c1SNeal Liu static void ast_udc_ep0_handle_setup(struct ast_udc_dev *udc) 1028055276c1SNeal Liu { 1029055276c1SNeal Liu struct ast_udc_ep *ep = &udc->ep[0]; 1030055276c1SNeal Liu struct ast_udc_request *req; 1031055276c1SNeal Liu struct usb_ctrlrequest crq; 1032055276c1SNeal Liu int req_num = 0; 1033055276c1SNeal Liu int rc = 0; 1034055276c1SNeal Liu u32 reg; 1035055276c1SNeal Liu 1036055276c1SNeal Liu memcpy_fromio(&crq, udc->creq, sizeof(crq)); 1037055276c1SNeal Liu 1038*e2900f74SColin Ian King SETUP_DBG(udc, "SETUP packet: %02x/%02x/%04x/%04x/%04x\n", 1039055276c1SNeal Liu crq.bRequestType, crq.bRequest, le16_to_cpu(crq.wValue), 1040055276c1SNeal Liu le16_to_cpu(crq.wIndex), le16_to_cpu(crq.wLength)); 1041055276c1SNeal Liu 1042055276c1SNeal Liu /* 1043055276c1SNeal Liu * Cleanup ep0 request(s) in queue because 1044055276c1SNeal Liu * there is a new control setup comes. 1045055276c1SNeal Liu */ 1046055276c1SNeal Liu list_for_each_entry(req, &udc->ep[0].queue, queue) { 1047055276c1SNeal Liu req_num++; 1048055276c1SNeal Liu EP_DBG(ep, "there is req %p in ep0 queue !\n", req); 1049055276c1SNeal Liu } 1050055276c1SNeal Liu 1051055276c1SNeal Liu if (req_num) 1052055276c1SNeal Liu ast_udc_nuke(&udc->ep[0], -ETIMEDOUT); 1053055276c1SNeal Liu 1054055276c1SNeal Liu udc->ep[0].dir_in = crq.bRequestType & USB_DIR_IN; 1055055276c1SNeal Liu 1056055276c1SNeal Liu if ((crq.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 1057055276c1SNeal Liu switch (crq.bRequest) { 1058055276c1SNeal Liu case USB_REQ_SET_ADDRESS: 1059055276c1SNeal Liu if (ast_udc_read(udc, AST_UDC_STS) & UDC_STS_HIGHSPEED) 1060055276c1SNeal Liu udc->gadget.speed = USB_SPEED_HIGH; 1061055276c1SNeal Liu else 1062055276c1SNeal Liu udc->gadget.speed = USB_SPEED_FULL; 1063055276c1SNeal Liu 1064055276c1SNeal Liu SETUP_DBG(udc, "set addr: 0x%x\n", crq.wValue); 1065055276c1SNeal Liu reg = ast_udc_read(udc, AST_UDC_CONFIG); 1066055276c1SNeal Liu reg &= ~UDC_CFG_ADDR_MASK; 1067055276c1SNeal Liu reg |= UDC_CFG_SET_ADDR(crq.wValue); 1068055276c1SNeal Liu ast_udc_write(udc, reg, AST_UDC_CONFIG); 1069055276c1SNeal Liu goto req_complete; 1070055276c1SNeal Liu 1071055276c1SNeal Liu case USB_REQ_CLEAR_FEATURE: 1072055276c1SNeal Liu SETUP_DBG(udc, "ep0: CLEAR FEATURE\n"); 1073055276c1SNeal Liu goto req_driver; 1074055276c1SNeal Liu 1075055276c1SNeal Liu case USB_REQ_SET_FEATURE: 1076055276c1SNeal Liu SETUP_DBG(udc, "ep0: SET FEATURE\n"); 1077055276c1SNeal Liu goto req_driver; 1078055276c1SNeal Liu 1079055276c1SNeal Liu case USB_REQ_GET_STATUS: 1080055276c1SNeal Liu ast_udc_getstatus(udc); 1081055276c1SNeal Liu return; 1082055276c1SNeal Liu 1083055276c1SNeal Liu default: 1084055276c1SNeal Liu goto req_driver; 1085055276c1SNeal Liu } 1086055276c1SNeal Liu 1087055276c1SNeal Liu } 1088055276c1SNeal Liu 1089055276c1SNeal Liu req_driver: 1090055276c1SNeal Liu if (udc->driver) { 1091055276c1SNeal Liu SETUP_DBG(udc, "Forwarding %s to gadget...\n", 1092055276c1SNeal Liu udc->gadget.name); 1093055276c1SNeal Liu 1094055276c1SNeal Liu spin_unlock(&udc->lock); 1095055276c1SNeal Liu rc = udc->driver->setup(&udc->gadget, &crq); 1096055276c1SNeal Liu spin_lock(&udc->lock); 1097055276c1SNeal Liu 1098055276c1SNeal Liu } else { 1099055276c1SNeal Liu SETUP_DBG(udc, "No gadget for request !\n"); 1100055276c1SNeal Liu } 1101055276c1SNeal Liu 1102055276c1SNeal Liu if (rc >= 0) 1103055276c1SNeal Liu return; 1104055276c1SNeal Liu 1105055276c1SNeal Liu /* Stall if gadget failed */ 1106055276c1SNeal Liu SETUP_DBG(udc, "Stalling, rc:0x%x\n", rc); 1107055276c1SNeal Liu ast_udc_write(udc, ast_udc_read(udc, AST_UDC_EP0_CTRL) | EP0_STALL, 1108055276c1SNeal Liu AST_UDC_EP0_CTRL); 1109055276c1SNeal Liu return; 1110055276c1SNeal Liu 1111055276c1SNeal Liu req_complete: 1112055276c1SNeal Liu SETUP_DBG(udc, "ep0: Sending IN status without data\n"); 1113055276c1SNeal Liu ast_udc_write(udc, EP0_TX_BUFF_RDY, AST_UDC_EP0_CTRL); 1114055276c1SNeal Liu } 1115055276c1SNeal Liu 1116055276c1SNeal Liu static irqreturn_t ast_udc_isr(int irq, void *data) 1117055276c1SNeal Liu { 1118055276c1SNeal Liu struct ast_udc_dev *udc = (struct ast_udc_dev *)data; 1119055276c1SNeal Liu struct ast_udc_ep *ep; 1120055276c1SNeal Liu u32 isr, ep_isr; 1121055276c1SNeal Liu int i; 1122055276c1SNeal Liu 1123055276c1SNeal Liu spin_lock(&udc->lock); 1124055276c1SNeal Liu 1125055276c1SNeal Liu isr = ast_udc_read(udc, AST_UDC_ISR); 1126055276c1SNeal Liu if (!isr) 1127055276c1SNeal Liu goto done; 1128055276c1SNeal Liu 1129055276c1SNeal Liu /* Ack interrupts */ 1130055276c1SNeal Liu ast_udc_write(udc, isr, AST_UDC_ISR); 1131055276c1SNeal Liu 1132055276c1SNeal Liu if (isr & UDC_IRQ_BUS_RESET) { 1133055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_BUS_RESET\n"); 1134055276c1SNeal Liu udc->gadget.speed = USB_SPEED_UNKNOWN; 1135055276c1SNeal Liu 1136055276c1SNeal Liu ep = &udc->ep[1]; 1137055276c1SNeal Liu EP_DBG(ep, "dctrl:0x%x\n", 1138055276c1SNeal Liu ast_ep_read(ep, AST_UDC_EP_DMA_CTRL)); 1139055276c1SNeal Liu 1140055276c1SNeal Liu if (udc->driver && udc->driver->reset) { 1141055276c1SNeal Liu spin_unlock(&udc->lock); 1142055276c1SNeal Liu udc->driver->reset(&udc->gadget); 1143055276c1SNeal Liu spin_lock(&udc->lock); 1144055276c1SNeal Liu } 1145055276c1SNeal Liu } 1146055276c1SNeal Liu 1147055276c1SNeal Liu if (isr & UDC_IRQ_BUS_SUSPEND) { 1148055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_BUS_SUSPEND\n"); 1149055276c1SNeal Liu udc->suspended_from = udc->gadget.state; 1150055276c1SNeal Liu usb_gadget_set_state(&udc->gadget, USB_STATE_SUSPENDED); 1151055276c1SNeal Liu 1152055276c1SNeal Liu if (udc->driver && udc->driver->suspend) { 1153055276c1SNeal Liu spin_unlock(&udc->lock); 1154055276c1SNeal Liu udc->driver->suspend(&udc->gadget); 1155055276c1SNeal Liu spin_lock(&udc->lock); 1156055276c1SNeal Liu } 1157055276c1SNeal Liu } 1158055276c1SNeal Liu 1159055276c1SNeal Liu if (isr & UDC_IRQ_BUS_RESUME) { 1160055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_BUS_RESUME\n"); 1161055276c1SNeal Liu usb_gadget_set_state(&udc->gadget, udc->suspended_from); 1162055276c1SNeal Liu 1163055276c1SNeal Liu if (udc->driver && udc->driver->resume) { 1164055276c1SNeal Liu spin_unlock(&udc->lock); 1165055276c1SNeal Liu udc->driver->resume(&udc->gadget); 1166055276c1SNeal Liu spin_lock(&udc->lock); 1167055276c1SNeal Liu } 1168055276c1SNeal Liu } 1169055276c1SNeal Liu 1170055276c1SNeal Liu if (isr & UDC_IRQ_EP0_IN_ACK_STALL) { 1171055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_EP0_IN_ACK_STALL\n"); 1172055276c1SNeal Liu ast_udc_ep0_in(udc); 1173055276c1SNeal Liu } 1174055276c1SNeal Liu 1175055276c1SNeal Liu if (isr & UDC_IRQ_EP0_OUT_ACK_STALL) { 1176055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_EP0_OUT_ACK_STALL\n"); 1177055276c1SNeal Liu ast_udc_ep0_out(udc); 1178055276c1SNeal Liu } 1179055276c1SNeal Liu 1180055276c1SNeal Liu if (isr & UDC_IRQ_EP0_SETUP) { 1181055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_EP0_SETUP\n"); 1182055276c1SNeal Liu ast_udc_ep0_handle_setup(udc); 1183055276c1SNeal Liu } 1184055276c1SNeal Liu 1185055276c1SNeal Liu if (isr & UDC_IRQ_EP_POOL_ACK_STALL) { 1186055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_EP_POOL_ACK_STALL\n"); 1187055276c1SNeal Liu ep_isr = ast_udc_read(udc, AST_UDC_EP_ACK_ISR); 1188055276c1SNeal Liu 1189055276c1SNeal Liu /* Ack EP interrupts */ 1190055276c1SNeal Liu ast_udc_write(udc, ep_isr, AST_UDC_EP_ACK_ISR); 1191055276c1SNeal Liu 1192055276c1SNeal Liu /* Handle each EP */ 1193055276c1SNeal Liu for (i = 0; i < AST_UDC_NUM_ENDPOINTS - 1; i++) { 1194055276c1SNeal Liu if (ep_isr & (0x1 << i)) { 1195055276c1SNeal Liu ep = &udc->ep[i + 1]; 1196055276c1SNeal Liu if (ep->desc_mode) 1197055276c1SNeal Liu ast_udc_epn_handle_desc(udc, i + 1); 1198055276c1SNeal Liu else 1199055276c1SNeal Liu ast_udc_epn_handle(udc, i + 1); 1200055276c1SNeal Liu } 1201055276c1SNeal Liu } 1202055276c1SNeal Liu } 1203055276c1SNeal Liu 1204055276c1SNeal Liu done: 1205055276c1SNeal Liu spin_unlock(&udc->lock); 1206055276c1SNeal Liu return IRQ_HANDLED; 1207055276c1SNeal Liu } 1208055276c1SNeal Liu 1209055276c1SNeal Liu static int ast_udc_gadget_getframe(struct usb_gadget *gadget) 1210055276c1SNeal Liu { 1211055276c1SNeal Liu struct ast_udc_dev *udc = to_ast_dev(gadget); 1212055276c1SNeal Liu 1213055276c1SNeal Liu return (ast_udc_read(udc, AST_UDC_STS) >> 16) & 0x7ff; 1214055276c1SNeal Liu } 1215055276c1SNeal Liu 1216055276c1SNeal Liu static void ast_udc_wake_work(struct work_struct *work) 1217055276c1SNeal Liu { 1218055276c1SNeal Liu struct ast_udc_dev *udc = container_of(work, struct ast_udc_dev, 1219055276c1SNeal Liu wake_work); 1220055276c1SNeal Liu unsigned long flags; 1221055276c1SNeal Liu u32 ctrl; 1222055276c1SNeal Liu 1223055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 1224055276c1SNeal Liu 1225055276c1SNeal Liu UDC_DBG(udc, "Wakeup Host !\n"); 1226055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL); 1227055276c1SNeal Liu ast_udc_write(udc, ctrl | USB_REMOTE_WAKEUP_EN, AST_UDC_FUNC_CTRL); 1228055276c1SNeal Liu 1229055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 1230055276c1SNeal Liu } 1231055276c1SNeal Liu 1232055276c1SNeal Liu static void ast_udc_wakeup_all(struct ast_udc_dev *udc) 1233055276c1SNeal Liu { 1234055276c1SNeal Liu /* 1235055276c1SNeal Liu * A device is trying to wake the world, because this 1236055276c1SNeal Liu * can recurse into the device, we break the call chain 1237055276c1SNeal Liu * using a work queue 1238055276c1SNeal Liu */ 1239055276c1SNeal Liu schedule_work(&udc->wake_work); 1240055276c1SNeal Liu } 1241055276c1SNeal Liu 1242055276c1SNeal Liu static int ast_udc_wakeup(struct usb_gadget *gadget) 1243055276c1SNeal Liu { 1244055276c1SNeal Liu struct ast_udc_dev *udc = to_ast_dev(gadget); 1245055276c1SNeal Liu unsigned long flags; 1246055276c1SNeal Liu int rc = 0; 1247055276c1SNeal Liu 1248055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 1249055276c1SNeal Liu 1250055276c1SNeal Liu if (!udc->wakeup_en) { 1251055276c1SNeal Liu UDC_DBG(udc, "Remote Wakeup is disabled\n"); 1252055276c1SNeal Liu rc = -EINVAL; 1253055276c1SNeal Liu goto err; 1254055276c1SNeal Liu } 1255055276c1SNeal Liu 1256055276c1SNeal Liu UDC_DBG(udc, "Device initiated wakeup\n"); 1257055276c1SNeal Liu ast_udc_wakeup_all(udc); 1258055276c1SNeal Liu 1259055276c1SNeal Liu err: 1260055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 1261055276c1SNeal Liu return rc; 1262055276c1SNeal Liu } 1263055276c1SNeal Liu 1264055276c1SNeal Liu /* 1265055276c1SNeal Liu * Activate/Deactivate link with host 1266055276c1SNeal Liu */ 1267055276c1SNeal Liu static int ast_udc_pullup(struct usb_gadget *gadget, int is_on) 1268055276c1SNeal Liu { 1269055276c1SNeal Liu struct ast_udc_dev *udc = to_ast_dev(gadget); 1270055276c1SNeal Liu unsigned long flags; 1271055276c1SNeal Liu u32 ctrl; 1272055276c1SNeal Liu 1273055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 1274055276c1SNeal Liu 1275055276c1SNeal Liu UDC_DBG(udc, "is_on: %d\n", is_on); 1276055276c1SNeal Liu if (is_on) 1277055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL) | USB_UPSTREAM_EN; 1278055276c1SNeal Liu else 1279055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL) & ~USB_UPSTREAM_EN; 1280055276c1SNeal Liu 1281055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); 1282055276c1SNeal Liu 1283055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 1284055276c1SNeal Liu 1285055276c1SNeal Liu return 0; 1286055276c1SNeal Liu } 1287055276c1SNeal Liu 1288055276c1SNeal Liu static int ast_udc_start(struct usb_gadget *gadget, 1289055276c1SNeal Liu struct usb_gadget_driver *driver) 1290055276c1SNeal Liu { 1291055276c1SNeal Liu struct ast_udc_dev *udc = to_ast_dev(gadget); 1292055276c1SNeal Liu struct ast_udc_ep *ep; 1293055276c1SNeal Liu unsigned long flags; 1294055276c1SNeal Liu int i; 1295055276c1SNeal Liu 1296055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 1297055276c1SNeal Liu 1298055276c1SNeal Liu UDC_DBG(udc, "\n"); 1299055276c1SNeal Liu udc->driver = driver; 1300055276c1SNeal Liu udc->gadget.dev.of_node = udc->pdev->dev.of_node; 1301055276c1SNeal Liu 1302055276c1SNeal Liu for (i = 0; i < AST_UDC_NUM_ENDPOINTS; i++) { 1303055276c1SNeal Liu ep = &udc->ep[i]; 1304055276c1SNeal Liu ep->stopped = 0; 1305055276c1SNeal Liu } 1306055276c1SNeal Liu 1307055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 1308055276c1SNeal Liu 1309055276c1SNeal Liu return 0; 1310055276c1SNeal Liu } 1311055276c1SNeal Liu 1312055276c1SNeal Liu static int ast_udc_stop(struct usb_gadget *gadget) 1313055276c1SNeal Liu { 1314055276c1SNeal Liu struct ast_udc_dev *udc = to_ast_dev(gadget); 1315055276c1SNeal Liu unsigned long flags; 1316055276c1SNeal Liu u32 ctrl; 1317055276c1SNeal Liu 1318055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 1319055276c1SNeal Liu 1320055276c1SNeal Liu UDC_DBG(udc, "\n"); 1321055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL) & ~USB_UPSTREAM_EN; 1322055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); 1323055276c1SNeal Liu 1324055276c1SNeal Liu udc->gadget.speed = USB_SPEED_UNKNOWN; 1325055276c1SNeal Liu udc->driver = NULL; 1326055276c1SNeal Liu 1327055276c1SNeal Liu ast_udc_stop_activity(udc); 1328055276c1SNeal Liu usb_gadget_set_state(&udc->gadget, USB_STATE_NOTATTACHED); 1329055276c1SNeal Liu 1330055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 1331055276c1SNeal Liu 1332055276c1SNeal Liu return 0; 1333055276c1SNeal Liu } 1334055276c1SNeal Liu 1335055276c1SNeal Liu static const struct usb_gadget_ops ast_udc_ops = { 1336055276c1SNeal Liu .get_frame = ast_udc_gadget_getframe, 1337055276c1SNeal Liu .wakeup = ast_udc_wakeup, 1338055276c1SNeal Liu .pullup = ast_udc_pullup, 1339055276c1SNeal Liu .udc_start = ast_udc_start, 1340055276c1SNeal Liu .udc_stop = ast_udc_stop, 1341055276c1SNeal Liu }; 1342055276c1SNeal Liu 1343055276c1SNeal Liu /* 1344055276c1SNeal Liu * Support 1 Control Endpoint. 1345055276c1SNeal Liu * Support multiple programmable endpoints that can be configured to 1346055276c1SNeal Liu * Bulk IN/OUT, Interrupt IN/OUT, and Isochronous IN/OUT type endpoint. 1347055276c1SNeal Liu */ 1348055276c1SNeal Liu static void ast_udc_init_ep(struct ast_udc_dev *udc) 1349055276c1SNeal Liu { 1350055276c1SNeal Liu struct ast_udc_ep *ep; 1351055276c1SNeal Liu int i; 1352055276c1SNeal Liu 1353055276c1SNeal Liu for (i = 0; i < AST_UDC_NUM_ENDPOINTS; i++) { 1354055276c1SNeal Liu ep = &udc->ep[i]; 1355055276c1SNeal Liu ep->ep.name = ast_ep_name[i]; 1356055276c1SNeal Liu if (i == 0) { 1357055276c1SNeal Liu ep->ep.caps.type_control = true; 1358055276c1SNeal Liu } else { 1359055276c1SNeal Liu ep->ep.caps.type_iso = true; 1360055276c1SNeal Liu ep->ep.caps.type_bulk = true; 1361055276c1SNeal Liu ep->ep.caps.type_int = true; 1362055276c1SNeal Liu } 1363055276c1SNeal Liu ep->ep.caps.dir_in = true; 1364055276c1SNeal Liu ep->ep.caps.dir_out = true; 1365055276c1SNeal Liu 1366055276c1SNeal Liu ep->ep.ops = &ast_udc_ep_ops; 1367055276c1SNeal Liu ep->udc = udc; 1368055276c1SNeal Liu 1369055276c1SNeal Liu INIT_LIST_HEAD(&ep->queue); 1370055276c1SNeal Liu 1371055276c1SNeal Liu if (i == 0) { 1372055276c1SNeal Liu usb_ep_set_maxpacket_limit(&ep->ep, 1373055276c1SNeal Liu AST_UDC_EP0_MAX_PACKET); 1374055276c1SNeal Liu continue; 1375055276c1SNeal Liu } 1376055276c1SNeal Liu 1377055276c1SNeal Liu ep->ep_reg = udc->reg + AST_UDC_EP_BASE + 1378055276c1SNeal Liu (AST_UDC_EP_OFFSET * (i - 1)); 1379055276c1SNeal Liu 1380055276c1SNeal Liu ep->epn_buf = udc->ep0_buf + (i * AST_UDC_EP_DMA_SIZE); 1381055276c1SNeal Liu ep->epn_buf_dma = udc->ep0_buf_dma + (i * AST_UDC_EP_DMA_SIZE); 1382055276c1SNeal Liu usb_ep_set_maxpacket_limit(&ep->ep, AST_UDC_EPn_MAX_PACKET); 1383055276c1SNeal Liu 1384055276c1SNeal Liu ep->descs = ep->epn_buf + AST_UDC_EPn_MAX_PACKET; 1385055276c1SNeal Liu ep->descs_dma = ep->epn_buf_dma + AST_UDC_EPn_MAX_PACKET; 1386055276c1SNeal Liu ep->descs_wptr = 0; 1387055276c1SNeal Liu 1388055276c1SNeal Liu list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); 1389055276c1SNeal Liu } 1390055276c1SNeal Liu } 1391055276c1SNeal Liu 1392055276c1SNeal Liu static void ast_udc_init_dev(struct ast_udc_dev *udc) 1393055276c1SNeal Liu { 1394055276c1SNeal Liu INIT_WORK(&udc->wake_work, ast_udc_wake_work); 1395055276c1SNeal Liu } 1396055276c1SNeal Liu 1397055276c1SNeal Liu static void ast_udc_init_hw(struct ast_udc_dev *udc) 1398055276c1SNeal Liu { 1399055276c1SNeal Liu u32 ctrl; 1400055276c1SNeal Liu 1401055276c1SNeal Liu /* Enable PHY */ 1402055276c1SNeal Liu ctrl = USB_PHY_CLK_EN | USB_PHY_RESET_DIS; 1403055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); 1404055276c1SNeal Liu 1405055276c1SNeal Liu udelay(1); 1406055276c1SNeal Liu ast_udc_write(udc, 0, AST_UDC_DEV_RESET); 1407055276c1SNeal Liu 1408055276c1SNeal Liu /* Set descriptor ring size */ 1409055276c1SNeal Liu if (AST_UDC_DESCS_COUNT == 256) { 1410055276c1SNeal Liu ctrl |= USB_EP_LONG_DESC; 1411055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); 1412055276c1SNeal Liu } 1413055276c1SNeal Liu 1414055276c1SNeal Liu /* Mask & ack all interrupts before installing the handler */ 1415055276c1SNeal Liu ast_udc_write(udc, 0, AST_UDC_IER); 1416055276c1SNeal Liu ast_udc_write(udc, UDC_IRQ_ACK_ALL, AST_UDC_ISR); 1417055276c1SNeal Liu 1418055276c1SNeal Liu /* Enable some interrupts */ 1419055276c1SNeal Liu ctrl = UDC_IRQ_EP_POOL_ACK_STALL | UDC_IRQ_BUS_RESUME | 1420055276c1SNeal Liu UDC_IRQ_BUS_SUSPEND | UDC_IRQ_BUS_RESET | 1421055276c1SNeal Liu UDC_IRQ_EP0_IN_ACK_STALL | UDC_IRQ_EP0_OUT_ACK_STALL | 1422055276c1SNeal Liu UDC_IRQ_EP0_SETUP; 1423055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_IER); 1424055276c1SNeal Liu 1425055276c1SNeal Liu /* Cleanup and enable ep ACK interrupts */ 1426055276c1SNeal Liu ast_udc_write(udc, UDC_IRQ_EP_ACK_ALL, AST_UDC_EP_ACK_IER); 1427055276c1SNeal Liu ast_udc_write(udc, UDC_IRQ_EP_ACK_ALL, AST_UDC_EP_ACK_ISR); 1428055276c1SNeal Liu 1429055276c1SNeal Liu ast_udc_write(udc, 0, AST_UDC_EP0_CTRL); 1430055276c1SNeal Liu } 1431055276c1SNeal Liu 1432055276c1SNeal Liu static int ast_udc_remove(struct platform_device *pdev) 1433055276c1SNeal Liu { 1434055276c1SNeal Liu struct ast_udc_dev *udc = platform_get_drvdata(pdev); 1435055276c1SNeal Liu unsigned long flags; 1436055276c1SNeal Liu u32 ctrl; 1437055276c1SNeal Liu 1438055276c1SNeal Liu usb_del_gadget_udc(&udc->gadget); 1439055276c1SNeal Liu if (udc->driver) 1440055276c1SNeal Liu return -EBUSY; 1441055276c1SNeal Liu 1442055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 1443055276c1SNeal Liu 1444055276c1SNeal Liu /* Disable upstream port connection */ 1445055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL) & ~USB_UPSTREAM_EN; 1446055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); 1447055276c1SNeal Liu 1448055276c1SNeal Liu clk_disable_unprepare(udc->clk); 1449055276c1SNeal Liu 1450055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 1451055276c1SNeal Liu 1452055276c1SNeal Liu if (udc->ep0_buf) 1453055276c1SNeal Liu dma_free_coherent(&pdev->dev, 1454055276c1SNeal Liu AST_UDC_EP_DMA_SIZE * AST_UDC_NUM_ENDPOINTS, 1455055276c1SNeal Liu udc->ep0_buf, 1456055276c1SNeal Liu udc->ep0_buf_dma); 1457055276c1SNeal Liu 1458055276c1SNeal Liu udc->ep0_buf = NULL; 1459055276c1SNeal Liu 1460055276c1SNeal Liu return 0; 1461055276c1SNeal Liu } 1462055276c1SNeal Liu 1463055276c1SNeal Liu static int ast_udc_probe(struct platform_device *pdev) 1464055276c1SNeal Liu { 1465055276c1SNeal Liu enum usb_device_speed max_speed; 1466055276c1SNeal Liu struct device *dev = &pdev->dev; 1467055276c1SNeal Liu struct ast_udc_dev *udc; 1468055276c1SNeal Liu struct resource *res; 1469055276c1SNeal Liu int rc; 1470055276c1SNeal Liu 1471055276c1SNeal Liu udc = devm_kzalloc(&pdev->dev, sizeof(struct ast_udc_dev), GFP_KERNEL); 1472055276c1SNeal Liu if (!udc) 1473055276c1SNeal Liu return -ENOMEM; 1474055276c1SNeal Liu 1475055276c1SNeal Liu udc->gadget.dev.parent = dev; 1476055276c1SNeal Liu udc->pdev = pdev; 1477055276c1SNeal Liu spin_lock_init(&udc->lock); 1478055276c1SNeal Liu 1479055276c1SNeal Liu udc->gadget.ops = &ast_udc_ops; 1480055276c1SNeal Liu udc->gadget.ep0 = &udc->ep[0].ep; 1481055276c1SNeal Liu udc->gadget.name = "aspeed-udc"; 1482055276c1SNeal Liu udc->gadget.dev.init_name = "gadget"; 1483055276c1SNeal Liu 1484055276c1SNeal Liu res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1485055276c1SNeal Liu udc->reg = devm_ioremap_resource(&pdev->dev, res); 1486055276c1SNeal Liu if (IS_ERR(udc->reg)) { 1487055276c1SNeal Liu dev_err(&pdev->dev, "Failed to map resources\n"); 1488055276c1SNeal Liu return PTR_ERR(udc->reg); 1489055276c1SNeal Liu } 1490055276c1SNeal Liu 1491055276c1SNeal Liu platform_set_drvdata(pdev, udc); 1492055276c1SNeal Liu 1493055276c1SNeal Liu udc->clk = devm_clk_get(&pdev->dev, NULL); 1494055276c1SNeal Liu if (IS_ERR(udc->clk)) { 1495055276c1SNeal Liu rc = PTR_ERR(udc->clk); 1496055276c1SNeal Liu goto err; 1497055276c1SNeal Liu } 1498055276c1SNeal Liu rc = clk_prepare_enable(udc->clk); 1499055276c1SNeal Liu if (rc) { 1500055276c1SNeal Liu dev_err(&pdev->dev, "Failed to enable clock (0x%x)\n", rc); 1501055276c1SNeal Liu goto err; 1502055276c1SNeal Liu } 1503055276c1SNeal Liu 1504055276c1SNeal Liu /* Check if we need to limit the HW to USB1 */ 1505055276c1SNeal Liu max_speed = usb_get_maximum_speed(&pdev->dev); 1506055276c1SNeal Liu if (max_speed != USB_SPEED_UNKNOWN && max_speed < USB_SPEED_HIGH) 1507055276c1SNeal Liu udc->force_usb1 = true; 1508055276c1SNeal Liu 1509055276c1SNeal Liu /* 1510055276c1SNeal Liu * Allocate DMA buffers for all EPs in one chunk 1511055276c1SNeal Liu */ 1512055276c1SNeal Liu udc->ep0_buf = dma_alloc_coherent(&pdev->dev, 1513055276c1SNeal Liu AST_UDC_EP_DMA_SIZE * 1514055276c1SNeal Liu AST_UDC_NUM_ENDPOINTS, 1515055276c1SNeal Liu &udc->ep0_buf_dma, GFP_KERNEL); 1516055276c1SNeal Liu 1517055276c1SNeal Liu udc->gadget.speed = USB_SPEED_UNKNOWN; 1518055276c1SNeal Liu udc->gadget.max_speed = USB_SPEED_HIGH; 1519055276c1SNeal Liu udc->creq = udc->reg + AST_UDC_SETUP0; 1520055276c1SNeal Liu 1521055276c1SNeal Liu /* 1522055276c1SNeal Liu * Support single stage mode or 32/256 stages descriptor mode. 1523055276c1SNeal Liu * Set default as Descriptor Mode. 1524055276c1SNeal Liu */ 1525055276c1SNeal Liu udc->desc_mode = AST_UDC_DESC_MODE; 1526055276c1SNeal Liu 1527055276c1SNeal Liu dev_info(&pdev->dev, "DMA %s\n", udc->desc_mode ? 1528055276c1SNeal Liu "descriptor mode" : "single mode"); 1529055276c1SNeal Liu 1530055276c1SNeal Liu INIT_LIST_HEAD(&udc->gadget.ep_list); 1531055276c1SNeal Liu INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); 1532055276c1SNeal Liu 1533055276c1SNeal Liu /* Initialized udc ep */ 1534055276c1SNeal Liu ast_udc_init_ep(udc); 1535055276c1SNeal Liu 1536055276c1SNeal Liu /* Initialized udc device */ 1537055276c1SNeal Liu ast_udc_init_dev(udc); 1538055276c1SNeal Liu 1539055276c1SNeal Liu /* Initialized udc hardware */ 1540055276c1SNeal Liu ast_udc_init_hw(udc); 1541055276c1SNeal Liu 1542055276c1SNeal Liu /* Find interrupt and install handler */ 1543055276c1SNeal Liu udc->irq = platform_get_irq(pdev, 0); 1544055276c1SNeal Liu if (udc->irq < 0) { 1545055276c1SNeal Liu dev_err(&pdev->dev, "Failed to get interrupt\n"); 1546055276c1SNeal Liu rc = udc->irq; 1547055276c1SNeal Liu goto err; 1548055276c1SNeal Liu } 1549055276c1SNeal Liu 1550055276c1SNeal Liu rc = devm_request_irq(&pdev->dev, udc->irq, ast_udc_isr, 0, 1551055276c1SNeal Liu KBUILD_MODNAME, udc); 1552055276c1SNeal Liu if (rc) { 1553055276c1SNeal Liu dev_err(&pdev->dev, "Failed to request interrupt\n"); 1554055276c1SNeal Liu goto err; 1555055276c1SNeal Liu } 1556055276c1SNeal Liu 1557055276c1SNeal Liu rc = usb_add_gadget_udc(&pdev->dev, &udc->gadget); 1558055276c1SNeal Liu if (rc) { 1559055276c1SNeal Liu dev_err(&pdev->dev, "Failed to add gadget udc\n"); 1560055276c1SNeal Liu goto err; 1561055276c1SNeal Liu } 1562055276c1SNeal Liu 1563055276c1SNeal Liu dev_info(&pdev->dev, "Initialized udc in USB%s mode\n", 1564055276c1SNeal Liu udc->force_usb1 ? "1" : "2"); 1565055276c1SNeal Liu 1566055276c1SNeal Liu return 0; 1567055276c1SNeal Liu 1568055276c1SNeal Liu err: 1569055276c1SNeal Liu dev_err(&pdev->dev, "Failed to udc probe, rc:0x%x\n", rc); 1570055276c1SNeal Liu ast_udc_remove(pdev); 1571055276c1SNeal Liu 1572055276c1SNeal Liu return rc; 1573055276c1SNeal Liu } 1574055276c1SNeal Liu 1575055276c1SNeal Liu static const struct of_device_id ast_udc_of_dt_ids[] = { 1576055276c1SNeal Liu { .compatible = "aspeed,ast2600-udc", }, 1577055276c1SNeal Liu {} 1578055276c1SNeal Liu }; 1579055276c1SNeal Liu 1580055276c1SNeal Liu MODULE_DEVICE_TABLE(of, ast_udc_of_dt_ids); 1581055276c1SNeal Liu 1582055276c1SNeal Liu static struct platform_driver ast_udc_driver = { 1583055276c1SNeal Liu .probe = ast_udc_probe, 1584055276c1SNeal Liu .remove = ast_udc_remove, 1585055276c1SNeal Liu .driver = { 1586055276c1SNeal Liu .name = KBUILD_MODNAME, 1587055276c1SNeal Liu .of_match_table = ast_udc_of_dt_ids, 1588055276c1SNeal Liu }, 1589055276c1SNeal Liu }; 1590055276c1SNeal Liu 1591055276c1SNeal Liu module_platform_driver(ast_udc_driver); 1592055276c1SNeal Liu 1593055276c1SNeal Liu MODULE_DESCRIPTION("ASPEED UDC driver"); 1594055276c1SNeal Liu MODULE_AUTHOR("Neal Liu <neal_liu@aspeedtech.com>"); 1595055276c1SNeal Liu MODULE_LICENSE("GPL"); 1596