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; 47970cdb930SDan Carpenter bool last = false; 480c09b1f37SDan Carpenter int chunk, count; 481c09b1f37SDan Carpenter u32 offset; 482055276c1SNeal Liu 483055276c1SNeal Liu if (!ep->descs) { 484055276c1SNeal Liu dev_warn(dev, "%s: Empty DMA descs list failure\n", 485055276c1SNeal Liu ep->ep.name); 486055276c1SNeal Liu return -EINVAL; 487055276c1SNeal Liu } 488055276c1SNeal Liu 489055276c1SNeal Liu chunk = tx_len; 490c09b1f37SDan Carpenter offset = count = 0; 491055276c1SNeal Liu 492055276c1SNeal Liu EP_DBG(ep, "req @%p, %s:%d, %s:0x%x, %s:0x%x\n", req, 493055276c1SNeal Liu "wptr", ep->descs_wptr, "dma_buf", dma_buf, 494055276c1SNeal Liu "tx_len", tx_len); 495055276c1SNeal Liu 496055276c1SNeal Liu /* Create Descriptor Lists */ 49770cdb930SDan Carpenter while (chunk >= 0 && !last && count < AST_UDC_DESCS_COUNT) { 498055276c1SNeal Liu 499055276c1SNeal Liu ep->descs[ep->descs_wptr].des_0 = dma_buf + offset; 500055276c1SNeal Liu 50170cdb930SDan Carpenter if (chunk > ep->chunk_max) { 502055276c1SNeal Liu ep->descs[ep->descs_wptr].des_1 = ep->chunk_max; 50370cdb930SDan Carpenter } else { 504c09b1f37SDan Carpenter ep->descs[ep->descs_wptr].des_1 = chunk; 50570cdb930SDan Carpenter last = true; 50670cdb930SDan Carpenter } 507055276c1SNeal Liu 508c09b1f37SDan Carpenter chunk -= ep->chunk_max; 509c09b1f37SDan Carpenter 510c09b1f37SDan Carpenter EP_DBG(ep, "descs[%d]: 0x%x 0x%x\n", 511055276c1SNeal Liu ep->descs_wptr, 512055276c1SNeal Liu ep->descs[ep->descs_wptr].des_0, 513c09b1f37SDan Carpenter ep->descs[ep->descs_wptr].des_1); 514055276c1SNeal Liu 515055276c1SNeal Liu if (count == 0) 516055276c1SNeal Liu req->saved_dma_wptr = ep->descs_wptr; 517055276c1SNeal Liu 518055276c1SNeal Liu ep->descs_wptr++; 519055276c1SNeal Liu count++; 520055276c1SNeal Liu 521055276c1SNeal Liu if (ep->descs_wptr >= AST_UDC_DESCS_COUNT) 522055276c1SNeal Liu ep->descs_wptr = 0; 523055276c1SNeal Liu 524055276c1SNeal Liu offset = ep->chunk_max * count; 525055276c1SNeal Liu } 526055276c1SNeal Liu 527055276c1SNeal Liu return 0; 528055276c1SNeal Liu } 529055276c1SNeal Liu 530055276c1SNeal Liu static void ast_udc_epn_kick(struct ast_udc_ep *ep, struct ast_udc_request *req) 531055276c1SNeal Liu { 532055276c1SNeal Liu u32 tx_len; 533055276c1SNeal Liu u32 last; 534055276c1SNeal Liu 535055276c1SNeal Liu last = req->req.length - req->req.actual; 536055276c1SNeal Liu tx_len = last > ep->ep.maxpacket ? ep->ep.maxpacket : last; 537055276c1SNeal Liu 538055276c1SNeal Liu EP_DBG(ep, "kick req @%p, len:%d, dir:%d\n", 539055276c1SNeal Liu req, tx_len, ep->dir_in); 540055276c1SNeal Liu 541055276c1SNeal Liu ast_ep_write(ep, req->req.dma + req->req.actual, AST_UDC_EP_DMA_BUFF); 542055276c1SNeal Liu 543055276c1SNeal Liu /* Start DMA */ 544055276c1SNeal Liu ast_ep_write(ep, EP_DMA_SET_TX_SIZE(tx_len), AST_UDC_EP_DMA_STS); 545055276c1SNeal Liu ast_ep_write(ep, EP_DMA_SET_TX_SIZE(tx_len) | EP_DMA_SINGLE_KICK, 546055276c1SNeal Liu AST_UDC_EP_DMA_STS); 547055276c1SNeal Liu } 548055276c1SNeal Liu 549055276c1SNeal Liu static void ast_udc_epn_kick_desc(struct ast_udc_ep *ep, 550055276c1SNeal Liu struct ast_udc_request *req) 551055276c1SNeal Liu { 552055276c1SNeal Liu u32 descs_max_size; 553055276c1SNeal Liu u32 tx_len; 554055276c1SNeal Liu u32 last; 555055276c1SNeal Liu 556055276c1SNeal Liu descs_max_size = AST_EP_DMA_DESC_MAX_LEN * AST_UDC_DESCS_COUNT; 557055276c1SNeal Liu 558055276c1SNeal Liu last = req->req.length - req->req.actual; 559055276c1SNeal Liu tx_len = last > descs_max_size ? descs_max_size : last; 560055276c1SNeal Liu 561055276c1SNeal Liu EP_DBG(ep, "kick req @%p, %s:%d, %s:0x%x, %s:0x%x (%d/%d), %s:0x%x\n", 562055276c1SNeal Liu req, "tx_len", tx_len, "dir_in", ep->dir_in, 563055276c1SNeal Liu "dma", req->req.dma + req->req.actual, 564055276c1SNeal Liu req->req.actual, req->req.length, 565055276c1SNeal Liu "descs_max_size", descs_max_size); 566055276c1SNeal Liu 567055276c1SNeal Liu if (!ast_dma_descriptor_setup(ep, req->req.dma + req->req.actual, 568055276c1SNeal Liu tx_len, req)) 569055276c1SNeal Liu req->actual_dma_length += tx_len; 570055276c1SNeal Liu 571055276c1SNeal Liu /* make sure CPU done everything before triggering DMA */ 572055276c1SNeal Liu mb(); 573055276c1SNeal Liu 574055276c1SNeal Liu ast_ep_write(ep, ep->descs_wptr, AST_UDC_EP_DMA_STS); 575055276c1SNeal Liu 576055276c1SNeal Liu EP_DBG(ep, "descs_wptr:%d, dstat:0x%x, dctrl:0x%x\n", 577055276c1SNeal Liu ep->descs_wptr, 578055276c1SNeal Liu ast_ep_read(ep, AST_UDC_EP_DMA_STS), 579055276c1SNeal Liu ast_ep_read(ep, AST_UDC_EP_DMA_CTRL)); 580055276c1SNeal Liu } 581055276c1SNeal Liu 582055276c1SNeal Liu static void ast_udc_ep0_queue(struct ast_udc_ep *ep, 583055276c1SNeal Liu struct ast_udc_request *req) 584055276c1SNeal Liu { 585055276c1SNeal Liu struct ast_udc_dev *udc = ep->udc; 586055276c1SNeal Liu u32 tx_len; 587055276c1SNeal Liu u32 last; 588055276c1SNeal Liu 589055276c1SNeal Liu last = req->req.length - req->req.actual; 590055276c1SNeal Liu tx_len = last > ep->ep.maxpacket ? ep->ep.maxpacket : last; 591055276c1SNeal Liu 592055276c1SNeal Liu ast_udc_write(udc, req->req.dma + req->req.actual, 593055276c1SNeal Liu AST_UDC_EP0_DATA_BUFF); 594055276c1SNeal Liu 595055276c1SNeal Liu if (ep->dir_in) { 596055276c1SNeal Liu /* IN requests, send data */ 597055276c1SNeal Liu SETUP_DBG(udc, "IN: %s:0x%x, %s:0x%x, %s:%d (%d/%d), %s:%d\n", 598055276c1SNeal Liu "buf", (u32)req->req.buf, 599055276c1SNeal Liu "dma", req->req.dma + req->req.actual, 600055276c1SNeal Liu "tx_len", tx_len, 601055276c1SNeal Liu req->req.actual, req->req.length, 602055276c1SNeal Liu "dir_in", ep->dir_in); 603055276c1SNeal Liu 604055276c1SNeal Liu req->req.actual += tx_len; 605055276c1SNeal Liu ast_udc_write(udc, EP0_TX_LEN(tx_len), AST_UDC_EP0_CTRL); 606055276c1SNeal Liu ast_udc_write(udc, EP0_TX_LEN(tx_len) | EP0_TX_BUFF_RDY, 607055276c1SNeal Liu AST_UDC_EP0_CTRL); 608055276c1SNeal Liu 609055276c1SNeal Liu } else { 610055276c1SNeal Liu /* OUT requests, receive data */ 611055276c1SNeal Liu SETUP_DBG(udc, "OUT: %s:%x, %s:%x, %s:(%d/%d), %s:%d\n", 612055276c1SNeal Liu "buf", (u32)req->req.buf, 613055276c1SNeal Liu "dma", req->req.dma + req->req.actual, 614055276c1SNeal Liu "len", req->req.actual, req->req.length, 615055276c1SNeal Liu "dir_in", ep->dir_in); 616055276c1SNeal Liu 617055276c1SNeal Liu if (!req->req.length) { 618055276c1SNeal Liu /* 0 len request, send tx as completion */ 619055276c1SNeal Liu ast_udc_write(udc, EP0_TX_BUFF_RDY, AST_UDC_EP0_CTRL); 620055276c1SNeal Liu ep->dir_in = 0x1; 621055276c1SNeal Liu } else 622055276c1SNeal Liu ast_udc_write(udc, EP0_RX_BUFF_RDY, AST_UDC_EP0_CTRL); 623055276c1SNeal Liu } 624055276c1SNeal Liu } 625055276c1SNeal Liu 626055276c1SNeal Liu static int ast_udc_ep_queue(struct usb_ep *_ep, struct usb_request *_req, 627055276c1SNeal Liu gfp_t gfp_flags) 628055276c1SNeal Liu { 629055276c1SNeal Liu struct ast_udc_request *req = to_ast_req(_req); 630055276c1SNeal Liu struct ast_udc_ep *ep = to_ast_ep(_ep); 631055276c1SNeal Liu struct ast_udc_dev *udc = ep->udc; 632055276c1SNeal Liu struct device *dev = &udc->pdev->dev; 633055276c1SNeal Liu unsigned long flags; 634055276c1SNeal Liu int rc; 635055276c1SNeal Liu 636055276c1SNeal Liu if (unlikely(!_req || !_req->complete || !_req->buf || !_ep)) { 637055276c1SNeal Liu dev_warn(dev, "Invalid EP request !\n"); 638055276c1SNeal Liu return -EINVAL; 639055276c1SNeal Liu } 640055276c1SNeal Liu 641055276c1SNeal Liu if (ep->stopped) { 642055276c1SNeal Liu dev_warn(dev, "%s is already stopped !\n", _ep->name); 643055276c1SNeal Liu return -ESHUTDOWN; 644055276c1SNeal Liu } 645055276c1SNeal Liu 646055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 647055276c1SNeal Liu 648055276c1SNeal Liu list_add_tail(&req->queue, &ep->queue); 649055276c1SNeal Liu 650055276c1SNeal Liu req->req.actual = 0; 651055276c1SNeal Liu req->req.status = -EINPROGRESS; 652055276c1SNeal Liu req->actual_dma_length = 0; 653055276c1SNeal Liu 654055276c1SNeal Liu rc = usb_gadget_map_request(&udc->gadget, &req->req, ep->dir_in); 655055276c1SNeal Liu if (rc) { 656055276c1SNeal Liu EP_DBG(ep, "Request mapping failure %d\n", rc); 657055276c1SNeal Liu dev_warn(dev, "Request mapping failure %d\n", rc); 658055276c1SNeal Liu goto end; 659055276c1SNeal Liu } 660055276c1SNeal Liu 661055276c1SNeal Liu EP_DBG(ep, "enqueue req @%p\n", req); 662055276c1SNeal Liu EP_DBG(ep, "l=%d, dma:0x%x, zero:%d, is_in:%d\n", 663055276c1SNeal Liu _req->length, _req->dma, _req->zero, ep->dir_in); 664055276c1SNeal Liu 665055276c1SNeal Liu /* EP0 request enqueue */ 666055276c1SNeal Liu if (ep->ep.desc == NULL) { 667055276c1SNeal Liu if ((req->req.dma % 4) != 0) { 668055276c1SNeal Liu dev_warn(dev, "EP0 req dma alignment error\n"); 6693d393f03SZheng Bin rc = -ESHUTDOWN; 6703d393f03SZheng Bin goto end; 671055276c1SNeal Liu } 672055276c1SNeal Liu 673055276c1SNeal Liu ast_udc_ep0_queue(ep, req); 674055276c1SNeal Liu goto end; 675055276c1SNeal Liu } 676055276c1SNeal Liu 677055276c1SNeal Liu /* EPn request enqueue */ 678055276c1SNeal Liu if (list_is_singular(&ep->queue)) { 679055276c1SNeal Liu if (ep->desc_mode) 680055276c1SNeal Liu ast_udc_epn_kick_desc(ep, req); 681055276c1SNeal Liu else 682055276c1SNeal Liu ast_udc_epn_kick(ep, req); 683055276c1SNeal Liu } 684055276c1SNeal Liu 685055276c1SNeal Liu end: 686055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 687055276c1SNeal Liu 688055276c1SNeal Liu return rc; 689055276c1SNeal Liu } 690055276c1SNeal Liu 691055276c1SNeal Liu static int ast_udc_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) 692055276c1SNeal Liu { 693055276c1SNeal Liu struct ast_udc_ep *ep = to_ast_ep(_ep); 694055276c1SNeal Liu struct ast_udc_dev *udc = ep->udc; 695055276c1SNeal Liu struct ast_udc_request *req; 696055276c1SNeal Liu unsigned long flags; 697055276c1SNeal Liu int rc = 0; 698055276c1SNeal Liu 699055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 700055276c1SNeal Liu 701055276c1SNeal Liu /* make sure it's actually queued on this endpoint */ 702055276c1SNeal Liu list_for_each_entry(req, &ep->queue, queue) { 703055276c1SNeal Liu if (&req->req == _req) { 704055276c1SNeal Liu list_del_init(&req->queue); 705055276c1SNeal Liu ast_udc_done(ep, req, -ESHUTDOWN); 706055276c1SNeal Liu _req->status = -ECONNRESET; 707055276c1SNeal Liu break; 708055276c1SNeal Liu } 709055276c1SNeal Liu } 710055276c1SNeal Liu 711055276c1SNeal Liu /* dequeue request not found */ 712055276c1SNeal Liu if (&req->req != _req) 713055276c1SNeal Liu rc = -EINVAL; 714055276c1SNeal Liu 715055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 716055276c1SNeal Liu 717055276c1SNeal Liu return rc; 718055276c1SNeal Liu } 719055276c1SNeal Liu 720055276c1SNeal Liu static int ast_udc_ep_set_halt(struct usb_ep *_ep, int value) 721055276c1SNeal Liu { 722055276c1SNeal Liu struct ast_udc_ep *ep = to_ast_ep(_ep); 723055276c1SNeal Liu struct ast_udc_dev *udc = ep->udc; 724055276c1SNeal Liu unsigned long flags; 725055276c1SNeal Liu int epnum; 726055276c1SNeal Liu u32 ctrl; 727055276c1SNeal Liu 728055276c1SNeal Liu EP_DBG(ep, "val:%d\n", value); 729055276c1SNeal Liu 730055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 731055276c1SNeal Liu 732055276c1SNeal Liu epnum = usb_endpoint_num(ep->desc); 733055276c1SNeal Liu 734055276c1SNeal Liu /* EP0 */ 735055276c1SNeal Liu if (epnum == 0) { 736055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_EP0_CTRL); 737055276c1SNeal Liu if (value) 738055276c1SNeal Liu ctrl |= EP0_STALL; 739055276c1SNeal Liu else 740055276c1SNeal Liu ctrl &= ~EP0_STALL; 741055276c1SNeal Liu 742055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_EP0_CTRL); 743055276c1SNeal Liu 744055276c1SNeal Liu } else { 745055276c1SNeal Liu /* EPn */ 746055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_EP_CONFIG); 747055276c1SNeal Liu if (value) 748055276c1SNeal Liu ctrl |= EP_SET_EP_STALL; 749055276c1SNeal Liu else 750055276c1SNeal Liu ctrl &= ~EP_SET_EP_STALL; 751055276c1SNeal Liu 752055276c1SNeal Liu ast_ep_write(ep, ctrl, AST_UDC_EP_CONFIG); 753055276c1SNeal Liu 754055276c1SNeal Liu /* only epn is stopped and waits for clear */ 755055276c1SNeal Liu ep->stopped = value ? 1 : 0; 756055276c1SNeal Liu } 757055276c1SNeal Liu 758055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 759055276c1SNeal Liu 760055276c1SNeal Liu return 0; 761055276c1SNeal Liu } 762055276c1SNeal Liu 763055276c1SNeal Liu static const struct usb_ep_ops ast_udc_ep_ops = { 764055276c1SNeal Liu .enable = ast_udc_ep_enable, 765055276c1SNeal Liu .disable = ast_udc_ep_disable, 766055276c1SNeal Liu .alloc_request = ast_udc_ep_alloc_request, 767055276c1SNeal Liu .free_request = ast_udc_ep_free_request, 768055276c1SNeal Liu .queue = ast_udc_ep_queue, 769055276c1SNeal Liu .dequeue = ast_udc_ep_dequeue, 770055276c1SNeal Liu .set_halt = ast_udc_ep_set_halt, 771055276c1SNeal Liu /* there's only imprecise fifo status reporting */ 772055276c1SNeal Liu }; 773055276c1SNeal Liu 774055276c1SNeal Liu static void ast_udc_ep0_rx(struct ast_udc_dev *udc) 775055276c1SNeal Liu { 776055276c1SNeal Liu ast_udc_write(udc, udc->ep0_buf_dma, AST_UDC_EP0_DATA_BUFF); 777055276c1SNeal Liu ast_udc_write(udc, EP0_RX_BUFF_RDY, AST_UDC_EP0_CTRL); 778055276c1SNeal Liu } 779055276c1SNeal Liu 780055276c1SNeal Liu static void ast_udc_ep0_tx(struct ast_udc_dev *udc) 781055276c1SNeal Liu { 782055276c1SNeal Liu ast_udc_write(udc, udc->ep0_buf_dma, AST_UDC_EP0_DATA_BUFF); 783055276c1SNeal Liu ast_udc_write(udc, EP0_TX_BUFF_RDY, AST_UDC_EP0_CTRL); 784055276c1SNeal Liu } 785055276c1SNeal Liu 786055276c1SNeal Liu static void ast_udc_ep0_out(struct ast_udc_dev *udc) 787055276c1SNeal Liu { 788055276c1SNeal Liu struct device *dev = &udc->pdev->dev; 789055276c1SNeal Liu struct ast_udc_ep *ep = &udc->ep[0]; 790055276c1SNeal Liu struct ast_udc_request *req; 791055276c1SNeal Liu u16 rx_len; 792055276c1SNeal Liu 793055276c1SNeal Liu if (list_empty(&ep->queue)) 794055276c1SNeal Liu return; 795055276c1SNeal Liu 796055276c1SNeal Liu req = list_entry(ep->queue.next, struct ast_udc_request, queue); 797055276c1SNeal Liu 798055276c1SNeal Liu rx_len = EP0_GET_RX_LEN(ast_udc_read(udc, AST_UDC_EP0_CTRL)); 799055276c1SNeal Liu req->req.actual += rx_len; 800055276c1SNeal Liu 801055276c1SNeal Liu SETUP_DBG(udc, "req %p (%d/%d)\n", req, 802055276c1SNeal Liu req->req.actual, req->req.length); 803055276c1SNeal Liu 804055276c1SNeal Liu if ((rx_len < ep->ep.maxpacket) || 805055276c1SNeal Liu (req->req.actual == req->req.length)) { 806055276c1SNeal Liu ast_udc_ep0_tx(udc); 807055276c1SNeal Liu if (!ep->dir_in) 808055276c1SNeal Liu ast_udc_done(ep, req, 0); 809055276c1SNeal Liu 810055276c1SNeal Liu } else { 811055276c1SNeal Liu if (rx_len > req->req.length) { 812055276c1SNeal Liu // Issue Fix 813055276c1SNeal Liu dev_warn(dev, "Something wrong (%d/%d)\n", 814055276c1SNeal Liu req->req.actual, req->req.length); 815055276c1SNeal Liu ast_udc_ep0_tx(udc); 816055276c1SNeal Liu ast_udc_done(ep, req, 0); 817055276c1SNeal Liu return; 818055276c1SNeal Liu } 819055276c1SNeal Liu 820055276c1SNeal Liu ep->dir_in = 0; 821055276c1SNeal Liu 822055276c1SNeal Liu /* More works */ 823055276c1SNeal Liu ast_udc_ep0_queue(ep, req); 824055276c1SNeal Liu } 825055276c1SNeal Liu } 826055276c1SNeal Liu 827055276c1SNeal Liu static void ast_udc_ep0_in(struct ast_udc_dev *udc) 828055276c1SNeal Liu { 829055276c1SNeal Liu struct ast_udc_ep *ep = &udc->ep[0]; 830055276c1SNeal Liu struct ast_udc_request *req; 831055276c1SNeal Liu 832055276c1SNeal Liu if (list_empty(&ep->queue)) { 833055276c1SNeal Liu if (udc->is_control_tx) { 834055276c1SNeal Liu ast_udc_ep0_rx(udc); 835055276c1SNeal Liu udc->is_control_tx = 0; 836055276c1SNeal Liu } 837055276c1SNeal Liu 838055276c1SNeal Liu return; 839055276c1SNeal Liu } 840055276c1SNeal Liu 841055276c1SNeal Liu req = list_entry(ep->queue.next, struct ast_udc_request, queue); 842055276c1SNeal Liu 843055276c1SNeal Liu SETUP_DBG(udc, "req %p (%d/%d)\n", req, 844055276c1SNeal Liu req->req.actual, req->req.length); 845055276c1SNeal Liu 846055276c1SNeal Liu if (req->req.length == req->req.actual) { 847055276c1SNeal Liu if (req->req.length) 848055276c1SNeal Liu ast_udc_ep0_rx(udc); 849055276c1SNeal Liu 850055276c1SNeal Liu if (ep->dir_in) 851055276c1SNeal Liu ast_udc_done(ep, req, 0); 852055276c1SNeal Liu 853055276c1SNeal Liu } else { 854055276c1SNeal Liu /* More works */ 855055276c1SNeal Liu ast_udc_ep0_queue(ep, req); 856055276c1SNeal Liu } 857055276c1SNeal Liu } 858055276c1SNeal Liu 859055276c1SNeal Liu static void ast_udc_epn_handle(struct ast_udc_dev *udc, u16 ep_num) 860055276c1SNeal Liu { 861055276c1SNeal Liu struct ast_udc_ep *ep = &udc->ep[ep_num]; 862055276c1SNeal Liu struct ast_udc_request *req; 863055276c1SNeal Liu u16 len = 0; 864055276c1SNeal Liu 865055276c1SNeal Liu if (list_empty(&ep->queue)) 866055276c1SNeal Liu return; 867055276c1SNeal Liu 868055276c1SNeal Liu req = list_first_entry(&ep->queue, struct ast_udc_request, queue); 869055276c1SNeal Liu 870055276c1SNeal Liu len = EP_DMA_GET_TX_SIZE(ast_ep_read(ep, AST_UDC_EP_DMA_STS)); 871055276c1SNeal Liu req->req.actual += len; 872055276c1SNeal Liu 873055276c1SNeal Liu EP_DBG(ep, "req @%p, length:(%d/%d), %s:0x%x\n", req, 874055276c1SNeal Liu req->req.actual, req->req.length, "len", len); 875055276c1SNeal Liu 876055276c1SNeal Liu /* Done this request */ 877055276c1SNeal Liu if (req->req.length == req->req.actual) { 878055276c1SNeal Liu ast_udc_done(ep, req, 0); 879055276c1SNeal Liu req = list_first_entry_or_null(&ep->queue, 880055276c1SNeal Liu struct ast_udc_request, 881055276c1SNeal Liu queue); 882055276c1SNeal Liu 883055276c1SNeal Liu } else { 884055276c1SNeal Liu /* Check for short packet */ 885055276c1SNeal Liu if (len < ep->ep.maxpacket) { 886055276c1SNeal Liu ast_udc_done(ep, req, 0); 887055276c1SNeal Liu req = list_first_entry_or_null(&ep->queue, 888055276c1SNeal Liu struct ast_udc_request, 889055276c1SNeal Liu queue); 890055276c1SNeal Liu } 891055276c1SNeal Liu } 892055276c1SNeal Liu 893055276c1SNeal Liu /* More requests */ 894055276c1SNeal Liu if (req) 895055276c1SNeal Liu ast_udc_epn_kick(ep, req); 896055276c1SNeal Liu } 897055276c1SNeal Liu 898055276c1SNeal Liu static void ast_udc_epn_handle_desc(struct ast_udc_dev *udc, u16 ep_num) 899055276c1SNeal Liu { 900055276c1SNeal Liu struct ast_udc_ep *ep = &udc->ep[ep_num]; 901055276c1SNeal Liu struct device *dev = &udc->pdev->dev; 902055276c1SNeal Liu struct ast_udc_request *req; 903055276c1SNeal Liu u32 proc_sts, wr_ptr, rd_ptr; 904055276c1SNeal Liu u32 len_in_desc, ctrl; 905055276c1SNeal Liu u16 total_len = 0; 906055276c1SNeal Liu int i; 907055276c1SNeal Liu 908055276c1SNeal Liu if (list_empty(&ep->queue)) { 909e2900f74SColin Ian King dev_warn(dev, "%s request queue empty!\n", ep->ep.name); 910055276c1SNeal Liu return; 911055276c1SNeal Liu } 912055276c1SNeal Liu 913055276c1SNeal Liu req = list_first_entry(&ep->queue, struct ast_udc_request, queue); 914055276c1SNeal Liu 915055276c1SNeal Liu ctrl = ast_ep_read(ep, AST_UDC_EP_DMA_CTRL); 916055276c1SNeal Liu proc_sts = EP_DMA_CTRL_GET_PROC_STS(ctrl); 917055276c1SNeal Liu 918055276c1SNeal Liu /* Check processing status is idle */ 919055276c1SNeal Liu if (proc_sts != EP_DMA_CTRL_STS_RX_IDLE && 920055276c1SNeal Liu proc_sts != EP_DMA_CTRL_STS_TX_IDLE) { 921055276c1SNeal Liu dev_warn(dev, "EP DMA CTRL: 0x%x, PS:0x%x\n", 922055276c1SNeal Liu ast_ep_read(ep, AST_UDC_EP_DMA_CTRL), 923055276c1SNeal Liu proc_sts); 924055276c1SNeal Liu return; 925055276c1SNeal Liu } 926055276c1SNeal Liu 927055276c1SNeal Liu ctrl = ast_ep_read(ep, AST_UDC_EP_DMA_STS); 928055276c1SNeal Liu rd_ptr = EP_DMA_GET_RPTR(ctrl); 929055276c1SNeal Liu wr_ptr = EP_DMA_GET_WPTR(ctrl); 930055276c1SNeal Liu 931055276c1SNeal Liu if (rd_ptr != wr_ptr) { 932055276c1SNeal Liu dev_warn(dev, "desc list is not empty ! %s:%d, %s:%d\n", 933055276c1SNeal Liu "rptr", rd_ptr, "wptr", wr_ptr); 934055276c1SNeal Liu return; 935055276c1SNeal Liu } 936055276c1SNeal Liu 937055276c1SNeal Liu EP_DBG(ep, "rd_ptr:%d, wr_ptr:%d\n", rd_ptr, wr_ptr); 938055276c1SNeal Liu i = req->saved_dma_wptr; 939055276c1SNeal Liu 940055276c1SNeal Liu do { 941055276c1SNeal Liu len_in_desc = EP_DESC1_IN_LEN(ep->descs[i].des_1); 942055276c1SNeal Liu EP_DBG(ep, "desc[%d] len: %d\n", i, len_in_desc); 943055276c1SNeal Liu total_len += len_in_desc; 944055276c1SNeal Liu i++; 945055276c1SNeal Liu if (i >= AST_UDC_DESCS_COUNT) 946055276c1SNeal Liu i = 0; 947055276c1SNeal Liu 948055276c1SNeal Liu } while (i != wr_ptr); 949055276c1SNeal Liu 950055276c1SNeal Liu req->req.actual += total_len; 951055276c1SNeal Liu 952055276c1SNeal Liu EP_DBG(ep, "req @%p, length:(%d/%d), %s:0x%x\n", req, 953055276c1SNeal Liu req->req.actual, req->req.length, "len", total_len); 954055276c1SNeal Liu 955055276c1SNeal Liu /* Done this request */ 956055276c1SNeal Liu if (req->req.length == req->req.actual) { 957055276c1SNeal Liu ast_udc_done(ep, req, 0); 958055276c1SNeal Liu req = list_first_entry_or_null(&ep->queue, 959055276c1SNeal Liu struct ast_udc_request, 960055276c1SNeal Liu queue); 961055276c1SNeal Liu 962055276c1SNeal Liu } else { 963055276c1SNeal Liu /* Check for short packet */ 964055276c1SNeal Liu if (total_len < ep->ep.maxpacket) { 965055276c1SNeal Liu ast_udc_done(ep, req, 0); 966055276c1SNeal Liu req = list_first_entry_or_null(&ep->queue, 967055276c1SNeal Liu struct ast_udc_request, 968055276c1SNeal Liu queue); 969055276c1SNeal Liu } 970055276c1SNeal Liu } 971055276c1SNeal Liu 972055276c1SNeal Liu /* More requests & dma descs not setup yet */ 973055276c1SNeal Liu if (req && (req->actual_dma_length == req->req.actual)) { 974055276c1SNeal Liu EP_DBG(ep, "More requests\n"); 975055276c1SNeal Liu ast_udc_epn_kick_desc(ep, req); 976055276c1SNeal Liu } 977055276c1SNeal Liu } 978055276c1SNeal Liu 979055276c1SNeal Liu static void ast_udc_ep0_data_tx(struct ast_udc_dev *udc, u8 *tx_data, u32 len) 980055276c1SNeal Liu { 981055276c1SNeal Liu if (len) { 982055276c1SNeal Liu memcpy(udc->ep0_buf, tx_data, len); 983055276c1SNeal Liu 984055276c1SNeal Liu ast_udc_write(udc, udc->ep0_buf_dma, AST_UDC_EP0_DATA_BUFF); 985055276c1SNeal Liu ast_udc_write(udc, EP0_TX_LEN(len), AST_UDC_EP0_CTRL); 986055276c1SNeal Liu ast_udc_write(udc, EP0_TX_LEN(len) | EP0_TX_BUFF_RDY, 987055276c1SNeal Liu AST_UDC_EP0_CTRL); 988055276c1SNeal Liu udc->is_control_tx = 1; 989055276c1SNeal Liu 990055276c1SNeal Liu } else 991055276c1SNeal Liu ast_udc_write(udc, EP0_TX_BUFF_RDY, AST_UDC_EP0_CTRL); 992055276c1SNeal Liu } 993055276c1SNeal Liu 994055276c1SNeal Liu static void ast_udc_getstatus(struct ast_udc_dev *udc) 995055276c1SNeal Liu { 996055276c1SNeal Liu struct usb_ctrlrequest crq; 997055276c1SNeal Liu struct ast_udc_ep *ep; 998055276c1SNeal Liu u16 status = 0; 999055276c1SNeal Liu u16 epnum = 0; 1000055276c1SNeal Liu 1001055276c1SNeal Liu memcpy_fromio(&crq, udc->creq, sizeof(crq)); 1002055276c1SNeal Liu 1003055276c1SNeal Liu switch (crq.bRequestType & USB_RECIP_MASK) { 1004055276c1SNeal Liu case USB_RECIP_DEVICE: 1005055276c1SNeal Liu /* Get device status */ 1006055276c1SNeal Liu status = 1 << USB_DEVICE_SELF_POWERED; 1007055276c1SNeal Liu break; 1008055276c1SNeal Liu case USB_RECIP_INTERFACE: 1009055276c1SNeal Liu break; 1010055276c1SNeal Liu case USB_RECIP_ENDPOINT: 1011055276c1SNeal Liu epnum = crq.wIndex & USB_ENDPOINT_NUMBER_MASK; 1012055276c1SNeal Liu status = udc->ep[epnum].stopped; 1013055276c1SNeal Liu break; 1014055276c1SNeal Liu default: 1015055276c1SNeal Liu goto stall; 1016055276c1SNeal Liu } 1017055276c1SNeal Liu 1018055276c1SNeal Liu ep = &udc->ep[epnum]; 1019055276c1SNeal Liu EP_DBG(ep, "status: 0x%x\n", status); 1020055276c1SNeal Liu ast_udc_ep0_data_tx(udc, (u8 *)&status, sizeof(status)); 1021055276c1SNeal Liu 1022055276c1SNeal Liu return; 1023055276c1SNeal Liu 1024055276c1SNeal Liu stall: 1025055276c1SNeal Liu EP_DBG(ep, "Can't respond request\n"); 1026055276c1SNeal Liu ast_udc_write(udc, ast_udc_read(udc, AST_UDC_EP0_CTRL) | EP0_STALL, 1027055276c1SNeal Liu AST_UDC_EP0_CTRL); 1028055276c1SNeal Liu } 1029055276c1SNeal Liu 1030055276c1SNeal Liu static void ast_udc_ep0_handle_setup(struct ast_udc_dev *udc) 1031055276c1SNeal Liu { 1032055276c1SNeal Liu struct ast_udc_ep *ep = &udc->ep[0]; 1033055276c1SNeal Liu struct ast_udc_request *req; 1034055276c1SNeal Liu struct usb_ctrlrequest crq; 1035055276c1SNeal Liu int req_num = 0; 1036055276c1SNeal Liu int rc = 0; 1037055276c1SNeal Liu u32 reg; 1038055276c1SNeal Liu 1039055276c1SNeal Liu memcpy_fromio(&crq, udc->creq, sizeof(crq)); 1040055276c1SNeal Liu 1041e2900f74SColin Ian King SETUP_DBG(udc, "SETUP packet: %02x/%02x/%04x/%04x/%04x\n", 1042055276c1SNeal Liu crq.bRequestType, crq.bRequest, le16_to_cpu(crq.wValue), 1043055276c1SNeal Liu le16_to_cpu(crq.wIndex), le16_to_cpu(crq.wLength)); 1044055276c1SNeal Liu 1045055276c1SNeal Liu /* 1046055276c1SNeal Liu * Cleanup ep0 request(s) in queue because 1047055276c1SNeal Liu * there is a new control setup comes. 1048055276c1SNeal Liu */ 1049055276c1SNeal Liu list_for_each_entry(req, &udc->ep[0].queue, queue) { 1050055276c1SNeal Liu req_num++; 1051055276c1SNeal Liu EP_DBG(ep, "there is req %p in ep0 queue !\n", req); 1052055276c1SNeal Liu } 1053055276c1SNeal Liu 1054055276c1SNeal Liu if (req_num) 1055055276c1SNeal Liu ast_udc_nuke(&udc->ep[0], -ETIMEDOUT); 1056055276c1SNeal Liu 1057055276c1SNeal Liu udc->ep[0].dir_in = crq.bRequestType & USB_DIR_IN; 1058055276c1SNeal Liu 1059055276c1SNeal Liu if ((crq.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 1060055276c1SNeal Liu switch (crq.bRequest) { 1061055276c1SNeal Liu case USB_REQ_SET_ADDRESS: 1062055276c1SNeal Liu if (ast_udc_read(udc, AST_UDC_STS) & UDC_STS_HIGHSPEED) 1063055276c1SNeal Liu udc->gadget.speed = USB_SPEED_HIGH; 1064055276c1SNeal Liu else 1065055276c1SNeal Liu udc->gadget.speed = USB_SPEED_FULL; 1066055276c1SNeal Liu 1067055276c1SNeal Liu SETUP_DBG(udc, "set addr: 0x%x\n", crq.wValue); 1068055276c1SNeal Liu reg = ast_udc_read(udc, AST_UDC_CONFIG); 1069055276c1SNeal Liu reg &= ~UDC_CFG_ADDR_MASK; 1070055276c1SNeal Liu reg |= UDC_CFG_SET_ADDR(crq.wValue); 1071055276c1SNeal Liu ast_udc_write(udc, reg, AST_UDC_CONFIG); 1072055276c1SNeal Liu goto req_complete; 1073055276c1SNeal Liu 1074055276c1SNeal Liu case USB_REQ_CLEAR_FEATURE: 1075055276c1SNeal Liu SETUP_DBG(udc, "ep0: CLEAR FEATURE\n"); 1076055276c1SNeal Liu goto req_driver; 1077055276c1SNeal Liu 1078055276c1SNeal Liu case USB_REQ_SET_FEATURE: 1079055276c1SNeal Liu SETUP_DBG(udc, "ep0: SET FEATURE\n"); 1080055276c1SNeal Liu goto req_driver; 1081055276c1SNeal Liu 1082055276c1SNeal Liu case USB_REQ_GET_STATUS: 1083055276c1SNeal Liu ast_udc_getstatus(udc); 1084055276c1SNeal Liu return; 1085055276c1SNeal Liu 1086055276c1SNeal Liu default: 1087055276c1SNeal Liu goto req_driver; 1088055276c1SNeal Liu } 1089055276c1SNeal Liu 1090055276c1SNeal Liu } 1091055276c1SNeal Liu 1092055276c1SNeal Liu req_driver: 1093055276c1SNeal Liu if (udc->driver) { 1094055276c1SNeal Liu SETUP_DBG(udc, "Forwarding %s to gadget...\n", 1095055276c1SNeal Liu udc->gadget.name); 1096055276c1SNeal Liu 1097055276c1SNeal Liu spin_unlock(&udc->lock); 1098055276c1SNeal Liu rc = udc->driver->setup(&udc->gadget, &crq); 1099055276c1SNeal Liu spin_lock(&udc->lock); 1100055276c1SNeal Liu 1101055276c1SNeal Liu } else { 1102055276c1SNeal Liu SETUP_DBG(udc, "No gadget for request !\n"); 1103055276c1SNeal Liu } 1104055276c1SNeal Liu 1105055276c1SNeal Liu if (rc >= 0) 1106055276c1SNeal Liu return; 1107055276c1SNeal Liu 1108055276c1SNeal Liu /* Stall if gadget failed */ 1109055276c1SNeal Liu SETUP_DBG(udc, "Stalling, rc:0x%x\n", rc); 1110055276c1SNeal Liu ast_udc_write(udc, ast_udc_read(udc, AST_UDC_EP0_CTRL) | EP0_STALL, 1111055276c1SNeal Liu AST_UDC_EP0_CTRL); 1112055276c1SNeal Liu return; 1113055276c1SNeal Liu 1114055276c1SNeal Liu req_complete: 1115055276c1SNeal Liu SETUP_DBG(udc, "ep0: Sending IN status without data\n"); 1116055276c1SNeal Liu ast_udc_write(udc, EP0_TX_BUFF_RDY, AST_UDC_EP0_CTRL); 1117055276c1SNeal Liu } 1118055276c1SNeal Liu 1119055276c1SNeal Liu static irqreturn_t ast_udc_isr(int irq, void *data) 1120055276c1SNeal Liu { 1121055276c1SNeal Liu struct ast_udc_dev *udc = (struct ast_udc_dev *)data; 1122055276c1SNeal Liu struct ast_udc_ep *ep; 1123055276c1SNeal Liu u32 isr, ep_isr; 1124055276c1SNeal Liu int i; 1125055276c1SNeal Liu 1126055276c1SNeal Liu spin_lock(&udc->lock); 1127055276c1SNeal Liu 1128055276c1SNeal Liu isr = ast_udc_read(udc, AST_UDC_ISR); 1129055276c1SNeal Liu if (!isr) 1130055276c1SNeal Liu goto done; 1131055276c1SNeal Liu 1132055276c1SNeal Liu /* Ack interrupts */ 1133055276c1SNeal Liu ast_udc_write(udc, isr, AST_UDC_ISR); 1134055276c1SNeal Liu 1135055276c1SNeal Liu if (isr & UDC_IRQ_BUS_RESET) { 1136055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_BUS_RESET\n"); 1137055276c1SNeal Liu udc->gadget.speed = USB_SPEED_UNKNOWN; 1138055276c1SNeal Liu 1139055276c1SNeal Liu ep = &udc->ep[1]; 1140055276c1SNeal Liu EP_DBG(ep, "dctrl:0x%x\n", 1141055276c1SNeal Liu ast_ep_read(ep, AST_UDC_EP_DMA_CTRL)); 1142055276c1SNeal Liu 1143055276c1SNeal Liu if (udc->driver && udc->driver->reset) { 1144055276c1SNeal Liu spin_unlock(&udc->lock); 1145055276c1SNeal Liu udc->driver->reset(&udc->gadget); 1146055276c1SNeal Liu spin_lock(&udc->lock); 1147055276c1SNeal Liu } 1148055276c1SNeal Liu } 1149055276c1SNeal Liu 1150055276c1SNeal Liu if (isr & UDC_IRQ_BUS_SUSPEND) { 1151055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_BUS_SUSPEND\n"); 1152055276c1SNeal Liu udc->suspended_from = udc->gadget.state; 1153055276c1SNeal Liu usb_gadget_set_state(&udc->gadget, USB_STATE_SUSPENDED); 1154055276c1SNeal Liu 1155055276c1SNeal Liu if (udc->driver && udc->driver->suspend) { 1156055276c1SNeal Liu spin_unlock(&udc->lock); 1157055276c1SNeal Liu udc->driver->suspend(&udc->gadget); 1158055276c1SNeal Liu spin_lock(&udc->lock); 1159055276c1SNeal Liu } 1160055276c1SNeal Liu } 1161055276c1SNeal Liu 1162055276c1SNeal Liu if (isr & UDC_IRQ_BUS_RESUME) { 1163055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_BUS_RESUME\n"); 1164055276c1SNeal Liu usb_gadget_set_state(&udc->gadget, udc->suspended_from); 1165055276c1SNeal Liu 1166055276c1SNeal Liu if (udc->driver && udc->driver->resume) { 1167055276c1SNeal Liu spin_unlock(&udc->lock); 1168055276c1SNeal Liu udc->driver->resume(&udc->gadget); 1169055276c1SNeal Liu spin_lock(&udc->lock); 1170055276c1SNeal Liu } 1171055276c1SNeal Liu } 1172055276c1SNeal Liu 1173055276c1SNeal Liu if (isr & UDC_IRQ_EP0_IN_ACK_STALL) { 1174055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_EP0_IN_ACK_STALL\n"); 1175055276c1SNeal Liu ast_udc_ep0_in(udc); 1176055276c1SNeal Liu } 1177055276c1SNeal Liu 1178055276c1SNeal Liu if (isr & UDC_IRQ_EP0_OUT_ACK_STALL) { 1179055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_EP0_OUT_ACK_STALL\n"); 1180055276c1SNeal Liu ast_udc_ep0_out(udc); 1181055276c1SNeal Liu } 1182055276c1SNeal Liu 1183055276c1SNeal Liu if (isr & UDC_IRQ_EP0_SETUP) { 1184055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_EP0_SETUP\n"); 1185055276c1SNeal Liu ast_udc_ep0_handle_setup(udc); 1186055276c1SNeal Liu } 1187055276c1SNeal Liu 1188055276c1SNeal Liu if (isr & UDC_IRQ_EP_POOL_ACK_STALL) { 1189055276c1SNeal Liu ISR_DBG(udc, "UDC_IRQ_EP_POOL_ACK_STALL\n"); 1190055276c1SNeal Liu ep_isr = ast_udc_read(udc, AST_UDC_EP_ACK_ISR); 1191055276c1SNeal Liu 1192055276c1SNeal Liu /* Ack EP interrupts */ 1193055276c1SNeal Liu ast_udc_write(udc, ep_isr, AST_UDC_EP_ACK_ISR); 1194055276c1SNeal Liu 1195055276c1SNeal Liu /* Handle each EP */ 1196055276c1SNeal Liu for (i = 0; i < AST_UDC_NUM_ENDPOINTS - 1; i++) { 1197055276c1SNeal Liu if (ep_isr & (0x1 << i)) { 1198055276c1SNeal Liu ep = &udc->ep[i + 1]; 1199055276c1SNeal Liu if (ep->desc_mode) 1200055276c1SNeal Liu ast_udc_epn_handle_desc(udc, i + 1); 1201055276c1SNeal Liu else 1202055276c1SNeal Liu ast_udc_epn_handle(udc, i + 1); 1203055276c1SNeal Liu } 1204055276c1SNeal Liu } 1205055276c1SNeal Liu } 1206055276c1SNeal Liu 1207055276c1SNeal Liu done: 1208055276c1SNeal Liu spin_unlock(&udc->lock); 1209055276c1SNeal Liu return IRQ_HANDLED; 1210055276c1SNeal Liu } 1211055276c1SNeal Liu 1212055276c1SNeal Liu static int ast_udc_gadget_getframe(struct usb_gadget *gadget) 1213055276c1SNeal Liu { 1214055276c1SNeal Liu struct ast_udc_dev *udc = to_ast_dev(gadget); 1215055276c1SNeal Liu 1216055276c1SNeal Liu return (ast_udc_read(udc, AST_UDC_STS) >> 16) & 0x7ff; 1217055276c1SNeal Liu } 1218055276c1SNeal Liu 1219055276c1SNeal Liu static void ast_udc_wake_work(struct work_struct *work) 1220055276c1SNeal Liu { 1221055276c1SNeal Liu struct ast_udc_dev *udc = container_of(work, struct ast_udc_dev, 1222055276c1SNeal Liu wake_work); 1223055276c1SNeal Liu unsigned long flags; 1224055276c1SNeal Liu u32 ctrl; 1225055276c1SNeal Liu 1226055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 1227055276c1SNeal Liu 1228055276c1SNeal Liu UDC_DBG(udc, "Wakeup Host !\n"); 1229055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL); 1230055276c1SNeal Liu ast_udc_write(udc, ctrl | USB_REMOTE_WAKEUP_EN, AST_UDC_FUNC_CTRL); 1231055276c1SNeal Liu 1232055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 1233055276c1SNeal Liu } 1234055276c1SNeal Liu 1235055276c1SNeal Liu static void ast_udc_wakeup_all(struct ast_udc_dev *udc) 1236055276c1SNeal Liu { 1237055276c1SNeal Liu /* 1238055276c1SNeal Liu * A device is trying to wake the world, because this 1239055276c1SNeal Liu * can recurse into the device, we break the call chain 1240055276c1SNeal Liu * using a work queue 1241055276c1SNeal Liu */ 1242055276c1SNeal Liu schedule_work(&udc->wake_work); 1243055276c1SNeal Liu } 1244055276c1SNeal Liu 1245055276c1SNeal Liu static int ast_udc_wakeup(struct usb_gadget *gadget) 1246055276c1SNeal Liu { 1247055276c1SNeal Liu struct ast_udc_dev *udc = to_ast_dev(gadget); 1248055276c1SNeal Liu unsigned long flags; 1249055276c1SNeal Liu int rc = 0; 1250055276c1SNeal Liu 1251055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 1252055276c1SNeal Liu 1253055276c1SNeal Liu if (!udc->wakeup_en) { 1254055276c1SNeal Liu UDC_DBG(udc, "Remote Wakeup is disabled\n"); 1255055276c1SNeal Liu rc = -EINVAL; 1256055276c1SNeal Liu goto err; 1257055276c1SNeal Liu } 1258055276c1SNeal Liu 1259055276c1SNeal Liu UDC_DBG(udc, "Device initiated wakeup\n"); 1260055276c1SNeal Liu ast_udc_wakeup_all(udc); 1261055276c1SNeal Liu 1262055276c1SNeal Liu err: 1263055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 1264055276c1SNeal Liu return rc; 1265055276c1SNeal Liu } 1266055276c1SNeal Liu 1267055276c1SNeal Liu /* 1268055276c1SNeal Liu * Activate/Deactivate link with host 1269055276c1SNeal Liu */ 1270055276c1SNeal Liu static int ast_udc_pullup(struct usb_gadget *gadget, int is_on) 1271055276c1SNeal Liu { 1272055276c1SNeal Liu struct ast_udc_dev *udc = to_ast_dev(gadget); 1273055276c1SNeal Liu unsigned long flags; 1274055276c1SNeal Liu u32 ctrl; 1275055276c1SNeal Liu 1276055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 1277055276c1SNeal Liu 1278055276c1SNeal Liu UDC_DBG(udc, "is_on: %d\n", is_on); 1279055276c1SNeal Liu if (is_on) 1280055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL) | USB_UPSTREAM_EN; 1281055276c1SNeal Liu else 1282055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL) & ~USB_UPSTREAM_EN; 1283055276c1SNeal Liu 1284055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); 1285055276c1SNeal Liu 1286055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 1287055276c1SNeal Liu 1288055276c1SNeal Liu return 0; 1289055276c1SNeal Liu } 1290055276c1SNeal Liu 1291055276c1SNeal Liu static int ast_udc_start(struct usb_gadget *gadget, 1292055276c1SNeal Liu struct usb_gadget_driver *driver) 1293055276c1SNeal Liu { 1294055276c1SNeal Liu struct ast_udc_dev *udc = to_ast_dev(gadget); 1295055276c1SNeal Liu struct ast_udc_ep *ep; 1296055276c1SNeal Liu unsigned long flags; 1297055276c1SNeal Liu int i; 1298055276c1SNeal Liu 1299055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 1300055276c1SNeal Liu 1301055276c1SNeal Liu UDC_DBG(udc, "\n"); 1302055276c1SNeal Liu udc->driver = driver; 1303055276c1SNeal Liu udc->gadget.dev.of_node = udc->pdev->dev.of_node; 1304055276c1SNeal Liu 1305055276c1SNeal Liu for (i = 0; i < AST_UDC_NUM_ENDPOINTS; i++) { 1306055276c1SNeal Liu ep = &udc->ep[i]; 1307055276c1SNeal Liu ep->stopped = 0; 1308055276c1SNeal Liu } 1309055276c1SNeal Liu 1310055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 1311055276c1SNeal Liu 1312055276c1SNeal Liu return 0; 1313055276c1SNeal Liu } 1314055276c1SNeal Liu 1315055276c1SNeal Liu static int ast_udc_stop(struct usb_gadget *gadget) 1316055276c1SNeal Liu { 1317055276c1SNeal Liu struct ast_udc_dev *udc = to_ast_dev(gadget); 1318055276c1SNeal Liu unsigned long flags; 1319055276c1SNeal Liu u32 ctrl; 1320055276c1SNeal Liu 1321055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 1322055276c1SNeal Liu 1323055276c1SNeal Liu UDC_DBG(udc, "\n"); 1324055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL) & ~USB_UPSTREAM_EN; 1325055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); 1326055276c1SNeal Liu 1327055276c1SNeal Liu udc->gadget.speed = USB_SPEED_UNKNOWN; 1328055276c1SNeal Liu udc->driver = NULL; 1329055276c1SNeal Liu 1330055276c1SNeal Liu ast_udc_stop_activity(udc); 1331055276c1SNeal Liu usb_gadget_set_state(&udc->gadget, USB_STATE_NOTATTACHED); 1332055276c1SNeal Liu 1333055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 1334055276c1SNeal Liu 1335055276c1SNeal Liu return 0; 1336055276c1SNeal Liu } 1337055276c1SNeal Liu 1338055276c1SNeal Liu static const struct usb_gadget_ops ast_udc_ops = { 1339055276c1SNeal Liu .get_frame = ast_udc_gadget_getframe, 1340055276c1SNeal Liu .wakeup = ast_udc_wakeup, 1341055276c1SNeal Liu .pullup = ast_udc_pullup, 1342055276c1SNeal Liu .udc_start = ast_udc_start, 1343055276c1SNeal Liu .udc_stop = ast_udc_stop, 1344055276c1SNeal Liu }; 1345055276c1SNeal Liu 1346055276c1SNeal Liu /* 1347055276c1SNeal Liu * Support 1 Control Endpoint. 1348055276c1SNeal Liu * Support multiple programmable endpoints that can be configured to 1349055276c1SNeal Liu * Bulk IN/OUT, Interrupt IN/OUT, and Isochronous IN/OUT type endpoint. 1350055276c1SNeal Liu */ 1351055276c1SNeal Liu static void ast_udc_init_ep(struct ast_udc_dev *udc) 1352055276c1SNeal Liu { 1353055276c1SNeal Liu struct ast_udc_ep *ep; 1354055276c1SNeal Liu int i; 1355055276c1SNeal Liu 1356055276c1SNeal Liu for (i = 0; i < AST_UDC_NUM_ENDPOINTS; i++) { 1357055276c1SNeal Liu ep = &udc->ep[i]; 1358055276c1SNeal Liu ep->ep.name = ast_ep_name[i]; 1359055276c1SNeal Liu if (i == 0) { 1360055276c1SNeal Liu ep->ep.caps.type_control = true; 1361055276c1SNeal Liu } else { 1362055276c1SNeal Liu ep->ep.caps.type_iso = true; 1363055276c1SNeal Liu ep->ep.caps.type_bulk = true; 1364055276c1SNeal Liu ep->ep.caps.type_int = true; 1365055276c1SNeal Liu } 1366055276c1SNeal Liu ep->ep.caps.dir_in = true; 1367055276c1SNeal Liu ep->ep.caps.dir_out = true; 1368055276c1SNeal Liu 1369055276c1SNeal Liu ep->ep.ops = &ast_udc_ep_ops; 1370055276c1SNeal Liu ep->udc = udc; 1371055276c1SNeal Liu 1372055276c1SNeal Liu INIT_LIST_HEAD(&ep->queue); 1373055276c1SNeal Liu 1374055276c1SNeal Liu if (i == 0) { 1375055276c1SNeal Liu usb_ep_set_maxpacket_limit(&ep->ep, 1376055276c1SNeal Liu AST_UDC_EP0_MAX_PACKET); 1377055276c1SNeal Liu continue; 1378055276c1SNeal Liu } 1379055276c1SNeal Liu 1380055276c1SNeal Liu ep->ep_reg = udc->reg + AST_UDC_EP_BASE + 1381055276c1SNeal Liu (AST_UDC_EP_OFFSET * (i - 1)); 1382055276c1SNeal Liu 1383055276c1SNeal Liu ep->epn_buf = udc->ep0_buf + (i * AST_UDC_EP_DMA_SIZE); 1384055276c1SNeal Liu ep->epn_buf_dma = udc->ep0_buf_dma + (i * AST_UDC_EP_DMA_SIZE); 1385055276c1SNeal Liu usb_ep_set_maxpacket_limit(&ep->ep, AST_UDC_EPn_MAX_PACKET); 1386055276c1SNeal Liu 1387055276c1SNeal Liu ep->descs = ep->epn_buf + AST_UDC_EPn_MAX_PACKET; 1388055276c1SNeal Liu ep->descs_dma = ep->epn_buf_dma + AST_UDC_EPn_MAX_PACKET; 1389055276c1SNeal Liu ep->descs_wptr = 0; 1390055276c1SNeal Liu 1391055276c1SNeal Liu list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); 1392055276c1SNeal Liu } 1393055276c1SNeal Liu } 1394055276c1SNeal Liu 1395055276c1SNeal Liu static void ast_udc_init_dev(struct ast_udc_dev *udc) 1396055276c1SNeal Liu { 1397055276c1SNeal Liu INIT_WORK(&udc->wake_work, ast_udc_wake_work); 1398055276c1SNeal Liu } 1399055276c1SNeal Liu 1400055276c1SNeal Liu static void ast_udc_init_hw(struct ast_udc_dev *udc) 1401055276c1SNeal Liu { 1402055276c1SNeal Liu u32 ctrl; 1403055276c1SNeal Liu 1404055276c1SNeal Liu /* Enable PHY */ 1405055276c1SNeal Liu ctrl = USB_PHY_CLK_EN | USB_PHY_RESET_DIS; 1406055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); 1407055276c1SNeal Liu 1408055276c1SNeal Liu udelay(1); 1409055276c1SNeal Liu ast_udc_write(udc, 0, AST_UDC_DEV_RESET); 1410055276c1SNeal Liu 1411055276c1SNeal Liu /* Set descriptor ring size */ 1412055276c1SNeal Liu if (AST_UDC_DESCS_COUNT == 256) { 1413055276c1SNeal Liu ctrl |= USB_EP_LONG_DESC; 1414055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); 1415055276c1SNeal Liu } 1416055276c1SNeal Liu 1417055276c1SNeal Liu /* Mask & ack all interrupts before installing the handler */ 1418055276c1SNeal Liu ast_udc_write(udc, 0, AST_UDC_IER); 1419055276c1SNeal Liu ast_udc_write(udc, UDC_IRQ_ACK_ALL, AST_UDC_ISR); 1420055276c1SNeal Liu 1421055276c1SNeal Liu /* Enable some interrupts */ 1422055276c1SNeal Liu ctrl = UDC_IRQ_EP_POOL_ACK_STALL | UDC_IRQ_BUS_RESUME | 1423055276c1SNeal Liu UDC_IRQ_BUS_SUSPEND | UDC_IRQ_BUS_RESET | 1424055276c1SNeal Liu UDC_IRQ_EP0_IN_ACK_STALL | UDC_IRQ_EP0_OUT_ACK_STALL | 1425055276c1SNeal Liu UDC_IRQ_EP0_SETUP; 1426055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_IER); 1427055276c1SNeal Liu 1428055276c1SNeal Liu /* Cleanup and enable ep ACK interrupts */ 1429055276c1SNeal Liu ast_udc_write(udc, UDC_IRQ_EP_ACK_ALL, AST_UDC_EP_ACK_IER); 1430055276c1SNeal Liu ast_udc_write(udc, UDC_IRQ_EP_ACK_ALL, AST_UDC_EP_ACK_ISR); 1431055276c1SNeal Liu 1432055276c1SNeal Liu ast_udc_write(udc, 0, AST_UDC_EP0_CTRL); 1433055276c1SNeal Liu } 1434055276c1SNeal Liu 1435*3d56e5aaSUwe Kleine-König static void ast_udc_remove(struct platform_device *pdev) 1436055276c1SNeal Liu { 1437055276c1SNeal Liu struct ast_udc_dev *udc = platform_get_drvdata(pdev); 1438055276c1SNeal Liu unsigned long flags; 1439055276c1SNeal Liu u32 ctrl; 1440055276c1SNeal Liu 1441055276c1SNeal Liu usb_del_gadget_udc(&udc->gadget); 1442*3d56e5aaSUwe Kleine-König if (udc->driver) { 1443*3d56e5aaSUwe Kleine-König /* 1444*3d56e5aaSUwe Kleine-König * This is broken as only some cleanup is skipped, *udev is 1445*3d56e5aaSUwe Kleine-König * freed and the register mapping goes away. Any further usage 1446*3d56e5aaSUwe Kleine-König * probably crashes. Also the device is unbound, so the skipped 1447*3d56e5aaSUwe Kleine-König * cleanup is never catched up later. 1448*3d56e5aaSUwe Kleine-König */ 1449*3d56e5aaSUwe Kleine-König dev_alert(&pdev->dev, 1450*3d56e5aaSUwe Kleine-König "Driver is busy and still going away. Fasten your seat belts!\n"); 1451*3d56e5aaSUwe Kleine-König return; 1452*3d56e5aaSUwe Kleine-König } 1453055276c1SNeal Liu 1454055276c1SNeal Liu spin_lock_irqsave(&udc->lock, flags); 1455055276c1SNeal Liu 1456055276c1SNeal Liu /* Disable upstream port connection */ 1457055276c1SNeal Liu ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL) & ~USB_UPSTREAM_EN; 1458055276c1SNeal Liu ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); 1459055276c1SNeal Liu 1460055276c1SNeal Liu clk_disable_unprepare(udc->clk); 1461055276c1SNeal Liu 1462055276c1SNeal Liu spin_unlock_irqrestore(&udc->lock, flags); 1463055276c1SNeal Liu 1464055276c1SNeal Liu if (udc->ep0_buf) 1465055276c1SNeal Liu dma_free_coherent(&pdev->dev, 1466055276c1SNeal Liu AST_UDC_EP_DMA_SIZE * AST_UDC_NUM_ENDPOINTS, 1467055276c1SNeal Liu udc->ep0_buf, 1468055276c1SNeal Liu udc->ep0_buf_dma); 1469055276c1SNeal Liu 1470055276c1SNeal Liu udc->ep0_buf = NULL; 1471055276c1SNeal Liu } 1472055276c1SNeal Liu 1473055276c1SNeal Liu static int ast_udc_probe(struct platform_device *pdev) 1474055276c1SNeal Liu { 1475055276c1SNeal Liu enum usb_device_speed max_speed; 1476055276c1SNeal Liu struct device *dev = &pdev->dev; 1477055276c1SNeal Liu struct ast_udc_dev *udc; 1478055276c1SNeal Liu int rc; 1479055276c1SNeal Liu 1480055276c1SNeal Liu udc = devm_kzalloc(&pdev->dev, sizeof(struct ast_udc_dev), GFP_KERNEL); 1481055276c1SNeal Liu if (!udc) 1482055276c1SNeal Liu return -ENOMEM; 1483055276c1SNeal Liu 1484055276c1SNeal Liu udc->gadget.dev.parent = dev; 1485055276c1SNeal Liu udc->pdev = pdev; 1486055276c1SNeal Liu spin_lock_init(&udc->lock); 1487055276c1SNeal Liu 1488055276c1SNeal Liu udc->gadget.ops = &ast_udc_ops; 1489055276c1SNeal Liu udc->gadget.ep0 = &udc->ep[0].ep; 1490055276c1SNeal Liu udc->gadget.name = "aspeed-udc"; 1491055276c1SNeal Liu udc->gadget.dev.init_name = "gadget"; 1492055276c1SNeal Liu 149350fd16ebSYangtao Li udc->reg = devm_platform_ioremap_resource(pdev, 0); 1494055276c1SNeal Liu if (IS_ERR(udc->reg)) { 1495055276c1SNeal Liu dev_err(&pdev->dev, "Failed to map resources\n"); 1496055276c1SNeal Liu return PTR_ERR(udc->reg); 1497055276c1SNeal Liu } 1498055276c1SNeal Liu 1499055276c1SNeal Liu platform_set_drvdata(pdev, udc); 1500055276c1SNeal Liu 1501055276c1SNeal Liu udc->clk = devm_clk_get(&pdev->dev, NULL); 1502055276c1SNeal Liu if (IS_ERR(udc->clk)) { 1503055276c1SNeal Liu rc = PTR_ERR(udc->clk); 1504055276c1SNeal Liu goto err; 1505055276c1SNeal Liu } 1506055276c1SNeal Liu rc = clk_prepare_enable(udc->clk); 1507055276c1SNeal Liu if (rc) { 1508055276c1SNeal Liu dev_err(&pdev->dev, "Failed to enable clock (0x%x)\n", rc); 1509055276c1SNeal Liu goto err; 1510055276c1SNeal Liu } 1511055276c1SNeal Liu 1512055276c1SNeal Liu /* Check if we need to limit the HW to USB1 */ 1513055276c1SNeal Liu max_speed = usb_get_maximum_speed(&pdev->dev); 1514055276c1SNeal Liu if (max_speed != USB_SPEED_UNKNOWN && max_speed < USB_SPEED_HIGH) 1515055276c1SNeal Liu udc->force_usb1 = true; 1516055276c1SNeal Liu 1517055276c1SNeal Liu /* 1518055276c1SNeal Liu * Allocate DMA buffers for all EPs in one chunk 1519055276c1SNeal Liu */ 1520055276c1SNeal Liu udc->ep0_buf = dma_alloc_coherent(&pdev->dev, 1521055276c1SNeal Liu AST_UDC_EP_DMA_SIZE * 1522055276c1SNeal Liu AST_UDC_NUM_ENDPOINTS, 1523055276c1SNeal Liu &udc->ep0_buf_dma, GFP_KERNEL); 1524055276c1SNeal Liu 1525055276c1SNeal Liu udc->gadget.speed = USB_SPEED_UNKNOWN; 1526055276c1SNeal Liu udc->gadget.max_speed = USB_SPEED_HIGH; 1527055276c1SNeal Liu udc->creq = udc->reg + AST_UDC_SETUP0; 1528055276c1SNeal Liu 1529055276c1SNeal Liu /* 1530055276c1SNeal Liu * Support single stage mode or 32/256 stages descriptor mode. 1531055276c1SNeal Liu * Set default as Descriptor Mode. 1532055276c1SNeal Liu */ 1533055276c1SNeal Liu udc->desc_mode = AST_UDC_DESC_MODE; 1534055276c1SNeal Liu 1535055276c1SNeal Liu dev_info(&pdev->dev, "DMA %s\n", udc->desc_mode ? 1536055276c1SNeal Liu "descriptor mode" : "single mode"); 1537055276c1SNeal Liu 1538055276c1SNeal Liu INIT_LIST_HEAD(&udc->gadget.ep_list); 1539055276c1SNeal Liu INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); 1540055276c1SNeal Liu 1541055276c1SNeal Liu /* Initialized udc ep */ 1542055276c1SNeal Liu ast_udc_init_ep(udc); 1543055276c1SNeal Liu 1544055276c1SNeal Liu /* Initialized udc device */ 1545055276c1SNeal Liu ast_udc_init_dev(udc); 1546055276c1SNeal Liu 1547055276c1SNeal Liu /* Initialized udc hardware */ 1548055276c1SNeal Liu ast_udc_init_hw(udc); 1549055276c1SNeal Liu 1550055276c1SNeal Liu /* Find interrupt and install handler */ 1551055276c1SNeal Liu udc->irq = platform_get_irq(pdev, 0); 1552055276c1SNeal Liu if (udc->irq < 0) { 1553055276c1SNeal Liu rc = udc->irq; 1554055276c1SNeal Liu goto err; 1555055276c1SNeal Liu } 1556055276c1SNeal Liu 1557055276c1SNeal Liu rc = devm_request_irq(&pdev->dev, udc->irq, ast_udc_isr, 0, 1558055276c1SNeal Liu KBUILD_MODNAME, udc); 1559055276c1SNeal Liu if (rc) { 1560055276c1SNeal Liu dev_err(&pdev->dev, "Failed to request interrupt\n"); 1561055276c1SNeal Liu goto err; 1562055276c1SNeal Liu } 1563055276c1SNeal Liu 1564055276c1SNeal Liu rc = usb_add_gadget_udc(&pdev->dev, &udc->gadget); 1565055276c1SNeal Liu if (rc) { 1566055276c1SNeal Liu dev_err(&pdev->dev, "Failed to add gadget udc\n"); 1567055276c1SNeal Liu goto err; 1568055276c1SNeal Liu } 1569055276c1SNeal Liu 1570055276c1SNeal Liu dev_info(&pdev->dev, "Initialized udc in USB%s mode\n", 1571055276c1SNeal Liu udc->force_usb1 ? "1" : "2"); 1572055276c1SNeal Liu 1573055276c1SNeal Liu return 0; 1574055276c1SNeal Liu 1575055276c1SNeal Liu err: 1576055276c1SNeal Liu dev_err(&pdev->dev, "Failed to udc probe, rc:0x%x\n", rc); 1577055276c1SNeal Liu ast_udc_remove(pdev); 1578055276c1SNeal Liu 1579055276c1SNeal Liu return rc; 1580055276c1SNeal Liu } 1581055276c1SNeal Liu 1582055276c1SNeal Liu static const struct of_device_id ast_udc_of_dt_ids[] = { 1583055276c1SNeal Liu { .compatible = "aspeed,ast2600-udc", }, 1584055276c1SNeal Liu {} 1585055276c1SNeal Liu }; 1586055276c1SNeal Liu 1587055276c1SNeal Liu MODULE_DEVICE_TABLE(of, ast_udc_of_dt_ids); 1588055276c1SNeal Liu 1589055276c1SNeal Liu static struct platform_driver ast_udc_driver = { 1590055276c1SNeal Liu .probe = ast_udc_probe, 1591*3d56e5aaSUwe Kleine-König .remove_new = ast_udc_remove, 1592055276c1SNeal Liu .driver = { 1593055276c1SNeal Liu .name = KBUILD_MODNAME, 1594055276c1SNeal Liu .of_match_table = ast_udc_of_dt_ids, 1595055276c1SNeal Liu }, 1596055276c1SNeal Liu }; 1597055276c1SNeal Liu 1598055276c1SNeal Liu module_platform_driver(ast_udc_driver); 1599055276c1SNeal Liu 1600055276c1SNeal Liu MODULE_DESCRIPTION("ASPEED UDC driver"); 1601055276c1SNeal Liu MODULE_AUTHOR("Neal Liu <neal_liu@aspeedtech.com>"); 1602055276c1SNeal Liu MODULE_LICENSE("GPL"); 1603