1dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang/* 2dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * Copyright (C) 2011 Marvell International Ltd. All rights reserved. 3dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * Author: Chao Xie <chao.xie@marvell.com> 4dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * Neil Zhang <zhangwm@marvell.com> 5dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * 6dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * This program is free software; you can redistribute it and/or modify it 7dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * under the terms of the GNU General Public License as published by the 8dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * Free Software Foundation; either version 2 of the License, or (at your 9dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * option) any later version. 10dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang */ 11dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang 12e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/module.h> 13e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/pci.h> 14e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/dma-mapping.h> 15e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/dmapool.h> 16e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/kernel.h> 17e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/delay.h> 18e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/ioport.h> 19e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/sched.h> 20e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/slab.h> 21e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/errno.h> 22e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/init.h> 23e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/timer.h> 24e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/list.h> 25e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/interrupt.h> 26e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/moduleparam.h> 27e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/device.h> 28e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/usb/ch9.h> 29e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/usb/gadget.h> 30e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/usb/otg.h> 31e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/pm.h> 32e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/io.h> 33e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/irq.h> 34e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/platform_device.h> 35e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/clk.h> 36dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang#include <linux/platform_data/mv_usb.h> 37e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <asm/unaligned.h> 38e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 39e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include "mv_udc.h" 40e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 41e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define DRIVER_DESC "Marvell PXA USB Device Controller driver" 42e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define DRIVER_VERSION "8 Nov 2010" 43e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 44e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define ep_dir(ep) (((ep)->ep_num == 0) ? \ 45e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ((ep)->udc->ep0_dir) : ((ep)->direction)) 46e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 47e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* timeout value -- usec */ 48e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define RESET_TIMEOUT 10000 49e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define FLUSH_TIMEOUT 10000 50e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define EPSTATUS_TIMEOUT 10000 51e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define PRIME_TIMEOUT 10000 52e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define READSAFE_TIMEOUT 1000 53e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define DTD_TIMEOUT 1000 54e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 55e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define LOOPS_USEC_SHIFT 4 56e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define LOOPS_USEC (1 << LOOPS_USEC_SHIFT) 57e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define LOOPS(timeout) ((timeout) >> LOOPS_USEC_SHIFT) 58e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 59dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangstatic DECLARE_COMPLETION(release_done); 60dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang 61e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic const char driver_name[] = "mv_udc"; 62e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic const char driver_desc[] = DRIVER_DESC; 63e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 64e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* controller device global variable */ 65e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic struct mv_udc *the_controller; 66e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieint mv_usb_otgsc; 67e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 68e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void nuke(struct mv_ep *ep, int status); 691aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhangstatic void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver); 70e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 71e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* for endpoint 0 operations */ 72e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic const struct usb_endpoint_descriptor mv_ep0_desc = { 73e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .bLength = USB_DT_ENDPOINT_SIZE, 74e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .bDescriptorType = USB_DT_ENDPOINT, 75e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .bEndpointAddress = 0, 76e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .bmAttributes = USB_ENDPOINT_XFER_CONTROL, 77e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .wMaxPacketSize = EP0_MAX_PKT_SIZE, 78e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}; 79e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 80e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ep0_reset(struct mv_udc *udc) 81e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 82e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_ep *ep; 83e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 epctrlx; 84e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int i = 0; 85e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 86e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* ep0 in and out */ 87e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie for (i = 0; i < 2; i++) { 88e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep = &udc->eps[i]; 89e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->udc = udc; 90e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 91e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* ep0 dQH */ 92e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->dqh = &udc->ep_dqh[i]; 93e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 94e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* configure ep0 endpoint capabilities in dQH */ 95e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->dqh->max_packet_length = 96e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie (EP0_MAX_PKT_SIZE << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) 97e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie | EP_QUEUE_HEAD_IOS; 98e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 99fbebe1f070a73c108415bb9ee0483570650e2712Neil Zhang ep->dqh->next_dtd_ptr = EP_QUEUE_HEAD_NEXT_TERMINATE; 100fbebe1f070a73c108415bb9ee0483570650e2712Neil Zhang 101e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx = readl(&udc->op_regs->epctrlx[0]); 102e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (i) { /* TX */ 10343ad9f3faea18d7b3e1183753d3e6372a7037edfNeil Zhang epctrlx |= EPCTRL_TX_ENABLE 104e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie | (USB_ENDPOINT_XFER_CONTROL 105e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie << EPCTRL_TX_EP_TYPE_SHIFT); 106e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 107e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { /* RX */ 10843ad9f3faea18d7b3e1183753d3e6372a7037edfNeil Zhang epctrlx |= EPCTRL_RX_ENABLE 109e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie | (USB_ENDPOINT_XFER_CONTROL 110e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie << EPCTRL_RX_EP_TYPE_SHIFT); 111e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 112e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 113e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(epctrlx, &udc->op_regs->epctrlx[0]); 114e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 115e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 116e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 117e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* protocol ep0 stall, will automatically be cleared on new transaction */ 118e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ep0_stall(struct mv_udc *udc) 119e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 120e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 epctrlx; 121e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 122e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* set TX and RX to stall */ 123e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx = readl(&udc->op_regs->epctrlx[0]); 124e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx |= EPCTRL_RX_EP_STALL | EPCTRL_TX_EP_STALL; 125e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(epctrlx, &udc->op_regs->epctrlx[0]); 126e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 127e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* update ep0 state */ 128e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_state = WAIT_FOR_SETUP; 129e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_dir = EP_DIR_OUT; 130e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 131e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 132e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int process_ep_req(struct mv_udc *udc, int index, 133e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_req *curr_req) 134e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 135e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_dtd *curr_dtd; 136e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_dqh *curr_dqh; 137e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int td_complete, actual, remaining_length; 138e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int i, direction; 139e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int retval = 0; 140e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 errors; 141daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang u32 bit_pos; 142e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 143e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie curr_dqh = &udc->ep_dqh[index]; 144e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie direction = index % 2; 145e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 146e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie curr_dtd = curr_req->head; 147e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie td_complete = 0; 148e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie actual = curr_req->req.length; 149e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 150e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie for (i = 0; i < curr_req->dtd_count; i++) { 151e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (curr_dtd->size_ioc_sts & DTD_STATUS_ACTIVE) { 152e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_dbg(&udc->dev->dev, "%s, dTD not completed\n", 153e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->eps[index].name); 154e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 1; 155e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 156e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 157e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie errors = curr_dtd->size_ioc_sts & DTD_ERROR_MASK; 158e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!errors) { 159daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang remaining_length = 160e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie (curr_dtd->size_ioc_sts & DTD_PACKET_SIZE) 161e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie >> DTD_LENGTH_BIT_POS; 162e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie actual -= remaining_length; 163daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang 164daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang if (remaining_length) { 165daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang if (direction) { 166daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang dev_dbg(&udc->dev->dev, 167daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang "TX dTD remains data\n"); 168daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang retval = -EPROTO; 169daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang break; 170daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang } else 171daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang break; 172daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang } 173e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { 174e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_info(&udc->dev->dev, 175e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie "complete_tr error: ep=%d %s: error = 0x%x\n", 176e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie index >> 1, direction ? "SEND" : "RECV", 177e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie errors); 178e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (errors & DTD_STATUS_HALTED) { 179e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Clear the errors and Halt condition */ 180e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie curr_dqh->size_ioc_int_sts &= ~errors; 181e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -EPIPE; 182e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else if (errors & DTD_STATUS_DATA_BUFF_ERR) { 183e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -EPROTO; 184e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else if (errors & DTD_STATUS_TRANSACTION_ERR) { 185e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -EILSEQ; 186e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 187e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 188e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (i != curr_req->dtd_count - 1) 189e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie curr_dtd = (struct mv_dtd *)curr_dtd->next_dtd_virt; 190e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 191e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (retval) 192e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return retval; 193e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 194daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang if (direction == EP_DIR_OUT) 195daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang bit_pos = 1 << curr_req->ep->ep_num; 196daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang else 197daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang bit_pos = 1 << (16 + curr_req->ep->ep_num); 198daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang 199daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang while ((curr_dqh->curr_dtd_ptr == curr_dtd->td_dma)) { 200daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang if (curr_dtd->dtd_next == EP_QUEUE_HEAD_NEXT_TERMINATE) { 201daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang while (readl(&udc->op_regs->epstatus) & bit_pos) 202daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang udelay(1); 203daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang break; 204daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang } 205daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang udelay(1); 206daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang } 207daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang 208e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie curr_req->req.actual = actual; 209e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 210e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 211e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 212e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 213e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* 214e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * done() - retire a request; caller blocked irqs 215e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * @status : request status to be set, only works when 216e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * request is still in progress. 217e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie */ 218e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void done(struct mv_ep *ep, struct mv_req *req, int status) 219e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 220e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc = NULL; 221e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned char stopped = ep->stopped; 222e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_dtd *curr_td, *next_td; 223e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int j; 224e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 225e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc = (struct mv_udc *)ep->udc; 226e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Removed the req from fsl_ep->queue */ 227e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie list_del_init(&req->queue); 228e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 229e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* req.status should be set as -EINPROGRESS in ep_queue() */ 230e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (req->req.status == -EINPROGRESS) 231e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.status = status; 232e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie else 233e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie status = req->req.status; 234e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 235e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Free dtd for the request */ 236e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie next_td = req->head; 237e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie for (j = 0; j < req->dtd_count; j++) { 238e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie curr_td = next_td; 239e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (j != req->dtd_count - 1) 240e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie next_td = curr_td->next_dtd_virt; 241e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dma_pool_free(udc->dtd_pool, curr_td, curr_td->td_dma); 242e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 243e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 244e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (req->mapped) { 245e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dma_unmap_single(ep->udc->gadget.dev.parent, 246e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.dma, req->req.length, 247e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ((ep_dir(ep) == EP_DIR_IN) ? 248e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie DMA_TO_DEVICE : DMA_FROM_DEVICE)); 249e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.dma = DMA_ADDR_INVALID; 250e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->mapped = 0; 251e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else 252e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, 253e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.dma, req->req.length, 254e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ((ep_dir(ep) == EP_DIR_IN) ? 255e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie DMA_TO_DEVICE : DMA_FROM_DEVICE)); 256e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 257e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (status && (status != -ESHUTDOWN)) 258e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_info(&udc->dev->dev, "complete %s req %p stat %d len %u/%u", 259e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->ep.name, &req->req, status, 260e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.actual, req->req.length); 261e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 262e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->stopped = 1; 263e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 264e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock(&ep->udc->lock); 265e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* 266e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * complete() is from gadget layer, 267e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * eg fsg->bulk_in_complete() 268e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie */ 269e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (req->req.complete) 270e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.complete(&ep->ep, &req->req); 271e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 272e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock(&ep->udc->lock); 273e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->stopped = stopped; 274e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 275e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 276e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int queue_dtd(struct mv_ep *ep, struct mv_req *req) 277e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 278e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc; 279e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_dqh *dqh; 28091d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang u32 bit_pos, direction; 28191d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang u32 usbcmd, epstatus; 282e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned int loops; 28391d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang int retval = 0; 284e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 285e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc = ep->udc; 286e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie direction = ep_dir(ep); 287e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dqh = &(udc->ep_dqh[ep->ep_num * 2 + direction]); 288e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie bit_pos = 1 << (((direction == EP_DIR_OUT) ? 0 : 16) + ep->ep_num); 289e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 290e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* check if the pipe is empty */ 291e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!(list_empty(&ep->queue))) { 292e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_req *lastreq; 293e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie lastreq = list_entry(ep->queue.prev, struct mv_req, queue); 294e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie lastreq->tail->dtd_next = 295e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK; 29691d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang 29791d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang wmb(); 29891d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang 29991d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang if (readl(&udc->op_regs->epprime) & bit_pos) 30091d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang goto done; 30191d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang 302e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie loops = LOOPS(READSAFE_TIMEOUT); 30391d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang while (1) { 304e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* start with setting the semaphores */ 30591d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang usbcmd = readl(&udc->op_regs->usbcmd); 30691d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang usbcmd |= USBCMD_ATDTW_TRIPWIRE_SET; 30791d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang writel(usbcmd, &udc->op_regs->usbcmd); 308e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 309e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* read the endpoint status */ 310e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epstatus = readl(&udc->op_regs->epstatus) & bit_pos; 311e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 312e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* 313e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * Reread the ATDTW semaphore bit to check if it is 314e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * cleared. When hardware see a hazard, it will clear 315e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * the bit or else we remain set to 1 and we can 316e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * proceed with priming of endpoint if not already 317e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * primed. 318e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie */ 319e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (readl(&udc->op_regs->usbcmd) 32091d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang & USBCMD_ATDTW_TRIPWIRE_SET) 32191d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang break; 32291d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang 323e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie loops--; 32491d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang if (loops == 0) { 32591d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang dev_err(&udc->dev->dev, 32691d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang "Timeout for ATDTW_TRIPWIRE...\n"); 32791d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang retval = -ETIME; 32891d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang goto done; 32991d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang } 330e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udelay(LOOPS_USEC); 331e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 332e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 333e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Clear the semaphore */ 33491d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang usbcmd = readl(&udc->op_regs->usbcmd); 33591d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR; 33691d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang writel(usbcmd, &udc->op_regs->usbcmd); 337e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 33891d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang if (epstatus) 33991d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang goto done; 34091d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang } 341e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 34291d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang /* Write dQH next pointer and terminate bit to 0 */ 34391d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang dqh->next_dtd_ptr = req->head->td_dma 344e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie & EP_QUEUE_HEAD_NEXT_POINTER_MASK; 345e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 34691d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang /* clear active and halt bit, in case set from a previous error */ 34791d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED); 348e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 34991d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang /* Ensure that updates to the QH will occure before priming. */ 35091d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang wmb(); 351e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 35291d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang /* Prime the Endpoint */ 35391d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang writel(bit_pos, &udc->op_regs->epprime); 354e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 355e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiedone: 356699324871fcc3650f2023c5e36cb119a92d7894bJustin P. Mattock return retval; 357e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 358e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 35991d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang 360e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length, 361e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dma_addr_t *dma, int *is_last) 362e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 363e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 temp; 364e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_dtd *dtd; 365e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc; 366e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 367e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* how big will this transfer be? */ 368e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie *length = min(req->req.length - req->req.actual, 369e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie (unsigned)EP_MAX_LENGTH_TRANSFER); 370e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 371e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc = req->ep->udc; 372e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 373e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* 374e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * Be careful that no _GFP_HIGHMEM is set, 375e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * or we can not use dma_to_virt 376e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie */ 377e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dtd = dma_pool_alloc(udc->dtd_pool, GFP_KERNEL, dma); 378e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (dtd == NULL) 379e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return dtd; 380e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 381e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dtd->td_dma = *dma; 382e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* initialize buffer page pointers */ 383e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie temp = (u32)(req->req.dma + req->req.actual); 384e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dtd->buff_ptr0 = cpu_to_le32(temp); 385e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie temp &= ~0xFFF; 386e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dtd->buff_ptr1 = cpu_to_le32(temp + 0x1000); 387e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dtd->buff_ptr2 = cpu_to_le32(temp + 0x2000); 388e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dtd->buff_ptr3 = cpu_to_le32(temp + 0x3000); 389e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dtd->buff_ptr4 = cpu_to_le32(temp + 0x4000); 390e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 391e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.actual += *length; 392e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 393e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* zlp is needed if req->req.zero is set */ 394e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (req->req.zero) { 395e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) 396e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie *is_last = 1; 397e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie else 398e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie *is_last = 0; 399e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else if (req->req.length == req->req.actual) 400e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie *is_last = 1; 401e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie else 402e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie *is_last = 0; 403e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 404e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Fill in the transfer size; set active bit */ 405e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE); 406e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 407e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Enable interrupt for the last dtd of a request */ 408e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (*is_last && !req->req.no_interrupt) 409e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie temp |= DTD_IOC; 410e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 411e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dtd->size_ioc_sts = temp; 412e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 413e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie mb(); 414e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 415e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return dtd; 416e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 417e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 418e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* generate dTD linked list for a request */ 419e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int req_to_dtd(struct mv_req *req) 420e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 421e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned count; 422e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int is_last, is_first = 1; 423e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_dtd *dtd, *last_dtd = NULL; 424e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc; 425e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dma_addr_t dma; 426e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 427e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc = req->ep->udc; 428e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 429e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie do { 430e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dtd = build_dtd(req, &count, &dma, &is_last); 431e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (dtd == NULL) 432e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -ENOMEM; 433e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 434e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (is_first) { 435e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie is_first = 0; 436e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->head = dtd; 437e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { 438e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie last_dtd->dtd_next = dma; 439e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie last_dtd->next_dtd_virt = dtd; 440e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 441e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie last_dtd = dtd; 442e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->dtd_count++; 443e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } while (!is_last); 444e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 445e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* set terminate bit to 1 for the last dTD */ 446e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dtd->dtd_next = DTD_NEXT_TERMINATE; 447e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 448e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->tail = dtd; 449e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 450e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 451e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 452e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 453e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_ep_enable(struct usb_ep *_ep, 454e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie const struct usb_endpoint_descriptor *desc) 455e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 456e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc; 457e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_ep *ep; 458e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_dqh *dqh; 459e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u16 max = 0; 460e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 bit_pos, epctrlx, direction; 461e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned char zlt = 0, ios = 0, mult = 0; 46227cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang unsigned long flags; 463e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 464e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep = container_of(_ep, struct mv_ep, ep); 465e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc = ep->udc; 466e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 467e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!_ep || !desc || ep->desc 468e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie || desc->bDescriptorType != USB_DT_ENDPOINT) 469e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -EINVAL; 470e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 471e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) 472e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -ESHUTDOWN; 473e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 474e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie direction = ep_dir(ep); 47529cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto max = usb_endpoint_maxp(desc); 476e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 477e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* 478e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * disable HW zero length termination select 479e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * driver handles zero length packet through req->req.zero 480e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie */ 481e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie zlt = 1; 482e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 483e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num); 484e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 485e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Check if the Endpoint is Primed */ 486e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if ((readl(&udc->op_regs->epprime) & bit_pos) 487e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie || (readl(&udc->op_regs->epstatus) & bit_pos)) { 488e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_info(&udc->dev->dev, 489e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie "ep=%d %s: Init ERROR: ENDPTPRIME=0x%x," 490e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie " ENDPTSTATUS=0x%x, bit_pos=0x%x\n", 491e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie (unsigned)ep->ep_num, direction ? "SEND" : "RECV", 492e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie (unsigned)readl(&udc->op_regs->epprime), 493e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie (unsigned)readl(&udc->op_regs->epstatus), 494e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie (unsigned)bit_pos); 495e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto en_done; 496e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 497e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Set the max packet length, interrupt on Setup and Mult fields */ 498e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { 499e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case USB_ENDPOINT_XFER_BULK: 500e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie zlt = 1; 501e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie mult = 0; 502e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 503e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case USB_ENDPOINT_XFER_CONTROL: 504e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ios = 1; 505e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case USB_ENDPOINT_XFER_INT: 506e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie mult = 0; 507e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 508e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case USB_ENDPOINT_XFER_ISOC: 509e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Calculate transactions needed for high bandwidth iso */ 510e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie mult = (unsigned char)(1 + ((max >> 11) & 0x03)); 511bedcff970e16d36324ddbfa61de33e4640c9d619Neil Zhang max = max & 0x7ff; /* bit 0~10 */ 512e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* 3 transactions at most */ 513e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (mult > 3) 514e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto en_done; 515e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 516e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie default: 517e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto en_done; 518e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 51927cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang 52027cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang spin_lock_irqsave(&udc->lock, flags); 52127cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang /* Get the endpoint queue head address */ 52227cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang dqh = ep->dqh; 523e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dqh->max_packet_length = (max << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) 524e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie | (mult << EP_QUEUE_HEAD_MULT_POS) 525e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie | (zlt ? EP_QUEUE_HEAD_ZLT_SEL : 0) 526e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie | (ios ? EP_QUEUE_HEAD_IOS : 0); 527e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dqh->next_dtd_ptr = 1; 528e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dqh->size_ioc_int_sts = 0; 529e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 530e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->ep.maxpacket = max; 531e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->desc = desc; 532e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->stopped = 0; 533e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 534e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Enable the endpoint for Rx or Tx and set the endpoint type */ 535e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); 536e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (direction == EP_DIR_IN) { 537e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx &= ~EPCTRL_TX_ALL_MASK; 538e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx |= EPCTRL_TX_ENABLE | EPCTRL_TX_DATA_TOGGLE_RST 539e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie | ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) 540e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie << EPCTRL_TX_EP_TYPE_SHIFT); 541e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { 542e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx &= ~EPCTRL_RX_ALL_MASK; 543e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx |= EPCTRL_RX_ENABLE | EPCTRL_RX_DATA_TOGGLE_RST 544e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie | ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) 545e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie << EPCTRL_RX_EP_TYPE_SHIFT); 546e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 547e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); 548e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 549e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* 550e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * Implement Guideline (GL# USB-7) The unused endpoint type must 551e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * be programmed to bulk. 552e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie */ 553e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); 554e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if ((epctrlx & EPCTRL_RX_ENABLE) == 0) { 555615268b05f6c719f5151c351022aa79ab73a0898Neil Zhang epctrlx |= (USB_ENDPOINT_XFER_BULK 556e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie << EPCTRL_RX_EP_TYPE_SHIFT); 557e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); 558e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 559e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 560e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); 561e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if ((epctrlx & EPCTRL_TX_ENABLE) == 0) { 562615268b05f6c719f5151c351022aa79ab73a0898Neil Zhang epctrlx |= (USB_ENDPOINT_XFER_BULK 563e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie << EPCTRL_TX_EP_TYPE_SHIFT); 564e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); 565e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 566e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 56727cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang spin_unlock_irqrestore(&udc->lock, flags); 56827cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang 569e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 570e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieen_done: 571e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -EINVAL; 572e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 573e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 574e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_ep_disable(struct usb_ep *_ep) 575e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 576e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc; 577e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_ep *ep; 578e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_dqh *dqh; 579e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 bit_pos, epctrlx, direction; 58027cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang unsigned long flags; 581e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 582e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep = container_of(_ep, struct mv_ep, ep); 583e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if ((_ep == NULL) || !ep->desc) 584e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -EINVAL; 585e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 586e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc = ep->udc; 587e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 588e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Get the endpoint queue head address */ 589e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dqh = ep->dqh; 590e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 59127cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang spin_lock_irqsave(&udc->lock, flags); 59227cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang 593e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie direction = ep_dir(ep); 594e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num); 595e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 596e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Reset the max packet length and the interrupt on Setup */ 597e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dqh->max_packet_length = 0; 598e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 599e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Disable the endpoint for Rx or Tx and reset the endpoint type */ 600e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); 601e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx &= ~((direction == EP_DIR_IN) 602e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ? (EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE) 603e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie : (EPCTRL_RX_ENABLE | EPCTRL_RX_TYPE)); 604e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); 605e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 606e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* nuke all pending requests (does flush) */ 607e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie nuke(ep, -ESHUTDOWN); 608e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 609e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->desc = NULL; 610f9c56cdd3905c96c600456203637bd7ec8ec6383Ido Shayevitz ep->ep.desc = NULL; 611e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->stopped = 1; 61227cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang 61327cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang spin_unlock_irqrestore(&udc->lock, flags); 61427cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang 615e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 616e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 617e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 618e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic struct usb_request * 619e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiemv_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) 620e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 621e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_req *req = NULL; 622e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 623e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req = kzalloc(sizeof *req, gfp_flags); 624e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!req) 625e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return NULL; 626e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 627e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.dma = DMA_ADDR_INVALID; 628e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie INIT_LIST_HEAD(&req->queue); 629e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 630e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return &req->req; 631e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 632e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 633e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void mv_free_request(struct usb_ep *_ep, struct usb_request *_req) 634e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 635e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_req *req = NULL; 636e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 637e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req = container_of(_req, struct mv_req, req); 638e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 639e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (_req) 640e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie kfree(req); 641e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 642e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 643e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void mv_ep_fifo_flush(struct usb_ep *_ep) 644e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 645e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc; 646e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 bit_pos, direction; 6470c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang struct mv_ep *ep; 648e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned int loops; 649e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 6500c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang if (!_ep) 6510c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang return; 6520c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang 6530c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang ep = container_of(_ep, struct mv_ep, ep); 6540c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang if (!ep->desc) 6550c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang return; 6560c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang 657e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc = ep->udc; 658e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie direction = ep_dir(ep); 659e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 6600c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang if (ep->ep_num == 0) 6610c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang bit_pos = (1 << 16) | 1; 6620c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang else if (direction == EP_DIR_OUT) 6630c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang bit_pos = 1 << ep->ep_num; 6640c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang else 6650c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang bit_pos = 1 << (16 + ep->ep_num); 6660c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang 667e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie loops = LOOPS(EPSTATUS_TIMEOUT); 6680c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang do { 669e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned int inter_loops; 670e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 671e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (loops == 0) { 672e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&udc->dev->dev, 673e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie "TIMEOUT for ENDPTSTATUS=0x%x, bit_pos=0x%x\n", 674e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie (unsigned)readl(&udc->op_regs->epstatus), 675e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie (unsigned)bit_pos); 676e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return; 677e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 678e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Write 1 to the Flush register */ 679e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(bit_pos, &udc->op_regs->epflush); 680e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 681e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Wait until flushing completed */ 682e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie inter_loops = LOOPS(FLUSH_TIMEOUT); 6830c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang while (readl(&udc->op_regs->epflush)) { 684e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* 685e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * ENDPTFLUSH bit should be cleared to indicate this 686e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * operation is complete 687e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie */ 688e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (inter_loops == 0) { 689e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&udc->dev->dev, 690e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie "TIMEOUT for ENDPTFLUSH=0x%x," 691e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie "bit_pos=0x%x\n", 692e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie (unsigned)readl(&udc->op_regs->epflush), 693e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie (unsigned)bit_pos); 694e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return; 695e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 696e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie inter_loops--; 697e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udelay(LOOPS_USEC); 698e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 699e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie loops--; 7000c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang } while (readl(&udc->op_regs->epstatus) & bit_pos); 701e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 702e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 703e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* queues (submits) an I/O request to an endpoint */ 704e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int 705e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiemv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) 706e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 707e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_ep *ep = container_of(_ep, struct mv_ep, ep); 708e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_req *req = container_of(_req, struct mv_req, req); 709e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc = ep->udc; 710e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned long flags; 711e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 712e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* catch various bogus parameters */ 713e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!_req || !req->req.complete || !req->req.buf 714e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie || !list_empty(&req->queue)) { 715e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&udc->dev->dev, "%s, bad params", __func__); 716e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -EINVAL; 717e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 718e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (unlikely(!_ep || !ep->desc)) { 719e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&udc->dev->dev, "%s, bad ep", __func__); 720e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -EINVAL; 721e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 722e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { 723e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (req->req.length > ep->ep.maxpacket) 724e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -EMSGSIZE; 725e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 726e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 727e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc = ep->udc; 728e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) 729e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -ESHUTDOWN; 730e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 731e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->ep = ep; 732e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 733e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* map virtual address to hardware */ 734e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (req->req.dma == DMA_ADDR_INVALID) { 735e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, 736e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.buf, 737e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.length, ep_dir(ep) 738e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ? DMA_TO_DEVICE 739e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie : DMA_FROM_DEVICE); 740e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->mapped = 1; 741e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { 742e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dma_sync_single_for_device(ep->udc->gadget.dev.parent, 743e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.dma, req->req.length, 744e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep_dir(ep) 745e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ? DMA_TO_DEVICE 746e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie : DMA_FROM_DEVICE); 747e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->mapped = 0; 748e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 749e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 750e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.status = -EINPROGRESS; 751e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.actual = 0; 752e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->dtd_count = 0; 753e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 754e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock_irqsave(&udc->lock, flags); 755e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 756e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* build dtds and push them to device queue */ 757e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!req_to_dtd(req)) { 758e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int retval; 759e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = queue_dtd(ep, req); 760e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (retval) { 761e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock_irqrestore(&udc->lock, flags); 762e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return retval; 763e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 764e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { 765e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock_irqrestore(&udc->lock, flags); 766e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -ENOMEM; 767e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 768e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 769e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Update ep0 state */ 770e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (ep->ep_num == 0) 771e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_state = DATA_STATE_XMIT; 772e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 773e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* irq handler advances the queue */ 77410800f2ca1a78e24cf92dc5e16a68a9b78f91bbeDan Carpenter list_add_tail(&req->queue, &ep->queue); 775e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock_irqrestore(&udc->lock, flags); 776e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 777e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 778e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 779e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 780c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhangstatic void mv_prime_ep(struct mv_ep *ep, struct mv_req *req) 781c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang{ 782c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang struct mv_dqh *dqh = ep->dqh; 783c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang u32 bit_pos; 784c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang 785c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang /* Write dQH next pointer and terminate bit to 0 */ 786c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang dqh->next_dtd_ptr = req->head->td_dma 787c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang & EP_QUEUE_HEAD_NEXT_POINTER_MASK; 788c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang 789c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang /* clear active and halt bit, in case set from a previous error */ 790c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED); 791c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang 792c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang /* Ensure that updates to the QH will occure before priming. */ 793c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang wmb(); 794c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang 795c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang bit_pos = 1 << (((ep_dir(ep) == EP_DIR_OUT) ? 0 : 16) + ep->ep_num); 796c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang 797c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang /* Prime the Endpoint */ 798c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang writel(bit_pos, &ep->udc->op_regs->epprime); 799c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang} 800c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang 801e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* dequeues (cancels, unlinks) an I/O request from an endpoint */ 802e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) 803e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 804e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_ep *ep = container_of(_ep, struct mv_ep, ep); 805e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_req *req; 806e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc = ep->udc; 807e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned long flags; 808e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int stopped, ret = 0; 809e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 epctrlx; 810e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 811e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!_ep || !_req) 812e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -EINVAL; 813e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 814e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock_irqsave(&ep->udc->lock, flags); 815e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie stopped = ep->stopped; 816e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 817e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Stop the ep before we deal with the queue */ 818e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->stopped = 1; 819e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); 820e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (ep_dir(ep) == EP_DIR_IN) 821e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx &= ~EPCTRL_TX_ENABLE; 822e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie else 823e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx &= ~EPCTRL_RX_ENABLE; 824e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); 825e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 826e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* make sure it's actually queued on this endpoint */ 827e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie list_for_each_entry(req, &ep->queue, queue) { 828e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (&req->req == _req) 829e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 830e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 831e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (&req->req != _req) { 832e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ret = -EINVAL; 833e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 834e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 835e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 836e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* The request is in progress, or completed but not dequeued */ 837e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (ep->queue.next == &req->queue) { 838e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie _req->status = -ECONNRESET; 839e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie mv_ep_fifo_flush(_ep); /* flush current transfer */ 840e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 841e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* The request isn't the last request in this ep queue */ 842e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (req->queue.next != &ep->queue) { 843e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_req *next_req; 844e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 845c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang next_req = list_entry(req->queue.next, 846c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang struct mv_req, queue); 847e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 848e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Point the QH to the first TD of next request */ 849c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang mv_prime_ep(ep, next_req); 850e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { 851e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_dqh *qh; 852e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 853e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie qh = ep->dqh; 854e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie qh->next_dtd_ptr = 1; 855e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie qh->size_ioc_int_sts = 0; 856e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 857e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 858e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* The request hasn't been processed, patch up the TD chain */ 859e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { 860e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_req *prev_req; 861e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 862e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie prev_req = list_entry(req->queue.prev, struct mv_req, queue); 863e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(readl(&req->tail->dtd_next), 864e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie &prev_req->tail->dtd_next); 865e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 866e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 867e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 868e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie done(ep, req, -ECONNRESET); 869e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 870e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Enable EP */ 871e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieout: 872e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); 873e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (ep_dir(ep) == EP_DIR_IN) 874e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx |= EPCTRL_TX_ENABLE; 875e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie else 876e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx |= EPCTRL_RX_ENABLE; 877e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); 878e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->stopped = stopped; 879e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 880e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock_irqrestore(&ep->udc->lock, flags); 881e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return ret; 882e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 883e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 884e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ep_set_stall(struct mv_udc *udc, u8 ep_num, u8 direction, int stall) 885e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 886e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 epctrlx; 887e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 888e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx = readl(&udc->op_regs->epctrlx[ep_num]); 889e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 890e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (stall) { 891e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (direction == EP_DIR_IN) 892e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx |= EPCTRL_TX_EP_STALL; 893e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie else 894e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx |= EPCTRL_RX_EP_STALL; 895e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { 896e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (direction == EP_DIR_IN) { 897e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx &= ~EPCTRL_TX_EP_STALL; 898e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx |= EPCTRL_TX_DATA_TOGGLE_RST; 899e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { 900e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx &= ~EPCTRL_RX_EP_STALL; 901e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx |= EPCTRL_RX_DATA_TOGGLE_RST; 902e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 903e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 904e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(epctrlx, &udc->op_regs->epctrlx[ep_num]); 905e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 906e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 907e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int ep_is_stall(struct mv_udc *udc, u8 ep_num, u8 direction) 908e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 909e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 epctrlx; 910e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 911e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie epctrlx = readl(&udc->op_regs->epctrlx[ep_num]); 912e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 913e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (direction == EP_DIR_OUT) 914e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return (epctrlx & EPCTRL_RX_EP_STALL) ? 1 : 0; 915e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie else 916e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return (epctrlx & EPCTRL_TX_EP_STALL) ? 1 : 0; 917e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 918e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 919e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge) 920e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 921e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_ep *ep; 922e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned long flags = 0; 923e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int status = 0; 924e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc; 925e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 926e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep = container_of(_ep, struct mv_ep, ep); 927e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc = ep->udc; 928e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!_ep || !ep->desc) { 929e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie status = -EINVAL; 930e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 931e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 932e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 933e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { 934e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie status = -EOPNOTSUPP; 935e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 936e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 937e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 938e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* 939e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * Attempt to halt IN ep will fail if any transfer requests 940e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * are still queue 941e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie */ 942e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (halt && (ep_dir(ep) == EP_DIR_IN) && !list_empty(&ep->queue)) { 943e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie status = -EAGAIN; 944e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 945e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 946e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 947e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock_irqsave(&ep->udc->lock, flags); 948e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep_set_stall(udc, ep->ep_num, ep_dir(ep), halt); 949e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (halt && wedge) 950e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->wedge = 1; 951e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie else if (!halt) 952e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->wedge = 0; 953e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock_irqrestore(&ep->udc->lock, flags); 954e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 955e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (ep->ep_num == 0) { 956e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_state = WAIT_FOR_SETUP; 957e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_dir = EP_DIR_OUT; 958e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 959e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieout: 960e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return status; 961e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 962e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 963e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_ep_set_halt(struct usb_ep *_ep, int halt) 964e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 965e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return mv_ep_set_halt_wedge(_ep, halt, 0); 966e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 967e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 968e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_ep_set_wedge(struct usb_ep *_ep) 969e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 970e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return mv_ep_set_halt_wedge(_ep, 1, 1); 971e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 972e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 973e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic struct usb_ep_ops mv_ep_ops = { 974e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .enable = mv_ep_enable, 975e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .disable = mv_ep_disable, 976e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 977e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .alloc_request = mv_alloc_request, 978e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .free_request = mv_free_request, 979e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 980e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .queue = mv_ep_queue, 981e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .dequeue = mv_ep_dequeue, 982e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 983e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .set_wedge = mv_ep_set_wedge, 984e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .set_halt = mv_ep_set_halt, 985e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .fifo_flush = mv_ep_fifo_flush, /* flush fifo */ 986e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}; 987e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 988dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangstatic void udc_clock_enable(struct mv_udc *udc) 989dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang{ 990dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang unsigned int i; 991dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang 992dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang for (i = 0; i < udc->clknum; i++) 993dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang clk_enable(udc->clk[i]); 994dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang} 995dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang 996dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangstatic void udc_clock_disable(struct mv_udc *udc) 997dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang{ 998dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang unsigned int i; 999dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang 1000dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang for (i = 0; i < udc->clknum; i++) 1001dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang clk_disable(udc->clk[i]); 1002dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang} 1003dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang 1004e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void udc_stop(struct mv_udc *udc) 1005e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1006e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 tmp; 1007e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1008e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Disable interrupts */ 1009e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp = readl(&udc->op_regs->usbintr); 1010e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp &= ~(USBINTR_INT_EN | USBINTR_ERR_INT_EN | 1011e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie USBINTR_PORT_CHANGE_DETECT_EN | USBINTR_RESET_EN); 1012e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(tmp, &udc->op_regs->usbintr); 1013e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1014309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang udc->stopped = 1; 1015309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang 1016e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Reset the Run the bit in the command register to stop VUSB */ 1017e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp = readl(&udc->op_regs->usbcmd); 1018e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp &= ~USBCMD_RUN_STOP; 1019e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(tmp, &udc->op_regs->usbcmd); 1020e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1021e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1022e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void udc_start(struct mv_udc *udc) 1023e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1024e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 usbintr; 1025e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1026e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie usbintr = USBINTR_INT_EN | USBINTR_ERR_INT_EN 1027e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie | USBINTR_PORT_CHANGE_DETECT_EN 1028e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie | USBINTR_RESET_EN | USBINTR_DEVICE_SUSPEND; 1029e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Enable interrupts */ 1030e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(usbintr, &udc->op_regs->usbintr); 1031e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1032309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang udc->stopped = 0; 1033309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang 1034e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Set the Run bit in the command register */ 1035e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(USBCMD_RUN_STOP, &udc->op_regs->usbcmd); 1036e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1037e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1038e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int udc_reset(struct mv_udc *udc) 1039e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1040e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned int loops; 1041e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 tmp, portsc; 1042e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1043e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Stop the controller */ 1044e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp = readl(&udc->op_regs->usbcmd); 1045e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp &= ~USBCMD_RUN_STOP; 1046e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(tmp, &udc->op_regs->usbcmd); 1047e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1048e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Reset the controller to get default values */ 1049e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(USBCMD_CTRL_RESET, &udc->op_regs->usbcmd); 1050e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1051e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* wait for reset to complete */ 1052e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie loops = LOOPS(RESET_TIMEOUT); 1053e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie while (readl(&udc->op_regs->usbcmd) & USBCMD_CTRL_RESET) { 1054e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (loops == 0) { 1055e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&udc->dev->dev, 1056e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie "Wait for RESET completed TIMEOUT\n"); 1057e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -ETIMEDOUT; 1058e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1059e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie loops--; 1060e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udelay(LOOPS_USEC); 1061e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1062e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1063e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* set controller to device mode */ 1064e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp = readl(&udc->op_regs->usbmode); 1065e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp |= USBMODE_CTRL_MODE_DEVICE; 1066e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1067e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* turn setup lockout off, require setup tripwire in usbcmd */ 1068e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp |= USBMODE_SETUP_LOCK_OFF | USBMODE_STREAM_DISABLE; 1069e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1070e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(tmp, &udc->op_regs->usbmode); 1071e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1072e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(0x0, &udc->op_regs->epsetupstat); 1073e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1074e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Configure the Endpoint List Address */ 1075e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(udc->ep_dqh_dma & USB_EP_LIST_ADDRESS_MASK, 1076e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie &udc->op_regs->eplistaddr); 1077e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1078e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie portsc = readl(&udc->op_regs->portsc[0]); 1079e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (readl(&udc->cap_regs->hcsparams) & HCSPARAMS_PPC) 1080e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie portsc &= (~PORTSCX_W1C_BITS | ~PORTSCX_PORT_POWER); 1081e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1082e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->force_fs) 1083e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie portsc |= PORTSCX_FORCE_FULL_SPEED_CONNECT; 1084e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie else 1085e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie portsc &= (~PORTSCX_FORCE_FULL_SPEED_CONNECT); 1086e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1087e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(portsc, &udc->op_regs->portsc[0]); 1088e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1089e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp = readl(&udc->op_regs->epctrlx[0]); 1090e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp &= ~(EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL); 1091e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(tmp, &udc->op_regs->epctrlx[0]); 1092e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1093e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 1094e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1095e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 109685ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhangstatic int mv_udc_enable_internal(struct mv_udc *udc) 10971aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang{ 10981aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang int retval; 10991aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 110085ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang if (udc->active) 11011aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang return 0; 11021aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 11031aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang dev_dbg(&udc->dev->dev, "enable udc\n"); 11041aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc_clock_enable(udc); 11051aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (udc->pdata->phy_init) { 11061aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang retval = udc->pdata->phy_init(udc->phy_regs); 11071aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (retval) { 11081aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang dev_err(&udc->dev->dev, 11091aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang "init phy error %d\n", retval); 11101aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc_clock_disable(udc); 11111aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang return retval; 11121aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang } 11131aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang } 11141aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc->active = 1; 11151aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 11161aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang return 0; 11171aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang} 11181aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 111985ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhangstatic int mv_udc_enable(struct mv_udc *udc) 11201aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang{ 112185ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang if (udc->clock_gating) 112285ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang return mv_udc_enable_internal(udc); 112385ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang 112485ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang return 0; 112585ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang} 112685ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang 112785ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhangstatic void mv_udc_disable_internal(struct mv_udc *udc) 112885ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang{ 112985ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang if (udc->active) { 11301aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang dev_dbg(&udc->dev->dev, "disable udc\n"); 11311aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (udc->pdata->phy_deinit) 11321aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc->pdata->phy_deinit(udc->phy_regs); 11331aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc_clock_disable(udc); 11341aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc->active = 0; 11351aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang } 11361aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang} 11371aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 113885ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhangstatic void mv_udc_disable(struct mv_udc *udc) 113985ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang{ 114085ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang if (udc->clock_gating) 114185ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang mv_udc_disable_internal(udc); 114285ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang} 114385ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang 1144e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_udc_get_frame(struct usb_gadget *gadget) 1145e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1146e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc; 1147e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u16 retval; 1148e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1149e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!gadget) 1150e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -ENODEV; 1151e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1152e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc = container_of(gadget, struct mv_udc, gadget); 1153e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 115486bb702813010a0870c45d7f080669450a95be8dNeil Zhang retval = readl(&udc->op_regs->frindex) & USB_FRINDEX_MASKS; 1155e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1156e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return retval; 1157e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1158e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1159e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* Tries to wake up the host connected to this gadget */ 1160e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_udc_wakeup(struct usb_gadget *gadget) 1161e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1162e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc = container_of(gadget, struct mv_udc, gadget); 1163e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 portsc; 1164e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1165e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Remote wakeup feature not enabled by host */ 1166e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!udc->remote_wakeup) 1167e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -ENOTSUPP; 1168e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1169e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie portsc = readl(&udc->op_regs->portsc); 1170e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* not suspended? */ 1171e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!(portsc & PORTSCX_PORT_SUSPEND)) 1172e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 1173e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* trigger force resume */ 1174e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie portsc |= PORTSCX_PORT_FORCE_RESUME; 1175e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(portsc, &udc->op_regs->portsc[0]); 1176e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 1177e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1178e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 11791aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhangstatic int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active) 11801aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang{ 11811aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang struct mv_udc *udc; 11821aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang unsigned long flags; 11831aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang int retval = 0; 11841aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 11851aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc = container_of(gadget, struct mv_udc, gadget); 11861aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang spin_lock_irqsave(&udc->lock, flags); 11871aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 11882bcb75144027fcee878319de87a967a4dec49403Neil Zhang udc->vbus_active = (is_active != 0); 11892bcb75144027fcee878319de87a967a4dec49403Neil Zhang 11901aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n", 11911aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang __func__, udc->softconnect, udc->vbus_active); 11921aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 11931aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (udc->driver && udc->softconnect && udc->vbus_active) { 11941aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang retval = mv_udc_enable(udc); 11951aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (retval == 0) { 11961aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang /* Clock is disabled, need re-init registers */ 11971aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc_reset(udc); 11981aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang ep0_reset(udc); 11991aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc_start(udc); 12001aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang } 12011aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang } else if (udc->driver && udc->softconnect) { 12021aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang /* stop all the transfer in queue*/ 12031aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang stop_activity(udc, udc->driver); 12041aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc_stop(udc); 12051aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang mv_udc_disable(udc); 12061aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang } 12071aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 12081aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang spin_unlock_irqrestore(&udc->lock, flags); 12091aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang return retval; 12101aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang} 12111aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 1212e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_udc_pullup(struct usb_gadget *gadget, int is_on) 1213e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1214e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc; 1215e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned long flags; 12161aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang int retval = 0; 1217e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1218e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc = container_of(gadget, struct mv_udc, gadget); 1219e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock_irqsave(&udc->lock, flags); 1220e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 12212bcb75144027fcee878319de87a967a4dec49403Neil Zhang udc->softconnect = (is_on != 0); 12222bcb75144027fcee878319de87a967a4dec49403Neil Zhang 12231aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n", 12241aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang __func__, udc->softconnect, udc->vbus_active); 12251aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 12261aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (udc->driver && udc->softconnect && udc->vbus_active) { 12271aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang retval = mv_udc_enable(udc); 12281aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (retval == 0) { 12291aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang /* Clock is disabled, need re-init registers */ 12301aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc_reset(udc); 12311aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang ep0_reset(udc); 12321aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc_start(udc); 12331aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang } 12341aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang } else if (udc->driver && udc->vbus_active) { 12351aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang /* stop all the transfer in queue*/ 12361aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang stop_activity(udc, udc->driver); 1237e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc_stop(udc); 12381aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang mv_udc_disable(udc); 12391aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang } 1240e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1241e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock_irqrestore(&udc->lock, flags); 12421aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang return retval; 1243e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1244e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 12450f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int mv_udc_start(struct usb_gadget_driver *driver, 12460f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior int (*bind)(struct usb_gadget *)); 12470f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int mv_udc_stop(struct usb_gadget_driver *driver); 1248e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* device controller usb_gadget_ops structure */ 1249e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic const struct usb_gadget_ops mv_ops = { 1250e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1251e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* returns the current frame number */ 1252e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .get_frame = mv_udc_get_frame, 1253e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1254e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* tries to wake up the host connected to this gadget */ 1255e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .wakeup = mv_udc_wakeup, 1256e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 12571aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang /* notify controller that VBUS is powered or not */ 12581aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang .vbus_session = mv_udc_vbus_session, 12591aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 1260e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* D+ pullup, software-controlled connect/disconnect to USB host */ 1261e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .pullup = mv_udc_pullup, 12620f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior .start = mv_udc_start, 12630f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior .stop = mv_udc_stop, 1264e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}; 1265e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1266e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int eps_init(struct mv_udc *udc) 1267e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1268e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_ep *ep; 1269e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie char name[14]; 1270e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int i; 1271e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1272e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* initialize ep0 */ 1273e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep = &udc->eps[0]; 1274e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->udc = udc; 1275e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie strncpy(ep->name, "ep0", sizeof(ep->name)); 1276e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->ep.name = ep->name; 1277e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->ep.ops = &mv_ep_ops; 1278e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->wedge = 0; 1279e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->stopped = 0; 1280e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->ep.maxpacket = EP0_MAX_PKT_SIZE; 1281e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->ep_num = 0; 1282e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->desc = &mv_ep0_desc; 1283e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie INIT_LIST_HEAD(&ep->queue); 1284e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1285e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->ep_type = USB_ENDPOINT_XFER_CONTROL; 1286e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1287e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* initialize other endpoints */ 1288e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie for (i = 2; i < udc->max_eps * 2; i++) { 1289e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep = &udc->eps[i]; 1290e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (i % 2) { 1291e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie snprintf(name, sizeof(name), "ep%din", i / 2); 1292e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->direction = EP_DIR_IN; 1293e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { 1294e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie snprintf(name, sizeof(name), "ep%dout", i / 2); 1295e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->direction = EP_DIR_OUT; 1296e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1297e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->udc = udc; 1298e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie strncpy(ep->name, name, sizeof(ep->name)); 1299e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->ep.name = ep->name; 1300e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1301e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->ep.ops = &mv_ep_ops; 1302e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->stopped = 0; 1303e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->ep.maxpacket = (unsigned short) ~0; 1304e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->ep_num = i / 2; 1305e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1306e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie INIT_LIST_HEAD(&ep->queue); 1307e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); 1308e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1309e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->dqh = &udc->ep_dqh[i]; 1310e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1311e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1312e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 1313e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1314e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1315e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* delete all endpoint requests, called with spinlock held */ 1316e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void nuke(struct mv_ep *ep, int status) 1317e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1318e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* called with spinlock held */ 1319e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep->stopped = 1; 1320e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1321e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* endpoint fifo flush */ 1322e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie mv_ep_fifo_flush(&ep->ep); 1323e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1324e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie while (!list_empty(&ep->queue)) { 1325e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_req *req = NULL; 1326e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req = list_entry(ep->queue.next, struct mv_req, queue); 1327e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie done(ep, req, status); 1328e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1329e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1330e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1331e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* stop all USB activities */ 1332e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver) 1333e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1334e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_ep *ep; 1335e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1336e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie nuke(&udc->eps[0], -ESHUTDOWN); 1337e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1338e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { 1339e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie nuke(ep, -ESHUTDOWN); 1340e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1341e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1342e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* report disconnect; the driver is already quiesced */ 1343e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (driver) { 1344e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock(&udc->lock); 1345e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie driver->disconnect(&udc->gadget); 1346e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock(&udc->lock); 1347e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1348e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1349e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 13500f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int mv_udc_start(struct usb_gadget_driver *driver, 1351e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int (*bind)(struct usb_gadget *)) 1352e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1353e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc = the_controller; 1354e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int retval = 0; 1355e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned long flags; 1356e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1357e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!udc) 1358e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -ENODEV; 1359e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1360e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->driver) 1361e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -EBUSY; 1362e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1363e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock_irqsave(&udc->lock, flags); 1364e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1365e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* hook up the driver ... */ 1366e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie driver->driver.bus = NULL; 1367e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->driver = driver; 1368e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.dev.driver = &driver->driver; 1369e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1370e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->usb_state = USB_STATE_ATTACHED; 1371e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_state = WAIT_FOR_SETUP; 13721aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc->ep0_dir = EP_DIR_OUT; 1373e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1374e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock_irqrestore(&udc->lock, flags); 1375e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1376e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = bind(&udc->gadget); 1377e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (retval) { 1378e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&udc->dev->dev, "bind to driver %s --> %d\n", 1379e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie driver->driver.name, retval); 1380e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->driver = NULL; 1381e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.dev.driver = NULL; 1382e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return retval; 1383e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 13841aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 1385487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang if (udc->transceiver) { 13866e13c6505cdff9766d5268ffb8c972c1a2f996e6Heikki Krogerus retval = otg_set_peripheral(udc->transceiver->otg, 13876e13c6505cdff9766d5268ffb8c972c1a2f996e6Heikki Krogerus &udc->gadget); 1388487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang if (retval) { 1389487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang dev_err(&udc->dev->dev, 1390487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang "unable to register peripheral to otg\n"); 1391487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang if (driver->unbind) { 1392487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang driver->unbind(&udc->gadget); 1393487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang udc->gadget.dev.driver = NULL; 1394487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang udc->driver = NULL; 1395487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang } 1396487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang return retval; 1397487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang } 1398487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang } 1399487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang 14001aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang /* pullup is always on */ 14011aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang mv_udc_pullup(&udc->gadget, 1); 14021aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 14031aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang /* When boot with cable attached, there will be no vbus irq occurred */ 14041aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (udc->qwork) 14051aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang queue_work(udc->qwork, &udc->vbus_work); 1406e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1407e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 1408e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1409e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 14100f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int mv_udc_stop(struct usb_gadget_driver *driver) 1411e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1412e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc = the_controller; 1413e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned long flags; 1414e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1415e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!udc) 1416e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return -ENODEV; 1417e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1418e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock_irqsave(&udc->lock, flags); 1419e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 14201aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang mv_udc_enable(udc); 14211aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc_stop(udc); 14221aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 1423e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* stop all usb activities */ 1424e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.speed = USB_SPEED_UNKNOWN; 1425e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie stop_activity(udc, driver); 14261aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang mv_udc_disable(udc); 14271aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 1428e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock_irqrestore(&udc->lock, flags); 1429e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1430e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* unbind gadget driver */ 1431e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie driver->unbind(&udc->gadget); 1432e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.dev.driver = NULL; 1433e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->driver = NULL; 1434e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1435e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 1436e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1437e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1438fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhangstatic void mv_set_ptc(struct mv_udc *udc, u32 mode) 1439fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang{ 1440fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang u32 portsc; 1441fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang 1442fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang portsc = readl(&udc->op_regs->portsc[0]); 1443fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang portsc |= mode << 16; 1444fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang writel(portsc, &udc->op_regs->portsc[0]); 1445fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang} 1446fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang 1447fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhangstatic void prime_status_complete(struct usb_ep *ep, struct usb_request *_req) 1448fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang{ 1449fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang struct mv_udc *udc = the_controller; 1450fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang struct mv_req *req = container_of(_req, struct mv_req, req); 1451fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang unsigned long flags; 1452fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang 1453fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang dev_info(&udc->dev->dev, "switch to test mode %d\n", req->test_mode); 1454fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang 1455fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang spin_lock_irqsave(&udc->lock, flags); 1456fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang if (req->test_mode) { 1457fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang mv_set_ptc(udc, req->test_mode); 1458fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang req->test_mode = 0; 1459fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang } 1460fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang spin_unlock_irqrestore(&udc->lock, flags); 1461fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang} 1462fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang 1463e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int 1464e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieudc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) 1465e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1466e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int retval = 0; 1467e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_req *req; 1468e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_ep *ep; 1469e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1470e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep = &udc->eps[0]; 1471e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_dir = direction; 1472366162245e619d59c9d615774ab3aa639deb7725Neil Zhang udc->ep0_state = WAIT_FOR_OUT_STATUS; 1473e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1474e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req = udc->status_req; 1475e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1476e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* fill in the reqest structure */ 1477e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (empty == false) { 1478e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie *((u16 *) req->req.buf) = cpu_to_le16(status); 1479e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.length = 2; 1480e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else 1481e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.length = 0; 1482e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1483e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->ep = ep; 1484e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.status = -EINPROGRESS; 1485e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->req.actual = 0; 1486fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang if (udc->test_mode) { 1487fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang req->req.complete = prime_status_complete; 1488fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang req->test_mode = udc->test_mode; 1489fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang udc->test_mode = 0; 1490fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang } else 1491fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang req->req.complete = NULL; 1492e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie req->dtd_count = 0; 1493e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 149446e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang if (req->req.dma == DMA_ADDR_INVALID) { 149546e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, 149646e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang req->req.buf, req->req.length, 149746e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang ep_dir(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); 149846e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang req->mapped = 1; 149946e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang } 150046e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang 1501e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* prime the data phase */ 1502e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!req_to_dtd(req)) 1503e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = queue_dtd(ep, req); 1504e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie else{ /* no mem */ 1505e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -ENOMEM; 1506e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 1507e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1508e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1509e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (retval) { 1510e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&udc->dev->dev, "response error on GET_STATUS request\n"); 1511e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 1512e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1513e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1514e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie list_add_tail(&req->queue, &ep->queue); 1515e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1516e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 1517e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieout: 1518e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return retval; 1519e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1520e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1521fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhangstatic void mv_udc_testmode(struct mv_udc *udc, u16 index) 1522fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang{ 1523fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang if (index <= TEST_FORCE_EN) { 1524fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang udc->test_mode = index; 1525fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang if (udc_prime_status(udc, EP_DIR_IN, 0, true)) 1526fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang ep0_stall(udc); 1527fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang } else 1528fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang dev_err(&udc->dev->dev, 1529fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang "This test mode(%d) is not supported\n", index); 1530fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang} 1531fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang 1532e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ch9setaddress(struct mv_udc *udc, struct usb_ctrlrequest *setup) 1533e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1534e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->dev_addr = (u8)setup->wValue; 1535e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1536e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* update usb state */ 1537e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->usb_state = USB_STATE_ADDRESS; 1538e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1539e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc_prime_status(udc, EP_DIR_IN, 0, true)) 1540e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep0_stall(udc); 1541e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1542e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1543e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ch9getstatus(struct mv_udc *udc, u8 ep_num, 1544e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct usb_ctrlrequest *setup) 1545e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1546431879a762277ddb9df959bba80216f3ef3d8e17Felipe Balbi u16 status = 0; 1547e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int retval; 1548e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1549e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) 1550e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie != (USB_DIR_IN | USB_TYPE_STANDARD)) 1551e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return; 1552e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1553e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { 1554e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie status = 1 << USB_DEVICE_SELF_POWERED; 1555e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie status |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP; 1556e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else if ((setup->bRequestType & USB_RECIP_MASK) 1557e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie == USB_RECIP_INTERFACE) { 1558e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* get interface status */ 1559e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie status = 0; 1560e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else if ((setup->bRequestType & USB_RECIP_MASK) 1561e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie == USB_RECIP_ENDPOINT) { 1562e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u8 ep_num, direction; 1563e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1564e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK; 1565e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK) 1566e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ? EP_DIR_IN : EP_DIR_OUT; 1567e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie status = ep_is_stall(udc, ep_num, direction) 1568e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie << USB_ENDPOINT_HALT; 1569e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1570e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1571e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = udc_prime_status(udc, EP_DIR_IN, status, false); 1572e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (retval) 1573e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep0_stall(udc); 1574366162245e619d59c9d615774ab3aa639deb7725Neil Zhang else 1575366162245e619d59c9d615774ab3aa639deb7725Neil Zhang udc->ep0_state = DATA_STATE_XMIT; 1576e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1577e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1578e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ch9clearfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup) 1579e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1580e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u8 ep_num; 1581e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u8 direction; 1582e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_ep *ep; 1583e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1584e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) 1585e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie == ((USB_TYPE_STANDARD | USB_RECIP_DEVICE))) { 1586e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie switch (setup->wValue) { 1587e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case USB_DEVICE_REMOTE_WAKEUP: 1588e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->remote_wakeup = 0; 1589e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1590e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie default: 1591e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 1592e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1593e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) 1594e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie == ((USB_TYPE_STANDARD | USB_RECIP_ENDPOINT))) { 1595e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie switch (setup->wValue) { 1596e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case USB_ENDPOINT_HALT: 1597e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK; 1598e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK) 1599e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ? EP_DIR_IN : EP_DIR_OUT; 1600e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (setup->wValue != 0 || setup->wLength != 0 1601e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie || ep_num > udc->max_eps) 1602e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 1603e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep = &udc->eps[ep_num * 2 + direction]; 1604e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (ep->wedge == 1) 1605e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1606e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock(&udc->lock); 1607e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep_set_stall(udc, ep_num, direction, 0); 1608e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock(&udc->lock); 1609e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1610e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie default: 1611e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 1612e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1613e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else 1614e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 1615e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1616e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc_prime_status(udc, EP_DIR_IN, 0, true)) 1617e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep0_stall(udc); 1618e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieout: 1619e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return; 1620e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1621e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1622e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ch9setfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup) 1623e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1624e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u8 ep_num; 1625e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u8 direction; 1626e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1627e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) 1628e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie == ((USB_TYPE_STANDARD | USB_RECIP_DEVICE))) { 1629e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie switch (setup->wValue) { 1630e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case USB_DEVICE_REMOTE_WAKEUP: 1631e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->remote_wakeup = 1; 1632e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1633e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case USB_DEVICE_TEST_MODE: 1634e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (setup->wIndex & 0xFF 1635fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang || udc->gadget.speed != USB_SPEED_HIGH) 1636fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang ep0_stall(udc); 1637fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang 1638fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang if (udc->usb_state != USB_STATE_CONFIGURED 1639fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang && udc->usb_state != USB_STATE_ADDRESS 1640fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang && udc->usb_state != USB_STATE_DEFAULT) 1641fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang ep0_stall(udc); 1642fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang 1643fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang mv_udc_testmode(udc, (setup->wIndex >> 8)); 1644fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang goto out; 1645e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie default: 1646e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 1647e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1648e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) 1649e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie == ((USB_TYPE_STANDARD | USB_RECIP_ENDPOINT))) { 1650e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie switch (setup->wValue) { 1651e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case USB_ENDPOINT_HALT: 1652e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK; 1653e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK) 1654e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ? EP_DIR_IN : EP_DIR_OUT; 1655e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (setup->wValue != 0 || setup->wLength != 0 1656e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie || ep_num > udc->max_eps) 1657e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 1658e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock(&udc->lock); 1659e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep_set_stall(udc, ep_num, direction, 1); 1660e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock(&udc->lock); 1661e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1662e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie default: 1663e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 1664e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1665e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else 1666e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie goto out; 1667e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1668e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc_prime_status(udc, EP_DIR_IN, 0, true)) 1669e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep0_stall(udc); 1670e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieout: 1671e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return; 1672e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1673e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1674e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void handle_setup_packet(struct mv_udc *udc, u8 ep_num, 1675e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct usb_ctrlrequest *setup) 1676e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1677e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie bool delegate = false; 1678e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1679e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie nuke(&udc->eps[ep_num * 2 + EP_DIR_OUT], -ESHUTDOWN); 1680e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1681e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_dbg(&udc->dev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", 1682e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie setup->bRequestType, setup->bRequest, 1683e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie setup->wValue, setup->wIndex, setup->wLength); 1684e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* We process some stardard setup requests here */ 1685e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 1686e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie switch (setup->bRequest) { 1687e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case USB_REQ_GET_STATUS: 1688e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ch9getstatus(udc, ep_num, setup); 1689e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1690e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1691e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case USB_REQ_SET_ADDRESS: 1692e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ch9setaddress(udc, setup); 1693e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1694e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1695e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case USB_REQ_CLEAR_FEATURE: 1696e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ch9clearfeature(udc, setup); 1697e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1698e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1699e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case USB_REQ_SET_FEATURE: 1700e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ch9setfeature(udc, setup); 1701e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1702e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1703e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie default: 1704e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie delegate = true; 1705e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1706e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else 1707e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie delegate = true; 1708e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1709e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* delegate USB standard requests to the gadget driver */ 1710e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (delegate == true) { 1711e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* USB requests handled by gadget */ 1712e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (setup->wLength) { 1713e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* DATA phase from gadget, STATUS phase from udc */ 1714e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_dir = (setup->bRequestType & USB_DIR_IN) 1715e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ? EP_DIR_IN : EP_DIR_OUT; 1716e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock(&udc->lock); 1717e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->driver->setup(&udc->gadget, 1718e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie &udc->local_setup_buff) < 0) 1719e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep0_stall(udc); 1720e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock(&udc->lock); 1721e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_state = (setup->bRequestType & USB_DIR_IN) 1722e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ? DATA_STATE_XMIT : DATA_STATE_RECV; 1723e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { 1724e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* no DATA phase, IN STATUS phase from gadget */ 1725e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_dir = EP_DIR_IN; 1726e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock(&udc->lock); 1727e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->driver->setup(&udc->gadget, 1728e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie &udc->local_setup_buff) < 0) 1729e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep0_stall(udc); 1730e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock(&udc->lock); 1731e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_state = WAIT_FOR_OUT_STATUS; 1732e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1733e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1734e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1735e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1736e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* complete DATA or STATUS phase of ep0 prime status phase if needed */ 1737e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ep0_req_complete(struct mv_udc *udc, 1738e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_ep *ep0, struct mv_req *req) 1739e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1740e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 new_addr; 1741e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1742e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->usb_state == USB_STATE_ADDRESS) { 1743e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* set the new address */ 1744e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie new_addr = (u32)udc->dev_addr; 1745e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(new_addr << USB_DEVICE_ADDRESS_BIT_SHIFT, 1746e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie &udc->op_regs->deviceaddr); 1747e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1748e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1749e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie done(ep0, req, 0); 1750e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1751e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie switch (udc->ep0_state) { 1752e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case DATA_STATE_XMIT: 1753e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* receive status phase */ 1754e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc_prime_status(udc, EP_DIR_OUT, 0, true)) 1755e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep0_stall(udc); 1756e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1757e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case DATA_STATE_RECV: 1758e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* send status phase */ 1759e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc_prime_status(udc, EP_DIR_IN, 0 , true)) 1760e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep0_stall(udc); 1761e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1762e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case WAIT_FOR_OUT_STATUS: 1763e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_state = WAIT_FOR_SETUP; 1764e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1765e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case WAIT_FOR_SETUP: 1766e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&udc->dev->dev, "unexpect ep0 packets\n"); 1767e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1768e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie default: 1769e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep0_stall(udc); 1770e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1771e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1772e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1773e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1774e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void get_setup_data(struct mv_udc *udc, u8 ep_num, u8 *buffer_ptr) 1775e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1776e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 temp; 1777e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_dqh *dqh; 1778e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1779e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dqh = &udc->ep_dqh[ep_num * 2 + EP_DIR_OUT]; 1780e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1781e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Clear bit in ENDPTSETUPSTAT */ 178296c2bbb09d0742148a305d7afbdf7c5803fd78c1Neil Zhang writel((1 << ep_num), &udc->op_regs->epsetupstat); 1783e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1784e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* while a hazard exists when setup package arrives */ 1785e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie do { 1786e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Set Setup Tripwire */ 1787e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie temp = readl(&udc->op_regs->usbcmd); 1788e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(temp | USBCMD_SETUP_TRIPWIRE_SET, &udc->op_regs->usbcmd); 1789e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1790e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Copy the setup packet to local buffer */ 1791e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie memcpy(buffer_ptr, (u8 *) dqh->setup_buffer, 8); 1792e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } while (!(readl(&udc->op_regs->usbcmd) & USBCMD_SETUP_TRIPWIRE_SET)); 1793e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1794e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Clear Setup Tripwire */ 1795e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie temp = readl(&udc->op_regs->usbcmd); 1796e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(temp & ~USBCMD_SETUP_TRIPWIRE_SET, &udc->op_regs->usbcmd); 1797e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1798e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1799e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void irq_process_tr_complete(struct mv_udc *udc) 1800e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1801e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 tmp, bit_pos; 1802e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int i, ep_num = 0, direction = 0; 1803e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_ep *curr_ep; 1804e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_req *curr_req, *temp_req; 1805e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int status; 1806e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1807e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* 1808e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * We use separate loops for ENDPTSETUPSTAT and ENDPTCOMPLETE 1809e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * because the setup packets are to be read ASAP 1810e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie */ 1811e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1812e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Process all Setup packet received interrupts */ 1813e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp = readl(&udc->op_regs->epsetupstat); 1814e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1815e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (tmp) { 1816e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie for (i = 0; i < udc->max_eps; i++) { 1817e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (tmp & (1 << i)) { 1818e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie get_setup_data(udc, i, 1819e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie (u8 *)(&udc->local_setup_buff)); 1820e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie handle_setup_packet(udc, i, 1821e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie &udc->local_setup_buff); 1822e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1823e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1824e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1825e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1826e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Don't clear the endpoint setup status register here. 1827e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * It is cleared as a setup packet is read out of the buffer 1828e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie */ 1829e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1830e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Process non-setup transaction complete interrupts */ 1831e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp = readl(&udc->op_regs->epcomplete); 1832e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1833e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!tmp) 1834e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return; 1835e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1836e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(tmp, &udc->op_regs->epcomplete); 1837e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1838e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie for (i = 0; i < udc->max_eps * 2; i++) { 1839e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep_num = i >> 1; 1840e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie direction = i % 2; 1841e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1842e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie bit_pos = 1 << (ep_num + 16 * direction); 1843e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1844e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!(bit_pos & tmp)) 1845e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie continue; 1846e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1847e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (i == 1) 1848e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie curr_ep = &udc->eps[0]; 1849e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie else 1850e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie curr_ep = &udc->eps[i]; 1851e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* process the req queue until an uncomplete request */ 1852e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie list_for_each_entry_safe(curr_req, temp_req, 1853e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie &curr_ep->queue, queue) { 1854e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie status = process_ep_req(udc, i, curr_req); 1855e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (status) 1856e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1857e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1858e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* write back status to req */ 1859e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie curr_req->req.status = status; 1860e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1861e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* ep0 request completion */ 1862e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (ep_num == 0) { 1863e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep0_req_complete(udc, curr_ep, curr_req); 1864e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1865e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { 1866e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie done(curr_ep, curr_req, status); 1867e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1868e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1869e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1870e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1871e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1872e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxievoid irq_process_reset(struct mv_udc *udc) 1873e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1874e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 tmp; 1875e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie unsigned int loops; 1876e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1877e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_dir = EP_DIR_OUT; 1878e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_state = WAIT_FOR_SETUP; 1879e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->remote_wakeup = 0; /* default to 0 on reset */ 1880e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1881e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* The address bits are past bit 25-31. Set the address */ 1882e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp = readl(&udc->op_regs->deviceaddr); 1883e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp &= ~(USB_DEVICE_ADDRESS_MASK); 1884e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(tmp, &udc->op_regs->deviceaddr); 1885e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1886e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Clear all the setup token semaphores */ 1887e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp = readl(&udc->op_regs->epsetupstat); 1888e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(tmp, &udc->op_regs->epsetupstat); 1889e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1890e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Clear all the endpoint complete status bits */ 1891e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie tmp = readl(&udc->op_regs->epcomplete); 1892e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(tmp, &udc->op_regs->epcomplete); 1893e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1894e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* wait until all endptprime bits cleared */ 1895e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie loops = LOOPS(PRIME_TIMEOUT); 1896e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie while (readl(&udc->op_regs->epprime) & 0xFFFFFFFF) { 1897e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (loops == 0) { 1898e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&udc->dev->dev, 1899e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie "Timeout for ENDPTPRIME = 0x%x\n", 1900e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie readl(&udc->op_regs->epprime)); 1901e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1902e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1903e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie loops--; 1904e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udelay(LOOPS_USEC); 1905e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1906e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1907e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Write 1s to the Flush register */ 1908e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel((u32)~0, &udc->op_regs->epflush); 1909e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1910e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (readl(&udc->op_regs->portsc[0]) & PORTSCX_PORT_RESET) { 1911e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_info(&udc->dev->dev, "usb bus reset\n"); 1912e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->usb_state = USB_STATE_DEFAULT; 1913e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* reset all the queues, stop all USB activities */ 1914e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie stop_activity(udc, udc->driver); 1915e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } else { 1916e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_info(&udc->dev->dev, "USB reset portsc 0x%x\n", 1917e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie readl(&udc->op_regs->portsc)); 1918e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1919e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* 1920e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * re-initialize 1921e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * controller reset 1922e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie */ 1923e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc_reset(udc); 1924e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1925e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* reset all the queues, stop all USB activities */ 1926e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie stop_activity(udc, udc->driver); 1927e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1928e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* reset ep0 dQH and endptctrl */ 1929e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ep0_reset(udc); 1930e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1931e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* enable interrupt and set controller to run state */ 1932e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc_start(udc); 1933e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1934e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->usb_state = USB_STATE_ATTACHED; 1935e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1936e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1937e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1938e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void handle_bus_resume(struct mv_udc *udc) 1939e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1940e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->usb_state = udc->resume_state; 1941e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->resume_state = 0; 1942e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1943e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* report resume to the driver */ 1944e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->driver) { 1945e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->driver->resume) { 1946e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock(&udc->lock); 1947e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->driver->resume(&udc->gadget); 1948e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock(&udc->lock); 1949e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1950e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1951e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1952e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1953e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void irq_process_suspend(struct mv_udc *udc) 1954e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1955e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->resume_state = udc->usb_state; 1956e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->usb_state = USB_STATE_SUSPENDED; 1957e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1958e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->driver->suspend) { 1959e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock(&udc->lock); 1960e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->driver->suspend(&udc->gadget); 1961e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock(&udc->lock); 1962e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1963e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 1964e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1965e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void irq_process_port_change(struct mv_udc *udc) 1966e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 1967e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 portsc; 1968e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1969e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie portsc = readl(&udc->op_regs->portsc[0]); 1970e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!(portsc & PORTSCX_PORT_RESET)) { 1971e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Get the speed */ 1972e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 speed = portsc & PORTSCX_PORT_SPEED_MASK; 1973e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie switch (speed) { 1974e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case PORTSCX_PORT_SPEED_HIGH: 1975e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.speed = USB_SPEED_HIGH; 1976e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1977e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case PORTSCX_PORT_SPEED_FULL: 1978e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.speed = USB_SPEED_FULL; 1979e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1980e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie case PORTSCX_PORT_SPEED_LOW: 1981e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.speed = USB_SPEED_LOW; 1982e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1983e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie default: 1984e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.speed = USB_SPEED_UNKNOWN; 1985e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie break; 1986e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1987e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1988e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1989e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (portsc & PORTSCX_PORT_SUSPEND) { 1990e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->resume_state = udc->usb_state; 1991e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->usb_state = USB_STATE_SUSPENDED; 1992e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->driver->suspend) { 1993e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock(&udc->lock); 1994e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->driver->suspend(&udc->gadget); 1995e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock(&udc->lock); 1996e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1997e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 1998e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 1999e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!(portsc & PORTSCX_PORT_SUSPEND) 2000e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie && udc->usb_state == USB_STATE_SUSPENDED) { 2001e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie handle_bus_resume(udc); 2002e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2003e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2004e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!udc->resume_state) 2005e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->usb_state = USB_STATE_DEFAULT; 2006e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 2007e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2008e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void irq_process_error(struct mv_udc *udc) 2009e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 2010e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* Increment the error count */ 2011e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->errors++; 2012e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 2013e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2014e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic irqreturn_t mv_udc_irq(int irq, void *dev) 2015e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 2016e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc = (struct mv_udc *)dev; 2017e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie u32 status, intr; 2018e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2019309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang /* Disable ISR when stopped bit is set */ 2020309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang if (udc->stopped) 2021309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang return IRQ_NONE; 2022309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang 2023e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock(&udc->lock); 2024e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2025e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie status = readl(&udc->op_regs->usbsts); 2026e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie intr = readl(&udc->op_regs->usbintr); 2027e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie status &= intr; 2028e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2029e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (status == 0) { 2030e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock(&udc->lock); 2031e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return IRQ_NONE; 2032e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2033e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 203425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi /* Clear all the interrupts occurred */ 2035e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie writel(status, &udc->op_regs->usbsts); 2036e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2037e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (status & USBSTS_ERR) 2038e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie irq_process_error(udc); 2039e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2040e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (status & USBSTS_RESET) 2041e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie irq_process_reset(udc); 2042e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2043e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (status & USBSTS_PORT_CHANGE) 2044e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie irq_process_port_change(udc); 2045e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2046e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (status & USBSTS_INT) 2047e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie irq_process_tr_complete(udc); 2048e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2049e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (status & USBSTS_SUSPEND) 2050e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie irq_process_suspend(udc); 2051e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2052e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_unlock(&udc->lock); 2053e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2054e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return IRQ_HANDLED; 2055e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 2056e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 20571aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhangstatic irqreturn_t mv_udc_vbus_irq(int irq, void *dev) 20581aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang{ 20591aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang struct mv_udc *udc = (struct mv_udc *)dev; 20601aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 20611aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang /* polling VBUS and init phy may cause too much time*/ 20621aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (udc->qwork) 20631aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang queue_work(udc->qwork, &udc->vbus_work); 20641aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 20651aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang return IRQ_HANDLED; 20661aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang} 20671aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 20681aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhangstatic void mv_udc_vbus_work(struct work_struct *work) 20691aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang{ 20701aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang struct mv_udc *udc; 20711aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang unsigned int vbus; 20721aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 20731aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc = container_of(work, struct mv_udc, vbus_work); 20741aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (!udc->pdata->vbus) 20751aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang return; 20761aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 20771aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang vbus = udc->pdata->vbus->poll(); 20781aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang dev_info(&udc->dev->dev, "vbus is %d\n", vbus); 20791aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 20801aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (vbus == VBUS_HIGH) 20811aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang mv_udc_vbus_session(&udc->gadget, 1); 20821aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang else if (vbus == VBUS_LOW) 20831aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang mv_udc_vbus_session(&udc->gadget, 0); 20841aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang} 20851aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 2086e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* release device structure */ 2087e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void gadget_release(struct device *_dev) 2088e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 2089e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc = the_controller; 2090e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2091e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie complete(udc->done); 2092e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 2093e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 20945d0b8d0f3af46c5364bc36f814cf2c407012dd1bNeil Zhangstatic int __devexit mv_udc_remove(struct platform_device *dev) 2095e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 2096e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc = the_controller; 2097dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang int clk_i; 2098e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 20990f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior usb_del_gadget_udc(&udc->gadget); 21000f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior 21011aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (udc->qwork) { 21021aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang flush_workqueue(udc->qwork); 21031aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang destroy_workqueue(udc->qwork); 21041aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang } 21051aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 2106487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang /* 2107487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang * If we have transceiver inited, 2108487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang * then vbus irq will not be requested in udc driver. 2109487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang */ 2110487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang if (udc->pdata && udc->pdata->vbus 2111487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang && udc->clock_gating && udc->transceiver == NULL) 21121aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang free_irq(udc->pdata->vbus->irq, &dev->dev); 2113e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2114e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* free memory allocated in probe */ 2115e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->dtd_pool) 2116e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dma_pool_destroy(udc->dtd_pool); 2117e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2118e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->ep_dqh) 2119e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dma_free_coherent(&dev->dev, udc->ep_dqh_size, 2120e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep_dqh, udc->ep_dqh_dma); 2121e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2122e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie kfree(udc->eps); 2123e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2124e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->irq) 2125e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie free_irq(udc->irq, &dev->dev); 2126e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 21271aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang mv_udc_disable(udc); 21281aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 2129e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->cap_regs) 2130e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie iounmap(udc->cap_regs); 2131e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2132e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->phy_regs) 21335e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang iounmap(udc->phy_regs); 2134e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2135e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->status_req) { 2136e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie kfree(udc->status_req->req.buf); 2137e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie kfree(udc->status_req); 2138e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2139e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2140dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang for (clk_i = 0; clk_i <= udc->clknum; clk_i++) 2141dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang clk_put(udc->clk[clk_i]); 2142dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang 2143e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie device_unregister(&udc->gadget.dev); 2144e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2145e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* free dev, wait for the release() finished */ 2146dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang wait_for_completion(udc->done); 2147dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang kfree(udc); 2148e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2149e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie the_controller = NULL; 2150e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2151e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 2152e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 2153e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 21545d0b8d0f3af46c5364bc36f814cf2c407012dd1bNeil Zhangstatic int __devinit mv_udc_probe(struct platform_device *dev) 2155e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 2156dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang struct mv_usb_platform_data *pdata = dev->dev.platform_data; 2157e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc; 2158e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int retval = 0; 2159dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang int clk_i = 0; 2160e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct resource *r; 2161e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie size_t size; 2162e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2163dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang if (pdata == NULL) { 2164dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang dev_err(&dev->dev, "missing platform_data\n"); 2165dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang return -ENODEV; 2166dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang } 2167dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang 2168dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum; 2169dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang udc = kzalloc(size, GFP_KERNEL); 2170e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc == NULL) { 2171e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&dev->dev, "failed to allocate memory for udc\n"); 2172dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang return -ENOMEM; 2173e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2174e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2175dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang the_controller = udc; 2176dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang udc->done = &release_done; 2177dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang udc->pdata = dev->dev.platform_data; 2178e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie spin_lock_init(&udc->lock); 2179e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2180e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->dev = dev; 2181e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2182487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang#ifdef CONFIG_USB_OTG_UTILS 2183487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang if (pdata->mode == MV_USB_MODE_OTG) 2184b96d3b08365f5a9603f50f3aadca6012f7eaffa1Heikki Krogerus udc->transceiver = usb_get_transceiver(); 2185487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang#endif 2186487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang 2187dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang udc->clknum = pdata->clknum; 2188dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang for (clk_i = 0; clk_i < udc->clknum; clk_i++) { 2189dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]); 2190dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang if (IS_ERR(udc->clk[clk_i])) { 2191dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang retval = PTR_ERR(udc->clk[clk_i]); 2192dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang goto err_put_clk; 2193dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang } 2194e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2195e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2196dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs"); 2197e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (r == NULL) { 2198e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&dev->dev, "no I/O memory resource defined\n"); 2199e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -ENODEV; 2200dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang goto err_put_clk; 2201e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2202e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2203e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->cap_regs = (struct mv_cap_regs __iomem *) 2204e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie ioremap(r->start, resource_size(r)); 2205e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->cap_regs == NULL) { 2206e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&dev->dev, "failed to map I/O memory\n"); 2207e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -EBUSY; 2208dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang goto err_put_clk; 2209e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2210e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2211dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "phyregs"); 2212e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (r == NULL) { 2213e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&dev->dev, "no phy I/O memory resource defined\n"); 2214e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -ENODEV; 2215dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang goto err_iounmap_capreg; 2216e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2217e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 22185e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang udc->phy_regs = ioremap(r->start, resource_size(r)); 22195e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang if (udc->phy_regs == NULL) { 2220e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&dev->dev, "failed to map phy I/O memory\n"); 2221e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -EBUSY; 2222dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang goto err_iounmap_capreg; 2223e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2224e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2225e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* we will acces controller register, so enable the clk */ 222685ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang retval = mv_udc_enable_internal(udc); 222785ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang if (retval) 222885ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang goto err_iounmap_phyreg; 2229e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 22305e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang udc->op_regs = 22315e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang (struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs 2232e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie + (readl(&udc->cap_regs->caplength_hciversion) 2233e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie & CAPLENGTH_MASK)); 2234e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK; 2235e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 22364540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang /* 22374540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang * some platform will use usb to download image, it may not disconnect 22384540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang * usb gadget before loading kernel. So first stop udc here. 22394540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang */ 22404540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang udc_stop(udc); 22414540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang writel(0xFFFFFFFF, &udc->op_regs->usbsts); 22424540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang 2243e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie size = udc->max_eps * sizeof(struct mv_dqh) *2; 2244e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie size = (size + DQH_ALIGNMENT - 1) & ~(DQH_ALIGNMENT - 1); 2245e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep_dqh = dma_alloc_coherent(&dev->dev, size, 2246e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie &udc->ep_dqh_dma, GFP_KERNEL); 2247e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2248e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->ep_dqh == NULL) { 2249e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&dev->dev, "allocate dQH memory failed\n"); 2250e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -ENOMEM; 2251dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang goto err_disable_clock; 2252e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2253e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep_dqh_size = size; 2254e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2255e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* create dTD dma_pool resource */ 2256e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->dtd_pool = dma_pool_create("mv_dtd", 2257e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie &dev->dev, 2258e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie sizeof(struct mv_dtd), 2259e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie DTD_ALIGNMENT, 2260e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie DMA_BOUNDARY); 2261e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2262e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!udc->dtd_pool) { 2263e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -ENOMEM; 2264dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang goto err_free_dma; 2265e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2266e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2267e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie size = udc->max_eps * sizeof(struct mv_ep) *2; 2268e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->eps = kzalloc(size, GFP_KERNEL); 2269e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (udc->eps == NULL) { 2270e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&dev->dev, "allocate ep memory failed\n"); 2271e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -ENOMEM; 2272dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang goto err_destroy_dma; 2273e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2274e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2275e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* initialize ep0 status request structure */ 2276e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->status_req = kzalloc(sizeof(struct mv_req), GFP_KERNEL); 2277e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (!udc->status_req) { 2278e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&dev->dev, "allocate status_req memory failed\n"); 2279e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -ENOMEM; 2280dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang goto err_free_eps; 2281e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2282e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie INIT_LIST_HEAD(&udc->status_req->queue); 2283e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2284e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* allocate a small amount of memory to get valid address */ 2285e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->status_req->req.buf = kzalloc(8, GFP_KERNEL); 228646e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang udc->status_req->req.dma = DMA_ADDR_INVALID; 2287e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2288e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->resume_state = USB_STATE_NOTATTACHED; 2289e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->usb_state = USB_STATE_POWERED; 2290e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->ep0_dir = EP_DIR_OUT; 2291e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->remote_wakeup = 0; 2292e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2293e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie r = platform_get_resource(udc->dev, IORESOURCE_IRQ, 0); 2294e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (r == NULL) { 2295e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&dev->dev, "no IRQ resource defined\n"); 2296e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -ENODEV; 2297dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang goto err_free_status_req; 2298e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2299e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->irq = r->start; 2300e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (request_irq(udc->irq, mv_udc_irq, 2301b5dd18d8747010e3f3eb1cc76a49f94291938559Yong Zhang IRQF_SHARED, driver_name, udc)) { 2302e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_err(&dev->dev, "Request irq %d for UDC failed\n", 2303e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->irq); 2304e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = -ENODEV; 2305dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang goto err_free_status_req; 2306e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2307e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2308e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* initialize gadget structure */ 2309e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.ops = &mv_ops; /* usb_gadget_ops */ 2310e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.ep0 = &udc->eps[0].ep; /* gadget ep0 */ 2311e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie INIT_LIST_HEAD(&udc->gadget.ep_list); /* ep_list */ 2312e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ 2313d327ab5b6d660d6fe22b073b743fde1668e593bbMichal Nazarewicz udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ 2314e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2315e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie /* the "gadget" abstracts/virtualizes the controller */ 2316e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie dev_set_name(&udc->gadget.dev, "gadget"); 2317e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.dev.parent = &dev->dev; 2318e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.dev.dma_mask = dev->dev.dma_mask; 2319e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.dev.release = gadget_release; 2320e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie udc->gadget.name = driver_name; /* gadget name */ 2321e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2322e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie retval = device_register(&udc->gadget.dev); 2323e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie if (retval) 2324dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang goto err_free_irq; 2325e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2326e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie eps_init(udc); 2327e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 23281aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang /* VBUS detect: we can disable/enable clock on demand.*/ 2329487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang if (udc->transceiver) 2330487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang udc->clock_gating = 1; 2331487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang else if (pdata->vbus) { 23321aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc->clock_gating = 1; 23331aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang retval = request_threaded_irq(pdata->vbus->irq, NULL, 23341aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc); 23351aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (retval) { 23361aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang dev_info(&dev->dev, 23371aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang "Can not request irq for VBUS, " 23381aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang "disable clock gating\n"); 23391aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc->clock_gating = 0; 23401aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang } 23411aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 23421aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc->qwork = create_singlethread_workqueue("mv_udc_queue"); 23431aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang if (!udc->qwork) { 23441aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang dev_err(&dev->dev, "cannot create workqueue\n"); 23451aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang retval = -ENOMEM; 23461aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang goto err_unregister; 23471aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang } 23481aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 23491aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang INIT_WORK(&udc->vbus_work, mv_udc_vbus_work); 23501aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang } 23511aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 23521aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang /* 23531aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang * When clock gating is supported, we can disable clk and phy. 23541aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang * If not, it means that VBUS detection is not supported, we 23551aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang * have to enable vbus active all the time to let controller work. 23561aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang */ 235785ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang if (udc->clock_gating) 235885ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang mv_udc_disable_internal(udc); 235985ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang else 23601aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc->vbus_active = 1; 2361e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 23620f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior retval = usb_add_gadget_udc(&dev->dev, &udc->gadget); 2363dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang if (retval) 2364dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang goto err_unregister; 2365dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang 23661aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang dev_info(&dev->dev, "successful probe UDC device %s clock gating.\n", 23671aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang udc->clock_gating ? "with" : "without"); 23681aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang 2369dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang return 0; 2370dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang 2371dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_unregister: 2372487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang if (udc->pdata && udc->pdata->vbus 2373487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang && udc->clock_gating && udc->transceiver == NULL) 23741aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang free_irq(pdata->vbus->irq, &dev->dev); 2375dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang device_unregister(&udc->gadget.dev); 2376dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_free_irq: 2377dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang free_irq(udc->irq, &dev->dev); 2378dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_free_status_req: 2379dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang kfree(udc->status_req->req.buf); 2380dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang kfree(udc->status_req); 2381dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_free_eps: 2382dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang kfree(udc->eps); 2383dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_destroy_dma: 2384dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang dma_pool_destroy(udc->dtd_pool); 2385dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_free_dma: 2386dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang dma_free_coherent(&dev->dev, udc->ep_dqh_size, 2387dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang udc->ep_dqh, udc->ep_dqh_dma); 2388dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_disable_clock: 238985ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang mv_udc_disable_internal(udc); 2390dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_iounmap_phyreg: 23915e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang iounmap(udc->phy_regs); 2392dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_iounmap_capreg: 2393dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang iounmap(udc->cap_regs); 2394dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_put_clk: 2395dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang for (clk_i--; clk_i >= 0; clk_i--) 2396dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang clk_put(udc->clk[clk_i]); 2397dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang the_controller = NULL; 2398dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang kfree(udc); 2399e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return retval; 2400e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 2401e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2402e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#ifdef CONFIG_PM 2403cb42447374eb4348b75ec677bf9c77958c7d10e0Sebastian Andrzej Siewiorstatic int mv_udc_suspend(struct device *_dev) 2404e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 2405e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc = the_controller; 2406e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 24075076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang /* if OTG is enabled, the following will be done in OTG driver*/ 24085076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang if (udc->transceiver) 24095076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang return 0; 24105076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang 24115076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang if (udc->pdata->vbus && udc->pdata->vbus->poll) 24125076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang if (udc->pdata->vbus->poll() == VBUS_HIGH) { 24135076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang dev_info(&udc->dev->dev, "USB cable is connected!\n"); 24145076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang return -EAGAIN; 24155076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang } 24165076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang 24175076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang /* 24185076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang * only cable is unplugged, udc can suspend. 24195076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang * So do not care about clock_gating == 1. 24205076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang */ 24215076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang if (!udc->clock_gating) { 24225076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang udc_stop(udc); 24235076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang 24245076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang spin_lock_irq(&udc->lock); 24255076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang /* stop all usb activities */ 24265076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang stop_activity(udc, udc->driver); 24275076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang spin_unlock_irq(&udc->lock); 24285076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang 24295076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang mv_udc_disable_internal(udc); 24305076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang } 2431e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2432e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 2433e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 2434e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2435cb42447374eb4348b75ec677bf9c77958c7d10e0Sebastian Andrzej Siewiorstatic int mv_udc_resume(struct device *_dev) 2436e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{ 2437e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie struct mv_udc *udc = the_controller; 2438e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie int retval; 2439e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 24405076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang /* if OTG is enabled, the following will be done in OTG driver*/ 24415076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang if (udc->transceiver) 24425076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang return 0; 24435076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang 24445076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang if (!udc->clock_gating) { 24455076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang retval = mv_udc_enable_internal(udc); 24465076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang if (retval) 2447dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang return retval; 24485076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang 24495076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang if (udc->driver && udc->softconnect) { 24505076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang udc_reset(udc); 24515076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang ep0_reset(udc); 24525076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang udc_start(udc); 2453dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang } 2454e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie } 2455dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang 2456e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie return 0; 2457e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie} 2458e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2459e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic const struct dev_pm_ops mv_udc_pm_ops = { 2460e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .suspend = mv_udc_suspend, 2461e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .resume = mv_udc_resume, 2462e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}; 2463e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#endif 2464e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie 2465046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhangstatic void mv_udc_shutdown(struct platform_device *dev) 2466046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang{ 2467046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang struct mv_udc *udc = the_controller; 2468046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang u32 mode; 2469046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang 2470046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang /* reset controller mode to IDLE */ 2471046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang mode = readl(&udc->op_regs->usbmode); 2472046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang mode &= ~3; 2473046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang writel(mode, &udc->op_regs->usbmode); 2474046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang} 2475046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang 2476e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic struct platform_driver udc_driver = { 2477e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .probe = mv_udc_probe, 2478e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .remove = __exit_p(mv_udc_remove), 2479046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang .shutdown = mv_udc_shutdown, 2480e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .driver = { 2481e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie .owner = THIS_MODULE, 24825e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang .name = "mv-udc", 2483e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#ifdef CONFIG_PM 2484cb42447374eb4348b75ec677bf9c77958c7d10e0Sebastian Andrzej Siewior .pm = &mv_udc_pm_ops, 2485e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#endif 2486e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie }, 2487e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}; 2488cc27c96c2bee93068bfc60ea6b09611d88cef429Axel Lin 2489cc27c96c2bee93068bfc60ea6b09611d88cef429Axel Linmodule_platform_driver(udc_driver); 2490ee0db58ade2c60342a7d648f375d0a4107c39527Greg Kroah-HartmanMODULE_ALIAS("platform:mv-udc"); 2491e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieMODULE_DESCRIPTION(DRIVER_DESC); 2492e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieMODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>"); 2493e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieMODULE_VERSION(DRIVER_VERSION); 2494e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieMODULE_LICENSE("GPL"); 2495