147a1685fSDinh Nguyen /** 247a1685fSDinh Nguyen * Copyright (c) 2011 Samsung Electronics Co., Ltd. 347a1685fSDinh Nguyen * http://www.samsung.com 447a1685fSDinh Nguyen * 547a1685fSDinh Nguyen * Copyright 2008 Openmoko, Inc. 647a1685fSDinh Nguyen * Copyright 2008 Simtec Electronics 747a1685fSDinh Nguyen * Ben Dooks <ben@simtec.co.uk> 847a1685fSDinh Nguyen * http://armlinux.simtec.co.uk/ 947a1685fSDinh Nguyen * 1047a1685fSDinh Nguyen * S3C USB2.0 High-speed / OtG driver 1147a1685fSDinh Nguyen * 1247a1685fSDinh Nguyen * This program is free software; you can redistribute it and/or modify 1347a1685fSDinh Nguyen * it under the terms of the GNU General Public License version 2 as 1447a1685fSDinh Nguyen * published by the Free Software Foundation. 1547a1685fSDinh Nguyen */ 1647a1685fSDinh Nguyen 1747a1685fSDinh Nguyen #include <linux/kernel.h> 1847a1685fSDinh Nguyen #include <linux/module.h> 1947a1685fSDinh Nguyen #include <linux/spinlock.h> 2047a1685fSDinh Nguyen #include <linux/interrupt.h> 2147a1685fSDinh Nguyen #include <linux/platform_device.h> 2247a1685fSDinh Nguyen #include <linux/dma-mapping.h> 2347a1685fSDinh Nguyen #include <linux/debugfs.h> 2447a1685fSDinh Nguyen #include <linux/seq_file.h> 2547a1685fSDinh Nguyen #include <linux/delay.h> 2647a1685fSDinh Nguyen #include <linux/io.h> 2747a1685fSDinh Nguyen #include <linux/slab.h> 2847a1685fSDinh Nguyen #include <linux/clk.h> 2947a1685fSDinh Nguyen #include <linux/regulator/consumer.h> 3047a1685fSDinh Nguyen #include <linux/of_platform.h> 3147a1685fSDinh Nguyen #include <linux/phy/phy.h> 3247a1685fSDinh Nguyen 3347a1685fSDinh Nguyen #include <linux/usb/ch9.h> 3447a1685fSDinh Nguyen #include <linux/usb/gadget.h> 3547a1685fSDinh Nguyen #include <linux/usb/phy.h> 3647a1685fSDinh Nguyen #include <linux/platform_data/s3c-hsotg.h> 3747a1685fSDinh Nguyen 38f7c0b143SDinh Nguyen #include "core.h" 3947a1685fSDinh Nguyen 4047a1685fSDinh Nguyen /* conversion functions */ 4147a1685fSDinh Nguyen static inline struct s3c_hsotg_req *our_req(struct usb_request *req) 4247a1685fSDinh Nguyen { 4347a1685fSDinh Nguyen return container_of(req, struct s3c_hsotg_req, req); 4447a1685fSDinh Nguyen } 4547a1685fSDinh Nguyen 4647a1685fSDinh Nguyen static inline struct s3c_hsotg_ep *our_ep(struct usb_ep *ep) 4747a1685fSDinh Nguyen { 4847a1685fSDinh Nguyen return container_of(ep, struct s3c_hsotg_ep, ep); 4947a1685fSDinh Nguyen } 5047a1685fSDinh Nguyen 5147a1685fSDinh Nguyen static inline struct s3c_hsotg *to_hsotg(struct usb_gadget *gadget) 5247a1685fSDinh Nguyen { 5347a1685fSDinh Nguyen return container_of(gadget, struct s3c_hsotg, gadget); 5447a1685fSDinh Nguyen } 5547a1685fSDinh Nguyen 5647a1685fSDinh Nguyen static inline void __orr32(void __iomem *ptr, u32 val) 5747a1685fSDinh Nguyen { 5847a1685fSDinh Nguyen writel(readl(ptr) | val, ptr); 5947a1685fSDinh Nguyen } 6047a1685fSDinh Nguyen 6147a1685fSDinh Nguyen static inline void __bic32(void __iomem *ptr, u32 val) 6247a1685fSDinh Nguyen { 6347a1685fSDinh Nguyen writel(readl(ptr) & ~val, ptr); 6447a1685fSDinh Nguyen } 6547a1685fSDinh Nguyen 6647a1685fSDinh Nguyen /* forward decleration of functions */ 6747a1685fSDinh Nguyen static void s3c_hsotg_dump(struct s3c_hsotg *hsotg); 6847a1685fSDinh Nguyen 6947a1685fSDinh Nguyen /** 7047a1685fSDinh Nguyen * using_dma - return the DMA status of the driver. 7147a1685fSDinh Nguyen * @hsotg: The driver state. 7247a1685fSDinh Nguyen * 7347a1685fSDinh Nguyen * Return true if we're using DMA. 7447a1685fSDinh Nguyen * 7547a1685fSDinh Nguyen * Currently, we have the DMA support code worked into everywhere 7647a1685fSDinh Nguyen * that needs it, but the AMBA DMA implementation in the hardware can 7747a1685fSDinh Nguyen * only DMA from 32bit aligned addresses. This means that gadgets such 7847a1685fSDinh Nguyen * as the CDC Ethernet cannot work as they often pass packets which are 7947a1685fSDinh Nguyen * not 32bit aligned. 8047a1685fSDinh Nguyen * 8147a1685fSDinh Nguyen * Unfortunately the choice to use DMA or not is global to the controller 8247a1685fSDinh Nguyen * and seems to be only settable when the controller is being put through 8347a1685fSDinh Nguyen * a core reset. This means we either need to fix the gadgets to take 8447a1685fSDinh Nguyen * account of DMA alignment, or add bounce buffers (yuerk). 8547a1685fSDinh Nguyen * 8647a1685fSDinh Nguyen * Until this issue is sorted out, we always return 'false'. 8747a1685fSDinh Nguyen */ 8847a1685fSDinh Nguyen static inline bool using_dma(struct s3c_hsotg *hsotg) 8947a1685fSDinh Nguyen { 9047a1685fSDinh Nguyen return false; /* support is not complete */ 9147a1685fSDinh Nguyen } 9247a1685fSDinh Nguyen 9347a1685fSDinh Nguyen /** 9447a1685fSDinh Nguyen * s3c_hsotg_en_gsint - enable one or more of the general interrupt 9547a1685fSDinh Nguyen * @hsotg: The device state 9647a1685fSDinh Nguyen * @ints: A bitmask of the interrupts to enable 9747a1685fSDinh Nguyen */ 9847a1685fSDinh Nguyen static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints) 9947a1685fSDinh Nguyen { 10047a1685fSDinh Nguyen u32 gsintmsk = readl(hsotg->regs + GINTMSK); 10147a1685fSDinh Nguyen u32 new_gsintmsk; 10247a1685fSDinh Nguyen 10347a1685fSDinh Nguyen new_gsintmsk = gsintmsk | ints; 10447a1685fSDinh Nguyen 10547a1685fSDinh Nguyen if (new_gsintmsk != gsintmsk) { 10647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); 10747a1685fSDinh Nguyen writel(new_gsintmsk, hsotg->regs + GINTMSK); 10847a1685fSDinh Nguyen } 10947a1685fSDinh Nguyen } 11047a1685fSDinh Nguyen 11147a1685fSDinh Nguyen /** 11247a1685fSDinh Nguyen * s3c_hsotg_disable_gsint - disable one or more of the general interrupt 11347a1685fSDinh Nguyen * @hsotg: The device state 11447a1685fSDinh Nguyen * @ints: A bitmask of the interrupts to enable 11547a1685fSDinh Nguyen */ 11647a1685fSDinh Nguyen static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints) 11747a1685fSDinh Nguyen { 11847a1685fSDinh Nguyen u32 gsintmsk = readl(hsotg->regs + GINTMSK); 11947a1685fSDinh Nguyen u32 new_gsintmsk; 12047a1685fSDinh Nguyen 12147a1685fSDinh Nguyen new_gsintmsk = gsintmsk & ~ints; 12247a1685fSDinh Nguyen 12347a1685fSDinh Nguyen if (new_gsintmsk != gsintmsk) 12447a1685fSDinh Nguyen writel(new_gsintmsk, hsotg->regs + GINTMSK); 12547a1685fSDinh Nguyen } 12647a1685fSDinh Nguyen 12747a1685fSDinh Nguyen /** 12847a1685fSDinh Nguyen * s3c_hsotg_ctrl_epint - enable/disable an endpoint irq 12947a1685fSDinh Nguyen * @hsotg: The device state 13047a1685fSDinh Nguyen * @ep: The endpoint index 13147a1685fSDinh Nguyen * @dir_in: True if direction is in. 13247a1685fSDinh Nguyen * @en: The enable value, true to enable 13347a1685fSDinh Nguyen * 13447a1685fSDinh Nguyen * Set or clear the mask for an individual endpoint's interrupt 13547a1685fSDinh Nguyen * request. 13647a1685fSDinh Nguyen */ 13747a1685fSDinh Nguyen static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg, 13847a1685fSDinh Nguyen unsigned int ep, unsigned int dir_in, 13947a1685fSDinh Nguyen unsigned int en) 14047a1685fSDinh Nguyen { 14147a1685fSDinh Nguyen unsigned long flags; 14247a1685fSDinh Nguyen u32 bit = 1 << ep; 14347a1685fSDinh Nguyen u32 daint; 14447a1685fSDinh Nguyen 14547a1685fSDinh Nguyen if (!dir_in) 14647a1685fSDinh Nguyen bit <<= 16; 14747a1685fSDinh Nguyen 14847a1685fSDinh Nguyen local_irq_save(flags); 14947a1685fSDinh Nguyen daint = readl(hsotg->regs + DAINTMSK); 15047a1685fSDinh Nguyen if (en) 15147a1685fSDinh Nguyen daint |= bit; 15247a1685fSDinh Nguyen else 15347a1685fSDinh Nguyen daint &= ~bit; 15447a1685fSDinh Nguyen writel(daint, hsotg->regs + DAINTMSK); 15547a1685fSDinh Nguyen local_irq_restore(flags); 15647a1685fSDinh Nguyen } 15747a1685fSDinh Nguyen 15847a1685fSDinh Nguyen /** 15947a1685fSDinh Nguyen * s3c_hsotg_init_fifo - initialise non-periodic FIFOs 16047a1685fSDinh Nguyen * @hsotg: The device instance. 16147a1685fSDinh Nguyen */ 16247a1685fSDinh Nguyen static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) 16347a1685fSDinh Nguyen { 16447a1685fSDinh Nguyen unsigned int ep; 16547a1685fSDinh Nguyen unsigned int addr; 16647a1685fSDinh Nguyen unsigned int size; 16747a1685fSDinh Nguyen int timeout; 16847a1685fSDinh Nguyen u32 val; 16947a1685fSDinh Nguyen 17047a1685fSDinh Nguyen /* set FIFO sizes to 2048/1024 */ 17147a1685fSDinh Nguyen 17247a1685fSDinh Nguyen writel(2048, hsotg->regs + GRXFSIZ); 17347a1685fSDinh Nguyen writel((2048 << FIFOSIZE_STARTADDR_SHIFT) | 17447a1685fSDinh Nguyen (1024 << FIFOSIZE_DEPTH_SHIFT), hsotg->regs + GNPTXFSIZ); 17547a1685fSDinh Nguyen 17647a1685fSDinh Nguyen /* 17747a1685fSDinh Nguyen * arange all the rest of the TX FIFOs, as some versions of this 17847a1685fSDinh Nguyen * block have overlapping default addresses. This also ensures 17947a1685fSDinh Nguyen * that if the settings have been changed, then they are set to 18047a1685fSDinh Nguyen * known values. 18147a1685fSDinh Nguyen */ 18247a1685fSDinh Nguyen 18347a1685fSDinh Nguyen /* start at the end of the GNPTXFSIZ, rounded up */ 18447a1685fSDinh Nguyen addr = 2048 + 1024; 18547a1685fSDinh Nguyen size = 768; 18647a1685fSDinh Nguyen 18747a1685fSDinh Nguyen /* 18847a1685fSDinh Nguyen * currently we allocate TX FIFOs for all possible endpoints, 18947a1685fSDinh Nguyen * and assume that they are all the same size. 19047a1685fSDinh Nguyen */ 19147a1685fSDinh Nguyen 19247a1685fSDinh Nguyen for (ep = 1; ep <= 15; ep++) { 19347a1685fSDinh Nguyen val = addr; 19447a1685fSDinh Nguyen val |= size << FIFOSIZE_DEPTH_SHIFT; 19547a1685fSDinh Nguyen addr += size; 19647a1685fSDinh Nguyen 19747a1685fSDinh Nguyen writel(val, hsotg->regs + DPTXFSIZN(ep)); 19847a1685fSDinh Nguyen } 19947a1685fSDinh Nguyen 20047a1685fSDinh Nguyen /* 20147a1685fSDinh Nguyen * according to p428 of the design guide, we need to ensure that 20247a1685fSDinh Nguyen * all fifos are flushed before continuing 20347a1685fSDinh Nguyen */ 20447a1685fSDinh Nguyen 20547a1685fSDinh Nguyen writel(GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | 20647a1685fSDinh Nguyen GRSTCTL_RXFFLSH, hsotg->regs + GRSTCTL); 20747a1685fSDinh Nguyen 20847a1685fSDinh Nguyen /* wait until the fifos are both flushed */ 20947a1685fSDinh Nguyen timeout = 100; 21047a1685fSDinh Nguyen while (1) { 21147a1685fSDinh Nguyen val = readl(hsotg->regs + GRSTCTL); 21247a1685fSDinh Nguyen 21347a1685fSDinh Nguyen if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0) 21447a1685fSDinh Nguyen break; 21547a1685fSDinh Nguyen 21647a1685fSDinh Nguyen if (--timeout == 0) { 21747a1685fSDinh Nguyen dev_err(hsotg->dev, 21847a1685fSDinh Nguyen "%s: timeout flushing fifos (GRSTCTL=%08x)\n", 21947a1685fSDinh Nguyen __func__, val); 22047a1685fSDinh Nguyen } 22147a1685fSDinh Nguyen 22247a1685fSDinh Nguyen udelay(1); 22347a1685fSDinh Nguyen } 22447a1685fSDinh Nguyen 22547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); 22647a1685fSDinh Nguyen } 22747a1685fSDinh Nguyen 22847a1685fSDinh Nguyen /** 22947a1685fSDinh Nguyen * @ep: USB endpoint to allocate request for. 23047a1685fSDinh Nguyen * @flags: Allocation flags 23147a1685fSDinh Nguyen * 23247a1685fSDinh Nguyen * Allocate a new USB request structure appropriate for the specified endpoint 23347a1685fSDinh Nguyen */ 23447a1685fSDinh Nguyen static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, 23547a1685fSDinh Nguyen gfp_t flags) 23647a1685fSDinh Nguyen { 23747a1685fSDinh Nguyen struct s3c_hsotg_req *req; 23847a1685fSDinh Nguyen 23947a1685fSDinh Nguyen req = kzalloc(sizeof(struct s3c_hsotg_req), flags); 24047a1685fSDinh Nguyen if (!req) 24147a1685fSDinh Nguyen return NULL; 24247a1685fSDinh Nguyen 24347a1685fSDinh Nguyen INIT_LIST_HEAD(&req->queue); 24447a1685fSDinh Nguyen 24547a1685fSDinh Nguyen return &req->req; 24647a1685fSDinh Nguyen } 24747a1685fSDinh Nguyen 24847a1685fSDinh Nguyen /** 24947a1685fSDinh Nguyen * is_ep_periodic - return true if the endpoint is in periodic mode. 25047a1685fSDinh Nguyen * @hs_ep: The endpoint to query. 25147a1685fSDinh Nguyen * 25247a1685fSDinh Nguyen * Returns true if the endpoint is in periodic mode, meaning it is being 25347a1685fSDinh Nguyen * used for an Interrupt or ISO transfer. 25447a1685fSDinh Nguyen */ 25547a1685fSDinh Nguyen static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep) 25647a1685fSDinh Nguyen { 25747a1685fSDinh Nguyen return hs_ep->periodic; 25847a1685fSDinh Nguyen } 25947a1685fSDinh Nguyen 26047a1685fSDinh Nguyen /** 26147a1685fSDinh Nguyen * s3c_hsotg_unmap_dma - unmap the DMA memory being used for the request 26247a1685fSDinh Nguyen * @hsotg: The device state. 26347a1685fSDinh Nguyen * @hs_ep: The endpoint for the request 26447a1685fSDinh Nguyen * @hs_req: The request being processed. 26547a1685fSDinh Nguyen * 26647a1685fSDinh Nguyen * This is the reverse of s3c_hsotg_map_dma(), called for the completion 26747a1685fSDinh Nguyen * of a request to ensure the buffer is ready for access by the caller. 26847a1685fSDinh Nguyen */ 26947a1685fSDinh Nguyen static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, 27047a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep, 27147a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req) 27247a1685fSDinh Nguyen { 27347a1685fSDinh Nguyen struct usb_request *req = &hs_req->req; 27447a1685fSDinh Nguyen 27547a1685fSDinh Nguyen /* ignore this if we're not moving any data */ 27647a1685fSDinh Nguyen if (hs_req->req.length == 0) 27747a1685fSDinh Nguyen return; 27847a1685fSDinh Nguyen 27947a1685fSDinh Nguyen usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); 28047a1685fSDinh Nguyen } 28147a1685fSDinh Nguyen 28247a1685fSDinh Nguyen /** 28347a1685fSDinh Nguyen * s3c_hsotg_write_fifo - write packet Data to the TxFIFO 28447a1685fSDinh Nguyen * @hsotg: The controller state. 28547a1685fSDinh Nguyen * @hs_ep: The endpoint we're going to write for. 28647a1685fSDinh Nguyen * @hs_req: The request to write data for. 28747a1685fSDinh Nguyen * 28847a1685fSDinh Nguyen * This is called when the TxFIFO has some space in it to hold a new 28947a1685fSDinh Nguyen * transmission and we have something to give it. The actual setup of 29047a1685fSDinh Nguyen * the data size is done elsewhere, so all we have to do is to actually 29147a1685fSDinh Nguyen * write the data. 29247a1685fSDinh Nguyen * 29347a1685fSDinh Nguyen * The return value is zero if there is more space (or nothing was done) 29447a1685fSDinh Nguyen * otherwise -ENOSPC is returned if the FIFO space was used up. 29547a1685fSDinh Nguyen * 29647a1685fSDinh Nguyen * This routine is only needed for PIO 29747a1685fSDinh Nguyen */ 29847a1685fSDinh Nguyen static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, 29947a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep, 30047a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req) 30147a1685fSDinh Nguyen { 30247a1685fSDinh Nguyen bool periodic = is_ep_periodic(hs_ep); 30347a1685fSDinh Nguyen u32 gnptxsts = readl(hsotg->regs + GNPTXSTS); 30447a1685fSDinh Nguyen int buf_pos = hs_req->req.actual; 30547a1685fSDinh Nguyen int to_write = hs_ep->size_loaded; 30647a1685fSDinh Nguyen void *data; 30747a1685fSDinh Nguyen int can_write; 30847a1685fSDinh Nguyen int pkt_round; 30947a1685fSDinh Nguyen int max_transfer; 31047a1685fSDinh Nguyen 31147a1685fSDinh Nguyen to_write -= (buf_pos - hs_ep->last_load); 31247a1685fSDinh Nguyen 31347a1685fSDinh Nguyen /* if there's nothing to write, get out early */ 31447a1685fSDinh Nguyen if (to_write == 0) 31547a1685fSDinh Nguyen return 0; 31647a1685fSDinh Nguyen 31747a1685fSDinh Nguyen if (periodic && !hsotg->dedicated_fifos) { 31847a1685fSDinh Nguyen u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); 31947a1685fSDinh Nguyen int size_left; 32047a1685fSDinh Nguyen int size_done; 32147a1685fSDinh Nguyen 32247a1685fSDinh Nguyen /* 32347a1685fSDinh Nguyen * work out how much data was loaded so we can calculate 32447a1685fSDinh Nguyen * how much data is left in the fifo. 32547a1685fSDinh Nguyen */ 32647a1685fSDinh Nguyen 32747a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 32847a1685fSDinh Nguyen 32947a1685fSDinh Nguyen /* 33047a1685fSDinh Nguyen * if shared fifo, we cannot write anything until the 33147a1685fSDinh Nguyen * previous data has been completely sent. 33247a1685fSDinh Nguyen */ 33347a1685fSDinh Nguyen if (hs_ep->fifo_load != 0) { 33447a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 33547a1685fSDinh Nguyen return -ENOSPC; 33647a1685fSDinh Nguyen } 33747a1685fSDinh Nguyen 33847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", 33947a1685fSDinh Nguyen __func__, size_left, 34047a1685fSDinh Nguyen hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); 34147a1685fSDinh Nguyen 34247a1685fSDinh Nguyen /* how much of the data has moved */ 34347a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 34447a1685fSDinh Nguyen 34547a1685fSDinh Nguyen /* how much data is left in the fifo */ 34647a1685fSDinh Nguyen can_write = hs_ep->fifo_load - size_done; 34747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", 34847a1685fSDinh Nguyen __func__, can_write); 34947a1685fSDinh Nguyen 35047a1685fSDinh Nguyen can_write = hs_ep->fifo_size - can_write; 35147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", 35247a1685fSDinh Nguyen __func__, can_write); 35347a1685fSDinh Nguyen 35447a1685fSDinh Nguyen if (can_write <= 0) { 35547a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 35647a1685fSDinh Nguyen return -ENOSPC; 35747a1685fSDinh Nguyen } 35847a1685fSDinh Nguyen } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { 35947a1685fSDinh Nguyen can_write = readl(hsotg->regs + DTXFSTS(hs_ep->index)); 36047a1685fSDinh Nguyen 36147a1685fSDinh Nguyen can_write &= 0xffff; 36247a1685fSDinh Nguyen can_write *= 4; 36347a1685fSDinh Nguyen } else { 36447a1685fSDinh Nguyen if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) { 36547a1685fSDinh Nguyen dev_dbg(hsotg->dev, 36647a1685fSDinh Nguyen "%s: no queue slots available (0x%08x)\n", 36747a1685fSDinh Nguyen __func__, gnptxsts); 36847a1685fSDinh Nguyen 36947a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP); 37047a1685fSDinh Nguyen return -ENOSPC; 37147a1685fSDinh Nguyen } 37247a1685fSDinh Nguyen 37347a1685fSDinh Nguyen can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts); 37447a1685fSDinh Nguyen can_write *= 4; /* fifo size is in 32bit quantities. */ 37547a1685fSDinh Nguyen } 37647a1685fSDinh Nguyen 37747a1685fSDinh Nguyen max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; 37847a1685fSDinh Nguyen 37947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", 38047a1685fSDinh Nguyen __func__, gnptxsts, can_write, to_write, max_transfer); 38147a1685fSDinh Nguyen 38247a1685fSDinh Nguyen /* 38347a1685fSDinh Nguyen * limit to 512 bytes of data, it seems at least on the non-periodic 38447a1685fSDinh Nguyen * FIFO, requests of >512 cause the endpoint to get stuck with a 38547a1685fSDinh Nguyen * fragment of the end of the transfer in it. 38647a1685fSDinh Nguyen */ 38747a1685fSDinh Nguyen if (can_write > 512 && !periodic) 38847a1685fSDinh Nguyen can_write = 512; 38947a1685fSDinh Nguyen 39047a1685fSDinh Nguyen /* 39147a1685fSDinh Nguyen * limit the write to one max-packet size worth of data, but allow 39247a1685fSDinh Nguyen * the transfer to return that it did not run out of fifo space 39347a1685fSDinh Nguyen * doing it. 39447a1685fSDinh Nguyen */ 39547a1685fSDinh Nguyen if (to_write > max_transfer) { 39647a1685fSDinh Nguyen to_write = max_transfer; 39747a1685fSDinh Nguyen 39847a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 39947a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 40047a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, 40147a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 40247a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 40347a1685fSDinh Nguyen } 40447a1685fSDinh Nguyen 40547a1685fSDinh Nguyen /* see if we can write data */ 40647a1685fSDinh Nguyen 40747a1685fSDinh Nguyen if (to_write > can_write) { 40847a1685fSDinh Nguyen to_write = can_write; 40947a1685fSDinh Nguyen pkt_round = to_write % max_transfer; 41047a1685fSDinh Nguyen 41147a1685fSDinh Nguyen /* 41247a1685fSDinh Nguyen * Round the write down to an 41347a1685fSDinh Nguyen * exact number of packets. 41447a1685fSDinh Nguyen * 41547a1685fSDinh Nguyen * Note, we do not currently check to see if we can ever 41647a1685fSDinh Nguyen * write a full packet or not to the FIFO. 41747a1685fSDinh Nguyen */ 41847a1685fSDinh Nguyen 41947a1685fSDinh Nguyen if (pkt_round) 42047a1685fSDinh Nguyen to_write -= pkt_round; 42147a1685fSDinh Nguyen 42247a1685fSDinh Nguyen /* 42347a1685fSDinh Nguyen * enable correct FIFO interrupt to alert us when there 42447a1685fSDinh Nguyen * is more room left. 42547a1685fSDinh Nguyen */ 42647a1685fSDinh Nguyen 42747a1685fSDinh Nguyen /* it's needed only when we do not use dedicated fifos */ 42847a1685fSDinh Nguyen if (!hsotg->dedicated_fifos) 42947a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, 43047a1685fSDinh Nguyen periodic ? GINTSTS_PTXFEMP : 43147a1685fSDinh Nguyen GINTSTS_NPTXFEMP); 43247a1685fSDinh Nguyen } 43347a1685fSDinh Nguyen 43447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", 43547a1685fSDinh Nguyen to_write, hs_req->req.length, can_write, buf_pos); 43647a1685fSDinh Nguyen 43747a1685fSDinh Nguyen if (to_write <= 0) 43847a1685fSDinh Nguyen return -ENOSPC; 43947a1685fSDinh Nguyen 44047a1685fSDinh Nguyen hs_req->req.actual = buf_pos + to_write; 44147a1685fSDinh Nguyen hs_ep->total_data += to_write; 44247a1685fSDinh Nguyen 44347a1685fSDinh Nguyen if (periodic) 44447a1685fSDinh Nguyen hs_ep->fifo_load += to_write; 44547a1685fSDinh Nguyen 44647a1685fSDinh Nguyen to_write = DIV_ROUND_UP(to_write, 4); 44747a1685fSDinh Nguyen data = hs_req->req.buf + buf_pos; 44847a1685fSDinh Nguyen 44947a1685fSDinh Nguyen iowrite32_rep(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); 45047a1685fSDinh Nguyen 45147a1685fSDinh Nguyen return (to_write >= can_write) ? -ENOSPC : 0; 45247a1685fSDinh Nguyen } 45347a1685fSDinh Nguyen 45447a1685fSDinh Nguyen /** 45547a1685fSDinh Nguyen * get_ep_limit - get the maximum data legnth for this endpoint 45647a1685fSDinh Nguyen * @hs_ep: The endpoint 45747a1685fSDinh Nguyen * 45847a1685fSDinh Nguyen * Return the maximum data that can be queued in one go on a given endpoint 45947a1685fSDinh Nguyen * so that transfers that are too long can be split. 46047a1685fSDinh Nguyen */ 46147a1685fSDinh Nguyen static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) 46247a1685fSDinh Nguyen { 46347a1685fSDinh Nguyen int index = hs_ep->index; 46447a1685fSDinh Nguyen unsigned maxsize; 46547a1685fSDinh Nguyen unsigned maxpkt; 46647a1685fSDinh Nguyen 46747a1685fSDinh Nguyen if (index != 0) { 46847a1685fSDinh Nguyen maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; 46947a1685fSDinh Nguyen maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; 47047a1685fSDinh Nguyen } else { 47147a1685fSDinh Nguyen maxsize = 64+64; 47247a1685fSDinh Nguyen if (hs_ep->dir_in) 47347a1685fSDinh Nguyen maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; 47447a1685fSDinh Nguyen else 47547a1685fSDinh Nguyen maxpkt = 2; 47647a1685fSDinh Nguyen } 47747a1685fSDinh Nguyen 47847a1685fSDinh Nguyen /* we made the constant loading easier above by using +1 */ 47947a1685fSDinh Nguyen maxpkt--; 48047a1685fSDinh Nguyen maxsize--; 48147a1685fSDinh Nguyen 48247a1685fSDinh Nguyen /* 48347a1685fSDinh Nguyen * constrain by packet count if maxpkts*pktsize is greater 48447a1685fSDinh Nguyen * than the length register size. 48547a1685fSDinh Nguyen */ 48647a1685fSDinh Nguyen 48747a1685fSDinh Nguyen if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) 48847a1685fSDinh Nguyen maxsize = maxpkt * hs_ep->ep.maxpacket; 48947a1685fSDinh Nguyen 49047a1685fSDinh Nguyen return maxsize; 49147a1685fSDinh Nguyen } 49247a1685fSDinh Nguyen 49347a1685fSDinh Nguyen /** 49447a1685fSDinh Nguyen * s3c_hsotg_start_req - start a USB request from an endpoint's queue 49547a1685fSDinh Nguyen * @hsotg: The controller state. 49647a1685fSDinh Nguyen * @hs_ep: The endpoint to process a request for 49747a1685fSDinh Nguyen * @hs_req: The request to start. 49847a1685fSDinh Nguyen * @continuing: True if we are doing more for the current request. 49947a1685fSDinh Nguyen * 50047a1685fSDinh Nguyen * Start the given request running by setting the endpoint registers 50147a1685fSDinh Nguyen * appropriately, and writing any data to the FIFOs. 50247a1685fSDinh Nguyen */ 50347a1685fSDinh Nguyen static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, 50447a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep, 50547a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req, 50647a1685fSDinh Nguyen bool continuing) 50747a1685fSDinh Nguyen { 50847a1685fSDinh Nguyen struct usb_request *ureq = &hs_req->req; 50947a1685fSDinh Nguyen int index = hs_ep->index; 51047a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 51147a1685fSDinh Nguyen u32 epctrl_reg; 51247a1685fSDinh Nguyen u32 epsize_reg; 51347a1685fSDinh Nguyen u32 epsize; 51447a1685fSDinh Nguyen u32 ctrl; 51547a1685fSDinh Nguyen unsigned length; 51647a1685fSDinh Nguyen unsigned packets; 51747a1685fSDinh Nguyen unsigned maxreq; 51847a1685fSDinh Nguyen 51947a1685fSDinh Nguyen if (index != 0) { 52047a1685fSDinh Nguyen if (hs_ep->req && !continuing) { 52147a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: active request\n", __func__); 52247a1685fSDinh Nguyen WARN_ON(1); 52347a1685fSDinh Nguyen return; 52447a1685fSDinh Nguyen } else if (hs_ep->req != hs_req && continuing) { 52547a1685fSDinh Nguyen dev_err(hsotg->dev, 52647a1685fSDinh Nguyen "%s: continue different req\n", __func__); 52747a1685fSDinh Nguyen WARN_ON(1); 52847a1685fSDinh Nguyen return; 52947a1685fSDinh Nguyen } 53047a1685fSDinh Nguyen } 53147a1685fSDinh Nguyen 53247a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 53347a1685fSDinh Nguyen epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 53447a1685fSDinh Nguyen 53547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", 53647a1685fSDinh Nguyen __func__, readl(hsotg->regs + epctrl_reg), index, 53747a1685fSDinh Nguyen hs_ep->dir_in ? "in" : "out"); 53847a1685fSDinh Nguyen 53947a1685fSDinh Nguyen /* If endpoint is stalled, we will restart request later */ 54047a1685fSDinh Nguyen ctrl = readl(hsotg->regs + epctrl_reg); 54147a1685fSDinh Nguyen 54247a1685fSDinh Nguyen if (ctrl & DXEPCTL_STALL) { 54347a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); 54447a1685fSDinh Nguyen return; 54547a1685fSDinh Nguyen } 54647a1685fSDinh Nguyen 54747a1685fSDinh Nguyen length = ureq->length - ureq->actual; 54847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", 54947a1685fSDinh Nguyen ureq->length, ureq->actual); 55047a1685fSDinh Nguyen if (0) 55147a1685fSDinh Nguyen dev_dbg(hsotg->dev, 5520cc4cf6fSFabio Estevam "REQ buf %p len %d dma %pad noi=%d zp=%d snok=%d\n", 55347a1685fSDinh Nguyen ureq->buf, length, &ureq->dma, 55447a1685fSDinh Nguyen ureq->no_interrupt, ureq->zero, ureq->short_not_ok); 55547a1685fSDinh Nguyen 55647a1685fSDinh Nguyen maxreq = get_ep_limit(hs_ep); 55747a1685fSDinh Nguyen if (length > maxreq) { 55847a1685fSDinh Nguyen int round = maxreq % hs_ep->ep.maxpacket; 55947a1685fSDinh Nguyen 56047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", 56147a1685fSDinh Nguyen __func__, length, maxreq, round); 56247a1685fSDinh Nguyen 56347a1685fSDinh Nguyen /* round down to multiple of packets */ 56447a1685fSDinh Nguyen if (round) 56547a1685fSDinh Nguyen maxreq -= round; 56647a1685fSDinh Nguyen 56747a1685fSDinh Nguyen length = maxreq; 56847a1685fSDinh Nguyen } 56947a1685fSDinh Nguyen 57047a1685fSDinh Nguyen if (length) 57147a1685fSDinh Nguyen packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); 57247a1685fSDinh Nguyen else 57347a1685fSDinh Nguyen packets = 1; /* send one packet if length is zero. */ 57447a1685fSDinh Nguyen 57547a1685fSDinh Nguyen if (hs_ep->isochronous && length > (hs_ep->mc * hs_ep->ep.maxpacket)) { 57647a1685fSDinh Nguyen dev_err(hsotg->dev, "req length > maxpacket*mc\n"); 57747a1685fSDinh Nguyen return; 57847a1685fSDinh Nguyen } 57947a1685fSDinh Nguyen 58047a1685fSDinh Nguyen if (dir_in && index != 0) 58147a1685fSDinh Nguyen if (hs_ep->isochronous) 58247a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(packets); 58347a1685fSDinh Nguyen else 58447a1685fSDinh Nguyen epsize = DXEPTSIZ_MC(1); 58547a1685fSDinh Nguyen else 58647a1685fSDinh Nguyen epsize = 0; 58747a1685fSDinh Nguyen 58847a1685fSDinh Nguyen if (index != 0 && ureq->zero) { 58947a1685fSDinh Nguyen /* 59047a1685fSDinh Nguyen * test for the packets being exactly right for the 59147a1685fSDinh Nguyen * transfer 59247a1685fSDinh Nguyen */ 59347a1685fSDinh Nguyen 59447a1685fSDinh Nguyen if (length == (packets * hs_ep->ep.maxpacket)) 59547a1685fSDinh Nguyen packets++; 59647a1685fSDinh Nguyen } 59747a1685fSDinh Nguyen 59847a1685fSDinh Nguyen epsize |= DXEPTSIZ_PKTCNT(packets); 59947a1685fSDinh Nguyen epsize |= DXEPTSIZ_XFERSIZE(length); 60047a1685fSDinh Nguyen 60147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", 60247a1685fSDinh Nguyen __func__, packets, length, ureq->length, epsize, epsize_reg); 60347a1685fSDinh Nguyen 60447a1685fSDinh Nguyen /* store the request as the current one we're doing */ 60547a1685fSDinh Nguyen hs_ep->req = hs_req; 60647a1685fSDinh Nguyen 60747a1685fSDinh Nguyen /* write size / packets */ 60847a1685fSDinh Nguyen writel(epsize, hsotg->regs + epsize_reg); 60947a1685fSDinh Nguyen 61047a1685fSDinh Nguyen if (using_dma(hsotg) && !continuing) { 61147a1685fSDinh Nguyen unsigned int dma_reg; 61247a1685fSDinh Nguyen 61347a1685fSDinh Nguyen /* 61447a1685fSDinh Nguyen * write DMA address to control register, buffer already 61547a1685fSDinh Nguyen * synced by s3c_hsotg_ep_queue(). 61647a1685fSDinh Nguyen */ 61747a1685fSDinh Nguyen 61847a1685fSDinh Nguyen dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); 61947a1685fSDinh Nguyen writel(ureq->dma, hsotg->regs + dma_reg); 62047a1685fSDinh Nguyen 6210cc4cf6fSFabio Estevam dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n", 62247a1685fSDinh Nguyen __func__, &ureq->dma, dma_reg); 62347a1685fSDinh Nguyen } 62447a1685fSDinh Nguyen 62547a1685fSDinh Nguyen ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 62647a1685fSDinh Nguyen ctrl |= DXEPCTL_USBACTEP; 62747a1685fSDinh Nguyen 62847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup); 62947a1685fSDinh Nguyen 63047a1685fSDinh Nguyen /* For Setup request do not clear NAK */ 63147a1685fSDinh Nguyen if (hsotg->setup && index == 0) 63247a1685fSDinh Nguyen hsotg->setup = 0; 63347a1685fSDinh Nguyen else 63447a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 63547a1685fSDinh Nguyen 63647a1685fSDinh Nguyen 63747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 63847a1685fSDinh Nguyen writel(ctrl, hsotg->regs + epctrl_reg); 63947a1685fSDinh Nguyen 64047a1685fSDinh Nguyen /* 64147a1685fSDinh Nguyen * set these, it seems that DMA support increments past the end 64247a1685fSDinh Nguyen * of the packet buffer so we need to calculate the length from 64347a1685fSDinh Nguyen * this information. 64447a1685fSDinh Nguyen */ 64547a1685fSDinh Nguyen hs_ep->size_loaded = length; 64647a1685fSDinh Nguyen hs_ep->last_load = ureq->actual; 64747a1685fSDinh Nguyen 64847a1685fSDinh Nguyen if (dir_in && !using_dma(hsotg)) { 64947a1685fSDinh Nguyen /* set these anyway, we may need them for non-periodic in */ 65047a1685fSDinh Nguyen hs_ep->fifo_load = 0; 65147a1685fSDinh Nguyen 65247a1685fSDinh Nguyen s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req); 65347a1685fSDinh Nguyen } 65447a1685fSDinh Nguyen 65547a1685fSDinh Nguyen /* 65647a1685fSDinh Nguyen * clear the INTknTXFEmpMsk when we start request, more as a aide 65747a1685fSDinh Nguyen * to debugging to see what is going on. 65847a1685fSDinh Nguyen */ 65947a1685fSDinh Nguyen if (dir_in) 66047a1685fSDinh Nguyen writel(DIEPMSK_INTKNTXFEMPMSK, 66147a1685fSDinh Nguyen hsotg->regs + DIEPINT(index)); 66247a1685fSDinh Nguyen 66347a1685fSDinh Nguyen /* 66447a1685fSDinh Nguyen * Note, trying to clear the NAK here causes problems with transmit 66547a1685fSDinh Nguyen * on the S3C6400 ending up with the TXFIFO becoming full. 66647a1685fSDinh Nguyen */ 66747a1685fSDinh Nguyen 66847a1685fSDinh Nguyen /* check ep is enabled */ 66947a1685fSDinh Nguyen if (!(readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA)) 67047a1685fSDinh Nguyen dev_warn(hsotg->dev, 67147a1685fSDinh Nguyen "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", 67247a1685fSDinh Nguyen index, readl(hsotg->regs + epctrl_reg)); 67347a1685fSDinh Nguyen 67447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n", 67547a1685fSDinh Nguyen __func__, readl(hsotg->regs + epctrl_reg)); 67647a1685fSDinh Nguyen 67747a1685fSDinh Nguyen /* enable ep interrupts */ 67847a1685fSDinh Nguyen s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1); 67947a1685fSDinh Nguyen } 68047a1685fSDinh Nguyen 68147a1685fSDinh Nguyen /** 68247a1685fSDinh Nguyen * s3c_hsotg_map_dma - map the DMA memory being used for the request 68347a1685fSDinh Nguyen * @hsotg: The device state. 68447a1685fSDinh Nguyen * @hs_ep: The endpoint the request is on. 68547a1685fSDinh Nguyen * @req: The request being processed. 68647a1685fSDinh Nguyen * 68747a1685fSDinh Nguyen * We've been asked to queue a request, so ensure that the memory buffer 68847a1685fSDinh Nguyen * is correctly setup for DMA. If we've been passed an extant DMA address 68947a1685fSDinh Nguyen * then ensure the buffer has been synced to memory. If our buffer has no 69047a1685fSDinh Nguyen * DMA memory, then we map the memory and mark our request to allow us to 69147a1685fSDinh Nguyen * cleanup on completion. 69247a1685fSDinh Nguyen */ 69347a1685fSDinh Nguyen static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg, 69447a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep, 69547a1685fSDinh Nguyen struct usb_request *req) 69647a1685fSDinh Nguyen { 69747a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = our_req(req); 69847a1685fSDinh Nguyen int ret; 69947a1685fSDinh Nguyen 70047a1685fSDinh Nguyen /* if the length is zero, ignore the DMA data */ 70147a1685fSDinh Nguyen if (hs_req->req.length == 0) 70247a1685fSDinh Nguyen return 0; 70347a1685fSDinh Nguyen 70447a1685fSDinh Nguyen ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in); 70547a1685fSDinh Nguyen if (ret) 70647a1685fSDinh Nguyen goto dma_error; 70747a1685fSDinh Nguyen 70847a1685fSDinh Nguyen return 0; 70947a1685fSDinh Nguyen 71047a1685fSDinh Nguyen dma_error: 71147a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n", 71247a1685fSDinh Nguyen __func__, req->buf, req->length); 71347a1685fSDinh Nguyen 71447a1685fSDinh Nguyen return -EIO; 71547a1685fSDinh Nguyen } 71647a1685fSDinh Nguyen 71747a1685fSDinh Nguyen static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, 71847a1685fSDinh Nguyen gfp_t gfp_flags) 71947a1685fSDinh Nguyen { 72047a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = our_req(req); 72147a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 72247a1685fSDinh Nguyen struct s3c_hsotg *hs = hs_ep->parent; 72347a1685fSDinh Nguyen bool first; 72447a1685fSDinh Nguyen 72547a1685fSDinh Nguyen dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", 72647a1685fSDinh Nguyen ep->name, req, req->length, req->buf, req->no_interrupt, 72747a1685fSDinh Nguyen req->zero, req->short_not_ok); 72847a1685fSDinh Nguyen 72947a1685fSDinh Nguyen /* initialise status of the request */ 73047a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_req->queue); 73147a1685fSDinh Nguyen req->actual = 0; 73247a1685fSDinh Nguyen req->status = -EINPROGRESS; 73347a1685fSDinh Nguyen 73447a1685fSDinh Nguyen /* if we're using DMA, sync the buffers as necessary */ 73547a1685fSDinh Nguyen if (using_dma(hs)) { 73647a1685fSDinh Nguyen int ret = s3c_hsotg_map_dma(hs, hs_ep, req); 73747a1685fSDinh Nguyen if (ret) 73847a1685fSDinh Nguyen return ret; 73947a1685fSDinh Nguyen } 74047a1685fSDinh Nguyen 74147a1685fSDinh Nguyen first = list_empty(&hs_ep->queue); 74247a1685fSDinh Nguyen list_add_tail(&hs_req->queue, &hs_ep->queue); 74347a1685fSDinh Nguyen 74447a1685fSDinh Nguyen if (first) 74547a1685fSDinh Nguyen s3c_hsotg_start_req(hs, hs_ep, hs_req, false); 74647a1685fSDinh Nguyen 74747a1685fSDinh Nguyen return 0; 74847a1685fSDinh Nguyen } 74947a1685fSDinh Nguyen 75047a1685fSDinh Nguyen static int s3c_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, 75147a1685fSDinh Nguyen gfp_t gfp_flags) 75247a1685fSDinh Nguyen { 75347a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 75447a1685fSDinh Nguyen struct s3c_hsotg *hs = hs_ep->parent; 75547a1685fSDinh Nguyen unsigned long flags = 0; 75647a1685fSDinh Nguyen int ret = 0; 75747a1685fSDinh Nguyen 75847a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 75947a1685fSDinh Nguyen ret = s3c_hsotg_ep_queue(ep, req, gfp_flags); 76047a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 76147a1685fSDinh Nguyen 76247a1685fSDinh Nguyen return ret; 76347a1685fSDinh Nguyen } 76447a1685fSDinh Nguyen 76547a1685fSDinh Nguyen static void s3c_hsotg_ep_free_request(struct usb_ep *ep, 76647a1685fSDinh Nguyen struct usb_request *req) 76747a1685fSDinh Nguyen { 76847a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = our_req(req); 76947a1685fSDinh Nguyen 77047a1685fSDinh Nguyen kfree(hs_req); 77147a1685fSDinh Nguyen } 77247a1685fSDinh Nguyen 77347a1685fSDinh Nguyen /** 77447a1685fSDinh Nguyen * s3c_hsotg_complete_oursetup - setup completion callback 77547a1685fSDinh Nguyen * @ep: The endpoint the request was on. 77647a1685fSDinh Nguyen * @req: The request completed. 77747a1685fSDinh Nguyen * 77847a1685fSDinh Nguyen * Called on completion of any requests the driver itself 77947a1685fSDinh Nguyen * submitted that need cleaning up. 78047a1685fSDinh Nguyen */ 78147a1685fSDinh Nguyen static void s3c_hsotg_complete_oursetup(struct usb_ep *ep, 78247a1685fSDinh Nguyen struct usb_request *req) 78347a1685fSDinh Nguyen { 78447a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 78547a1685fSDinh Nguyen struct s3c_hsotg *hsotg = hs_ep->parent; 78647a1685fSDinh Nguyen 78747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); 78847a1685fSDinh Nguyen 78947a1685fSDinh Nguyen s3c_hsotg_ep_free_request(ep, req); 79047a1685fSDinh Nguyen } 79147a1685fSDinh Nguyen 79247a1685fSDinh Nguyen /** 79347a1685fSDinh Nguyen * ep_from_windex - convert control wIndex value to endpoint 79447a1685fSDinh Nguyen * @hsotg: The driver state. 79547a1685fSDinh Nguyen * @windex: The control request wIndex field (in host order). 79647a1685fSDinh Nguyen * 79747a1685fSDinh Nguyen * Convert the given wIndex into a pointer to an driver endpoint 79847a1685fSDinh Nguyen * structure, or return NULL if it is not a valid endpoint. 79947a1685fSDinh Nguyen */ 80047a1685fSDinh Nguyen static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg, 80147a1685fSDinh Nguyen u32 windex) 80247a1685fSDinh Nguyen { 80347a1685fSDinh Nguyen struct s3c_hsotg_ep *ep = &hsotg->eps[windex & 0x7F]; 80447a1685fSDinh Nguyen int dir = (windex & USB_DIR_IN) ? 1 : 0; 80547a1685fSDinh Nguyen int idx = windex & 0x7F; 80647a1685fSDinh Nguyen 80747a1685fSDinh Nguyen if (windex >= 0x100) 80847a1685fSDinh Nguyen return NULL; 80947a1685fSDinh Nguyen 81047a1685fSDinh Nguyen if (idx > hsotg->num_of_eps) 81147a1685fSDinh Nguyen return NULL; 81247a1685fSDinh Nguyen 81347a1685fSDinh Nguyen if (idx && ep->dir_in != dir) 81447a1685fSDinh Nguyen return NULL; 81547a1685fSDinh Nguyen 81647a1685fSDinh Nguyen return ep; 81747a1685fSDinh Nguyen } 81847a1685fSDinh Nguyen 81947a1685fSDinh Nguyen /** 82047a1685fSDinh Nguyen * s3c_hsotg_send_reply - send reply to control request 82147a1685fSDinh Nguyen * @hsotg: The device state 82247a1685fSDinh Nguyen * @ep: Endpoint 0 82347a1685fSDinh Nguyen * @buff: Buffer for request 82447a1685fSDinh Nguyen * @length: Length of reply. 82547a1685fSDinh Nguyen * 82647a1685fSDinh Nguyen * Create a request and queue it on the given endpoint. This is useful as 82747a1685fSDinh Nguyen * an internal method of sending replies to certain control requests, etc. 82847a1685fSDinh Nguyen */ 82947a1685fSDinh Nguyen static int s3c_hsotg_send_reply(struct s3c_hsotg *hsotg, 83047a1685fSDinh Nguyen struct s3c_hsotg_ep *ep, 83147a1685fSDinh Nguyen void *buff, 83247a1685fSDinh Nguyen int length) 83347a1685fSDinh Nguyen { 83447a1685fSDinh Nguyen struct usb_request *req; 83547a1685fSDinh Nguyen int ret; 83647a1685fSDinh Nguyen 83747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length); 83847a1685fSDinh Nguyen 83947a1685fSDinh Nguyen req = s3c_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC); 84047a1685fSDinh Nguyen hsotg->ep0_reply = req; 84147a1685fSDinh Nguyen if (!req) { 84247a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__); 84347a1685fSDinh Nguyen return -ENOMEM; 84447a1685fSDinh Nguyen } 84547a1685fSDinh Nguyen 84647a1685fSDinh Nguyen req->buf = hsotg->ep0_buff; 84747a1685fSDinh Nguyen req->length = length; 84847a1685fSDinh Nguyen req->zero = 1; /* always do zero-length final transfer */ 84947a1685fSDinh Nguyen req->complete = s3c_hsotg_complete_oursetup; 85047a1685fSDinh Nguyen 85147a1685fSDinh Nguyen if (length) 85247a1685fSDinh Nguyen memcpy(req->buf, buff, length); 85347a1685fSDinh Nguyen else 85447a1685fSDinh Nguyen ep->sent_zlp = 1; 85547a1685fSDinh Nguyen 85647a1685fSDinh Nguyen ret = s3c_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC); 85747a1685fSDinh Nguyen if (ret) { 85847a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__); 85947a1685fSDinh Nguyen return ret; 86047a1685fSDinh Nguyen } 86147a1685fSDinh Nguyen 86247a1685fSDinh Nguyen return 0; 86347a1685fSDinh Nguyen } 86447a1685fSDinh Nguyen 86547a1685fSDinh Nguyen /** 86647a1685fSDinh Nguyen * s3c_hsotg_process_req_status - process request GET_STATUS 86747a1685fSDinh Nguyen * @hsotg: The device state 86847a1685fSDinh Nguyen * @ctrl: USB control request 86947a1685fSDinh Nguyen */ 87047a1685fSDinh Nguyen static int s3c_hsotg_process_req_status(struct s3c_hsotg *hsotg, 87147a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 87247a1685fSDinh Nguyen { 87347a1685fSDinh Nguyen struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; 87447a1685fSDinh Nguyen struct s3c_hsotg_ep *ep; 87547a1685fSDinh Nguyen __le16 reply; 87647a1685fSDinh Nguyen int ret; 87747a1685fSDinh Nguyen 87847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); 87947a1685fSDinh Nguyen 88047a1685fSDinh Nguyen if (!ep0->dir_in) { 88147a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: direction out?\n", __func__); 88247a1685fSDinh Nguyen return -EINVAL; 88347a1685fSDinh Nguyen } 88447a1685fSDinh Nguyen 88547a1685fSDinh Nguyen switch (ctrl->bRequestType & USB_RECIP_MASK) { 88647a1685fSDinh Nguyen case USB_RECIP_DEVICE: 88747a1685fSDinh Nguyen reply = cpu_to_le16(0); /* bit 0 => self powered, 88847a1685fSDinh Nguyen * bit 1 => remote wakeup */ 88947a1685fSDinh Nguyen break; 89047a1685fSDinh Nguyen 89147a1685fSDinh Nguyen case USB_RECIP_INTERFACE: 89247a1685fSDinh Nguyen /* currently, the data result should be zero */ 89347a1685fSDinh Nguyen reply = cpu_to_le16(0); 89447a1685fSDinh Nguyen break; 89547a1685fSDinh Nguyen 89647a1685fSDinh Nguyen case USB_RECIP_ENDPOINT: 89747a1685fSDinh Nguyen ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); 89847a1685fSDinh Nguyen if (!ep) 89947a1685fSDinh Nguyen return -ENOENT; 90047a1685fSDinh Nguyen 90147a1685fSDinh Nguyen reply = cpu_to_le16(ep->halted ? 1 : 0); 90247a1685fSDinh Nguyen break; 90347a1685fSDinh Nguyen 90447a1685fSDinh Nguyen default: 90547a1685fSDinh Nguyen return 0; 90647a1685fSDinh Nguyen } 90747a1685fSDinh Nguyen 90847a1685fSDinh Nguyen if (le16_to_cpu(ctrl->wLength) != 2) 90947a1685fSDinh Nguyen return -EINVAL; 91047a1685fSDinh Nguyen 91147a1685fSDinh Nguyen ret = s3c_hsotg_send_reply(hsotg, ep0, &reply, 2); 91247a1685fSDinh Nguyen if (ret) { 91347a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to send reply\n", __func__); 91447a1685fSDinh Nguyen return ret; 91547a1685fSDinh Nguyen } 91647a1685fSDinh Nguyen 91747a1685fSDinh Nguyen return 1; 91847a1685fSDinh Nguyen } 91947a1685fSDinh Nguyen 92047a1685fSDinh Nguyen static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value); 92147a1685fSDinh Nguyen 92247a1685fSDinh Nguyen /** 92347a1685fSDinh Nguyen * get_ep_head - return the first request on the endpoint 92447a1685fSDinh Nguyen * @hs_ep: The controller endpoint to get 92547a1685fSDinh Nguyen * 92647a1685fSDinh Nguyen * Get the first request on the endpoint. 92747a1685fSDinh Nguyen */ 92847a1685fSDinh Nguyen static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep) 92947a1685fSDinh Nguyen { 93047a1685fSDinh Nguyen if (list_empty(&hs_ep->queue)) 93147a1685fSDinh Nguyen return NULL; 93247a1685fSDinh Nguyen 93347a1685fSDinh Nguyen return list_first_entry(&hs_ep->queue, struct s3c_hsotg_req, queue); 93447a1685fSDinh Nguyen } 93547a1685fSDinh Nguyen 93647a1685fSDinh Nguyen /** 93747a1685fSDinh Nguyen * s3c_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE 93847a1685fSDinh Nguyen * @hsotg: The device state 93947a1685fSDinh Nguyen * @ctrl: USB control request 94047a1685fSDinh Nguyen */ 94147a1685fSDinh Nguyen static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, 94247a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 94347a1685fSDinh Nguyen { 94447a1685fSDinh Nguyen struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; 94547a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req; 94647a1685fSDinh Nguyen bool restart; 94747a1685fSDinh Nguyen bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); 94847a1685fSDinh Nguyen struct s3c_hsotg_ep *ep; 94947a1685fSDinh Nguyen int ret; 95047a1685fSDinh Nguyen bool halted; 95147a1685fSDinh Nguyen 95247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", 95347a1685fSDinh Nguyen __func__, set ? "SET" : "CLEAR"); 95447a1685fSDinh Nguyen 95547a1685fSDinh Nguyen if (ctrl->bRequestType == USB_RECIP_ENDPOINT) { 95647a1685fSDinh Nguyen ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); 95747a1685fSDinh Nguyen if (!ep) { 95847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", 95947a1685fSDinh Nguyen __func__, le16_to_cpu(ctrl->wIndex)); 96047a1685fSDinh Nguyen return -ENOENT; 96147a1685fSDinh Nguyen } 96247a1685fSDinh Nguyen 96347a1685fSDinh Nguyen switch (le16_to_cpu(ctrl->wValue)) { 96447a1685fSDinh Nguyen case USB_ENDPOINT_HALT: 96547a1685fSDinh Nguyen halted = ep->halted; 96647a1685fSDinh Nguyen 96747a1685fSDinh Nguyen s3c_hsotg_ep_sethalt(&ep->ep, set); 96847a1685fSDinh Nguyen 96947a1685fSDinh Nguyen ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0); 97047a1685fSDinh Nguyen if (ret) { 97147a1685fSDinh Nguyen dev_err(hsotg->dev, 97247a1685fSDinh Nguyen "%s: failed to send reply\n", __func__); 97347a1685fSDinh Nguyen return ret; 97447a1685fSDinh Nguyen } 97547a1685fSDinh Nguyen 97647a1685fSDinh Nguyen /* 97747a1685fSDinh Nguyen * we have to complete all requests for ep if it was 97847a1685fSDinh Nguyen * halted, and the halt was cleared by CLEAR_FEATURE 97947a1685fSDinh Nguyen */ 98047a1685fSDinh Nguyen 98147a1685fSDinh Nguyen if (!set && halted) { 98247a1685fSDinh Nguyen /* 98347a1685fSDinh Nguyen * If we have request in progress, 98447a1685fSDinh Nguyen * then complete it 98547a1685fSDinh Nguyen */ 98647a1685fSDinh Nguyen if (ep->req) { 98747a1685fSDinh Nguyen hs_req = ep->req; 98847a1685fSDinh Nguyen ep->req = NULL; 98947a1685fSDinh Nguyen list_del_init(&hs_req->queue); 99047a1685fSDinh Nguyen hs_req->req.complete(&ep->ep, 99147a1685fSDinh Nguyen &hs_req->req); 99247a1685fSDinh Nguyen } 99347a1685fSDinh Nguyen 99447a1685fSDinh Nguyen /* If we have pending request, then start it */ 99547a1685fSDinh Nguyen restart = !list_empty(&ep->queue); 99647a1685fSDinh Nguyen if (restart) { 99747a1685fSDinh Nguyen hs_req = get_ep_head(ep); 99847a1685fSDinh Nguyen s3c_hsotg_start_req(hsotg, ep, 99947a1685fSDinh Nguyen hs_req, false); 100047a1685fSDinh Nguyen } 100147a1685fSDinh Nguyen } 100247a1685fSDinh Nguyen 100347a1685fSDinh Nguyen break; 100447a1685fSDinh Nguyen 100547a1685fSDinh Nguyen default: 100647a1685fSDinh Nguyen return -ENOENT; 100747a1685fSDinh Nguyen } 100847a1685fSDinh Nguyen } else 100947a1685fSDinh Nguyen return -ENOENT; /* currently only deal with endpoint */ 101047a1685fSDinh Nguyen 101147a1685fSDinh Nguyen return 1; 101247a1685fSDinh Nguyen } 101347a1685fSDinh Nguyen 101447a1685fSDinh Nguyen static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg); 101547a1685fSDinh Nguyen static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg); 101647a1685fSDinh Nguyen 101747a1685fSDinh Nguyen /** 101847a1685fSDinh Nguyen * s3c_hsotg_stall_ep0 - stall ep0 101947a1685fSDinh Nguyen * @hsotg: The device state 102047a1685fSDinh Nguyen * 102147a1685fSDinh Nguyen * Set stall for ep0 as response for setup request. 102247a1685fSDinh Nguyen */ 1023e9ebe7c3SJingoo Han static void s3c_hsotg_stall_ep0(struct s3c_hsotg *hsotg) 1024e9ebe7c3SJingoo Han { 102547a1685fSDinh Nguyen struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; 102647a1685fSDinh Nguyen u32 reg; 102747a1685fSDinh Nguyen u32 ctrl; 102847a1685fSDinh Nguyen 102947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); 103047a1685fSDinh Nguyen reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; 103147a1685fSDinh Nguyen 103247a1685fSDinh Nguyen /* 103347a1685fSDinh Nguyen * DxEPCTL_Stall will be cleared by EP once it has 103447a1685fSDinh Nguyen * taken effect, so no need to clear later. 103547a1685fSDinh Nguyen */ 103647a1685fSDinh Nguyen 103747a1685fSDinh Nguyen ctrl = readl(hsotg->regs + reg); 103847a1685fSDinh Nguyen ctrl |= DXEPCTL_STALL; 103947a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; 104047a1685fSDinh Nguyen writel(ctrl, hsotg->regs + reg); 104147a1685fSDinh Nguyen 104247a1685fSDinh Nguyen dev_dbg(hsotg->dev, 104347a1685fSDinh Nguyen "written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n", 104447a1685fSDinh Nguyen ctrl, reg, readl(hsotg->regs + reg)); 104547a1685fSDinh Nguyen 104647a1685fSDinh Nguyen /* 104747a1685fSDinh Nguyen * complete won't be called, so we enqueue 104847a1685fSDinh Nguyen * setup request here 104947a1685fSDinh Nguyen */ 105047a1685fSDinh Nguyen s3c_hsotg_enqueue_setup(hsotg); 105147a1685fSDinh Nguyen } 105247a1685fSDinh Nguyen 105347a1685fSDinh Nguyen /** 105447a1685fSDinh Nguyen * s3c_hsotg_process_control - process a control request 105547a1685fSDinh Nguyen * @hsotg: The device state 105647a1685fSDinh Nguyen * @ctrl: The control request received 105747a1685fSDinh Nguyen * 105847a1685fSDinh Nguyen * The controller has received the SETUP phase of a control request, and 105947a1685fSDinh Nguyen * needs to work out what to do next (and whether to pass it on to the 106047a1685fSDinh Nguyen * gadget driver). 106147a1685fSDinh Nguyen */ 106247a1685fSDinh Nguyen static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, 106347a1685fSDinh Nguyen struct usb_ctrlrequest *ctrl) 106447a1685fSDinh Nguyen { 106547a1685fSDinh Nguyen struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; 106647a1685fSDinh Nguyen int ret = 0; 106747a1685fSDinh Nguyen u32 dcfg; 106847a1685fSDinh Nguyen 106947a1685fSDinh Nguyen ep0->sent_zlp = 0; 107047a1685fSDinh Nguyen 107147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ctrl Req=%02x, Type=%02x, V=%04x, L=%04x\n", 107247a1685fSDinh Nguyen ctrl->bRequest, ctrl->bRequestType, 107347a1685fSDinh Nguyen ctrl->wValue, ctrl->wLength); 107447a1685fSDinh Nguyen 107547a1685fSDinh Nguyen /* 107647a1685fSDinh Nguyen * record the direction of the request, for later use when enquing 107747a1685fSDinh Nguyen * packets onto EP0. 107847a1685fSDinh Nguyen */ 107947a1685fSDinh Nguyen 108047a1685fSDinh Nguyen ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0; 108147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in); 108247a1685fSDinh Nguyen 108347a1685fSDinh Nguyen /* 108447a1685fSDinh Nguyen * if we've no data with this request, then the last part of the 108547a1685fSDinh Nguyen * transaction is going to implicitly be IN. 108647a1685fSDinh Nguyen */ 108747a1685fSDinh Nguyen if (ctrl->wLength == 0) 108847a1685fSDinh Nguyen ep0->dir_in = 1; 108947a1685fSDinh Nguyen 109047a1685fSDinh Nguyen if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 109147a1685fSDinh Nguyen switch (ctrl->bRequest) { 109247a1685fSDinh Nguyen case USB_REQ_SET_ADDRESS: 109347a1685fSDinh Nguyen s3c_hsotg_disconnect(hsotg); 109447a1685fSDinh Nguyen dcfg = readl(hsotg->regs + DCFG); 109547a1685fSDinh Nguyen dcfg &= ~DCFG_DEVADDR_MASK; 1096d5dbd3f7SPaul Zimmerman dcfg |= (le16_to_cpu(ctrl->wValue) << 1097d5dbd3f7SPaul Zimmerman DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK; 109847a1685fSDinh Nguyen writel(dcfg, hsotg->regs + DCFG); 109947a1685fSDinh Nguyen 110047a1685fSDinh Nguyen dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); 110147a1685fSDinh Nguyen 110247a1685fSDinh Nguyen ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0); 110347a1685fSDinh Nguyen return; 110447a1685fSDinh Nguyen 110547a1685fSDinh Nguyen case USB_REQ_GET_STATUS: 110647a1685fSDinh Nguyen ret = s3c_hsotg_process_req_status(hsotg, ctrl); 110747a1685fSDinh Nguyen break; 110847a1685fSDinh Nguyen 110947a1685fSDinh Nguyen case USB_REQ_CLEAR_FEATURE: 111047a1685fSDinh Nguyen case USB_REQ_SET_FEATURE: 111147a1685fSDinh Nguyen ret = s3c_hsotg_process_req_feature(hsotg, ctrl); 111247a1685fSDinh Nguyen break; 111347a1685fSDinh Nguyen } 111447a1685fSDinh Nguyen } 111547a1685fSDinh Nguyen 111647a1685fSDinh Nguyen /* as a fallback, try delivering it to the driver to deal with */ 111747a1685fSDinh Nguyen 111847a1685fSDinh Nguyen if (ret == 0 && hsotg->driver) { 111947a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 112047a1685fSDinh Nguyen ret = hsotg->driver->setup(&hsotg->gadget, ctrl); 112147a1685fSDinh Nguyen spin_lock(&hsotg->lock); 112247a1685fSDinh Nguyen if (ret < 0) 112347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); 112447a1685fSDinh Nguyen } 112547a1685fSDinh Nguyen 112647a1685fSDinh Nguyen /* 112747a1685fSDinh Nguyen * the request is either unhandlable, or is not formatted correctly 112847a1685fSDinh Nguyen * so respond with a STALL for the status stage to indicate failure. 112947a1685fSDinh Nguyen */ 113047a1685fSDinh Nguyen 113147a1685fSDinh Nguyen if (ret < 0) 113247a1685fSDinh Nguyen s3c_hsotg_stall_ep0(hsotg); 113347a1685fSDinh Nguyen } 113447a1685fSDinh Nguyen 113547a1685fSDinh Nguyen /** 113647a1685fSDinh Nguyen * s3c_hsotg_complete_setup - completion of a setup transfer 113747a1685fSDinh Nguyen * @ep: The endpoint the request was on. 113847a1685fSDinh Nguyen * @req: The request completed. 113947a1685fSDinh Nguyen * 114047a1685fSDinh Nguyen * Called on completion of any requests the driver itself submitted for 114147a1685fSDinh Nguyen * EP0 setup packets 114247a1685fSDinh Nguyen */ 114347a1685fSDinh Nguyen static void s3c_hsotg_complete_setup(struct usb_ep *ep, 114447a1685fSDinh Nguyen struct usb_request *req) 114547a1685fSDinh Nguyen { 114647a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 114747a1685fSDinh Nguyen struct s3c_hsotg *hsotg = hs_ep->parent; 114847a1685fSDinh Nguyen 114947a1685fSDinh Nguyen if (req->status < 0) { 115047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); 115147a1685fSDinh Nguyen return; 115247a1685fSDinh Nguyen } 115347a1685fSDinh Nguyen 115447a1685fSDinh Nguyen spin_lock(&hsotg->lock); 115547a1685fSDinh Nguyen if (req->actual == 0) 115647a1685fSDinh Nguyen s3c_hsotg_enqueue_setup(hsotg); 115747a1685fSDinh Nguyen else 115847a1685fSDinh Nguyen s3c_hsotg_process_control(hsotg, req->buf); 115947a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 116047a1685fSDinh Nguyen } 116147a1685fSDinh Nguyen 116247a1685fSDinh Nguyen /** 116347a1685fSDinh Nguyen * s3c_hsotg_enqueue_setup - start a request for EP0 packets 116447a1685fSDinh Nguyen * @hsotg: The device state. 116547a1685fSDinh Nguyen * 116647a1685fSDinh Nguyen * Enqueue a request on EP0 if necessary to received any SETUP packets 116747a1685fSDinh Nguyen * received from the host. 116847a1685fSDinh Nguyen */ 116947a1685fSDinh Nguyen static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg) 117047a1685fSDinh Nguyen { 117147a1685fSDinh Nguyen struct usb_request *req = hsotg->ctrl_req; 117247a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = our_req(req); 117347a1685fSDinh Nguyen int ret; 117447a1685fSDinh Nguyen 117547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__); 117647a1685fSDinh Nguyen 117747a1685fSDinh Nguyen req->zero = 0; 117847a1685fSDinh Nguyen req->length = 8; 117947a1685fSDinh Nguyen req->buf = hsotg->ctrl_buff; 118047a1685fSDinh Nguyen req->complete = s3c_hsotg_complete_setup; 118147a1685fSDinh Nguyen 118247a1685fSDinh Nguyen if (!list_empty(&hs_req->queue)) { 118347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s already queued???\n", __func__); 118447a1685fSDinh Nguyen return; 118547a1685fSDinh Nguyen } 118647a1685fSDinh Nguyen 118747a1685fSDinh Nguyen hsotg->eps[0].dir_in = 0; 118847a1685fSDinh Nguyen 118947a1685fSDinh Nguyen ret = s3c_hsotg_ep_queue(&hsotg->eps[0].ep, req, GFP_ATOMIC); 119047a1685fSDinh Nguyen if (ret < 0) { 119147a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); 119247a1685fSDinh Nguyen /* 119347a1685fSDinh Nguyen * Don't think there's much we can do other than watch the 119447a1685fSDinh Nguyen * driver fail. 119547a1685fSDinh Nguyen */ 119647a1685fSDinh Nguyen } 119747a1685fSDinh Nguyen } 119847a1685fSDinh Nguyen 119947a1685fSDinh Nguyen /** 120047a1685fSDinh Nguyen * s3c_hsotg_complete_request - complete a request given to us 120147a1685fSDinh Nguyen * @hsotg: The device state. 120247a1685fSDinh Nguyen * @hs_ep: The endpoint the request was on. 120347a1685fSDinh Nguyen * @hs_req: The request to complete. 120447a1685fSDinh Nguyen * @result: The result code (0 => Ok, otherwise errno) 120547a1685fSDinh Nguyen * 120647a1685fSDinh Nguyen * The given request has finished, so call the necessary completion 120747a1685fSDinh Nguyen * if it has one and then look to see if we can start a new request 120847a1685fSDinh Nguyen * on the endpoint. 120947a1685fSDinh Nguyen * 121047a1685fSDinh Nguyen * Note, expects the ep to already be locked as appropriate. 121147a1685fSDinh Nguyen */ 121247a1685fSDinh Nguyen static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, 121347a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep, 121447a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req, 121547a1685fSDinh Nguyen int result) 121647a1685fSDinh Nguyen { 121747a1685fSDinh Nguyen bool restart; 121847a1685fSDinh Nguyen 121947a1685fSDinh Nguyen if (!hs_req) { 122047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); 122147a1685fSDinh Nguyen return; 122247a1685fSDinh Nguyen } 122347a1685fSDinh Nguyen 122447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", 122547a1685fSDinh Nguyen hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); 122647a1685fSDinh Nguyen 122747a1685fSDinh Nguyen /* 122847a1685fSDinh Nguyen * only replace the status if we've not already set an error 122947a1685fSDinh Nguyen * from a previous transaction 123047a1685fSDinh Nguyen */ 123147a1685fSDinh Nguyen 123247a1685fSDinh Nguyen if (hs_req->req.status == -EINPROGRESS) 123347a1685fSDinh Nguyen hs_req->req.status = result; 123447a1685fSDinh Nguyen 123547a1685fSDinh Nguyen hs_ep->req = NULL; 123647a1685fSDinh Nguyen list_del_init(&hs_req->queue); 123747a1685fSDinh Nguyen 123847a1685fSDinh Nguyen if (using_dma(hsotg)) 123947a1685fSDinh Nguyen s3c_hsotg_unmap_dma(hsotg, hs_ep, hs_req); 124047a1685fSDinh Nguyen 124147a1685fSDinh Nguyen /* 124247a1685fSDinh Nguyen * call the complete request with the locks off, just in case the 124347a1685fSDinh Nguyen * request tries to queue more work for this endpoint. 124447a1685fSDinh Nguyen */ 124547a1685fSDinh Nguyen 124647a1685fSDinh Nguyen if (hs_req->req.complete) { 124747a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 124847a1685fSDinh Nguyen hs_req->req.complete(&hs_ep->ep, &hs_req->req); 124947a1685fSDinh Nguyen spin_lock(&hsotg->lock); 125047a1685fSDinh Nguyen } 125147a1685fSDinh Nguyen 125247a1685fSDinh Nguyen /* 125347a1685fSDinh Nguyen * Look to see if there is anything else to do. Note, the completion 125447a1685fSDinh Nguyen * of the previous request may have caused a new request to be started 125547a1685fSDinh Nguyen * so be careful when doing this. 125647a1685fSDinh Nguyen */ 125747a1685fSDinh Nguyen 125847a1685fSDinh Nguyen if (!hs_ep->req && result >= 0) { 125947a1685fSDinh Nguyen restart = !list_empty(&hs_ep->queue); 126047a1685fSDinh Nguyen if (restart) { 126147a1685fSDinh Nguyen hs_req = get_ep_head(hs_ep); 126247a1685fSDinh Nguyen s3c_hsotg_start_req(hsotg, hs_ep, hs_req, false); 126347a1685fSDinh Nguyen } 126447a1685fSDinh Nguyen } 126547a1685fSDinh Nguyen } 126647a1685fSDinh Nguyen 126747a1685fSDinh Nguyen /** 126847a1685fSDinh Nguyen * s3c_hsotg_rx_data - receive data from the FIFO for an endpoint 126947a1685fSDinh Nguyen * @hsotg: The device state. 127047a1685fSDinh Nguyen * @ep_idx: The endpoint index for the data 127147a1685fSDinh Nguyen * @size: The size of data in the fifo, in bytes 127247a1685fSDinh Nguyen * 127347a1685fSDinh Nguyen * The FIFO status shows there is data to read from the FIFO for a given 127447a1685fSDinh Nguyen * endpoint, so sort out whether we need to read the data into a request 127547a1685fSDinh Nguyen * that has been made for that endpoint. 127647a1685fSDinh Nguyen */ 127747a1685fSDinh Nguyen static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) 127847a1685fSDinh Nguyen { 127947a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx]; 128047a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = hs_ep->req; 128147a1685fSDinh Nguyen void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx); 128247a1685fSDinh Nguyen int to_read; 128347a1685fSDinh Nguyen int max_req; 128447a1685fSDinh Nguyen int read_ptr; 128547a1685fSDinh Nguyen 128647a1685fSDinh Nguyen 128747a1685fSDinh Nguyen if (!hs_req) { 128847a1685fSDinh Nguyen u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx)); 128947a1685fSDinh Nguyen int ptr; 129047a1685fSDinh Nguyen 129147a1685fSDinh Nguyen dev_warn(hsotg->dev, 129247a1685fSDinh Nguyen "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", 129347a1685fSDinh Nguyen __func__, size, ep_idx, epctl); 129447a1685fSDinh Nguyen 129547a1685fSDinh Nguyen /* dump the data from the FIFO, we've nothing we can do */ 129647a1685fSDinh Nguyen for (ptr = 0; ptr < size; ptr += 4) 129747a1685fSDinh Nguyen (void)readl(fifo); 129847a1685fSDinh Nguyen 129947a1685fSDinh Nguyen return; 130047a1685fSDinh Nguyen } 130147a1685fSDinh Nguyen 130247a1685fSDinh Nguyen to_read = size; 130347a1685fSDinh Nguyen read_ptr = hs_req->req.actual; 130447a1685fSDinh Nguyen max_req = hs_req->req.length - read_ptr; 130547a1685fSDinh Nguyen 130647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", 130747a1685fSDinh Nguyen __func__, to_read, max_req, read_ptr, hs_req->req.length); 130847a1685fSDinh Nguyen 130947a1685fSDinh Nguyen if (to_read > max_req) { 131047a1685fSDinh Nguyen /* 131147a1685fSDinh Nguyen * more data appeared than we where willing 131247a1685fSDinh Nguyen * to deal with in this request. 131347a1685fSDinh Nguyen */ 131447a1685fSDinh Nguyen 131547a1685fSDinh Nguyen /* currently we don't deal this */ 131647a1685fSDinh Nguyen WARN_ON_ONCE(1); 131747a1685fSDinh Nguyen } 131847a1685fSDinh Nguyen 131947a1685fSDinh Nguyen hs_ep->total_data += to_read; 132047a1685fSDinh Nguyen hs_req->req.actual += to_read; 132147a1685fSDinh Nguyen to_read = DIV_ROUND_UP(to_read, 4); 132247a1685fSDinh Nguyen 132347a1685fSDinh Nguyen /* 132447a1685fSDinh Nguyen * note, we might over-write the buffer end by 3 bytes depending on 132547a1685fSDinh Nguyen * alignment of the data. 132647a1685fSDinh Nguyen */ 132747a1685fSDinh Nguyen ioread32_rep(fifo, hs_req->req.buf + read_ptr, to_read); 132847a1685fSDinh Nguyen } 132947a1685fSDinh Nguyen 133047a1685fSDinh Nguyen /** 133147a1685fSDinh Nguyen * s3c_hsotg_send_zlp - send zero-length packet on control endpoint 133247a1685fSDinh Nguyen * @hsotg: The device instance 133347a1685fSDinh Nguyen * @req: The request currently on this endpoint 133447a1685fSDinh Nguyen * 133547a1685fSDinh Nguyen * Generate a zero-length IN packet request for terminating a SETUP 133647a1685fSDinh Nguyen * transaction. 133747a1685fSDinh Nguyen * 133847a1685fSDinh Nguyen * Note, since we don't write any data to the TxFIFO, then it is 133947a1685fSDinh Nguyen * currently believed that we do not need to wait for any space in 134047a1685fSDinh Nguyen * the TxFIFO. 134147a1685fSDinh Nguyen */ 134247a1685fSDinh Nguyen static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg, 134347a1685fSDinh Nguyen struct s3c_hsotg_req *req) 134447a1685fSDinh Nguyen { 134547a1685fSDinh Nguyen u32 ctrl; 134647a1685fSDinh Nguyen 134747a1685fSDinh Nguyen if (!req) { 134847a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: no request?\n", __func__); 134947a1685fSDinh Nguyen return; 135047a1685fSDinh Nguyen } 135147a1685fSDinh Nguyen 135247a1685fSDinh Nguyen if (req->req.length == 0) { 135347a1685fSDinh Nguyen hsotg->eps[0].sent_zlp = 1; 135447a1685fSDinh Nguyen s3c_hsotg_enqueue_setup(hsotg); 135547a1685fSDinh Nguyen return; 135647a1685fSDinh Nguyen } 135747a1685fSDinh Nguyen 135847a1685fSDinh Nguyen hsotg->eps[0].dir_in = 1; 135947a1685fSDinh Nguyen hsotg->eps[0].sent_zlp = 1; 136047a1685fSDinh Nguyen 136147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "sending zero-length packet\n"); 136247a1685fSDinh Nguyen 136347a1685fSDinh Nguyen /* issue a zero-sized packet to terminate this */ 136447a1685fSDinh Nguyen writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 136547a1685fSDinh Nguyen DXEPTSIZ_XFERSIZE(0), hsotg->regs + DIEPTSIZ(0)); 136647a1685fSDinh Nguyen 136747a1685fSDinh Nguyen ctrl = readl(hsotg->regs + DIEPCTL0); 136847a1685fSDinh Nguyen ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 136947a1685fSDinh Nguyen ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 137047a1685fSDinh Nguyen ctrl |= DXEPCTL_USBACTEP; 137147a1685fSDinh Nguyen writel(ctrl, hsotg->regs + DIEPCTL0); 137247a1685fSDinh Nguyen } 137347a1685fSDinh Nguyen 137447a1685fSDinh Nguyen /** 137547a1685fSDinh Nguyen * s3c_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO 137647a1685fSDinh Nguyen * @hsotg: The device instance 137747a1685fSDinh Nguyen * @epnum: The endpoint received from 137847a1685fSDinh Nguyen * @was_setup: Set if processing a SetupDone event. 137947a1685fSDinh Nguyen * 138047a1685fSDinh Nguyen * The RXFIFO has delivered an OutDone event, which means that the data 138147a1685fSDinh Nguyen * transfer for an OUT endpoint has been completed, either by a short 138247a1685fSDinh Nguyen * packet or by the finish of a transfer. 138347a1685fSDinh Nguyen */ 138447a1685fSDinh Nguyen static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, 138547a1685fSDinh Nguyen int epnum, bool was_setup) 138647a1685fSDinh Nguyen { 138747a1685fSDinh Nguyen u32 epsize = readl(hsotg->regs + DOEPTSIZ(epnum)); 138847a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum]; 138947a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = hs_ep->req; 139047a1685fSDinh Nguyen struct usb_request *req = &hs_req->req; 139147a1685fSDinh Nguyen unsigned size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 139247a1685fSDinh Nguyen int result = 0; 139347a1685fSDinh Nguyen 139447a1685fSDinh Nguyen if (!hs_req) { 139547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: no request active\n", __func__); 139647a1685fSDinh Nguyen return; 139747a1685fSDinh Nguyen } 139847a1685fSDinh Nguyen 139947a1685fSDinh Nguyen if (using_dma(hsotg)) { 140047a1685fSDinh Nguyen unsigned size_done; 140147a1685fSDinh Nguyen 140247a1685fSDinh Nguyen /* 140347a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much 140447a1685fSDinh Nguyen * is left in the endpoint size register and then working it 140547a1685fSDinh Nguyen * out from the amount we loaded for the transfer. 140647a1685fSDinh Nguyen * 140747a1685fSDinh Nguyen * We need to do this as DMA pointers are always 32bit aligned 140847a1685fSDinh Nguyen * so may overshoot/undershoot the transfer. 140947a1685fSDinh Nguyen */ 141047a1685fSDinh Nguyen 141147a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 141247a1685fSDinh Nguyen size_done += hs_ep->last_load; 141347a1685fSDinh Nguyen 141447a1685fSDinh Nguyen req->actual = size_done; 141547a1685fSDinh Nguyen } 141647a1685fSDinh Nguyen 141747a1685fSDinh Nguyen /* if there is more request to do, schedule new transfer */ 141847a1685fSDinh Nguyen if (req->actual < req->length && size_left == 0) { 141947a1685fSDinh Nguyen s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true); 142047a1685fSDinh Nguyen return; 142147a1685fSDinh Nguyen } else if (epnum == 0) { 142247a1685fSDinh Nguyen /* 142347a1685fSDinh Nguyen * After was_setup = 1 => 142447a1685fSDinh Nguyen * set CNAK for non Setup requests 142547a1685fSDinh Nguyen */ 142647a1685fSDinh Nguyen hsotg->setup = was_setup ? 0 : 1; 142747a1685fSDinh Nguyen } 142847a1685fSDinh Nguyen 142947a1685fSDinh Nguyen if (req->actual < req->length && req->short_not_ok) { 143047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", 143147a1685fSDinh Nguyen __func__, req->actual, req->length); 143247a1685fSDinh Nguyen 143347a1685fSDinh Nguyen /* 143447a1685fSDinh Nguyen * todo - what should we return here? there's no one else 143547a1685fSDinh Nguyen * even bothering to check the status. 143647a1685fSDinh Nguyen */ 143747a1685fSDinh Nguyen } 143847a1685fSDinh Nguyen 143947a1685fSDinh Nguyen if (epnum == 0) { 144047a1685fSDinh Nguyen /* 144147a1685fSDinh Nguyen * Condition req->complete != s3c_hsotg_complete_setup says: 144247a1685fSDinh Nguyen * send ZLP when we have an asynchronous request from gadget 144347a1685fSDinh Nguyen */ 144447a1685fSDinh Nguyen if (!was_setup && req->complete != s3c_hsotg_complete_setup) 144547a1685fSDinh Nguyen s3c_hsotg_send_zlp(hsotg, hs_req); 144647a1685fSDinh Nguyen } 144747a1685fSDinh Nguyen 144847a1685fSDinh Nguyen s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result); 144947a1685fSDinh Nguyen } 145047a1685fSDinh Nguyen 145147a1685fSDinh Nguyen /** 145247a1685fSDinh Nguyen * s3c_hsotg_read_frameno - read current frame number 145347a1685fSDinh Nguyen * @hsotg: The device instance 145447a1685fSDinh Nguyen * 145547a1685fSDinh Nguyen * Return the current frame number 145647a1685fSDinh Nguyen */ 145747a1685fSDinh Nguyen static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg) 145847a1685fSDinh Nguyen { 145947a1685fSDinh Nguyen u32 dsts; 146047a1685fSDinh Nguyen 146147a1685fSDinh Nguyen dsts = readl(hsotg->regs + DSTS); 146247a1685fSDinh Nguyen dsts &= DSTS_SOFFN_MASK; 146347a1685fSDinh Nguyen dsts >>= DSTS_SOFFN_SHIFT; 146447a1685fSDinh Nguyen 146547a1685fSDinh Nguyen return dsts; 146647a1685fSDinh Nguyen } 146747a1685fSDinh Nguyen 146847a1685fSDinh Nguyen /** 146947a1685fSDinh Nguyen * s3c_hsotg_handle_rx - RX FIFO has data 147047a1685fSDinh Nguyen * @hsotg: The device instance 147147a1685fSDinh Nguyen * 147247a1685fSDinh Nguyen * The IRQ handler has detected that the RX FIFO has some data in it 147347a1685fSDinh Nguyen * that requires processing, so find out what is in there and do the 147447a1685fSDinh Nguyen * appropriate read. 147547a1685fSDinh Nguyen * 147647a1685fSDinh Nguyen * The RXFIFO is a true FIFO, the packets coming out are still in packet 147747a1685fSDinh Nguyen * chunks, so if you have x packets received on an endpoint you'll get x 147847a1685fSDinh Nguyen * FIFO events delivered, each with a packet's worth of data in it. 147947a1685fSDinh Nguyen * 148047a1685fSDinh Nguyen * When using DMA, we should not be processing events from the RXFIFO 148147a1685fSDinh Nguyen * as the actual data should be sent to the memory directly and we turn 148247a1685fSDinh Nguyen * on the completion interrupts to get notifications of transfer completion. 148347a1685fSDinh Nguyen */ 148447a1685fSDinh Nguyen static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) 148547a1685fSDinh Nguyen { 148647a1685fSDinh Nguyen u32 grxstsr = readl(hsotg->regs + GRXSTSP); 148747a1685fSDinh Nguyen u32 epnum, status, size; 148847a1685fSDinh Nguyen 148947a1685fSDinh Nguyen WARN_ON(using_dma(hsotg)); 149047a1685fSDinh Nguyen 149147a1685fSDinh Nguyen epnum = grxstsr & GRXSTS_EPNUM_MASK; 149247a1685fSDinh Nguyen status = grxstsr & GRXSTS_PKTSTS_MASK; 149347a1685fSDinh Nguyen 149447a1685fSDinh Nguyen size = grxstsr & GRXSTS_BYTECNT_MASK; 149547a1685fSDinh Nguyen size >>= GRXSTS_BYTECNT_SHIFT; 149647a1685fSDinh Nguyen 149747a1685fSDinh Nguyen if (1) 149847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", 149947a1685fSDinh Nguyen __func__, grxstsr, size, epnum); 150047a1685fSDinh Nguyen 150147a1685fSDinh Nguyen switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { 150247a1685fSDinh Nguyen case GRXSTS_PKTSTS_GLOBALOUTNAK: 150347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GLOBALOUTNAK\n"); 150447a1685fSDinh Nguyen break; 150547a1685fSDinh Nguyen 150647a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTDONE: 150747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", 150847a1685fSDinh Nguyen s3c_hsotg_read_frameno(hsotg)); 150947a1685fSDinh Nguyen 151047a1685fSDinh Nguyen if (!using_dma(hsotg)) 151147a1685fSDinh Nguyen s3c_hsotg_handle_outdone(hsotg, epnum, false); 151247a1685fSDinh Nguyen break; 151347a1685fSDinh Nguyen 151447a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPDONE: 151547a1685fSDinh Nguyen dev_dbg(hsotg->dev, 151647a1685fSDinh Nguyen "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 151747a1685fSDinh Nguyen s3c_hsotg_read_frameno(hsotg), 151847a1685fSDinh Nguyen readl(hsotg->regs + DOEPCTL(0))); 151947a1685fSDinh Nguyen 152047a1685fSDinh Nguyen s3c_hsotg_handle_outdone(hsotg, epnum, true); 152147a1685fSDinh Nguyen break; 152247a1685fSDinh Nguyen 152347a1685fSDinh Nguyen case GRXSTS_PKTSTS_OUTRX: 152447a1685fSDinh Nguyen s3c_hsotg_rx_data(hsotg, epnum, size); 152547a1685fSDinh Nguyen break; 152647a1685fSDinh Nguyen 152747a1685fSDinh Nguyen case GRXSTS_PKTSTS_SETUPRX: 152847a1685fSDinh Nguyen dev_dbg(hsotg->dev, 152947a1685fSDinh Nguyen "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 153047a1685fSDinh Nguyen s3c_hsotg_read_frameno(hsotg), 153147a1685fSDinh Nguyen readl(hsotg->regs + DOEPCTL(0))); 153247a1685fSDinh Nguyen 153347a1685fSDinh Nguyen s3c_hsotg_rx_data(hsotg, epnum, size); 153447a1685fSDinh Nguyen break; 153547a1685fSDinh Nguyen 153647a1685fSDinh Nguyen default: 153747a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: unknown status %08x\n", 153847a1685fSDinh Nguyen __func__, grxstsr); 153947a1685fSDinh Nguyen 154047a1685fSDinh Nguyen s3c_hsotg_dump(hsotg); 154147a1685fSDinh Nguyen break; 154247a1685fSDinh Nguyen } 154347a1685fSDinh Nguyen } 154447a1685fSDinh Nguyen 154547a1685fSDinh Nguyen /** 154647a1685fSDinh Nguyen * s3c_hsotg_ep0_mps - turn max packet size into register setting 154747a1685fSDinh Nguyen * @mps: The maximum packet size in bytes. 154847a1685fSDinh Nguyen */ 154947a1685fSDinh Nguyen static u32 s3c_hsotg_ep0_mps(unsigned int mps) 155047a1685fSDinh Nguyen { 155147a1685fSDinh Nguyen switch (mps) { 155247a1685fSDinh Nguyen case 64: 155347a1685fSDinh Nguyen return D0EPCTL_MPS_64; 155447a1685fSDinh Nguyen case 32: 155547a1685fSDinh Nguyen return D0EPCTL_MPS_32; 155647a1685fSDinh Nguyen case 16: 155747a1685fSDinh Nguyen return D0EPCTL_MPS_16; 155847a1685fSDinh Nguyen case 8: 155947a1685fSDinh Nguyen return D0EPCTL_MPS_8; 156047a1685fSDinh Nguyen } 156147a1685fSDinh Nguyen 156247a1685fSDinh Nguyen /* bad max packet size, warn and return invalid result */ 156347a1685fSDinh Nguyen WARN_ON(1); 156447a1685fSDinh Nguyen return (u32)-1; 156547a1685fSDinh Nguyen } 156647a1685fSDinh Nguyen 156747a1685fSDinh Nguyen /** 156847a1685fSDinh Nguyen * s3c_hsotg_set_ep_maxpacket - set endpoint's max-packet field 156947a1685fSDinh Nguyen * @hsotg: The driver state. 157047a1685fSDinh Nguyen * @ep: The index number of the endpoint 157147a1685fSDinh Nguyen * @mps: The maximum packet size in bytes 157247a1685fSDinh Nguyen * 157347a1685fSDinh Nguyen * Configure the maximum packet size for the given endpoint, updating 157447a1685fSDinh Nguyen * the hardware control registers to reflect this. 157547a1685fSDinh Nguyen */ 157647a1685fSDinh Nguyen static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, 157747a1685fSDinh Nguyen unsigned int ep, unsigned int mps) 157847a1685fSDinh Nguyen { 157947a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep]; 158047a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 158147a1685fSDinh Nguyen u32 mpsval; 158247a1685fSDinh Nguyen u32 mcval; 158347a1685fSDinh Nguyen u32 reg; 158447a1685fSDinh Nguyen 158547a1685fSDinh Nguyen if (ep == 0) { 158647a1685fSDinh Nguyen /* EP0 is a special case */ 158747a1685fSDinh Nguyen mpsval = s3c_hsotg_ep0_mps(mps); 158847a1685fSDinh Nguyen if (mpsval > 3) 158947a1685fSDinh Nguyen goto bad_mps; 159047a1685fSDinh Nguyen hs_ep->ep.maxpacket = mps; 159147a1685fSDinh Nguyen hs_ep->mc = 1; 159247a1685fSDinh Nguyen } else { 159347a1685fSDinh Nguyen mpsval = mps & DXEPCTL_MPS_MASK; 159447a1685fSDinh Nguyen if (mpsval > 1024) 159547a1685fSDinh Nguyen goto bad_mps; 159647a1685fSDinh Nguyen mcval = ((mps >> 11) & 0x3) + 1; 159747a1685fSDinh Nguyen hs_ep->mc = mcval; 159847a1685fSDinh Nguyen if (mcval > 3) 159947a1685fSDinh Nguyen goto bad_mps; 160047a1685fSDinh Nguyen hs_ep->ep.maxpacket = mpsval; 160147a1685fSDinh Nguyen } 160247a1685fSDinh Nguyen 160347a1685fSDinh Nguyen /* 160447a1685fSDinh Nguyen * update both the in and out endpoint controldir_ registers, even 160547a1685fSDinh Nguyen * if one of the directions may not be in use. 160647a1685fSDinh Nguyen */ 160747a1685fSDinh Nguyen 160847a1685fSDinh Nguyen reg = readl(regs + DIEPCTL(ep)); 160947a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 161047a1685fSDinh Nguyen reg |= mpsval; 161147a1685fSDinh Nguyen writel(reg, regs + DIEPCTL(ep)); 161247a1685fSDinh Nguyen 161347a1685fSDinh Nguyen if (ep) { 161447a1685fSDinh Nguyen reg = readl(regs + DOEPCTL(ep)); 161547a1685fSDinh Nguyen reg &= ~DXEPCTL_MPS_MASK; 161647a1685fSDinh Nguyen reg |= mpsval; 161747a1685fSDinh Nguyen writel(reg, regs + DOEPCTL(ep)); 161847a1685fSDinh Nguyen } 161947a1685fSDinh Nguyen 162047a1685fSDinh Nguyen return; 162147a1685fSDinh Nguyen 162247a1685fSDinh Nguyen bad_mps: 162347a1685fSDinh Nguyen dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); 162447a1685fSDinh Nguyen } 162547a1685fSDinh Nguyen 162647a1685fSDinh Nguyen /** 162747a1685fSDinh Nguyen * s3c_hsotg_txfifo_flush - flush Tx FIFO 162847a1685fSDinh Nguyen * @hsotg: The driver state 162947a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 163047a1685fSDinh Nguyen */ 163147a1685fSDinh Nguyen static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx) 163247a1685fSDinh Nguyen { 163347a1685fSDinh Nguyen int timeout; 163447a1685fSDinh Nguyen int val; 163547a1685fSDinh Nguyen 163647a1685fSDinh Nguyen writel(GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH, 163747a1685fSDinh Nguyen hsotg->regs + GRSTCTL); 163847a1685fSDinh Nguyen 163947a1685fSDinh Nguyen /* wait until the fifo is flushed */ 164047a1685fSDinh Nguyen timeout = 100; 164147a1685fSDinh Nguyen 164247a1685fSDinh Nguyen while (1) { 164347a1685fSDinh Nguyen val = readl(hsotg->regs + GRSTCTL); 164447a1685fSDinh Nguyen 164547a1685fSDinh Nguyen if ((val & (GRSTCTL_TXFFLSH)) == 0) 164647a1685fSDinh Nguyen break; 164747a1685fSDinh Nguyen 164847a1685fSDinh Nguyen if (--timeout == 0) { 164947a1685fSDinh Nguyen dev_err(hsotg->dev, 165047a1685fSDinh Nguyen "%s: timeout flushing fifo (GRSTCTL=%08x)\n", 165147a1685fSDinh Nguyen __func__, val); 1652e0cbe595SMarek Szyprowski break; 165347a1685fSDinh Nguyen } 165447a1685fSDinh Nguyen 165547a1685fSDinh Nguyen udelay(1); 165647a1685fSDinh Nguyen } 165747a1685fSDinh Nguyen } 165847a1685fSDinh Nguyen 165947a1685fSDinh Nguyen /** 166047a1685fSDinh Nguyen * s3c_hsotg_trytx - check to see if anything needs transmitting 166147a1685fSDinh Nguyen * @hsotg: The driver state 166247a1685fSDinh Nguyen * @hs_ep: The driver endpoint to check. 166347a1685fSDinh Nguyen * 166447a1685fSDinh Nguyen * Check to see if there is a request that has data to send, and if so 166547a1685fSDinh Nguyen * make an attempt to write data into the FIFO. 166647a1685fSDinh Nguyen */ 166747a1685fSDinh Nguyen static int s3c_hsotg_trytx(struct s3c_hsotg *hsotg, 166847a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep) 166947a1685fSDinh Nguyen { 167047a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = hs_ep->req; 167147a1685fSDinh Nguyen 167247a1685fSDinh Nguyen if (!hs_ep->dir_in || !hs_req) { 167347a1685fSDinh Nguyen /** 167447a1685fSDinh Nguyen * if request is not enqueued, we disable interrupts 167547a1685fSDinh Nguyen * for endpoints, excepting ep0 167647a1685fSDinh Nguyen */ 167747a1685fSDinh Nguyen if (hs_ep->index != 0) 167847a1685fSDinh Nguyen s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, 167947a1685fSDinh Nguyen hs_ep->dir_in, 0); 168047a1685fSDinh Nguyen return 0; 168147a1685fSDinh Nguyen } 168247a1685fSDinh Nguyen 168347a1685fSDinh Nguyen if (hs_req->req.actual < hs_req->req.length) { 168447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "trying to write more for ep%d\n", 168547a1685fSDinh Nguyen hs_ep->index); 168647a1685fSDinh Nguyen return s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req); 168747a1685fSDinh Nguyen } 168847a1685fSDinh Nguyen 168947a1685fSDinh Nguyen return 0; 169047a1685fSDinh Nguyen } 169147a1685fSDinh Nguyen 169247a1685fSDinh Nguyen /** 169347a1685fSDinh Nguyen * s3c_hsotg_complete_in - complete IN transfer 169447a1685fSDinh Nguyen * @hsotg: The device state. 169547a1685fSDinh Nguyen * @hs_ep: The endpoint that has just completed. 169647a1685fSDinh Nguyen * 169747a1685fSDinh Nguyen * An IN transfer has been completed, update the transfer's state and then 169847a1685fSDinh Nguyen * call the relevant completion routines. 169947a1685fSDinh Nguyen */ 170047a1685fSDinh Nguyen static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, 170147a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep) 170247a1685fSDinh Nguyen { 170347a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = hs_ep->req; 170447a1685fSDinh Nguyen u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); 170547a1685fSDinh Nguyen int size_left, size_done; 170647a1685fSDinh Nguyen 170747a1685fSDinh Nguyen if (!hs_req) { 170847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "XferCompl but no req\n"); 170947a1685fSDinh Nguyen return; 171047a1685fSDinh Nguyen } 171147a1685fSDinh Nguyen 171247a1685fSDinh Nguyen /* Finish ZLP handling for IN EP0 transactions */ 171347a1685fSDinh Nguyen if (hsotg->eps[0].sent_zlp) { 171447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "zlp packet received\n"); 171547a1685fSDinh Nguyen s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 171647a1685fSDinh Nguyen return; 171747a1685fSDinh Nguyen } 171847a1685fSDinh Nguyen 171947a1685fSDinh Nguyen /* 172047a1685fSDinh Nguyen * Calculate the size of the transfer by checking how much is left 172147a1685fSDinh Nguyen * in the endpoint size register and then working it out from 172247a1685fSDinh Nguyen * the amount we loaded for the transfer. 172347a1685fSDinh Nguyen * 172447a1685fSDinh Nguyen * We do this even for DMA, as the transfer may have incremented 172547a1685fSDinh Nguyen * past the end of the buffer (DMA transfers are always 32bit 172647a1685fSDinh Nguyen * aligned). 172747a1685fSDinh Nguyen */ 172847a1685fSDinh Nguyen 172947a1685fSDinh Nguyen size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 173047a1685fSDinh Nguyen 173147a1685fSDinh Nguyen size_done = hs_ep->size_loaded - size_left; 173247a1685fSDinh Nguyen size_done += hs_ep->last_load; 173347a1685fSDinh Nguyen 173447a1685fSDinh Nguyen if (hs_req->req.actual != size_done) 173547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n", 173647a1685fSDinh Nguyen __func__, hs_req->req.actual, size_done); 173747a1685fSDinh Nguyen 173847a1685fSDinh Nguyen hs_req->req.actual = size_done; 173947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n", 174047a1685fSDinh Nguyen hs_req->req.length, hs_req->req.actual, hs_req->req.zero); 174147a1685fSDinh Nguyen 174247a1685fSDinh Nguyen /* 174347a1685fSDinh Nguyen * Check if dealing with Maximum Packet Size(MPS) IN transfer at EP0 174447a1685fSDinh Nguyen * When sent data is a multiple MPS size (e.g. 64B ,128B ,192B 174547a1685fSDinh Nguyen * ,256B ... ), after last MPS sized packet send IN ZLP packet to 174647a1685fSDinh Nguyen * inform the host that no more data is available. 174747a1685fSDinh Nguyen * The state of req.zero member is checked to be sure that the value to 174847a1685fSDinh Nguyen * send is smaller than wValue expected from host. 174947a1685fSDinh Nguyen * Check req.length to NOT send another ZLP when the current one is 175047a1685fSDinh Nguyen * under completion (the one for which this completion has been called). 175147a1685fSDinh Nguyen */ 175247a1685fSDinh Nguyen if (hs_req->req.length && hs_ep->index == 0 && hs_req->req.zero && 175347a1685fSDinh Nguyen hs_req->req.length == hs_req->req.actual && 175447a1685fSDinh Nguyen !(hs_req->req.length % hs_ep->ep.maxpacket)) { 175547a1685fSDinh Nguyen 175647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ep0 zlp IN packet sent\n"); 175747a1685fSDinh Nguyen s3c_hsotg_send_zlp(hsotg, hs_req); 175847a1685fSDinh Nguyen 175947a1685fSDinh Nguyen return; 176047a1685fSDinh Nguyen } 176147a1685fSDinh Nguyen 176247a1685fSDinh Nguyen if (!size_left && hs_req->req.actual < hs_req->req.length) { 176347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); 176447a1685fSDinh Nguyen s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true); 176547a1685fSDinh Nguyen } else 176647a1685fSDinh Nguyen s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 176747a1685fSDinh Nguyen } 176847a1685fSDinh Nguyen 176947a1685fSDinh Nguyen /** 177047a1685fSDinh Nguyen * s3c_hsotg_epint - handle an in/out endpoint interrupt 177147a1685fSDinh Nguyen * @hsotg: The driver state 177247a1685fSDinh Nguyen * @idx: The index for the endpoint (0..15) 177347a1685fSDinh Nguyen * @dir_in: Set if this is an IN endpoint 177447a1685fSDinh Nguyen * 177547a1685fSDinh Nguyen * Process and clear any interrupt pending for an individual endpoint 177647a1685fSDinh Nguyen */ 177747a1685fSDinh Nguyen static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, 177847a1685fSDinh Nguyen int dir_in) 177947a1685fSDinh Nguyen { 178047a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx]; 178147a1685fSDinh Nguyen u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 178247a1685fSDinh Nguyen u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 178347a1685fSDinh Nguyen u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); 178447a1685fSDinh Nguyen u32 ints; 178547a1685fSDinh Nguyen u32 ctrl; 178647a1685fSDinh Nguyen 178747a1685fSDinh Nguyen ints = readl(hsotg->regs + epint_reg); 178847a1685fSDinh Nguyen ctrl = readl(hsotg->regs + epctl_reg); 178947a1685fSDinh Nguyen 179047a1685fSDinh Nguyen /* Clear endpoint interrupts */ 179147a1685fSDinh Nguyen writel(ints, hsotg->regs + epint_reg); 179247a1685fSDinh Nguyen 179347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", 179447a1685fSDinh Nguyen __func__, idx, dir_in ? "in" : "out", ints); 179547a1685fSDinh Nguyen 179647a1685fSDinh Nguyen if (ints & DXEPINT_XFERCOMPL) { 179747a1685fSDinh Nguyen if (hs_ep->isochronous && hs_ep->interval == 1) { 179847a1685fSDinh Nguyen if (ctrl & DXEPCTL_EOFRNUM) 179947a1685fSDinh Nguyen ctrl |= DXEPCTL_SETEVENFR; 180047a1685fSDinh Nguyen else 180147a1685fSDinh Nguyen ctrl |= DXEPCTL_SETODDFR; 180247a1685fSDinh Nguyen writel(ctrl, hsotg->regs + epctl_reg); 180347a1685fSDinh Nguyen } 180447a1685fSDinh Nguyen 180547a1685fSDinh Nguyen dev_dbg(hsotg->dev, 180647a1685fSDinh Nguyen "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n", 180747a1685fSDinh Nguyen __func__, readl(hsotg->regs + epctl_reg), 180847a1685fSDinh Nguyen readl(hsotg->regs + epsiz_reg)); 180947a1685fSDinh Nguyen 181047a1685fSDinh Nguyen /* 181147a1685fSDinh Nguyen * we get OutDone from the FIFO, so we only need to look 181247a1685fSDinh Nguyen * at completing IN requests here 181347a1685fSDinh Nguyen */ 181447a1685fSDinh Nguyen if (dir_in) { 181547a1685fSDinh Nguyen s3c_hsotg_complete_in(hsotg, hs_ep); 181647a1685fSDinh Nguyen 181747a1685fSDinh Nguyen if (idx == 0 && !hs_ep->req) 181847a1685fSDinh Nguyen s3c_hsotg_enqueue_setup(hsotg); 181947a1685fSDinh Nguyen } else if (using_dma(hsotg)) { 182047a1685fSDinh Nguyen /* 182147a1685fSDinh Nguyen * We're using DMA, we need to fire an OutDone here 182247a1685fSDinh Nguyen * as we ignore the RXFIFO. 182347a1685fSDinh Nguyen */ 182447a1685fSDinh Nguyen 182547a1685fSDinh Nguyen s3c_hsotg_handle_outdone(hsotg, idx, false); 182647a1685fSDinh Nguyen } 182747a1685fSDinh Nguyen } 182847a1685fSDinh Nguyen 182947a1685fSDinh Nguyen if (ints & DXEPINT_EPDISBLD) { 183047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); 183147a1685fSDinh Nguyen 183247a1685fSDinh Nguyen if (dir_in) { 183347a1685fSDinh Nguyen int epctl = readl(hsotg->regs + epctl_reg); 183447a1685fSDinh Nguyen 183547a1685fSDinh Nguyen s3c_hsotg_txfifo_flush(hsotg, idx); 183647a1685fSDinh Nguyen 183747a1685fSDinh Nguyen if ((epctl & DXEPCTL_STALL) && 183847a1685fSDinh Nguyen (epctl & DXEPCTL_EPTYPE_BULK)) { 183947a1685fSDinh Nguyen int dctl = readl(hsotg->regs + DCTL); 184047a1685fSDinh Nguyen 184147a1685fSDinh Nguyen dctl |= DCTL_CGNPINNAK; 184247a1685fSDinh Nguyen writel(dctl, hsotg->regs + DCTL); 184347a1685fSDinh Nguyen } 184447a1685fSDinh Nguyen } 184547a1685fSDinh Nguyen } 184647a1685fSDinh Nguyen 184747a1685fSDinh Nguyen if (ints & DXEPINT_AHBERR) 184847a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); 184947a1685fSDinh Nguyen 185047a1685fSDinh Nguyen if (ints & DXEPINT_SETUP) { /* Setup or Timeout */ 185147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); 185247a1685fSDinh Nguyen 185347a1685fSDinh Nguyen if (using_dma(hsotg) && idx == 0) { 185447a1685fSDinh Nguyen /* 185547a1685fSDinh Nguyen * this is the notification we've received a 185647a1685fSDinh Nguyen * setup packet. In non-DMA mode we'd get this 185747a1685fSDinh Nguyen * from the RXFIFO, instead we need to process 185847a1685fSDinh Nguyen * the setup here. 185947a1685fSDinh Nguyen */ 186047a1685fSDinh Nguyen 186147a1685fSDinh Nguyen if (dir_in) 186247a1685fSDinh Nguyen WARN_ON_ONCE(1); 186347a1685fSDinh Nguyen else 186447a1685fSDinh Nguyen s3c_hsotg_handle_outdone(hsotg, 0, true); 186547a1685fSDinh Nguyen } 186647a1685fSDinh Nguyen } 186747a1685fSDinh Nguyen 186847a1685fSDinh Nguyen if (ints & DXEPINT_BACK2BACKSETUP) 186947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); 187047a1685fSDinh Nguyen 187147a1685fSDinh Nguyen if (dir_in && !hs_ep->isochronous) { 187247a1685fSDinh Nguyen /* not sure if this is important, but we'll clear it anyway */ 187347a1685fSDinh Nguyen if (ints & DIEPMSK_INTKNTXFEMPMSK) { 187447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", 187547a1685fSDinh Nguyen __func__, idx); 187647a1685fSDinh Nguyen } 187747a1685fSDinh Nguyen 187847a1685fSDinh Nguyen /* this probably means something bad is happening */ 187947a1685fSDinh Nguyen if (ints & DIEPMSK_INTKNEPMISMSK) { 188047a1685fSDinh Nguyen dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", 188147a1685fSDinh Nguyen __func__, idx); 188247a1685fSDinh Nguyen } 188347a1685fSDinh Nguyen 188447a1685fSDinh Nguyen /* FIFO has space or is empty (see GAHBCFG) */ 188547a1685fSDinh Nguyen if (hsotg->dedicated_fifos && 188647a1685fSDinh Nguyen ints & DIEPMSK_TXFIFOEMPTY) { 188747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", 188847a1685fSDinh Nguyen __func__, idx); 188947a1685fSDinh Nguyen if (!using_dma(hsotg)) 189047a1685fSDinh Nguyen s3c_hsotg_trytx(hsotg, hs_ep); 189147a1685fSDinh Nguyen } 189247a1685fSDinh Nguyen } 189347a1685fSDinh Nguyen } 189447a1685fSDinh Nguyen 189547a1685fSDinh Nguyen /** 189647a1685fSDinh Nguyen * s3c_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) 189747a1685fSDinh Nguyen * @hsotg: The device state. 189847a1685fSDinh Nguyen * 189947a1685fSDinh Nguyen * Handle updating the device settings after the enumeration phase has 190047a1685fSDinh Nguyen * been completed. 190147a1685fSDinh Nguyen */ 190247a1685fSDinh Nguyen static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) 190347a1685fSDinh Nguyen { 190447a1685fSDinh Nguyen u32 dsts = readl(hsotg->regs + DSTS); 19059b2667f1SJingoo Han int ep0_mps = 0, ep_mps = 8; 190647a1685fSDinh Nguyen 190747a1685fSDinh Nguyen /* 190847a1685fSDinh Nguyen * This should signal the finish of the enumeration phase 190947a1685fSDinh Nguyen * of the USB handshaking, so we should now know what rate 191047a1685fSDinh Nguyen * we connected at. 191147a1685fSDinh Nguyen */ 191247a1685fSDinh Nguyen 191347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); 191447a1685fSDinh Nguyen 191547a1685fSDinh Nguyen /* 191647a1685fSDinh Nguyen * note, since we're limited by the size of transfer on EP0, and 191747a1685fSDinh Nguyen * it seems IN transfers must be a even number of packets we do 191847a1685fSDinh Nguyen * not advertise a 64byte MPS on EP0. 191947a1685fSDinh Nguyen */ 192047a1685fSDinh Nguyen 192147a1685fSDinh Nguyen /* catch both EnumSpd_FS and EnumSpd_FS48 */ 192247a1685fSDinh Nguyen switch (dsts & DSTS_ENUMSPD_MASK) { 192347a1685fSDinh Nguyen case DSTS_ENUMSPD_FS: 192447a1685fSDinh Nguyen case DSTS_ENUMSPD_FS48: 192547a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_FULL; 192647a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 192747a1685fSDinh Nguyen ep_mps = 1023; 192847a1685fSDinh Nguyen break; 192947a1685fSDinh Nguyen 193047a1685fSDinh Nguyen case DSTS_ENUMSPD_HS: 193147a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_HIGH; 193247a1685fSDinh Nguyen ep0_mps = EP0_MPS_LIMIT; 193347a1685fSDinh Nguyen ep_mps = 1024; 193447a1685fSDinh Nguyen break; 193547a1685fSDinh Nguyen 193647a1685fSDinh Nguyen case DSTS_ENUMSPD_LS: 193747a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_LOW; 193847a1685fSDinh Nguyen /* 193947a1685fSDinh Nguyen * note, we don't actually support LS in this driver at the 194047a1685fSDinh Nguyen * moment, and the documentation seems to imply that it isn't 194147a1685fSDinh Nguyen * supported by the PHYs on some of the devices. 194247a1685fSDinh Nguyen */ 194347a1685fSDinh Nguyen break; 194447a1685fSDinh Nguyen } 194547a1685fSDinh Nguyen dev_info(hsotg->dev, "new device is %s\n", 194647a1685fSDinh Nguyen usb_speed_string(hsotg->gadget.speed)); 194747a1685fSDinh Nguyen 194847a1685fSDinh Nguyen /* 194947a1685fSDinh Nguyen * we should now know the maximum packet size for an 195047a1685fSDinh Nguyen * endpoint, so set the endpoints to a default value. 195147a1685fSDinh Nguyen */ 195247a1685fSDinh Nguyen 195347a1685fSDinh Nguyen if (ep0_mps) { 195447a1685fSDinh Nguyen int i; 195547a1685fSDinh Nguyen s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps); 195647a1685fSDinh Nguyen for (i = 1; i < hsotg->num_of_eps; i++) 195747a1685fSDinh Nguyen s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps); 195847a1685fSDinh Nguyen } 195947a1685fSDinh Nguyen 196047a1685fSDinh Nguyen /* ensure after enumeration our EP0 is active */ 196147a1685fSDinh Nguyen 196247a1685fSDinh Nguyen s3c_hsotg_enqueue_setup(hsotg); 196347a1685fSDinh Nguyen 196447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 196547a1685fSDinh Nguyen readl(hsotg->regs + DIEPCTL0), 196647a1685fSDinh Nguyen readl(hsotg->regs + DOEPCTL0)); 196747a1685fSDinh Nguyen } 196847a1685fSDinh Nguyen 196947a1685fSDinh Nguyen /** 197047a1685fSDinh Nguyen * kill_all_requests - remove all requests from the endpoint's queue 197147a1685fSDinh Nguyen * @hsotg: The device state. 197247a1685fSDinh Nguyen * @ep: The endpoint the requests may be on. 197347a1685fSDinh Nguyen * @result: The result code to use. 197447a1685fSDinh Nguyen * @force: Force removal of any current requests 197547a1685fSDinh Nguyen * 197647a1685fSDinh Nguyen * Go through the requests on the given endpoint and mark them 197747a1685fSDinh Nguyen * completed with the given result code. 197847a1685fSDinh Nguyen */ 197947a1685fSDinh Nguyen static void kill_all_requests(struct s3c_hsotg *hsotg, 198047a1685fSDinh Nguyen struct s3c_hsotg_ep *ep, 198147a1685fSDinh Nguyen int result, bool force) 198247a1685fSDinh Nguyen { 198347a1685fSDinh Nguyen struct s3c_hsotg_req *req, *treq; 198447a1685fSDinh Nguyen 198547a1685fSDinh Nguyen list_for_each_entry_safe(req, treq, &ep->queue, queue) { 198647a1685fSDinh Nguyen /* 198747a1685fSDinh Nguyen * currently, we can't do much about an already 198847a1685fSDinh Nguyen * running request on an in endpoint 198947a1685fSDinh Nguyen */ 199047a1685fSDinh Nguyen 199147a1685fSDinh Nguyen if (ep->req == req && ep->dir_in && !force) 199247a1685fSDinh Nguyen continue; 199347a1685fSDinh Nguyen 199447a1685fSDinh Nguyen s3c_hsotg_complete_request(hsotg, ep, req, 199547a1685fSDinh Nguyen result); 199647a1685fSDinh Nguyen } 199747a1685fSDinh Nguyen if (hsotg->dedicated_fifos) 199847a1685fSDinh Nguyen if ((readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4 < 3072) 199947a1685fSDinh Nguyen s3c_hsotg_txfifo_flush(hsotg, ep->index); 200047a1685fSDinh Nguyen } 200147a1685fSDinh Nguyen 200247a1685fSDinh Nguyen /** 200347a1685fSDinh Nguyen * s3c_hsotg_disconnect - disconnect service 200447a1685fSDinh Nguyen * @hsotg: The device state. 200547a1685fSDinh Nguyen * 200647a1685fSDinh Nguyen * The device has been disconnected. Remove all current 200747a1685fSDinh Nguyen * transactions and signal the gadget driver that this 200847a1685fSDinh Nguyen * has happened. 200947a1685fSDinh Nguyen */ 201047a1685fSDinh Nguyen static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg) 201147a1685fSDinh Nguyen { 201247a1685fSDinh Nguyen unsigned ep; 201347a1685fSDinh Nguyen 201447a1685fSDinh Nguyen for (ep = 0; ep < hsotg->num_of_eps; ep++) 201547a1685fSDinh Nguyen kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true); 201647a1685fSDinh Nguyen 201747a1685fSDinh Nguyen call_gadget(hsotg, disconnect); 201847a1685fSDinh Nguyen } 201947a1685fSDinh Nguyen 202047a1685fSDinh Nguyen /** 202147a1685fSDinh Nguyen * s3c_hsotg_irq_fifoempty - TX FIFO empty interrupt handler 202247a1685fSDinh Nguyen * @hsotg: The device state: 202347a1685fSDinh Nguyen * @periodic: True if this is a periodic FIFO interrupt 202447a1685fSDinh Nguyen */ 202547a1685fSDinh Nguyen static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic) 202647a1685fSDinh Nguyen { 202747a1685fSDinh Nguyen struct s3c_hsotg_ep *ep; 202847a1685fSDinh Nguyen int epno, ret; 202947a1685fSDinh Nguyen 203047a1685fSDinh Nguyen /* look through for any more data to transmit */ 203147a1685fSDinh Nguyen 203247a1685fSDinh Nguyen for (epno = 0; epno < hsotg->num_of_eps; epno++) { 203347a1685fSDinh Nguyen ep = &hsotg->eps[epno]; 203447a1685fSDinh Nguyen 203547a1685fSDinh Nguyen if (!ep->dir_in) 203647a1685fSDinh Nguyen continue; 203747a1685fSDinh Nguyen 203847a1685fSDinh Nguyen if ((periodic && !ep->periodic) || 203947a1685fSDinh Nguyen (!periodic && ep->periodic)) 204047a1685fSDinh Nguyen continue; 204147a1685fSDinh Nguyen 204247a1685fSDinh Nguyen ret = s3c_hsotg_trytx(hsotg, ep); 204347a1685fSDinh Nguyen if (ret < 0) 204447a1685fSDinh Nguyen break; 204547a1685fSDinh Nguyen } 204647a1685fSDinh Nguyen } 204747a1685fSDinh Nguyen 204847a1685fSDinh Nguyen /* IRQ flags which will trigger a retry around the IRQ loop */ 204947a1685fSDinh Nguyen #define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \ 205047a1685fSDinh Nguyen GINTSTS_PTXFEMP | \ 205147a1685fSDinh Nguyen GINTSTS_RXFLVL) 205247a1685fSDinh Nguyen 205347a1685fSDinh Nguyen /** 205447a1685fSDinh Nguyen * s3c_hsotg_corereset - issue softreset to the core 205547a1685fSDinh Nguyen * @hsotg: The device state 205647a1685fSDinh Nguyen * 205747a1685fSDinh Nguyen * Issue a soft reset to the core, and await the core finishing it. 205847a1685fSDinh Nguyen */ 205947a1685fSDinh Nguyen static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) 206047a1685fSDinh Nguyen { 206147a1685fSDinh Nguyen int timeout; 206247a1685fSDinh Nguyen u32 grstctl; 206347a1685fSDinh Nguyen 206447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "resetting core\n"); 206547a1685fSDinh Nguyen 206647a1685fSDinh Nguyen /* issue soft reset */ 206747a1685fSDinh Nguyen writel(GRSTCTL_CSFTRST, hsotg->regs + GRSTCTL); 206847a1685fSDinh Nguyen 206947a1685fSDinh Nguyen timeout = 10000; 207047a1685fSDinh Nguyen do { 207147a1685fSDinh Nguyen grstctl = readl(hsotg->regs + GRSTCTL); 207247a1685fSDinh Nguyen } while ((grstctl & GRSTCTL_CSFTRST) && timeout-- > 0); 207347a1685fSDinh Nguyen 207447a1685fSDinh Nguyen if (grstctl & GRSTCTL_CSFTRST) { 207547a1685fSDinh Nguyen dev_err(hsotg->dev, "Failed to get CSftRst asserted\n"); 207647a1685fSDinh Nguyen return -EINVAL; 207747a1685fSDinh Nguyen } 207847a1685fSDinh Nguyen 207947a1685fSDinh Nguyen timeout = 10000; 208047a1685fSDinh Nguyen 208147a1685fSDinh Nguyen while (1) { 208247a1685fSDinh Nguyen u32 grstctl = readl(hsotg->regs + GRSTCTL); 208347a1685fSDinh Nguyen 208447a1685fSDinh Nguyen if (timeout-- < 0) { 208547a1685fSDinh Nguyen dev_info(hsotg->dev, 208647a1685fSDinh Nguyen "%s: reset failed, GRSTCTL=%08x\n", 208747a1685fSDinh Nguyen __func__, grstctl); 208847a1685fSDinh Nguyen return -ETIMEDOUT; 208947a1685fSDinh Nguyen } 209047a1685fSDinh Nguyen 209147a1685fSDinh Nguyen if (!(grstctl & GRSTCTL_AHBIDLE)) 209247a1685fSDinh Nguyen continue; 209347a1685fSDinh Nguyen 209447a1685fSDinh Nguyen break; /* reset done */ 209547a1685fSDinh Nguyen } 209647a1685fSDinh Nguyen 209747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "reset successful\n"); 209847a1685fSDinh Nguyen return 0; 209947a1685fSDinh Nguyen } 210047a1685fSDinh Nguyen 210147a1685fSDinh Nguyen /** 210247a1685fSDinh Nguyen * s3c_hsotg_core_init - issue softreset to the core 210347a1685fSDinh Nguyen * @hsotg: The device state 210447a1685fSDinh Nguyen * 210547a1685fSDinh Nguyen * Issue a soft reset to the core, and await the core finishing it. 210647a1685fSDinh Nguyen */ 210747a1685fSDinh Nguyen static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) 210847a1685fSDinh Nguyen { 210947a1685fSDinh Nguyen s3c_hsotg_corereset(hsotg); 211047a1685fSDinh Nguyen 211147a1685fSDinh Nguyen /* 211247a1685fSDinh Nguyen * we must now enable ep0 ready for host detection and then 211347a1685fSDinh Nguyen * set configuration. 211447a1685fSDinh Nguyen */ 211547a1685fSDinh Nguyen 211647a1685fSDinh Nguyen /* set the PLL on, remove the HNP/SRP and set the PHY */ 211747a1685fSDinh Nguyen writel(hsotg->phyif | GUSBCFG_TOUTCAL(7) | 211847a1685fSDinh Nguyen (0x5 << 10), hsotg->regs + GUSBCFG); 211947a1685fSDinh Nguyen 212047a1685fSDinh Nguyen s3c_hsotg_init_fifo(hsotg); 212147a1685fSDinh Nguyen 212247a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 212347a1685fSDinh Nguyen 212447a1685fSDinh Nguyen writel(1 << 18 | DCFG_DEVSPD_HS, hsotg->regs + DCFG); 212547a1685fSDinh Nguyen 212647a1685fSDinh Nguyen /* Clear any pending OTG interrupts */ 212747a1685fSDinh Nguyen writel(0xffffffff, hsotg->regs + GOTGINT); 212847a1685fSDinh Nguyen 212947a1685fSDinh Nguyen /* Clear any pending interrupts */ 213047a1685fSDinh Nguyen writel(0xffffffff, hsotg->regs + GINTSTS); 213147a1685fSDinh Nguyen 213247a1685fSDinh Nguyen writel(GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT | 213347a1685fSDinh Nguyen GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF | 213447a1685fSDinh Nguyen GINTSTS_CONIDSTSCHNG | GINTSTS_USBRST | 213547a1685fSDinh Nguyen GINTSTS_ENUMDONE | GINTSTS_OTGINT | 213647a1685fSDinh Nguyen GINTSTS_USBSUSP | GINTSTS_WKUPINT, 213747a1685fSDinh Nguyen hsotg->regs + GINTMSK); 213847a1685fSDinh Nguyen 213947a1685fSDinh Nguyen if (using_dma(hsotg)) 214047a1685fSDinh Nguyen writel(GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN | 214147a1685fSDinh Nguyen GAHBCFG_HBSTLEN_INCR4, 214247a1685fSDinh Nguyen hsotg->regs + GAHBCFG); 214347a1685fSDinh Nguyen else 214447a1685fSDinh Nguyen writel(((hsotg->dedicated_fifos) ? (GAHBCFG_NP_TXF_EMP_LVL | 214547a1685fSDinh Nguyen GAHBCFG_P_TXF_EMP_LVL) : 0) | 214647a1685fSDinh Nguyen GAHBCFG_GLBL_INTR_EN, 214747a1685fSDinh Nguyen hsotg->regs + GAHBCFG); 214847a1685fSDinh Nguyen 214947a1685fSDinh Nguyen /* 215047a1685fSDinh Nguyen * If INTknTXFEmpMsk is enabled, it's important to disable ep interrupts 215147a1685fSDinh Nguyen * when we have no data to transfer. Otherwise we get being flooded by 215247a1685fSDinh Nguyen * interrupts. 215347a1685fSDinh Nguyen */ 215447a1685fSDinh Nguyen 215547a1685fSDinh Nguyen writel(((hsotg->dedicated_fifos) ? DIEPMSK_TXFIFOEMPTY | 215647a1685fSDinh Nguyen DIEPMSK_INTKNTXFEMPMSK : 0) | 215747a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK | 215847a1685fSDinh Nguyen DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | 215947a1685fSDinh Nguyen DIEPMSK_INTKNEPMISMSK, 216047a1685fSDinh Nguyen hsotg->regs + DIEPMSK); 216147a1685fSDinh Nguyen 216247a1685fSDinh Nguyen /* 216347a1685fSDinh Nguyen * don't need XferCompl, we get that from RXFIFO in slave mode. In 216447a1685fSDinh Nguyen * DMA mode we may need this. 216547a1685fSDinh Nguyen */ 216647a1685fSDinh Nguyen writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK | 216747a1685fSDinh Nguyen DIEPMSK_TIMEOUTMSK) : 0) | 216847a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK | 216947a1685fSDinh Nguyen DOEPMSK_SETUPMSK, 217047a1685fSDinh Nguyen hsotg->regs + DOEPMSK); 217147a1685fSDinh Nguyen 217247a1685fSDinh Nguyen writel(0, hsotg->regs + DAINTMSK); 217347a1685fSDinh Nguyen 217447a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 217547a1685fSDinh Nguyen readl(hsotg->regs + DIEPCTL0), 217647a1685fSDinh Nguyen readl(hsotg->regs + DOEPCTL0)); 217747a1685fSDinh Nguyen 217847a1685fSDinh Nguyen /* enable in and out endpoint interrupts */ 217947a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT); 218047a1685fSDinh Nguyen 218147a1685fSDinh Nguyen /* 218247a1685fSDinh Nguyen * Enable the RXFIFO when in slave mode, as this is how we collect 218347a1685fSDinh Nguyen * the data. In DMA mode, we get events from the FIFO but also 218447a1685fSDinh Nguyen * things we cannot process, so do not use it. 218547a1685fSDinh Nguyen */ 218647a1685fSDinh Nguyen if (!using_dma(hsotg)) 218747a1685fSDinh Nguyen s3c_hsotg_en_gsint(hsotg, GINTSTS_RXFLVL); 218847a1685fSDinh Nguyen 218947a1685fSDinh Nguyen /* Enable interrupts for EP0 in and out */ 219047a1685fSDinh Nguyen s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1); 219147a1685fSDinh Nguyen s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1); 219247a1685fSDinh Nguyen 219347a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); 219447a1685fSDinh Nguyen udelay(10); /* see openiboot */ 219547a1685fSDinh Nguyen __bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE); 219647a1685fSDinh Nguyen 219747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL)); 219847a1685fSDinh Nguyen 219947a1685fSDinh Nguyen /* 220047a1685fSDinh Nguyen * DxEPCTL_USBActEp says RO in manual, but seems to be set by 220147a1685fSDinh Nguyen * writing to the EPCTL register.. 220247a1685fSDinh Nguyen */ 220347a1685fSDinh Nguyen 220447a1685fSDinh Nguyen /* set to read 1 8byte packet */ 220547a1685fSDinh Nguyen writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 220647a1685fSDinh Nguyen DXEPTSIZ_XFERSIZE(8), hsotg->regs + DOEPTSIZ0); 220747a1685fSDinh Nguyen 220847a1685fSDinh Nguyen writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | 220947a1685fSDinh Nguyen DXEPCTL_CNAK | DXEPCTL_EPENA | 221047a1685fSDinh Nguyen DXEPCTL_USBACTEP, 221147a1685fSDinh Nguyen hsotg->regs + DOEPCTL0); 221247a1685fSDinh Nguyen 221347a1685fSDinh Nguyen /* enable, but don't activate EP0in */ 221447a1685fSDinh Nguyen writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | 221547a1685fSDinh Nguyen DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0); 221647a1685fSDinh Nguyen 221747a1685fSDinh Nguyen s3c_hsotg_enqueue_setup(hsotg); 221847a1685fSDinh Nguyen 221947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 222047a1685fSDinh Nguyen readl(hsotg->regs + DIEPCTL0), 222147a1685fSDinh Nguyen readl(hsotg->regs + DOEPCTL0)); 222247a1685fSDinh Nguyen 222347a1685fSDinh Nguyen /* clear global NAKs */ 222447a1685fSDinh Nguyen writel(DCTL_CGOUTNAK | DCTL_CGNPINNAK, 222547a1685fSDinh Nguyen hsotg->regs + DCTL); 222647a1685fSDinh Nguyen 222747a1685fSDinh Nguyen /* must be at-least 3ms to allow bus to see disconnect */ 222847a1685fSDinh Nguyen mdelay(3); 222947a1685fSDinh Nguyen 223047a1685fSDinh Nguyen /* remove the soft-disconnect and let's go */ 223147a1685fSDinh Nguyen __bic32(hsotg->regs + DCTL, DCTL_SFTDISCON); 223247a1685fSDinh Nguyen } 223347a1685fSDinh Nguyen 223447a1685fSDinh Nguyen /** 223547a1685fSDinh Nguyen * s3c_hsotg_irq - handle device interrupt 223647a1685fSDinh Nguyen * @irq: The IRQ number triggered 223747a1685fSDinh Nguyen * @pw: The pw value when registered the handler. 223847a1685fSDinh Nguyen */ 223947a1685fSDinh Nguyen static irqreturn_t s3c_hsotg_irq(int irq, void *pw) 224047a1685fSDinh Nguyen { 224147a1685fSDinh Nguyen struct s3c_hsotg *hsotg = pw; 224247a1685fSDinh Nguyen int retry_count = 8; 224347a1685fSDinh Nguyen u32 gintsts; 224447a1685fSDinh Nguyen u32 gintmsk; 224547a1685fSDinh Nguyen 224647a1685fSDinh Nguyen spin_lock(&hsotg->lock); 224747a1685fSDinh Nguyen irq_retry: 224847a1685fSDinh Nguyen gintsts = readl(hsotg->regs + GINTSTS); 224947a1685fSDinh Nguyen gintmsk = readl(hsotg->regs + GINTMSK); 225047a1685fSDinh Nguyen 225147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", 225247a1685fSDinh Nguyen __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); 225347a1685fSDinh Nguyen 225447a1685fSDinh Nguyen gintsts &= gintmsk; 225547a1685fSDinh Nguyen 225647a1685fSDinh Nguyen if (gintsts & GINTSTS_OTGINT) { 225747a1685fSDinh Nguyen u32 otgint = readl(hsotg->regs + GOTGINT); 225847a1685fSDinh Nguyen 225947a1685fSDinh Nguyen dev_info(hsotg->dev, "OTGInt: %08x\n", otgint); 226047a1685fSDinh Nguyen 226147a1685fSDinh Nguyen writel(otgint, hsotg->regs + GOTGINT); 226247a1685fSDinh Nguyen } 226347a1685fSDinh Nguyen 226447a1685fSDinh Nguyen if (gintsts & GINTSTS_SESSREQINT) { 226547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__); 226647a1685fSDinh Nguyen writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS); 226747a1685fSDinh Nguyen } 226847a1685fSDinh Nguyen 226947a1685fSDinh Nguyen if (gintsts & GINTSTS_ENUMDONE) { 227047a1685fSDinh Nguyen writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS); 227147a1685fSDinh Nguyen 227247a1685fSDinh Nguyen s3c_hsotg_irq_enumdone(hsotg); 227347a1685fSDinh Nguyen } 227447a1685fSDinh Nguyen 227547a1685fSDinh Nguyen if (gintsts & GINTSTS_CONIDSTSCHNG) { 227647a1685fSDinh Nguyen dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n", 227747a1685fSDinh Nguyen readl(hsotg->regs + DSTS), 227847a1685fSDinh Nguyen readl(hsotg->regs + GOTGCTL)); 227947a1685fSDinh Nguyen 228047a1685fSDinh Nguyen writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS); 228147a1685fSDinh Nguyen } 228247a1685fSDinh Nguyen 228347a1685fSDinh Nguyen if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { 228447a1685fSDinh Nguyen u32 daint = readl(hsotg->regs + DAINT); 228547a1685fSDinh Nguyen u32 daintmsk = readl(hsotg->regs + DAINTMSK); 228647a1685fSDinh Nguyen u32 daint_out, daint_in; 228747a1685fSDinh Nguyen int ep; 228847a1685fSDinh Nguyen 228947a1685fSDinh Nguyen daint &= daintmsk; 229047a1685fSDinh Nguyen daint_out = daint >> DAINT_OUTEP_SHIFT; 229147a1685fSDinh Nguyen daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); 229247a1685fSDinh Nguyen 229347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); 229447a1685fSDinh Nguyen 229547a1685fSDinh Nguyen for (ep = 0; ep < 15 && daint_out; ep++, daint_out >>= 1) { 229647a1685fSDinh Nguyen if (daint_out & 1) 229747a1685fSDinh Nguyen s3c_hsotg_epint(hsotg, ep, 0); 229847a1685fSDinh Nguyen } 229947a1685fSDinh Nguyen 230047a1685fSDinh Nguyen for (ep = 0; ep < 15 && daint_in; ep++, daint_in >>= 1) { 230147a1685fSDinh Nguyen if (daint_in & 1) 230247a1685fSDinh Nguyen s3c_hsotg_epint(hsotg, ep, 1); 230347a1685fSDinh Nguyen } 230447a1685fSDinh Nguyen } 230547a1685fSDinh Nguyen 230647a1685fSDinh Nguyen if (gintsts & GINTSTS_USBRST) { 230747a1685fSDinh Nguyen 230847a1685fSDinh Nguyen u32 usb_status = readl(hsotg->regs + GOTGCTL); 230947a1685fSDinh Nguyen 231047a1685fSDinh Nguyen dev_info(hsotg->dev, "%s: USBRst\n", __func__); 231147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", 231247a1685fSDinh Nguyen readl(hsotg->regs + GNPTXSTS)); 231347a1685fSDinh Nguyen 231447a1685fSDinh Nguyen writel(GINTSTS_USBRST, hsotg->regs + GINTSTS); 231547a1685fSDinh Nguyen 231647a1685fSDinh Nguyen if (usb_status & GOTGCTL_BSESVLD) { 231747a1685fSDinh Nguyen if (time_after(jiffies, hsotg->last_rst + 231847a1685fSDinh Nguyen msecs_to_jiffies(200))) { 231947a1685fSDinh Nguyen 232047a1685fSDinh Nguyen kill_all_requests(hsotg, &hsotg->eps[0], 232147a1685fSDinh Nguyen -ECONNRESET, true); 232247a1685fSDinh Nguyen 232347a1685fSDinh Nguyen s3c_hsotg_core_init(hsotg); 232447a1685fSDinh Nguyen hsotg->last_rst = jiffies; 232547a1685fSDinh Nguyen } 232647a1685fSDinh Nguyen } 232747a1685fSDinh Nguyen } 232847a1685fSDinh Nguyen 232947a1685fSDinh Nguyen /* check both FIFOs */ 233047a1685fSDinh Nguyen 233147a1685fSDinh Nguyen if (gintsts & GINTSTS_NPTXFEMP) { 233247a1685fSDinh Nguyen dev_dbg(hsotg->dev, "NPTxFEmp\n"); 233347a1685fSDinh Nguyen 233447a1685fSDinh Nguyen /* 233547a1685fSDinh Nguyen * Disable the interrupt to stop it happening again 233647a1685fSDinh Nguyen * unless one of these endpoint routines decides that 233747a1685fSDinh Nguyen * it needs re-enabling 233847a1685fSDinh Nguyen */ 233947a1685fSDinh Nguyen 234047a1685fSDinh Nguyen s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP); 234147a1685fSDinh Nguyen s3c_hsotg_irq_fifoempty(hsotg, false); 234247a1685fSDinh Nguyen } 234347a1685fSDinh Nguyen 234447a1685fSDinh Nguyen if (gintsts & GINTSTS_PTXFEMP) { 234547a1685fSDinh Nguyen dev_dbg(hsotg->dev, "PTxFEmp\n"); 234647a1685fSDinh Nguyen 234747a1685fSDinh Nguyen /* See note in GINTSTS_NPTxFEmp */ 234847a1685fSDinh Nguyen 234947a1685fSDinh Nguyen s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP); 235047a1685fSDinh Nguyen s3c_hsotg_irq_fifoempty(hsotg, true); 235147a1685fSDinh Nguyen } 235247a1685fSDinh Nguyen 235347a1685fSDinh Nguyen if (gintsts & GINTSTS_RXFLVL) { 235447a1685fSDinh Nguyen /* 235547a1685fSDinh Nguyen * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, 235647a1685fSDinh Nguyen * we need to retry s3c_hsotg_handle_rx if this is still 235747a1685fSDinh Nguyen * set. 235847a1685fSDinh Nguyen */ 235947a1685fSDinh Nguyen 236047a1685fSDinh Nguyen s3c_hsotg_handle_rx(hsotg); 236147a1685fSDinh Nguyen } 236247a1685fSDinh Nguyen 236347a1685fSDinh Nguyen if (gintsts & GINTSTS_MODEMIS) { 236447a1685fSDinh Nguyen dev_warn(hsotg->dev, "warning, mode mismatch triggered\n"); 236547a1685fSDinh Nguyen writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS); 236647a1685fSDinh Nguyen } 236747a1685fSDinh Nguyen 236847a1685fSDinh Nguyen if (gintsts & GINTSTS_USBSUSP) { 236947a1685fSDinh Nguyen dev_info(hsotg->dev, "GINTSTS_USBSusp\n"); 237047a1685fSDinh Nguyen writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS); 237147a1685fSDinh Nguyen 237247a1685fSDinh Nguyen call_gadget(hsotg, suspend); 237347a1685fSDinh Nguyen } 237447a1685fSDinh Nguyen 237547a1685fSDinh Nguyen if (gintsts & GINTSTS_WKUPINT) { 237647a1685fSDinh Nguyen dev_info(hsotg->dev, "GINTSTS_WkUpIn\n"); 237747a1685fSDinh Nguyen writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS); 237847a1685fSDinh Nguyen 237947a1685fSDinh Nguyen call_gadget(hsotg, resume); 238047a1685fSDinh Nguyen } 238147a1685fSDinh Nguyen 238247a1685fSDinh Nguyen if (gintsts & GINTSTS_ERLYSUSP) { 238347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); 238447a1685fSDinh Nguyen writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS); 238547a1685fSDinh Nguyen } 238647a1685fSDinh Nguyen 238747a1685fSDinh Nguyen /* 238847a1685fSDinh Nguyen * these next two seem to crop-up occasionally causing the core 238947a1685fSDinh Nguyen * to shutdown the USB transfer, so try clearing them and logging 239047a1685fSDinh Nguyen * the occurrence. 239147a1685fSDinh Nguyen */ 239247a1685fSDinh Nguyen 239347a1685fSDinh Nguyen if (gintsts & GINTSTS_GOUTNAKEFF) { 239447a1685fSDinh Nguyen dev_info(hsotg->dev, "GOUTNakEff triggered\n"); 239547a1685fSDinh Nguyen 239647a1685fSDinh Nguyen writel(DCTL_CGOUTNAK, hsotg->regs + DCTL); 239747a1685fSDinh Nguyen 239847a1685fSDinh Nguyen s3c_hsotg_dump(hsotg); 239947a1685fSDinh Nguyen } 240047a1685fSDinh Nguyen 240147a1685fSDinh Nguyen if (gintsts & GINTSTS_GINNAKEFF) { 240247a1685fSDinh Nguyen dev_info(hsotg->dev, "GINNakEff triggered\n"); 240347a1685fSDinh Nguyen 240447a1685fSDinh Nguyen writel(DCTL_CGNPINNAK, hsotg->regs + DCTL); 240547a1685fSDinh Nguyen 240647a1685fSDinh Nguyen s3c_hsotg_dump(hsotg); 240747a1685fSDinh Nguyen } 240847a1685fSDinh Nguyen 240947a1685fSDinh Nguyen /* 241047a1685fSDinh Nguyen * if we've had fifo events, we should try and go around the 241147a1685fSDinh Nguyen * loop again to see if there's any point in returning yet. 241247a1685fSDinh Nguyen */ 241347a1685fSDinh Nguyen 241447a1685fSDinh Nguyen if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) 241547a1685fSDinh Nguyen goto irq_retry; 241647a1685fSDinh Nguyen 241747a1685fSDinh Nguyen spin_unlock(&hsotg->lock); 241847a1685fSDinh Nguyen 241947a1685fSDinh Nguyen return IRQ_HANDLED; 242047a1685fSDinh Nguyen } 242147a1685fSDinh Nguyen 242247a1685fSDinh Nguyen /** 242347a1685fSDinh Nguyen * s3c_hsotg_ep_enable - enable the given endpoint 242447a1685fSDinh Nguyen * @ep: The USB endpint to configure 242547a1685fSDinh Nguyen * @desc: The USB endpoint descriptor to configure with. 242647a1685fSDinh Nguyen * 242747a1685fSDinh Nguyen * This is called from the USB gadget code's usb_ep_enable(). 242847a1685fSDinh Nguyen */ 242947a1685fSDinh Nguyen static int s3c_hsotg_ep_enable(struct usb_ep *ep, 243047a1685fSDinh Nguyen const struct usb_endpoint_descriptor *desc) 243147a1685fSDinh Nguyen { 243247a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 243347a1685fSDinh Nguyen struct s3c_hsotg *hsotg = hs_ep->parent; 243447a1685fSDinh Nguyen unsigned long flags; 243547a1685fSDinh Nguyen int index = hs_ep->index; 243647a1685fSDinh Nguyen u32 epctrl_reg; 243747a1685fSDinh Nguyen u32 epctrl; 243847a1685fSDinh Nguyen u32 mps; 243947a1685fSDinh Nguyen int dir_in; 244047a1685fSDinh Nguyen int ret = 0; 244147a1685fSDinh Nguyen 244247a1685fSDinh Nguyen dev_dbg(hsotg->dev, 244347a1685fSDinh Nguyen "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", 244447a1685fSDinh Nguyen __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes, 244547a1685fSDinh Nguyen desc->wMaxPacketSize, desc->bInterval); 244647a1685fSDinh Nguyen 244747a1685fSDinh Nguyen /* not to be called for EP0 */ 244847a1685fSDinh Nguyen WARN_ON(index == 0); 244947a1685fSDinh Nguyen 245047a1685fSDinh Nguyen dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; 245147a1685fSDinh Nguyen if (dir_in != hs_ep->dir_in) { 245247a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__); 245347a1685fSDinh Nguyen return -EINVAL; 245447a1685fSDinh Nguyen } 245547a1685fSDinh Nguyen 245647a1685fSDinh Nguyen mps = usb_endpoint_maxp(desc); 245747a1685fSDinh Nguyen 245847a1685fSDinh Nguyen /* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */ 245947a1685fSDinh Nguyen 246047a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 246147a1685fSDinh Nguyen epctrl = readl(hsotg->regs + epctrl_reg); 246247a1685fSDinh Nguyen 246347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", 246447a1685fSDinh Nguyen __func__, epctrl, epctrl_reg); 246547a1685fSDinh Nguyen 246647a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 246747a1685fSDinh Nguyen 246847a1685fSDinh Nguyen epctrl &= ~(DXEPCTL_EPTYPE_MASK | DXEPCTL_MPS_MASK); 246947a1685fSDinh Nguyen epctrl |= DXEPCTL_MPS(mps); 247047a1685fSDinh Nguyen 247147a1685fSDinh Nguyen /* 247247a1685fSDinh Nguyen * mark the endpoint as active, otherwise the core may ignore 247347a1685fSDinh Nguyen * transactions entirely for this endpoint 247447a1685fSDinh Nguyen */ 247547a1685fSDinh Nguyen epctrl |= DXEPCTL_USBACTEP; 247647a1685fSDinh Nguyen 247747a1685fSDinh Nguyen /* 247847a1685fSDinh Nguyen * set the NAK status on the endpoint, otherwise we might try and 247947a1685fSDinh Nguyen * do something with data that we've yet got a request to process 248047a1685fSDinh Nguyen * since the RXFIFO will take data for an endpoint even if the 248147a1685fSDinh Nguyen * size register hasn't been set. 248247a1685fSDinh Nguyen */ 248347a1685fSDinh Nguyen 248447a1685fSDinh Nguyen epctrl |= DXEPCTL_SNAK; 248547a1685fSDinh Nguyen 248647a1685fSDinh Nguyen /* update the endpoint state */ 248747a1685fSDinh Nguyen s3c_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps); 248847a1685fSDinh Nguyen 248947a1685fSDinh Nguyen /* default, set to non-periodic */ 249047a1685fSDinh Nguyen hs_ep->isochronous = 0; 249147a1685fSDinh Nguyen hs_ep->periodic = 0; 249247a1685fSDinh Nguyen hs_ep->halted = 0; 249347a1685fSDinh Nguyen hs_ep->interval = desc->bInterval; 249447a1685fSDinh Nguyen 249547a1685fSDinh Nguyen if (hs_ep->interval > 1 && hs_ep->mc > 1) 249647a1685fSDinh Nguyen dev_err(hsotg->dev, "MC > 1 when interval is not 1\n"); 249747a1685fSDinh Nguyen 249847a1685fSDinh Nguyen switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { 249947a1685fSDinh Nguyen case USB_ENDPOINT_XFER_ISOC: 250047a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_ISO; 250147a1685fSDinh Nguyen epctrl |= DXEPCTL_SETEVENFR; 250247a1685fSDinh Nguyen hs_ep->isochronous = 1; 250347a1685fSDinh Nguyen if (dir_in) 250447a1685fSDinh Nguyen hs_ep->periodic = 1; 250547a1685fSDinh Nguyen break; 250647a1685fSDinh Nguyen 250747a1685fSDinh Nguyen case USB_ENDPOINT_XFER_BULK: 250847a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_BULK; 250947a1685fSDinh Nguyen break; 251047a1685fSDinh Nguyen 251147a1685fSDinh Nguyen case USB_ENDPOINT_XFER_INT: 251247a1685fSDinh Nguyen if (dir_in) { 251347a1685fSDinh Nguyen /* 251447a1685fSDinh Nguyen * Allocate our TxFNum by simply using the index 251547a1685fSDinh Nguyen * of the endpoint for the moment. We could do 251647a1685fSDinh Nguyen * something better if the host indicates how 251747a1685fSDinh Nguyen * many FIFOs we are expecting to use. 251847a1685fSDinh Nguyen */ 251947a1685fSDinh Nguyen 252047a1685fSDinh Nguyen hs_ep->periodic = 1; 252147a1685fSDinh Nguyen epctrl |= DXEPCTL_TXFNUM(index); 252247a1685fSDinh Nguyen } 252347a1685fSDinh Nguyen 252447a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_INTERRUPT; 252547a1685fSDinh Nguyen break; 252647a1685fSDinh Nguyen 252747a1685fSDinh Nguyen case USB_ENDPOINT_XFER_CONTROL: 252847a1685fSDinh Nguyen epctrl |= DXEPCTL_EPTYPE_CONTROL; 252947a1685fSDinh Nguyen break; 253047a1685fSDinh Nguyen } 253147a1685fSDinh Nguyen 253247a1685fSDinh Nguyen /* 253347a1685fSDinh Nguyen * if the hardware has dedicated fifos, we must give each IN EP 253447a1685fSDinh Nguyen * a unique tx-fifo even if it is non-periodic. 253547a1685fSDinh Nguyen */ 253647a1685fSDinh Nguyen if (dir_in && hsotg->dedicated_fifos) 253747a1685fSDinh Nguyen epctrl |= DXEPCTL_TXFNUM(index); 253847a1685fSDinh Nguyen 253947a1685fSDinh Nguyen /* for non control endpoints, set PID to D0 */ 254047a1685fSDinh Nguyen if (index) 254147a1685fSDinh Nguyen epctrl |= DXEPCTL_SETD0PID; 254247a1685fSDinh Nguyen 254347a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", 254447a1685fSDinh Nguyen __func__, epctrl); 254547a1685fSDinh Nguyen 254647a1685fSDinh Nguyen writel(epctrl, hsotg->regs + epctrl_reg); 254747a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n", 254847a1685fSDinh Nguyen __func__, readl(hsotg->regs + epctrl_reg)); 254947a1685fSDinh Nguyen 255047a1685fSDinh Nguyen /* enable the endpoint interrupt */ 255147a1685fSDinh Nguyen s3c_hsotg_ctrl_epint(hsotg, index, dir_in, 1); 255247a1685fSDinh Nguyen 255347a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 255447a1685fSDinh Nguyen return ret; 255547a1685fSDinh Nguyen } 255647a1685fSDinh Nguyen 255747a1685fSDinh Nguyen /** 255847a1685fSDinh Nguyen * s3c_hsotg_ep_disable - disable given endpoint 255947a1685fSDinh Nguyen * @ep: The endpoint to disable. 256047a1685fSDinh Nguyen */ 256147a1685fSDinh Nguyen static int s3c_hsotg_ep_disable(struct usb_ep *ep) 256247a1685fSDinh Nguyen { 256347a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 256447a1685fSDinh Nguyen struct s3c_hsotg *hsotg = hs_ep->parent; 256547a1685fSDinh Nguyen int dir_in = hs_ep->dir_in; 256647a1685fSDinh Nguyen int index = hs_ep->index; 256747a1685fSDinh Nguyen unsigned long flags; 256847a1685fSDinh Nguyen u32 epctrl_reg; 256947a1685fSDinh Nguyen u32 ctrl; 257047a1685fSDinh Nguyen 257147a1685fSDinh Nguyen dev_info(hsotg->dev, "%s(ep %p)\n", __func__, ep); 257247a1685fSDinh Nguyen 257347a1685fSDinh Nguyen if (ep == &hsotg->eps[0].ep) { 257447a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: called for ep0\n", __func__); 257547a1685fSDinh Nguyen return -EINVAL; 257647a1685fSDinh Nguyen } 257747a1685fSDinh Nguyen 257847a1685fSDinh Nguyen epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 257947a1685fSDinh Nguyen 258047a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 258147a1685fSDinh Nguyen /* terminate all requests with shutdown */ 258247a1685fSDinh Nguyen kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false); 258347a1685fSDinh Nguyen 258447a1685fSDinh Nguyen 258547a1685fSDinh Nguyen ctrl = readl(hsotg->regs + epctrl_reg); 258647a1685fSDinh Nguyen ctrl &= ~DXEPCTL_EPENA; 258747a1685fSDinh Nguyen ctrl &= ~DXEPCTL_USBACTEP; 258847a1685fSDinh Nguyen ctrl |= DXEPCTL_SNAK; 258947a1685fSDinh Nguyen 259047a1685fSDinh Nguyen dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 259147a1685fSDinh Nguyen writel(ctrl, hsotg->regs + epctrl_reg); 259247a1685fSDinh Nguyen 259347a1685fSDinh Nguyen /* disable endpoint interrupts */ 259447a1685fSDinh Nguyen s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0); 259547a1685fSDinh Nguyen 259647a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 259747a1685fSDinh Nguyen return 0; 259847a1685fSDinh Nguyen } 259947a1685fSDinh Nguyen 260047a1685fSDinh Nguyen /** 260147a1685fSDinh Nguyen * on_list - check request is on the given endpoint 260247a1685fSDinh Nguyen * @ep: The endpoint to check. 260347a1685fSDinh Nguyen * @test: The request to test if it is on the endpoint. 260447a1685fSDinh Nguyen */ 260547a1685fSDinh Nguyen static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test) 260647a1685fSDinh Nguyen { 260747a1685fSDinh Nguyen struct s3c_hsotg_req *req, *treq; 260847a1685fSDinh Nguyen 260947a1685fSDinh Nguyen list_for_each_entry_safe(req, treq, &ep->queue, queue) { 261047a1685fSDinh Nguyen if (req == test) 261147a1685fSDinh Nguyen return true; 261247a1685fSDinh Nguyen } 261347a1685fSDinh Nguyen 261447a1685fSDinh Nguyen return false; 261547a1685fSDinh Nguyen } 261647a1685fSDinh Nguyen 261747a1685fSDinh Nguyen /** 261847a1685fSDinh Nguyen * s3c_hsotg_ep_dequeue - dequeue given endpoint 261947a1685fSDinh Nguyen * @ep: The endpoint to dequeue. 262047a1685fSDinh Nguyen * @req: The request to be removed from a queue. 262147a1685fSDinh Nguyen */ 262247a1685fSDinh Nguyen static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) 262347a1685fSDinh Nguyen { 262447a1685fSDinh Nguyen struct s3c_hsotg_req *hs_req = our_req(req); 262547a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 262647a1685fSDinh Nguyen struct s3c_hsotg *hs = hs_ep->parent; 262747a1685fSDinh Nguyen unsigned long flags; 262847a1685fSDinh Nguyen 262947a1685fSDinh Nguyen dev_info(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); 263047a1685fSDinh Nguyen 263147a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 263247a1685fSDinh Nguyen 263347a1685fSDinh Nguyen if (!on_list(hs_ep, hs_req)) { 263447a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 263547a1685fSDinh Nguyen return -EINVAL; 263647a1685fSDinh Nguyen } 263747a1685fSDinh Nguyen 263847a1685fSDinh Nguyen s3c_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET); 263947a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 264047a1685fSDinh Nguyen 264147a1685fSDinh Nguyen return 0; 264247a1685fSDinh Nguyen } 264347a1685fSDinh Nguyen 264447a1685fSDinh Nguyen /** 264547a1685fSDinh Nguyen * s3c_hsotg_ep_sethalt - set halt on a given endpoint 264647a1685fSDinh Nguyen * @ep: The endpoint to set halt. 264747a1685fSDinh Nguyen * @value: Set or unset the halt. 264847a1685fSDinh Nguyen */ 264947a1685fSDinh Nguyen static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) 265047a1685fSDinh Nguyen { 265147a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 265247a1685fSDinh Nguyen struct s3c_hsotg *hs = hs_ep->parent; 265347a1685fSDinh Nguyen int index = hs_ep->index; 265447a1685fSDinh Nguyen u32 epreg; 265547a1685fSDinh Nguyen u32 epctl; 265647a1685fSDinh Nguyen u32 xfertype; 265747a1685fSDinh Nguyen 265847a1685fSDinh Nguyen dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); 265947a1685fSDinh Nguyen 266047a1685fSDinh Nguyen if (index == 0) { 266147a1685fSDinh Nguyen if (value) 266247a1685fSDinh Nguyen s3c_hsotg_stall_ep0(hs); 266347a1685fSDinh Nguyen else 266447a1685fSDinh Nguyen dev_warn(hs->dev, 266547a1685fSDinh Nguyen "%s: can't clear halt on ep0\n", __func__); 266647a1685fSDinh Nguyen return 0; 266747a1685fSDinh Nguyen } 266847a1685fSDinh Nguyen 266947a1685fSDinh Nguyen /* write both IN and OUT control registers */ 267047a1685fSDinh Nguyen 267147a1685fSDinh Nguyen epreg = DIEPCTL(index); 267247a1685fSDinh Nguyen epctl = readl(hs->regs + epreg); 267347a1685fSDinh Nguyen 267447a1685fSDinh Nguyen if (value) { 267547a1685fSDinh Nguyen epctl |= DXEPCTL_STALL + DXEPCTL_SNAK; 267647a1685fSDinh Nguyen if (epctl & DXEPCTL_EPENA) 267747a1685fSDinh Nguyen epctl |= DXEPCTL_EPDIS; 267847a1685fSDinh Nguyen } else { 267947a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 268047a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 268147a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 268247a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 268347a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 268447a1685fSDinh Nguyen } 268547a1685fSDinh Nguyen 268647a1685fSDinh Nguyen writel(epctl, hs->regs + epreg); 268747a1685fSDinh Nguyen 268847a1685fSDinh Nguyen epreg = DOEPCTL(index); 268947a1685fSDinh Nguyen epctl = readl(hs->regs + epreg); 269047a1685fSDinh Nguyen 269147a1685fSDinh Nguyen if (value) 269247a1685fSDinh Nguyen epctl |= DXEPCTL_STALL; 269347a1685fSDinh Nguyen else { 269447a1685fSDinh Nguyen epctl &= ~DXEPCTL_STALL; 269547a1685fSDinh Nguyen xfertype = epctl & DXEPCTL_EPTYPE_MASK; 269647a1685fSDinh Nguyen if (xfertype == DXEPCTL_EPTYPE_BULK || 269747a1685fSDinh Nguyen xfertype == DXEPCTL_EPTYPE_INTERRUPT) 269847a1685fSDinh Nguyen epctl |= DXEPCTL_SETD0PID; 269947a1685fSDinh Nguyen } 270047a1685fSDinh Nguyen 270147a1685fSDinh Nguyen writel(epctl, hs->regs + epreg); 270247a1685fSDinh Nguyen 270347a1685fSDinh Nguyen hs_ep->halted = value; 270447a1685fSDinh Nguyen 270547a1685fSDinh Nguyen return 0; 270647a1685fSDinh Nguyen } 270747a1685fSDinh Nguyen 270847a1685fSDinh Nguyen /** 270947a1685fSDinh Nguyen * s3c_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held 271047a1685fSDinh Nguyen * @ep: The endpoint to set halt. 271147a1685fSDinh Nguyen * @value: Set or unset the halt. 271247a1685fSDinh Nguyen */ 271347a1685fSDinh Nguyen static int s3c_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) 271447a1685fSDinh Nguyen { 271547a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep = our_ep(ep); 271647a1685fSDinh Nguyen struct s3c_hsotg *hs = hs_ep->parent; 271747a1685fSDinh Nguyen unsigned long flags = 0; 271847a1685fSDinh Nguyen int ret = 0; 271947a1685fSDinh Nguyen 272047a1685fSDinh Nguyen spin_lock_irqsave(&hs->lock, flags); 272147a1685fSDinh Nguyen ret = s3c_hsotg_ep_sethalt(ep, value); 272247a1685fSDinh Nguyen spin_unlock_irqrestore(&hs->lock, flags); 272347a1685fSDinh Nguyen 272447a1685fSDinh Nguyen return ret; 272547a1685fSDinh Nguyen } 272647a1685fSDinh Nguyen 272747a1685fSDinh Nguyen static struct usb_ep_ops s3c_hsotg_ep_ops = { 272847a1685fSDinh Nguyen .enable = s3c_hsotg_ep_enable, 272947a1685fSDinh Nguyen .disable = s3c_hsotg_ep_disable, 273047a1685fSDinh Nguyen .alloc_request = s3c_hsotg_ep_alloc_request, 273147a1685fSDinh Nguyen .free_request = s3c_hsotg_ep_free_request, 273247a1685fSDinh Nguyen .queue = s3c_hsotg_ep_queue_lock, 273347a1685fSDinh Nguyen .dequeue = s3c_hsotg_ep_dequeue, 273447a1685fSDinh Nguyen .set_halt = s3c_hsotg_ep_sethalt_lock, 273547a1685fSDinh Nguyen /* note, don't believe we have any call for the fifo routines */ 273647a1685fSDinh Nguyen }; 273747a1685fSDinh Nguyen 273847a1685fSDinh Nguyen /** 273947a1685fSDinh Nguyen * s3c_hsotg_phy_enable - enable platform phy dev 274047a1685fSDinh Nguyen * @hsotg: The driver state 274147a1685fSDinh Nguyen * 274247a1685fSDinh Nguyen * A wrapper for platform code responsible for controlling 274347a1685fSDinh Nguyen * low-level USB code 274447a1685fSDinh Nguyen */ 274547a1685fSDinh Nguyen static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg) 274647a1685fSDinh Nguyen { 274747a1685fSDinh Nguyen struct platform_device *pdev = to_platform_device(hsotg->dev); 274847a1685fSDinh Nguyen 274947a1685fSDinh Nguyen dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev); 275047a1685fSDinh Nguyen 2751ca2c5ba8SKamil Debski if (hsotg->uphy) 2752ca2c5ba8SKamil Debski usb_phy_init(hsotg->uphy); 2753ca2c5ba8SKamil Debski else if (hsotg->plat && hsotg->plat->phy_init) 2754ca2c5ba8SKamil Debski hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); 2755ca2c5ba8SKamil Debski else { 275647a1685fSDinh Nguyen phy_init(hsotg->phy); 275747a1685fSDinh Nguyen phy_power_on(hsotg->phy); 2758ca2c5ba8SKamil Debski } 275947a1685fSDinh Nguyen } 276047a1685fSDinh Nguyen 276147a1685fSDinh Nguyen /** 276247a1685fSDinh Nguyen * s3c_hsotg_phy_disable - disable platform phy dev 276347a1685fSDinh Nguyen * @hsotg: The driver state 276447a1685fSDinh Nguyen * 276547a1685fSDinh Nguyen * A wrapper for platform code responsible for controlling 276647a1685fSDinh Nguyen * low-level USB code 276747a1685fSDinh Nguyen */ 276847a1685fSDinh Nguyen static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg) 276947a1685fSDinh Nguyen { 277047a1685fSDinh Nguyen struct platform_device *pdev = to_platform_device(hsotg->dev); 277147a1685fSDinh Nguyen 2772ca2c5ba8SKamil Debski if (hsotg->uphy) 2773ca2c5ba8SKamil Debski usb_phy_shutdown(hsotg->uphy); 2774ca2c5ba8SKamil Debski else if (hsotg->plat && hsotg->plat->phy_exit) 2775ca2c5ba8SKamil Debski hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); 2776ca2c5ba8SKamil Debski else { 277747a1685fSDinh Nguyen phy_power_off(hsotg->phy); 277847a1685fSDinh Nguyen phy_exit(hsotg->phy); 2779ca2c5ba8SKamil Debski } 278047a1685fSDinh Nguyen } 278147a1685fSDinh Nguyen 278247a1685fSDinh Nguyen /** 278347a1685fSDinh Nguyen * s3c_hsotg_init - initalize the usb core 278447a1685fSDinh Nguyen * @hsotg: The driver state 278547a1685fSDinh Nguyen */ 278647a1685fSDinh Nguyen static void s3c_hsotg_init(struct s3c_hsotg *hsotg) 278747a1685fSDinh Nguyen { 278847a1685fSDinh Nguyen /* unmask subset of endpoint interrupts */ 278947a1685fSDinh Nguyen 279047a1685fSDinh Nguyen writel(DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | 279147a1685fSDinh Nguyen DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK, 279247a1685fSDinh Nguyen hsotg->regs + DIEPMSK); 279347a1685fSDinh Nguyen 279447a1685fSDinh Nguyen writel(DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK | 279547a1685fSDinh Nguyen DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK, 279647a1685fSDinh Nguyen hsotg->regs + DOEPMSK); 279747a1685fSDinh Nguyen 279847a1685fSDinh Nguyen writel(0, hsotg->regs + DAINTMSK); 279947a1685fSDinh Nguyen 280047a1685fSDinh Nguyen /* Be in disconnected state until gadget is registered */ 280147a1685fSDinh Nguyen __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); 280247a1685fSDinh Nguyen 280347a1685fSDinh Nguyen if (0) { 280447a1685fSDinh Nguyen /* post global nak until we're ready */ 280547a1685fSDinh Nguyen writel(DCTL_SGNPINNAK | DCTL_SGOUTNAK, 280647a1685fSDinh Nguyen hsotg->regs + DCTL); 280747a1685fSDinh Nguyen } 280847a1685fSDinh Nguyen 280947a1685fSDinh Nguyen /* setup fifos */ 281047a1685fSDinh Nguyen 281147a1685fSDinh Nguyen dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 281247a1685fSDinh Nguyen readl(hsotg->regs + GRXFSIZ), 281347a1685fSDinh Nguyen readl(hsotg->regs + GNPTXFSIZ)); 281447a1685fSDinh Nguyen 281547a1685fSDinh Nguyen s3c_hsotg_init_fifo(hsotg); 281647a1685fSDinh Nguyen 281747a1685fSDinh Nguyen /* set the PLL on, remove the HNP/SRP and set the PHY */ 281847a1685fSDinh Nguyen writel(GUSBCFG_PHYIF16 | GUSBCFG_TOUTCAL(7) | (0x5 << 10), 281947a1685fSDinh Nguyen hsotg->regs + GUSBCFG); 282047a1685fSDinh Nguyen 282147a1685fSDinh Nguyen writel(using_dma(hsotg) ? GAHBCFG_DMA_EN : 0x0, 282247a1685fSDinh Nguyen hsotg->regs + GAHBCFG); 282347a1685fSDinh Nguyen } 282447a1685fSDinh Nguyen 282547a1685fSDinh Nguyen /** 282647a1685fSDinh Nguyen * s3c_hsotg_udc_start - prepare the udc for work 282747a1685fSDinh Nguyen * @gadget: The usb gadget state 282847a1685fSDinh Nguyen * @driver: The usb gadget driver 282947a1685fSDinh Nguyen * 283047a1685fSDinh Nguyen * Perform initialization to prepare udc device and driver 283147a1685fSDinh Nguyen * to work. 283247a1685fSDinh Nguyen */ 283347a1685fSDinh Nguyen static int s3c_hsotg_udc_start(struct usb_gadget *gadget, 283447a1685fSDinh Nguyen struct usb_gadget_driver *driver) 283547a1685fSDinh Nguyen { 283647a1685fSDinh Nguyen struct s3c_hsotg *hsotg = to_hsotg(gadget); 283747a1685fSDinh Nguyen int ret; 283847a1685fSDinh Nguyen 283947a1685fSDinh Nguyen if (!hsotg) { 284047a1685fSDinh Nguyen pr_err("%s: called with no device\n", __func__); 284147a1685fSDinh Nguyen return -ENODEV; 284247a1685fSDinh Nguyen } 284347a1685fSDinh Nguyen 284447a1685fSDinh Nguyen if (!driver) { 284547a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: no driver\n", __func__); 284647a1685fSDinh Nguyen return -EINVAL; 284747a1685fSDinh Nguyen } 284847a1685fSDinh Nguyen 284947a1685fSDinh Nguyen if (driver->max_speed < USB_SPEED_FULL) 285047a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: bad speed\n", __func__); 285147a1685fSDinh Nguyen 285247a1685fSDinh Nguyen if (!driver->setup) { 285347a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: missing entry points\n", __func__); 285447a1685fSDinh Nguyen return -EINVAL; 285547a1685fSDinh Nguyen } 285647a1685fSDinh Nguyen 285747a1685fSDinh Nguyen WARN_ON(hsotg->driver); 285847a1685fSDinh Nguyen 285947a1685fSDinh Nguyen driver->driver.bus = NULL; 286047a1685fSDinh Nguyen hsotg->driver = driver; 286147a1685fSDinh Nguyen hsotg->gadget.dev.of_node = hsotg->dev->of_node; 286247a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 286347a1685fSDinh Nguyen 286447a1685fSDinh Nguyen ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), 286547a1685fSDinh Nguyen hsotg->supplies); 286647a1685fSDinh Nguyen if (ret) { 286747a1685fSDinh Nguyen dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret); 286847a1685fSDinh Nguyen goto err; 286947a1685fSDinh Nguyen } 287047a1685fSDinh Nguyen 287147a1685fSDinh Nguyen hsotg->last_rst = jiffies; 287247a1685fSDinh Nguyen dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); 287347a1685fSDinh Nguyen return 0; 287447a1685fSDinh Nguyen 287547a1685fSDinh Nguyen err: 287647a1685fSDinh Nguyen hsotg->driver = NULL; 287747a1685fSDinh Nguyen return ret; 287847a1685fSDinh Nguyen } 287947a1685fSDinh Nguyen 288047a1685fSDinh Nguyen /** 288147a1685fSDinh Nguyen * s3c_hsotg_udc_stop - stop the udc 288247a1685fSDinh Nguyen * @gadget: The usb gadget state 288347a1685fSDinh Nguyen * @driver: The usb gadget driver 288447a1685fSDinh Nguyen * 288547a1685fSDinh Nguyen * Stop udc hw block and stay tunned for future transmissions 288647a1685fSDinh Nguyen */ 288747a1685fSDinh Nguyen static int s3c_hsotg_udc_stop(struct usb_gadget *gadget, 288847a1685fSDinh Nguyen struct usb_gadget_driver *driver) 288947a1685fSDinh Nguyen { 289047a1685fSDinh Nguyen struct s3c_hsotg *hsotg = to_hsotg(gadget); 289147a1685fSDinh Nguyen unsigned long flags = 0; 289247a1685fSDinh Nguyen int ep; 289347a1685fSDinh Nguyen 289447a1685fSDinh Nguyen if (!hsotg) 289547a1685fSDinh Nguyen return -ENODEV; 289647a1685fSDinh Nguyen 289747a1685fSDinh Nguyen /* all endpoints should be shutdown */ 2898604eac3cSRobert Baldyga for (ep = 1; ep < hsotg->num_of_eps; ep++) 289947a1685fSDinh Nguyen s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); 290047a1685fSDinh Nguyen 290147a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 290247a1685fSDinh Nguyen 290347a1685fSDinh Nguyen if (!driver) 290447a1685fSDinh Nguyen hsotg->driver = NULL; 290547a1685fSDinh Nguyen 290647a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 290747a1685fSDinh Nguyen 290847a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 290947a1685fSDinh Nguyen 291047a1685fSDinh Nguyen regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); 291147a1685fSDinh Nguyen 291247a1685fSDinh Nguyen return 0; 291347a1685fSDinh Nguyen } 291447a1685fSDinh Nguyen 291547a1685fSDinh Nguyen /** 291647a1685fSDinh Nguyen * s3c_hsotg_gadget_getframe - read the frame number 291747a1685fSDinh Nguyen * @gadget: The usb gadget state 291847a1685fSDinh Nguyen * 291947a1685fSDinh Nguyen * Read the {micro} frame number 292047a1685fSDinh Nguyen */ 292147a1685fSDinh Nguyen static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget) 292247a1685fSDinh Nguyen { 292347a1685fSDinh Nguyen return s3c_hsotg_read_frameno(to_hsotg(gadget)); 292447a1685fSDinh Nguyen } 292547a1685fSDinh Nguyen 292647a1685fSDinh Nguyen /** 292747a1685fSDinh Nguyen * s3c_hsotg_pullup - connect/disconnect the USB PHY 292847a1685fSDinh Nguyen * @gadget: The usb gadget state 292947a1685fSDinh Nguyen * @is_on: Current state of the USB PHY 293047a1685fSDinh Nguyen * 293147a1685fSDinh Nguyen * Connect/Disconnect the USB PHY pullup 293247a1685fSDinh Nguyen */ 293347a1685fSDinh Nguyen static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on) 293447a1685fSDinh Nguyen { 293547a1685fSDinh Nguyen struct s3c_hsotg *hsotg = to_hsotg(gadget); 293647a1685fSDinh Nguyen unsigned long flags = 0; 293747a1685fSDinh Nguyen 2938*d784f1e5SAndrzej Pietrasiewicz dev_dbg(hsotg->dev, "%s: is_on: %d\n", __func__, is_on); 293947a1685fSDinh Nguyen 294047a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 294147a1685fSDinh Nguyen if (is_on) { 294247a1685fSDinh Nguyen s3c_hsotg_phy_enable(hsotg); 294347a1685fSDinh Nguyen s3c_hsotg_core_init(hsotg); 294447a1685fSDinh Nguyen } else { 294547a1685fSDinh Nguyen s3c_hsotg_phy_disable(hsotg); 294647a1685fSDinh Nguyen } 294747a1685fSDinh Nguyen 294847a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 294947a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 295047a1685fSDinh Nguyen 295147a1685fSDinh Nguyen return 0; 295247a1685fSDinh Nguyen } 295347a1685fSDinh Nguyen 295447a1685fSDinh Nguyen static const struct usb_gadget_ops s3c_hsotg_gadget_ops = { 295547a1685fSDinh Nguyen .get_frame = s3c_hsotg_gadget_getframe, 295647a1685fSDinh Nguyen .udc_start = s3c_hsotg_udc_start, 295747a1685fSDinh Nguyen .udc_stop = s3c_hsotg_udc_stop, 295847a1685fSDinh Nguyen .pullup = s3c_hsotg_pullup, 295947a1685fSDinh Nguyen }; 296047a1685fSDinh Nguyen 296147a1685fSDinh Nguyen /** 296247a1685fSDinh Nguyen * s3c_hsotg_initep - initialise a single endpoint 296347a1685fSDinh Nguyen * @hsotg: The device state. 296447a1685fSDinh Nguyen * @hs_ep: The endpoint to be initialised. 296547a1685fSDinh Nguyen * @epnum: The endpoint number 296647a1685fSDinh Nguyen * 296747a1685fSDinh Nguyen * Initialise the given endpoint (as part of the probe and device state 296847a1685fSDinh Nguyen * creation) to give to the gadget driver. Setup the endpoint name, any 296947a1685fSDinh Nguyen * direction information and other state that may be required. 297047a1685fSDinh Nguyen */ 297147a1685fSDinh Nguyen static void s3c_hsotg_initep(struct s3c_hsotg *hsotg, 297247a1685fSDinh Nguyen struct s3c_hsotg_ep *hs_ep, 297347a1685fSDinh Nguyen int epnum) 297447a1685fSDinh Nguyen { 297547a1685fSDinh Nguyen u32 ptxfifo; 297647a1685fSDinh Nguyen char *dir; 297747a1685fSDinh Nguyen 297847a1685fSDinh Nguyen if (epnum == 0) 297947a1685fSDinh Nguyen dir = ""; 298047a1685fSDinh Nguyen else if ((epnum % 2) == 0) { 298147a1685fSDinh Nguyen dir = "out"; 298247a1685fSDinh Nguyen } else { 298347a1685fSDinh Nguyen dir = "in"; 298447a1685fSDinh Nguyen hs_ep->dir_in = 1; 298547a1685fSDinh Nguyen } 298647a1685fSDinh Nguyen 298747a1685fSDinh Nguyen hs_ep->index = epnum; 298847a1685fSDinh Nguyen 298947a1685fSDinh Nguyen snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir); 299047a1685fSDinh Nguyen 299147a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->queue); 299247a1685fSDinh Nguyen INIT_LIST_HEAD(&hs_ep->ep.ep_list); 299347a1685fSDinh Nguyen 299447a1685fSDinh Nguyen /* add to the list of endpoints known by the gadget driver */ 299547a1685fSDinh Nguyen if (epnum) 299647a1685fSDinh Nguyen list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list); 299747a1685fSDinh Nguyen 299847a1685fSDinh Nguyen hs_ep->parent = hsotg; 299947a1685fSDinh Nguyen hs_ep->ep.name = hs_ep->name; 300047a1685fSDinh Nguyen usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT); 300147a1685fSDinh Nguyen hs_ep->ep.ops = &s3c_hsotg_ep_ops; 300247a1685fSDinh Nguyen 300347a1685fSDinh Nguyen /* 300447a1685fSDinh Nguyen * Read the FIFO size for the Periodic TX FIFO, even if we're 300547a1685fSDinh Nguyen * an OUT endpoint, we may as well do this if in future the 300647a1685fSDinh Nguyen * code is changed to make each endpoint's direction changeable. 300747a1685fSDinh Nguyen */ 300847a1685fSDinh Nguyen 300947a1685fSDinh Nguyen ptxfifo = readl(hsotg->regs + DPTXFSIZN(epnum)); 301047a1685fSDinh Nguyen hs_ep->fifo_size = FIFOSIZE_DEPTH_GET(ptxfifo) * 4; 301147a1685fSDinh Nguyen 301247a1685fSDinh Nguyen /* 301347a1685fSDinh Nguyen * if we're using dma, we need to set the next-endpoint pointer 301447a1685fSDinh Nguyen * to be something valid. 301547a1685fSDinh Nguyen */ 301647a1685fSDinh Nguyen 301747a1685fSDinh Nguyen if (using_dma(hsotg)) { 301847a1685fSDinh Nguyen u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15); 301947a1685fSDinh Nguyen writel(next, hsotg->regs + DIEPCTL(epnum)); 302047a1685fSDinh Nguyen writel(next, hsotg->regs + DOEPCTL(epnum)); 302147a1685fSDinh Nguyen } 302247a1685fSDinh Nguyen } 302347a1685fSDinh Nguyen 302447a1685fSDinh Nguyen /** 302547a1685fSDinh Nguyen * s3c_hsotg_hw_cfg - read HW configuration registers 302647a1685fSDinh Nguyen * @param: The device state 302747a1685fSDinh Nguyen * 302847a1685fSDinh Nguyen * Read the USB core HW configuration registers 302947a1685fSDinh Nguyen */ 303047a1685fSDinh Nguyen static void s3c_hsotg_hw_cfg(struct s3c_hsotg *hsotg) 303147a1685fSDinh Nguyen { 303247a1685fSDinh Nguyen u32 cfg2, cfg4; 303347a1685fSDinh Nguyen /* check hardware configuration */ 303447a1685fSDinh Nguyen 303547a1685fSDinh Nguyen cfg2 = readl(hsotg->regs + 0x48); 303647a1685fSDinh Nguyen hsotg->num_of_eps = (cfg2 >> 10) & 0xF; 303747a1685fSDinh Nguyen 303847a1685fSDinh Nguyen dev_info(hsotg->dev, "EPs:%d\n", hsotg->num_of_eps); 303947a1685fSDinh Nguyen 304047a1685fSDinh Nguyen cfg4 = readl(hsotg->regs + 0x50); 304147a1685fSDinh Nguyen hsotg->dedicated_fifos = (cfg4 >> 25) & 1; 304247a1685fSDinh Nguyen 304347a1685fSDinh Nguyen dev_info(hsotg->dev, "%s fifos\n", 304447a1685fSDinh Nguyen hsotg->dedicated_fifos ? "dedicated" : "shared"); 304547a1685fSDinh Nguyen } 304647a1685fSDinh Nguyen 304747a1685fSDinh Nguyen /** 304847a1685fSDinh Nguyen * s3c_hsotg_dump - dump state of the udc 304947a1685fSDinh Nguyen * @param: The device state 305047a1685fSDinh Nguyen */ 305147a1685fSDinh Nguyen static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) 305247a1685fSDinh Nguyen { 305347a1685fSDinh Nguyen #ifdef DEBUG 305447a1685fSDinh Nguyen struct device *dev = hsotg->dev; 305547a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 305647a1685fSDinh Nguyen u32 val; 305747a1685fSDinh Nguyen int idx; 305847a1685fSDinh Nguyen 305947a1685fSDinh Nguyen dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", 306047a1685fSDinh Nguyen readl(regs + DCFG), readl(regs + DCTL), 306147a1685fSDinh Nguyen readl(regs + DIEPMSK)); 306247a1685fSDinh Nguyen 306347a1685fSDinh Nguyen dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n", 306447a1685fSDinh Nguyen readl(regs + GAHBCFG), readl(regs + 0x44)); 306547a1685fSDinh Nguyen 306647a1685fSDinh Nguyen dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 306747a1685fSDinh Nguyen readl(regs + GRXFSIZ), readl(regs + GNPTXFSIZ)); 306847a1685fSDinh Nguyen 306947a1685fSDinh Nguyen /* show periodic fifo settings */ 307047a1685fSDinh Nguyen 307147a1685fSDinh Nguyen for (idx = 1; idx <= 15; idx++) { 307247a1685fSDinh Nguyen val = readl(regs + DPTXFSIZN(idx)); 307347a1685fSDinh Nguyen dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, 307447a1685fSDinh Nguyen val >> FIFOSIZE_DEPTH_SHIFT, 307547a1685fSDinh Nguyen val & FIFOSIZE_STARTADDR_MASK); 307647a1685fSDinh Nguyen } 307747a1685fSDinh Nguyen 307847a1685fSDinh Nguyen for (idx = 0; idx < 15; idx++) { 307947a1685fSDinh Nguyen dev_info(dev, 308047a1685fSDinh Nguyen "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, 308147a1685fSDinh Nguyen readl(regs + DIEPCTL(idx)), 308247a1685fSDinh Nguyen readl(regs + DIEPTSIZ(idx)), 308347a1685fSDinh Nguyen readl(regs + DIEPDMA(idx))); 308447a1685fSDinh Nguyen 308547a1685fSDinh Nguyen val = readl(regs + DOEPCTL(idx)); 308647a1685fSDinh Nguyen dev_info(dev, 308747a1685fSDinh Nguyen "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", 308847a1685fSDinh Nguyen idx, readl(regs + DOEPCTL(idx)), 308947a1685fSDinh Nguyen readl(regs + DOEPTSIZ(idx)), 309047a1685fSDinh Nguyen readl(regs + DOEPDMA(idx))); 309147a1685fSDinh Nguyen 309247a1685fSDinh Nguyen } 309347a1685fSDinh Nguyen 309447a1685fSDinh Nguyen dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", 309547a1685fSDinh Nguyen readl(regs + DVBUSDIS), readl(regs + DVBUSPULSE)); 309647a1685fSDinh Nguyen #endif 309747a1685fSDinh Nguyen } 309847a1685fSDinh Nguyen 309947a1685fSDinh Nguyen /** 310047a1685fSDinh Nguyen * state_show - debugfs: show overall driver and device state. 310147a1685fSDinh Nguyen * @seq: The seq file to write to. 310247a1685fSDinh Nguyen * @v: Unused parameter. 310347a1685fSDinh Nguyen * 310447a1685fSDinh Nguyen * This debugfs entry shows the overall state of the hardware and 310547a1685fSDinh Nguyen * some general information about each of the endpoints available 310647a1685fSDinh Nguyen * to the system. 310747a1685fSDinh Nguyen */ 310847a1685fSDinh Nguyen static int state_show(struct seq_file *seq, void *v) 310947a1685fSDinh Nguyen { 311047a1685fSDinh Nguyen struct s3c_hsotg *hsotg = seq->private; 311147a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 311247a1685fSDinh Nguyen int idx; 311347a1685fSDinh Nguyen 311447a1685fSDinh Nguyen seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n", 311547a1685fSDinh Nguyen readl(regs + DCFG), 311647a1685fSDinh Nguyen readl(regs + DCTL), 311747a1685fSDinh Nguyen readl(regs + DSTS)); 311847a1685fSDinh Nguyen 311947a1685fSDinh Nguyen seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n", 312047a1685fSDinh Nguyen readl(regs + DIEPMSK), readl(regs + DOEPMSK)); 312147a1685fSDinh Nguyen 312247a1685fSDinh Nguyen seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n", 312347a1685fSDinh Nguyen readl(regs + GINTMSK), 312447a1685fSDinh Nguyen readl(regs + GINTSTS)); 312547a1685fSDinh Nguyen 312647a1685fSDinh Nguyen seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n", 312747a1685fSDinh Nguyen readl(regs + DAINTMSK), 312847a1685fSDinh Nguyen readl(regs + DAINT)); 312947a1685fSDinh Nguyen 313047a1685fSDinh Nguyen seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n", 313147a1685fSDinh Nguyen readl(regs + GNPTXSTS), 313247a1685fSDinh Nguyen readl(regs + GRXSTSR)); 313347a1685fSDinh Nguyen 313447a1685fSDinh Nguyen seq_puts(seq, "\nEndpoint status:\n"); 313547a1685fSDinh Nguyen 313647a1685fSDinh Nguyen for (idx = 0; idx < 15; idx++) { 313747a1685fSDinh Nguyen u32 in, out; 313847a1685fSDinh Nguyen 313947a1685fSDinh Nguyen in = readl(regs + DIEPCTL(idx)); 314047a1685fSDinh Nguyen out = readl(regs + DOEPCTL(idx)); 314147a1685fSDinh Nguyen 314247a1685fSDinh Nguyen seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x", 314347a1685fSDinh Nguyen idx, in, out); 314447a1685fSDinh Nguyen 314547a1685fSDinh Nguyen in = readl(regs + DIEPTSIZ(idx)); 314647a1685fSDinh Nguyen out = readl(regs + DOEPTSIZ(idx)); 314747a1685fSDinh Nguyen 314847a1685fSDinh Nguyen seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x", 314947a1685fSDinh Nguyen in, out); 315047a1685fSDinh Nguyen 315147a1685fSDinh Nguyen seq_puts(seq, "\n"); 315247a1685fSDinh Nguyen } 315347a1685fSDinh Nguyen 315447a1685fSDinh Nguyen return 0; 315547a1685fSDinh Nguyen } 315647a1685fSDinh Nguyen 315747a1685fSDinh Nguyen static int state_open(struct inode *inode, struct file *file) 315847a1685fSDinh Nguyen { 315947a1685fSDinh Nguyen return single_open(file, state_show, inode->i_private); 316047a1685fSDinh Nguyen } 316147a1685fSDinh Nguyen 316247a1685fSDinh Nguyen static const struct file_operations state_fops = { 316347a1685fSDinh Nguyen .owner = THIS_MODULE, 316447a1685fSDinh Nguyen .open = state_open, 316547a1685fSDinh Nguyen .read = seq_read, 316647a1685fSDinh Nguyen .llseek = seq_lseek, 316747a1685fSDinh Nguyen .release = single_release, 316847a1685fSDinh Nguyen }; 316947a1685fSDinh Nguyen 317047a1685fSDinh Nguyen /** 317147a1685fSDinh Nguyen * fifo_show - debugfs: show the fifo information 317247a1685fSDinh Nguyen * @seq: The seq_file to write data to. 317347a1685fSDinh Nguyen * @v: Unused parameter. 317447a1685fSDinh Nguyen * 317547a1685fSDinh Nguyen * Show the FIFO information for the overall fifo and all the 317647a1685fSDinh Nguyen * periodic transmission FIFOs. 317747a1685fSDinh Nguyen */ 317847a1685fSDinh Nguyen static int fifo_show(struct seq_file *seq, void *v) 317947a1685fSDinh Nguyen { 318047a1685fSDinh Nguyen struct s3c_hsotg *hsotg = seq->private; 318147a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 318247a1685fSDinh Nguyen u32 val; 318347a1685fSDinh Nguyen int idx; 318447a1685fSDinh Nguyen 318547a1685fSDinh Nguyen seq_puts(seq, "Non-periodic FIFOs:\n"); 318647a1685fSDinh Nguyen seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ)); 318747a1685fSDinh Nguyen 318847a1685fSDinh Nguyen val = readl(regs + GNPTXFSIZ); 318947a1685fSDinh Nguyen seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n", 319047a1685fSDinh Nguyen val >> FIFOSIZE_DEPTH_SHIFT, 319147a1685fSDinh Nguyen val & FIFOSIZE_DEPTH_MASK); 319247a1685fSDinh Nguyen 319347a1685fSDinh Nguyen seq_puts(seq, "\nPeriodic TXFIFOs:\n"); 319447a1685fSDinh Nguyen 319547a1685fSDinh Nguyen for (idx = 1; idx <= 15; idx++) { 319647a1685fSDinh Nguyen val = readl(regs + DPTXFSIZN(idx)); 319747a1685fSDinh Nguyen 319847a1685fSDinh Nguyen seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx, 319947a1685fSDinh Nguyen val >> FIFOSIZE_DEPTH_SHIFT, 320047a1685fSDinh Nguyen val & FIFOSIZE_STARTADDR_MASK); 320147a1685fSDinh Nguyen } 320247a1685fSDinh Nguyen 320347a1685fSDinh Nguyen return 0; 320447a1685fSDinh Nguyen } 320547a1685fSDinh Nguyen 320647a1685fSDinh Nguyen static int fifo_open(struct inode *inode, struct file *file) 320747a1685fSDinh Nguyen { 320847a1685fSDinh Nguyen return single_open(file, fifo_show, inode->i_private); 320947a1685fSDinh Nguyen } 321047a1685fSDinh Nguyen 321147a1685fSDinh Nguyen static const struct file_operations fifo_fops = { 321247a1685fSDinh Nguyen .owner = THIS_MODULE, 321347a1685fSDinh Nguyen .open = fifo_open, 321447a1685fSDinh Nguyen .read = seq_read, 321547a1685fSDinh Nguyen .llseek = seq_lseek, 321647a1685fSDinh Nguyen .release = single_release, 321747a1685fSDinh Nguyen }; 321847a1685fSDinh Nguyen 321947a1685fSDinh Nguyen 322047a1685fSDinh Nguyen static const char *decode_direction(int is_in) 322147a1685fSDinh Nguyen { 322247a1685fSDinh Nguyen return is_in ? "in" : "out"; 322347a1685fSDinh Nguyen } 322447a1685fSDinh Nguyen 322547a1685fSDinh Nguyen /** 322647a1685fSDinh Nguyen * ep_show - debugfs: show the state of an endpoint. 322747a1685fSDinh Nguyen * @seq: The seq_file to write data to. 322847a1685fSDinh Nguyen * @v: Unused parameter. 322947a1685fSDinh Nguyen * 323047a1685fSDinh Nguyen * This debugfs entry shows the state of the given endpoint (one is 323147a1685fSDinh Nguyen * registered for each available). 323247a1685fSDinh Nguyen */ 323347a1685fSDinh Nguyen static int ep_show(struct seq_file *seq, void *v) 323447a1685fSDinh Nguyen { 323547a1685fSDinh Nguyen struct s3c_hsotg_ep *ep = seq->private; 323647a1685fSDinh Nguyen struct s3c_hsotg *hsotg = ep->parent; 323747a1685fSDinh Nguyen struct s3c_hsotg_req *req; 323847a1685fSDinh Nguyen void __iomem *regs = hsotg->regs; 323947a1685fSDinh Nguyen int index = ep->index; 324047a1685fSDinh Nguyen int show_limit = 15; 324147a1685fSDinh Nguyen unsigned long flags; 324247a1685fSDinh Nguyen 324347a1685fSDinh Nguyen seq_printf(seq, "Endpoint index %d, named %s, dir %s:\n", 324447a1685fSDinh Nguyen ep->index, ep->ep.name, decode_direction(ep->dir_in)); 324547a1685fSDinh Nguyen 324647a1685fSDinh Nguyen /* first show the register state */ 324747a1685fSDinh Nguyen 324847a1685fSDinh Nguyen seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n", 324947a1685fSDinh Nguyen readl(regs + DIEPCTL(index)), 325047a1685fSDinh Nguyen readl(regs + DOEPCTL(index))); 325147a1685fSDinh Nguyen 325247a1685fSDinh Nguyen seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n", 325347a1685fSDinh Nguyen readl(regs + DIEPDMA(index)), 325447a1685fSDinh Nguyen readl(regs + DOEPDMA(index))); 325547a1685fSDinh Nguyen 325647a1685fSDinh Nguyen seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n", 325747a1685fSDinh Nguyen readl(regs + DIEPINT(index)), 325847a1685fSDinh Nguyen readl(regs + DOEPINT(index))); 325947a1685fSDinh Nguyen 326047a1685fSDinh Nguyen seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n", 326147a1685fSDinh Nguyen readl(regs + DIEPTSIZ(index)), 326247a1685fSDinh Nguyen readl(regs + DOEPTSIZ(index))); 326347a1685fSDinh Nguyen 326447a1685fSDinh Nguyen seq_puts(seq, "\n"); 326547a1685fSDinh Nguyen seq_printf(seq, "mps %d\n", ep->ep.maxpacket); 326647a1685fSDinh Nguyen seq_printf(seq, "total_data=%ld\n", ep->total_data); 326747a1685fSDinh Nguyen 326847a1685fSDinh Nguyen seq_printf(seq, "request list (%p,%p):\n", 326947a1685fSDinh Nguyen ep->queue.next, ep->queue.prev); 327047a1685fSDinh Nguyen 327147a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 327247a1685fSDinh Nguyen 327347a1685fSDinh Nguyen list_for_each_entry(req, &ep->queue, queue) { 327447a1685fSDinh Nguyen if (--show_limit < 0) { 327547a1685fSDinh Nguyen seq_puts(seq, "not showing more requests...\n"); 327647a1685fSDinh Nguyen break; 327747a1685fSDinh Nguyen } 327847a1685fSDinh Nguyen 327947a1685fSDinh Nguyen seq_printf(seq, "%c req %p: %d bytes @%p, ", 328047a1685fSDinh Nguyen req == ep->req ? '*' : ' ', 328147a1685fSDinh Nguyen req, req->req.length, req->req.buf); 328247a1685fSDinh Nguyen seq_printf(seq, "%d done, res %d\n", 328347a1685fSDinh Nguyen req->req.actual, req->req.status); 328447a1685fSDinh Nguyen } 328547a1685fSDinh Nguyen 328647a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 328747a1685fSDinh Nguyen 328847a1685fSDinh Nguyen return 0; 328947a1685fSDinh Nguyen } 329047a1685fSDinh Nguyen 329147a1685fSDinh Nguyen static int ep_open(struct inode *inode, struct file *file) 329247a1685fSDinh Nguyen { 329347a1685fSDinh Nguyen return single_open(file, ep_show, inode->i_private); 329447a1685fSDinh Nguyen } 329547a1685fSDinh Nguyen 329647a1685fSDinh Nguyen static const struct file_operations ep_fops = { 329747a1685fSDinh Nguyen .owner = THIS_MODULE, 329847a1685fSDinh Nguyen .open = ep_open, 329947a1685fSDinh Nguyen .read = seq_read, 330047a1685fSDinh Nguyen .llseek = seq_lseek, 330147a1685fSDinh Nguyen .release = single_release, 330247a1685fSDinh Nguyen }; 330347a1685fSDinh Nguyen 330447a1685fSDinh Nguyen /** 330547a1685fSDinh Nguyen * s3c_hsotg_create_debug - create debugfs directory and files 330647a1685fSDinh Nguyen * @hsotg: The driver state 330747a1685fSDinh Nguyen * 330847a1685fSDinh Nguyen * Create the debugfs files to allow the user to get information 330947a1685fSDinh Nguyen * about the state of the system. The directory name is created 331047a1685fSDinh Nguyen * with the same name as the device itself, in case we end up 331147a1685fSDinh Nguyen * with multiple blocks in future systems. 331247a1685fSDinh Nguyen */ 331347a1685fSDinh Nguyen static void s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) 331447a1685fSDinh Nguyen { 331547a1685fSDinh Nguyen struct dentry *root; 331647a1685fSDinh Nguyen unsigned epidx; 331747a1685fSDinh Nguyen 331847a1685fSDinh Nguyen root = debugfs_create_dir(dev_name(hsotg->dev), NULL); 331947a1685fSDinh Nguyen hsotg->debug_root = root; 332047a1685fSDinh Nguyen if (IS_ERR(root)) { 332147a1685fSDinh Nguyen dev_err(hsotg->dev, "cannot create debug root\n"); 332247a1685fSDinh Nguyen return; 332347a1685fSDinh Nguyen } 332447a1685fSDinh Nguyen 332547a1685fSDinh Nguyen /* create general state file */ 332647a1685fSDinh Nguyen 332747a1685fSDinh Nguyen hsotg->debug_file = debugfs_create_file("state", 0444, root, 332847a1685fSDinh Nguyen hsotg, &state_fops); 332947a1685fSDinh Nguyen 333047a1685fSDinh Nguyen if (IS_ERR(hsotg->debug_file)) 333147a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to create state\n", __func__); 333247a1685fSDinh Nguyen 333347a1685fSDinh Nguyen hsotg->debug_fifo = debugfs_create_file("fifo", 0444, root, 333447a1685fSDinh Nguyen hsotg, &fifo_fops); 333547a1685fSDinh Nguyen 333647a1685fSDinh Nguyen if (IS_ERR(hsotg->debug_fifo)) 333747a1685fSDinh Nguyen dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__); 333847a1685fSDinh Nguyen 333947a1685fSDinh Nguyen /* create one file for each endpoint */ 334047a1685fSDinh Nguyen 334147a1685fSDinh Nguyen for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { 334247a1685fSDinh Nguyen struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; 334347a1685fSDinh Nguyen 334447a1685fSDinh Nguyen ep->debugfs = debugfs_create_file(ep->name, 0444, 334547a1685fSDinh Nguyen root, ep, &ep_fops); 334647a1685fSDinh Nguyen 334747a1685fSDinh Nguyen if (IS_ERR(ep->debugfs)) 334847a1685fSDinh Nguyen dev_err(hsotg->dev, "failed to create %s debug file\n", 334947a1685fSDinh Nguyen ep->name); 335047a1685fSDinh Nguyen } 335147a1685fSDinh Nguyen } 335247a1685fSDinh Nguyen 335347a1685fSDinh Nguyen /** 335447a1685fSDinh Nguyen * s3c_hsotg_delete_debug - cleanup debugfs entries 335547a1685fSDinh Nguyen * @hsotg: The driver state 335647a1685fSDinh Nguyen * 335747a1685fSDinh Nguyen * Cleanup (remove) the debugfs files for use on module exit. 335847a1685fSDinh Nguyen */ 335947a1685fSDinh Nguyen static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) 336047a1685fSDinh Nguyen { 336147a1685fSDinh Nguyen unsigned epidx; 336247a1685fSDinh Nguyen 336347a1685fSDinh Nguyen for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { 336447a1685fSDinh Nguyen struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; 336547a1685fSDinh Nguyen debugfs_remove(ep->debugfs); 336647a1685fSDinh Nguyen } 336747a1685fSDinh Nguyen 336847a1685fSDinh Nguyen debugfs_remove(hsotg->debug_file); 336947a1685fSDinh Nguyen debugfs_remove(hsotg->debug_fifo); 337047a1685fSDinh Nguyen debugfs_remove(hsotg->debug_root); 337147a1685fSDinh Nguyen } 337247a1685fSDinh Nguyen 337347a1685fSDinh Nguyen /** 337447a1685fSDinh Nguyen * s3c_hsotg_probe - probe function for hsotg driver 337547a1685fSDinh Nguyen * @pdev: The platform information for the driver 337647a1685fSDinh Nguyen */ 337747a1685fSDinh Nguyen 337847a1685fSDinh Nguyen static int s3c_hsotg_probe(struct platform_device *pdev) 337947a1685fSDinh Nguyen { 338047a1685fSDinh Nguyen struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev); 338147a1685fSDinh Nguyen struct phy *phy; 338247a1685fSDinh Nguyen struct usb_phy *uphy; 338347a1685fSDinh Nguyen struct device *dev = &pdev->dev; 338447a1685fSDinh Nguyen struct s3c_hsotg_ep *eps; 338547a1685fSDinh Nguyen struct s3c_hsotg *hsotg; 338647a1685fSDinh Nguyen struct resource *res; 338747a1685fSDinh Nguyen int epnum; 338847a1685fSDinh Nguyen int ret; 338947a1685fSDinh Nguyen int i; 339047a1685fSDinh Nguyen 339147a1685fSDinh Nguyen hsotg = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsotg), GFP_KERNEL); 3392d04477d8SJingoo Han if (!hsotg) 339347a1685fSDinh Nguyen return -ENOMEM; 339447a1685fSDinh Nguyen 339547a1685fSDinh Nguyen /* 339647a1685fSDinh Nguyen * Attempt to find a generic PHY, then look for an old style 339747a1685fSDinh Nguyen * USB PHY, finally fall back to pdata 339847a1685fSDinh Nguyen */ 339947a1685fSDinh Nguyen phy = devm_phy_get(&pdev->dev, "usb2-phy"); 340047a1685fSDinh Nguyen if (IS_ERR(phy)) { 340147a1685fSDinh Nguyen uphy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); 340247a1685fSDinh Nguyen if (IS_ERR(uphy)) { 340347a1685fSDinh Nguyen /* Fallback for pdata */ 340447a1685fSDinh Nguyen plat = dev_get_platdata(&pdev->dev); 340547a1685fSDinh Nguyen if (!plat) { 340647a1685fSDinh Nguyen dev_err(&pdev->dev, 340747a1685fSDinh Nguyen "no platform data or transceiver defined\n"); 340847a1685fSDinh Nguyen return -EPROBE_DEFER; 340947a1685fSDinh Nguyen } 341047a1685fSDinh Nguyen hsotg->plat = plat; 341147a1685fSDinh Nguyen } else 341247a1685fSDinh Nguyen hsotg->uphy = uphy; 341347a1685fSDinh Nguyen } else 341447a1685fSDinh Nguyen hsotg->phy = phy; 341547a1685fSDinh Nguyen 341647a1685fSDinh Nguyen hsotg->dev = dev; 341747a1685fSDinh Nguyen 341847a1685fSDinh Nguyen hsotg->clk = devm_clk_get(&pdev->dev, "otg"); 341947a1685fSDinh Nguyen if (IS_ERR(hsotg->clk)) { 342047a1685fSDinh Nguyen dev_err(dev, "cannot get otg clock\n"); 342147a1685fSDinh Nguyen return PTR_ERR(hsotg->clk); 342247a1685fSDinh Nguyen } 342347a1685fSDinh Nguyen 342447a1685fSDinh Nguyen platform_set_drvdata(pdev, hsotg); 342547a1685fSDinh Nguyen 342647a1685fSDinh Nguyen res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 342747a1685fSDinh Nguyen 342847a1685fSDinh Nguyen hsotg->regs = devm_ioremap_resource(&pdev->dev, res); 342947a1685fSDinh Nguyen if (IS_ERR(hsotg->regs)) { 343047a1685fSDinh Nguyen ret = PTR_ERR(hsotg->regs); 343147a1685fSDinh Nguyen goto err_clk; 343247a1685fSDinh Nguyen } 343347a1685fSDinh Nguyen 343447a1685fSDinh Nguyen ret = platform_get_irq(pdev, 0); 343547a1685fSDinh Nguyen if (ret < 0) { 343647a1685fSDinh Nguyen dev_err(dev, "cannot find IRQ\n"); 343747a1685fSDinh Nguyen goto err_clk; 343847a1685fSDinh Nguyen } 343947a1685fSDinh Nguyen 344047a1685fSDinh Nguyen spin_lock_init(&hsotg->lock); 344147a1685fSDinh Nguyen 344247a1685fSDinh Nguyen hsotg->irq = ret; 344347a1685fSDinh Nguyen 344447a1685fSDinh Nguyen dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq); 344547a1685fSDinh Nguyen 344647a1685fSDinh Nguyen hsotg->gadget.max_speed = USB_SPEED_HIGH; 344747a1685fSDinh Nguyen hsotg->gadget.ops = &s3c_hsotg_gadget_ops; 344847a1685fSDinh Nguyen hsotg->gadget.name = dev_name(dev); 344947a1685fSDinh Nguyen 345047a1685fSDinh Nguyen /* reset the system */ 345147a1685fSDinh Nguyen 345247a1685fSDinh Nguyen clk_prepare_enable(hsotg->clk); 345347a1685fSDinh Nguyen 345447a1685fSDinh Nguyen /* regulators */ 345547a1685fSDinh Nguyen 345647a1685fSDinh Nguyen for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) 345747a1685fSDinh Nguyen hsotg->supplies[i].supply = s3c_hsotg_supply_names[i]; 345847a1685fSDinh Nguyen 345947a1685fSDinh Nguyen ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies), 346047a1685fSDinh Nguyen hsotg->supplies); 346147a1685fSDinh Nguyen if (ret) { 346247a1685fSDinh Nguyen dev_err(dev, "failed to request supplies: %d\n", ret); 346347a1685fSDinh Nguyen goto err_clk; 346447a1685fSDinh Nguyen } 346547a1685fSDinh Nguyen 346647a1685fSDinh Nguyen ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), 346747a1685fSDinh Nguyen hsotg->supplies); 346847a1685fSDinh Nguyen 346947a1685fSDinh Nguyen if (ret) { 347047a1685fSDinh Nguyen dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret); 347147a1685fSDinh Nguyen goto err_supplies; 347247a1685fSDinh Nguyen } 347347a1685fSDinh Nguyen 347447a1685fSDinh Nguyen /* Set default UTMI width */ 347547a1685fSDinh Nguyen hsotg->phyif = GUSBCFG_PHYIF16; 347647a1685fSDinh Nguyen 347747a1685fSDinh Nguyen /* 347847a1685fSDinh Nguyen * If using the generic PHY framework, check if the PHY bus 347947a1685fSDinh Nguyen * width is 8-bit and set the phyif appropriately. 348047a1685fSDinh Nguyen */ 348147a1685fSDinh Nguyen if (hsotg->phy && (phy_get_bus_width(phy) == 8)) 348247a1685fSDinh Nguyen hsotg->phyif = GUSBCFG_PHYIF8; 348347a1685fSDinh Nguyen 348447a1685fSDinh Nguyen /* usb phy enable */ 348547a1685fSDinh Nguyen s3c_hsotg_phy_enable(hsotg); 348647a1685fSDinh Nguyen 348747a1685fSDinh Nguyen s3c_hsotg_corereset(hsotg); 348847a1685fSDinh Nguyen s3c_hsotg_init(hsotg); 348947a1685fSDinh Nguyen s3c_hsotg_hw_cfg(hsotg); 349047a1685fSDinh Nguyen 3491eb3c56c5SMarek Szyprowski ret = devm_request_irq(&pdev->dev, hsotg->irq, s3c_hsotg_irq, 0, 3492eb3c56c5SMarek Szyprowski dev_name(dev), hsotg); 3493eb3c56c5SMarek Szyprowski if (ret < 0) { 3494eb3c56c5SMarek Szyprowski s3c_hsotg_phy_disable(hsotg); 3495eb3c56c5SMarek Szyprowski clk_disable_unprepare(hsotg->clk); 3496eb3c56c5SMarek Szyprowski regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), 3497eb3c56c5SMarek Szyprowski hsotg->supplies); 3498eb3c56c5SMarek Szyprowski dev_err(dev, "cannot claim IRQ\n"); 3499eb3c56c5SMarek Szyprowski goto err_clk; 3500eb3c56c5SMarek Szyprowski } 3501eb3c56c5SMarek Szyprowski 350247a1685fSDinh Nguyen /* hsotg->num_of_eps holds number of EPs other than ep0 */ 350347a1685fSDinh Nguyen 350447a1685fSDinh Nguyen if (hsotg->num_of_eps == 0) { 350547a1685fSDinh Nguyen dev_err(dev, "wrong number of EPs (zero)\n"); 350647a1685fSDinh Nguyen ret = -EINVAL; 350747a1685fSDinh Nguyen goto err_supplies; 350847a1685fSDinh Nguyen } 350947a1685fSDinh Nguyen 351047a1685fSDinh Nguyen eps = kcalloc(hsotg->num_of_eps + 1, sizeof(struct s3c_hsotg_ep), 351147a1685fSDinh Nguyen GFP_KERNEL); 351247a1685fSDinh Nguyen if (!eps) { 351347a1685fSDinh Nguyen ret = -ENOMEM; 351447a1685fSDinh Nguyen goto err_supplies; 351547a1685fSDinh Nguyen } 351647a1685fSDinh Nguyen 351747a1685fSDinh Nguyen hsotg->eps = eps; 351847a1685fSDinh Nguyen 351947a1685fSDinh Nguyen /* setup endpoint information */ 352047a1685fSDinh Nguyen 352147a1685fSDinh Nguyen INIT_LIST_HEAD(&hsotg->gadget.ep_list); 352247a1685fSDinh Nguyen hsotg->gadget.ep0 = &hsotg->eps[0].ep; 352347a1685fSDinh Nguyen 352447a1685fSDinh Nguyen /* allocate EP0 request */ 352547a1685fSDinh Nguyen 352647a1685fSDinh Nguyen hsotg->ctrl_req = s3c_hsotg_ep_alloc_request(&hsotg->eps[0].ep, 352747a1685fSDinh Nguyen GFP_KERNEL); 352847a1685fSDinh Nguyen if (!hsotg->ctrl_req) { 352947a1685fSDinh Nguyen dev_err(dev, "failed to allocate ctrl req\n"); 353047a1685fSDinh Nguyen ret = -ENOMEM; 353147a1685fSDinh Nguyen goto err_ep_mem; 353247a1685fSDinh Nguyen } 353347a1685fSDinh Nguyen 353447a1685fSDinh Nguyen /* initialise the endpoints now the core has been initialised */ 353547a1685fSDinh Nguyen for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) 353647a1685fSDinh Nguyen s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum); 353747a1685fSDinh Nguyen 353847a1685fSDinh Nguyen /* disable power and clock */ 353947a1685fSDinh Nguyen 354047a1685fSDinh Nguyen ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), 354147a1685fSDinh Nguyen hsotg->supplies); 354247a1685fSDinh Nguyen if (ret) { 354347a1685fSDinh Nguyen dev_err(hsotg->dev, "failed to disable supplies: %d\n", ret); 354447a1685fSDinh Nguyen goto err_ep_mem; 354547a1685fSDinh Nguyen } 354647a1685fSDinh Nguyen 354747a1685fSDinh Nguyen s3c_hsotg_phy_disable(hsotg); 354847a1685fSDinh Nguyen 354947a1685fSDinh Nguyen ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget); 355047a1685fSDinh Nguyen if (ret) 355147a1685fSDinh Nguyen goto err_ep_mem; 355247a1685fSDinh Nguyen 355347a1685fSDinh Nguyen s3c_hsotg_create_debug(hsotg); 355447a1685fSDinh Nguyen 355547a1685fSDinh Nguyen s3c_hsotg_dump(hsotg); 355647a1685fSDinh Nguyen 355747a1685fSDinh Nguyen return 0; 355847a1685fSDinh Nguyen 355947a1685fSDinh Nguyen err_ep_mem: 356047a1685fSDinh Nguyen kfree(eps); 356147a1685fSDinh Nguyen err_supplies: 356247a1685fSDinh Nguyen s3c_hsotg_phy_disable(hsotg); 356347a1685fSDinh Nguyen err_clk: 356447a1685fSDinh Nguyen clk_disable_unprepare(hsotg->clk); 356547a1685fSDinh Nguyen 356647a1685fSDinh Nguyen return ret; 356747a1685fSDinh Nguyen } 356847a1685fSDinh Nguyen 356947a1685fSDinh Nguyen /** 357047a1685fSDinh Nguyen * s3c_hsotg_remove - remove function for hsotg driver 357147a1685fSDinh Nguyen * @pdev: The platform information for the driver 357247a1685fSDinh Nguyen */ 357347a1685fSDinh Nguyen static int s3c_hsotg_remove(struct platform_device *pdev) 357447a1685fSDinh Nguyen { 357547a1685fSDinh Nguyen struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); 357647a1685fSDinh Nguyen 357747a1685fSDinh Nguyen usb_del_gadget_udc(&hsotg->gadget); 357847a1685fSDinh Nguyen 357947a1685fSDinh Nguyen s3c_hsotg_delete_debug(hsotg); 358047a1685fSDinh Nguyen 358147a1685fSDinh Nguyen if (hsotg->driver) { 358247a1685fSDinh Nguyen /* should have been done already by driver model core */ 358347a1685fSDinh Nguyen usb_gadget_unregister_driver(hsotg->driver); 358447a1685fSDinh Nguyen } 358547a1685fSDinh Nguyen 358647a1685fSDinh Nguyen clk_disable_unprepare(hsotg->clk); 358747a1685fSDinh Nguyen 358847a1685fSDinh Nguyen return 0; 358947a1685fSDinh Nguyen } 359047a1685fSDinh Nguyen 359147a1685fSDinh Nguyen static int s3c_hsotg_suspend(struct platform_device *pdev, pm_message_t state) 359247a1685fSDinh Nguyen { 359347a1685fSDinh Nguyen struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); 359447a1685fSDinh Nguyen unsigned long flags; 359547a1685fSDinh Nguyen int ret = 0; 359647a1685fSDinh Nguyen 359747a1685fSDinh Nguyen if (hsotg->driver) 359847a1685fSDinh Nguyen dev_info(hsotg->dev, "suspending usb gadget %s\n", 359947a1685fSDinh Nguyen hsotg->driver->driver.name); 360047a1685fSDinh Nguyen 360147a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 360247a1685fSDinh Nguyen s3c_hsotg_disconnect(hsotg); 360347a1685fSDinh Nguyen s3c_hsotg_phy_disable(hsotg); 360447a1685fSDinh Nguyen hsotg->gadget.speed = USB_SPEED_UNKNOWN; 360547a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 360647a1685fSDinh Nguyen 360747a1685fSDinh Nguyen if (hsotg->driver) { 360847a1685fSDinh Nguyen int ep; 360947a1685fSDinh Nguyen for (ep = 0; ep < hsotg->num_of_eps; ep++) 361047a1685fSDinh Nguyen s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); 361147a1685fSDinh Nguyen 361247a1685fSDinh Nguyen ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), 361347a1685fSDinh Nguyen hsotg->supplies); 361447a1685fSDinh Nguyen } 361547a1685fSDinh Nguyen 361647a1685fSDinh Nguyen return ret; 361747a1685fSDinh Nguyen } 361847a1685fSDinh Nguyen 361947a1685fSDinh Nguyen static int s3c_hsotg_resume(struct platform_device *pdev) 362047a1685fSDinh Nguyen { 362147a1685fSDinh Nguyen struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); 362247a1685fSDinh Nguyen unsigned long flags; 362347a1685fSDinh Nguyen int ret = 0; 362447a1685fSDinh Nguyen 362547a1685fSDinh Nguyen if (hsotg->driver) { 362647a1685fSDinh Nguyen dev_info(hsotg->dev, "resuming usb gadget %s\n", 362747a1685fSDinh Nguyen hsotg->driver->driver.name); 362847a1685fSDinh Nguyen ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), 362947a1685fSDinh Nguyen hsotg->supplies); 363047a1685fSDinh Nguyen } 363147a1685fSDinh Nguyen 363247a1685fSDinh Nguyen spin_lock_irqsave(&hsotg->lock, flags); 363347a1685fSDinh Nguyen hsotg->last_rst = jiffies; 363447a1685fSDinh Nguyen s3c_hsotg_phy_enable(hsotg); 363547a1685fSDinh Nguyen s3c_hsotg_core_init(hsotg); 363647a1685fSDinh Nguyen spin_unlock_irqrestore(&hsotg->lock, flags); 363747a1685fSDinh Nguyen 363847a1685fSDinh Nguyen return ret; 363947a1685fSDinh Nguyen } 364047a1685fSDinh Nguyen 364147a1685fSDinh Nguyen #ifdef CONFIG_OF 364247a1685fSDinh Nguyen static const struct of_device_id s3c_hsotg_of_ids[] = { 364347a1685fSDinh Nguyen { .compatible = "samsung,s3c6400-hsotg", }, 364447a1685fSDinh Nguyen { .compatible = "snps,dwc2", }, 364547a1685fSDinh Nguyen { /* sentinel */ } 364647a1685fSDinh Nguyen }; 364747a1685fSDinh Nguyen MODULE_DEVICE_TABLE(of, s3c_hsotg_of_ids); 364847a1685fSDinh Nguyen #endif 364947a1685fSDinh Nguyen 365047a1685fSDinh Nguyen static struct platform_driver s3c_hsotg_driver = { 365147a1685fSDinh Nguyen .driver = { 365247a1685fSDinh Nguyen .name = "s3c-hsotg", 365347a1685fSDinh Nguyen .owner = THIS_MODULE, 365447a1685fSDinh Nguyen .of_match_table = of_match_ptr(s3c_hsotg_of_ids), 365547a1685fSDinh Nguyen }, 365647a1685fSDinh Nguyen .probe = s3c_hsotg_probe, 365747a1685fSDinh Nguyen .remove = s3c_hsotg_remove, 365847a1685fSDinh Nguyen .suspend = s3c_hsotg_suspend, 365947a1685fSDinh Nguyen .resume = s3c_hsotg_resume, 366047a1685fSDinh Nguyen }; 366147a1685fSDinh Nguyen 366247a1685fSDinh Nguyen module_platform_driver(s3c_hsotg_driver); 366347a1685fSDinh Nguyen 366447a1685fSDinh Nguyen MODULE_DESCRIPTION("Samsung S3C USB High-speed/OtG device"); 366547a1685fSDinh Nguyen MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 366647a1685fSDinh Nguyen MODULE_LICENSE("GPL"); 366747a1685fSDinh Nguyen MODULE_ALIAS("platform:s3c-hsotg"); 3668