162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * M66592 UDC (USB gadget) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2006-2007 Renesas Solutions Corp. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/platform_device.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/usb/ch9.h> 1862306a36Sopenharmony_ci#include <linux/usb/gadget.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "m66592-udc.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciMODULE_DESCRIPTION("M66592 USB gadget driver"); 2362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2462306a36Sopenharmony_ciMODULE_AUTHOR("Yoshihiro Shimoda"); 2562306a36Sopenharmony_ciMODULE_ALIAS("platform:m66592_udc"); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define DRIVER_VERSION "21 July 2009" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic const char udc_name[] = "m66592_udc"; 3062306a36Sopenharmony_cistatic const char *m66592_ep_name[] = { 3162306a36Sopenharmony_ci "ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7" 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic void disable_controller(struct m66592 *m66592); 3562306a36Sopenharmony_cistatic void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req); 3662306a36Sopenharmony_cistatic void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req); 3762306a36Sopenharmony_cistatic int m66592_queue(struct usb_ep *_ep, struct usb_request *_req, 3862306a36Sopenharmony_ci gfp_t gfp_flags); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void transfer_complete(struct m66592_ep *ep, 4162306a36Sopenharmony_ci struct m66592_request *req, int status); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 4462306a36Sopenharmony_cistatic inline u16 get_usb_speed(struct m66592 *m66592) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci return (m66592_read(m66592, M66592_DVSTCTR) & M66592_RHST); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic void enable_pipe_irq(struct m66592 *m66592, u16 pipenum, 5062306a36Sopenharmony_ci unsigned long reg) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci u16 tmp; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci tmp = m66592_read(m66592, M66592_INTENB0); 5562306a36Sopenharmony_ci m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE, 5662306a36Sopenharmony_ci M66592_INTENB0); 5762306a36Sopenharmony_ci m66592_bset(m66592, (1 << pipenum), reg); 5862306a36Sopenharmony_ci m66592_write(m66592, tmp, M66592_INTENB0); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic void disable_pipe_irq(struct m66592 *m66592, u16 pipenum, 6262306a36Sopenharmony_ci unsigned long reg) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci u16 tmp; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci tmp = m66592_read(m66592, M66592_INTENB0); 6762306a36Sopenharmony_ci m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE, 6862306a36Sopenharmony_ci M66592_INTENB0); 6962306a36Sopenharmony_ci m66592_bclr(m66592, (1 << pipenum), reg); 7062306a36Sopenharmony_ci m66592_write(m66592, tmp, M66592_INTENB0); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic void m66592_usb_connect(struct m66592 *m66592) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci m66592_bset(m66592, M66592_CTRE, M66592_INTENB0); 7662306a36Sopenharmony_ci m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL, 7762306a36Sopenharmony_ci M66592_INTENB0); 7862306a36Sopenharmony_ci m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic void m66592_usb_disconnect(struct m66592 *m66592) 8462306a36Sopenharmony_ci__releases(m66592->lock) 8562306a36Sopenharmony_ci__acquires(m66592->lock) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0); 8862306a36Sopenharmony_ci m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL, 8962306a36Sopenharmony_ci M66592_INTENB0); 9062306a36Sopenharmony_ci m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0); 9162306a36Sopenharmony_ci m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci m66592->gadget.speed = USB_SPEED_UNKNOWN; 9462306a36Sopenharmony_ci spin_unlock(&m66592->lock); 9562306a36Sopenharmony_ci m66592->driver->disconnect(&m66592->gadget); 9662306a36Sopenharmony_ci spin_lock(&m66592->lock); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci disable_controller(m66592); 9962306a36Sopenharmony_ci INIT_LIST_HEAD(&m66592->ep[0].queue); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci u16 pid = 0; 10562306a36Sopenharmony_ci unsigned long offset; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (pipenum == 0) 10862306a36Sopenharmony_ci pid = m66592_read(m66592, M66592_DCPCTR) & M66592_PID; 10962306a36Sopenharmony_ci else if (pipenum < M66592_MAX_NUM_PIPE) { 11062306a36Sopenharmony_ci offset = get_pipectr_addr(pipenum); 11162306a36Sopenharmony_ci pid = m66592_read(m66592, offset) & M66592_PID; 11262306a36Sopenharmony_ci } else 11362306a36Sopenharmony_ci pr_err("unexpect pipe num (%d)\n", pipenum); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return pid; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum, 11962306a36Sopenharmony_ci u16 pid) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci unsigned long offset; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (pipenum == 0) 12462306a36Sopenharmony_ci m66592_mdfy(m66592, pid, M66592_PID, M66592_DCPCTR); 12562306a36Sopenharmony_ci else if (pipenum < M66592_MAX_NUM_PIPE) { 12662306a36Sopenharmony_ci offset = get_pipectr_addr(pipenum); 12762306a36Sopenharmony_ci m66592_mdfy(m66592, pid, M66592_PID, offset); 12862306a36Sopenharmony_ci } else 12962306a36Sopenharmony_ci pr_err("unexpect pipe num (%d)\n", pipenum); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic inline void pipe_start(struct m66592 *m66592, u16 pipenum) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci control_reg_set_pid(m66592, pipenum, M66592_PID_BUF); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic inline void pipe_stop(struct m66592 *m66592, u16 pipenum) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci control_reg_set_pid(m66592, pipenum, M66592_PID_NAK); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic inline void pipe_stall(struct m66592 *m66592, u16 pipenum) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci control_reg_set_pid(m66592, pipenum, M66592_PID_STALL); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic inline u16 control_reg_get(struct m66592 *m66592, u16 pipenum) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci u16 ret = 0; 15062306a36Sopenharmony_ci unsigned long offset; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (pipenum == 0) 15362306a36Sopenharmony_ci ret = m66592_read(m66592, M66592_DCPCTR); 15462306a36Sopenharmony_ci else if (pipenum < M66592_MAX_NUM_PIPE) { 15562306a36Sopenharmony_ci offset = get_pipectr_addr(pipenum); 15662306a36Sopenharmony_ci ret = m66592_read(m66592, offset); 15762306a36Sopenharmony_ci } else 15862306a36Sopenharmony_ci pr_err("unexpect pipe num (%d)\n", pipenum); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci return ret; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic inline void control_reg_sqclr(struct m66592 *m66592, u16 pipenum) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci unsigned long offset; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci pipe_stop(m66592, pipenum); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (pipenum == 0) 17062306a36Sopenharmony_ci m66592_bset(m66592, M66592_SQCLR, M66592_DCPCTR); 17162306a36Sopenharmony_ci else if (pipenum < M66592_MAX_NUM_PIPE) { 17262306a36Sopenharmony_ci offset = get_pipectr_addr(pipenum); 17362306a36Sopenharmony_ci m66592_bset(m66592, M66592_SQCLR, offset); 17462306a36Sopenharmony_ci } else 17562306a36Sopenharmony_ci pr_err("unexpect pipe num(%d)\n", pipenum); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic inline int get_buffer_size(struct m66592 *m66592, u16 pipenum) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci u16 tmp; 18162306a36Sopenharmony_ci int size; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (pipenum == 0) { 18462306a36Sopenharmony_ci tmp = m66592_read(m66592, M66592_DCPCFG); 18562306a36Sopenharmony_ci if ((tmp & M66592_CNTMD) != 0) 18662306a36Sopenharmony_ci size = 256; 18762306a36Sopenharmony_ci else { 18862306a36Sopenharmony_ci tmp = m66592_read(m66592, M66592_DCPMAXP); 18962306a36Sopenharmony_ci size = tmp & M66592_MAXP; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci } else { 19262306a36Sopenharmony_ci m66592_write(m66592, pipenum, M66592_PIPESEL); 19362306a36Sopenharmony_ci tmp = m66592_read(m66592, M66592_PIPECFG); 19462306a36Sopenharmony_ci if ((tmp & M66592_CNTMD) != 0) { 19562306a36Sopenharmony_ci tmp = m66592_read(m66592, M66592_PIPEBUF); 19662306a36Sopenharmony_ci size = ((tmp >> 10) + 1) * 64; 19762306a36Sopenharmony_ci } else { 19862306a36Sopenharmony_ci tmp = m66592_read(m66592, M66592_PIPEMAXP); 19962306a36Sopenharmony_ci size = tmp & M66592_MXPS; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return size; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic inline void pipe_change(struct m66592 *m66592, u16 pipenum) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct m66592_ep *ep = m66592->pipenum2ep[pipenum]; 20962306a36Sopenharmony_ci unsigned short mbw; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (ep->use_dma) 21262306a36Sopenharmony_ci return; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci m66592_mdfy(m66592, pipenum, M66592_CURPIPE, ep->fifosel); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci ndelay(450); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (m66592->pdata->on_chip) 21962306a36Sopenharmony_ci mbw = M66592_MBW_32; 22062306a36Sopenharmony_ci else 22162306a36Sopenharmony_ci mbw = M66592_MBW_16; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci m66592_bset(m66592, mbw, ep->fifosel); 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic int pipe_buffer_setting(struct m66592 *m66592, 22762306a36Sopenharmony_ci struct m66592_pipe_info *info) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci u16 bufnum = 0, buf_bsize = 0; 23062306a36Sopenharmony_ci u16 pipecfg = 0; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (info->pipe == 0) 23362306a36Sopenharmony_ci return -EINVAL; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci m66592_write(m66592, info->pipe, M66592_PIPESEL); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (info->dir_in) 23862306a36Sopenharmony_ci pipecfg |= M66592_DIR; 23962306a36Sopenharmony_ci pipecfg |= info->type; 24062306a36Sopenharmony_ci pipecfg |= info->epnum; 24162306a36Sopenharmony_ci switch (info->type) { 24262306a36Sopenharmony_ci case M66592_INT: 24362306a36Sopenharmony_ci bufnum = 4 + (info->pipe - M66592_BASE_PIPENUM_INT); 24462306a36Sopenharmony_ci buf_bsize = 0; 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci case M66592_BULK: 24762306a36Sopenharmony_ci /* isochronous pipes may be used as bulk pipes */ 24862306a36Sopenharmony_ci if (info->pipe >= M66592_BASE_PIPENUM_BULK) 24962306a36Sopenharmony_ci bufnum = info->pipe - M66592_BASE_PIPENUM_BULK; 25062306a36Sopenharmony_ci else 25162306a36Sopenharmony_ci bufnum = info->pipe - M66592_BASE_PIPENUM_ISOC; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci bufnum = M66592_BASE_BUFNUM + (bufnum * 16); 25462306a36Sopenharmony_ci buf_bsize = 7; 25562306a36Sopenharmony_ci pipecfg |= M66592_DBLB; 25662306a36Sopenharmony_ci if (!info->dir_in) 25762306a36Sopenharmony_ci pipecfg |= M66592_SHTNAK; 25862306a36Sopenharmony_ci break; 25962306a36Sopenharmony_ci case M66592_ISO: 26062306a36Sopenharmony_ci bufnum = M66592_BASE_BUFNUM + 26162306a36Sopenharmony_ci (info->pipe - M66592_BASE_PIPENUM_ISOC) * 16; 26262306a36Sopenharmony_ci buf_bsize = 7; 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (buf_bsize && ((bufnum + 16) >= M66592_MAX_BUFNUM)) { 26762306a36Sopenharmony_ci pr_err("m66592 pipe memory is insufficient\n"); 26862306a36Sopenharmony_ci return -ENOMEM; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci m66592_write(m66592, pipecfg, M66592_PIPECFG); 27262306a36Sopenharmony_ci m66592_write(m66592, (buf_bsize << 10) | (bufnum), M66592_PIPEBUF); 27362306a36Sopenharmony_ci m66592_write(m66592, info->maxpacket, M66592_PIPEMAXP); 27462306a36Sopenharmony_ci if (info->interval) 27562306a36Sopenharmony_ci info->interval--; 27662306a36Sopenharmony_ci m66592_write(m66592, info->interval, M66592_PIPEPERI); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic void pipe_buffer_release(struct m66592 *m66592, 28262306a36Sopenharmony_ci struct m66592_pipe_info *info) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci if (info->pipe == 0) 28562306a36Sopenharmony_ci return; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (is_bulk_pipe(info->pipe)) { 28862306a36Sopenharmony_ci m66592->bulk--; 28962306a36Sopenharmony_ci } else if (is_interrupt_pipe(info->pipe)) 29062306a36Sopenharmony_ci m66592->interrupt--; 29162306a36Sopenharmony_ci else if (is_isoc_pipe(info->pipe)) { 29262306a36Sopenharmony_ci m66592->isochronous--; 29362306a36Sopenharmony_ci if (info->type == M66592_BULK) 29462306a36Sopenharmony_ci m66592->bulk--; 29562306a36Sopenharmony_ci } else 29662306a36Sopenharmony_ci pr_err("ep_release: unexpect pipenum (%d)\n", 29762306a36Sopenharmony_ci info->pipe); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic void pipe_initialize(struct m66592_ep *ep) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct m66592 *m66592 = ep->m66592; 30362306a36Sopenharmony_ci unsigned short mbw; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci m66592_mdfy(m66592, 0, M66592_CURPIPE, ep->fifosel); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci m66592_write(m66592, M66592_ACLRM, ep->pipectr); 30862306a36Sopenharmony_ci m66592_write(m66592, 0, ep->pipectr); 30962306a36Sopenharmony_ci m66592_write(m66592, M66592_SQCLR, ep->pipectr); 31062306a36Sopenharmony_ci if (ep->use_dma) { 31162306a36Sopenharmony_ci m66592_mdfy(m66592, ep->pipenum, M66592_CURPIPE, ep->fifosel); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci ndelay(450); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (m66592->pdata->on_chip) 31662306a36Sopenharmony_ci mbw = M66592_MBW_32; 31762306a36Sopenharmony_ci else 31862306a36Sopenharmony_ci mbw = M66592_MBW_16; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci m66592_bset(m66592, mbw, ep->fifosel); 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, 32562306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc, 32662306a36Sopenharmony_ci u16 pipenum, int dma) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci if ((pipenum != 0) && dma) { 32962306a36Sopenharmony_ci if (m66592->num_dma == 0) { 33062306a36Sopenharmony_ci m66592->num_dma++; 33162306a36Sopenharmony_ci ep->use_dma = 1; 33262306a36Sopenharmony_ci ep->fifoaddr = M66592_D0FIFO; 33362306a36Sopenharmony_ci ep->fifosel = M66592_D0FIFOSEL; 33462306a36Sopenharmony_ci ep->fifoctr = M66592_D0FIFOCTR; 33562306a36Sopenharmony_ci ep->fifotrn = M66592_D0FIFOTRN; 33662306a36Sopenharmony_ci } else if (!m66592->pdata->on_chip && m66592->num_dma == 1) { 33762306a36Sopenharmony_ci m66592->num_dma++; 33862306a36Sopenharmony_ci ep->use_dma = 1; 33962306a36Sopenharmony_ci ep->fifoaddr = M66592_D1FIFO; 34062306a36Sopenharmony_ci ep->fifosel = M66592_D1FIFOSEL; 34162306a36Sopenharmony_ci ep->fifoctr = M66592_D1FIFOCTR; 34262306a36Sopenharmony_ci ep->fifotrn = M66592_D1FIFOTRN; 34362306a36Sopenharmony_ci } else { 34462306a36Sopenharmony_ci ep->use_dma = 0; 34562306a36Sopenharmony_ci ep->fifoaddr = M66592_CFIFO; 34662306a36Sopenharmony_ci ep->fifosel = M66592_CFIFOSEL; 34762306a36Sopenharmony_ci ep->fifoctr = M66592_CFIFOCTR; 34862306a36Sopenharmony_ci ep->fifotrn = 0; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci } else { 35162306a36Sopenharmony_ci ep->use_dma = 0; 35262306a36Sopenharmony_ci ep->fifoaddr = M66592_CFIFO; 35362306a36Sopenharmony_ci ep->fifosel = M66592_CFIFOSEL; 35462306a36Sopenharmony_ci ep->fifoctr = M66592_CFIFOCTR; 35562306a36Sopenharmony_ci ep->fifotrn = 0; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci ep->pipectr = get_pipectr_addr(pipenum); 35962306a36Sopenharmony_ci ep->pipenum = pipenum; 36062306a36Sopenharmony_ci ep->ep.maxpacket = usb_endpoint_maxp(desc); 36162306a36Sopenharmony_ci m66592->pipenum2ep[pipenum] = ep; 36262306a36Sopenharmony_ci m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep; 36362306a36Sopenharmony_ci INIT_LIST_HEAD(&ep->queue); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic void m66592_ep_release(struct m66592_ep *ep) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct m66592 *m66592 = ep->m66592; 36962306a36Sopenharmony_ci u16 pipenum = ep->pipenum; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (pipenum == 0) 37262306a36Sopenharmony_ci return; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (ep->use_dma) 37562306a36Sopenharmony_ci m66592->num_dma--; 37662306a36Sopenharmony_ci ep->pipenum = 0; 37762306a36Sopenharmony_ci ep->busy = 0; 37862306a36Sopenharmony_ci ep->use_dma = 0; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic int alloc_pipe_config(struct m66592_ep *ep, 38262306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct m66592 *m66592 = ep->m66592; 38562306a36Sopenharmony_ci struct m66592_pipe_info info; 38662306a36Sopenharmony_ci int dma = 0; 38762306a36Sopenharmony_ci int *counter; 38862306a36Sopenharmony_ci int ret; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci ep->ep.desc = desc; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci BUG_ON(ep->pipenum); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { 39562306a36Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 39662306a36Sopenharmony_ci if (m66592->bulk >= M66592_MAX_NUM_BULK) { 39762306a36Sopenharmony_ci if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { 39862306a36Sopenharmony_ci pr_err("bulk pipe is insufficient\n"); 39962306a36Sopenharmony_ci return -ENODEV; 40062306a36Sopenharmony_ci } else { 40162306a36Sopenharmony_ci info.pipe = M66592_BASE_PIPENUM_ISOC 40262306a36Sopenharmony_ci + m66592->isochronous; 40362306a36Sopenharmony_ci counter = &m66592->isochronous; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci } else { 40662306a36Sopenharmony_ci info.pipe = M66592_BASE_PIPENUM_BULK + m66592->bulk; 40762306a36Sopenharmony_ci counter = &m66592->bulk; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci info.type = M66592_BULK; 41062306a36Sopenharmony_ci dma = 1; 41162306a36Sopenharmony_ci break; 41262306a36Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 41362306a36Sopenharmony_ci if (m66592->interrupt >= M66592_MAX_NUM_INT) { 41462306a36Sopenharmony_ci pr_err("interrupt pipe is insufficient\n"); 41562306a36Sopenharmony_ci return -ENODEV; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci info.pipe = M66592_BASE_PIPENUM_INT + m66592->interrupt; 41862306a36Sopenharmony_ci info.type = M66592_INT; 41962306a36Sopenharmony_ci counter = &m66592->interrupt; 42062306a36Sopenharmony_ci break; 42162306a36Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 42262306a36Sopenharmony_ci if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { 42362306a36Sopenharmony_ci pr_err("isochronous pipe is insufficient\n"); 42462306a36Sopenharmony_ci return -ENODEV; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci info.pipe = M66592_BASE_PIPENUM_ISOC + m66592->isochronous; 42762306a36Sopenharmony_ci info.type = M66592_ISO; 42862306a36Sopenharmony_ci counter = &m66592->isochronous; 42962306a36Sopenharmony_ci break; 43062306a36Sopenharmony_ci default: 43162306a36Sopenharmony_ci pr_err("unexpect xfer type\n"); 43262306a36Sopenharmony_ci return -EINVAL; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci ep->type = info.type; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; 43762306a36Sopenharmony_ci info.maxpacket = usb_endpoint_maxp(desc); 43862306a36Sopenharmony_ci info.interval = desc->bInterval; 43962306a36Sopenharmony_ci if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) 44062306a36Sopenharmony_ci info.dir_in = 1; 44162306a36Sopenharmony_ci else 44262306a36Sopenharmony_ci info.dir_in = 0; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci ret = pipe_buffer_setting(m66592, &info); 44562306a36Sopenharmony_ci if (ret < 0) { 44662306a36Sopenharmony_ci pr_err("pipe_buffer_setting fail\n"); 44762306a36Sopenharmony_ci return ret; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci (*counter)++; 45162306a36Sopenharmony_ci if ((counter == &m66592->isochronous) && info.type == M66592_BULK) 45262306a36Sopenharmony_ci m66592->bulk++; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci m66592_ep_setting(m66592, ep, desc, info.pipe, dma); 45562306a36Sopenharmony_ci pipe_initialize(ep); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci return 0; 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic int free_pipe_config(struct m66592_ep *ep) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci struct m66592 *m66592 = ep->m66592; 46362306a36Sopenharmony_ci struct m66592_pipe_info info; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci info.pipe = ep->pipenum; 46662306a36Sopenharmony_ci info.type = ep->type; 46762306a36Sopenharmony_ci pipe_buffer_release(m66592, &info); 46862306a36Sopenharmony_ci m66592_ep_release(ep); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci return 0; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 47462306a36Sopenharmony_cistatic void pipe_irq_enable(struct m66592 *m66592, u16 pipenum) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci enable_irq_ready(m66592, pipenum); 47762306a36Sopenharmony_ci enable_irq_nrdy(m66592, pipenum); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic void pipe_irq_disable(struct m66592 *m66592, u16 pipenum) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci disable_irq_ready(m66592, pipenum); 48362306a36Sopenharmony_ci disable_irq_nrdy(m66592, pipenum); 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci/* if complete is true, gadget driver complete function is not call */ 48762306a36Sopenharmony_cistatic void control_end(struct m66592 *m66592, unsigned ccpl) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci m66592->ep[0].internal_ccpl = ccpl; 49062306a36Sopenharmony_ci pipe_start(m66592, 0); 49162306a36Sopenharmony_ci m66592_bset(m66592, M66592_CCPL, M66592_DCPCTR); 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic void start_ep0_write(struct m66592_ep *ep, struct m66592_request *req) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci struct m66592 *m66592 = ep->m66592; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci pipe_change(m66592, ep->pipenum); 49962306a36Sopenharmony_ci m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0, 50062306a36Sopenharmony_ci (M66592_ISEL | M66592_CURPIPE), 50162306a36Sopenharmony_ci M66592_CFIFOSEL); 50262306a36Sopenharmony_ci m66592_write(m66592, M66592_BCLR, ep->fifoctr); 50362306a36Sopenharmony_ci if (req->req.length == 0) { 50462306a36Sopenharmony_ci m66592_bset(m66592, M66592_BVAL, ep->fifoctr); 50562306a36Sopenharmony_ci pipe_start(m66592, 0); 50662306a36Sopenharmony_ci transfer_complete(ep, req, 0); 50762306a36Sopenharmony_ci } else { 50862306a36Sopenharmony_ci m66592_write(m66592, ~M66592_BEMP0, M66592_BEMPSTS); 50962306a36Sopenharmony_ci irq_ep0_write(ep, req); 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic void start_packet_write(struct m66592_ep *ep, struct m66592_request *req) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci struct m66592 *m66592 = ep->m66592; 51662306a36Sopenharmony_ci u16 tmp; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci pipe_change(m66592, ep->pipenum); 51962306a36Sopenharmony_ci disable_irq_empty(m66592, ep->pipenum); 52062306a36Sopenharmony_ci pipe_start(m66592, ep->pipenum); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci tmp = m66592_read(m66592, ep->fifoctr); 52362306a36Sopenharmony_ci if (unlikely((tmp & M66592_FRDY) == 0)) 52462306a36Sopenharmony_ci pipe_irq_enable(m66592, ep->pipenum); 52562306a36Sopenharmony_ci else 52662306a36Sopenharmony_ci irq_packet_write(ep, req); 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic void start_packet_read(struct m66592_ep *ep, struct m66592_request *req) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct m66592 *m66592 = ep->m66592; 53262306a36Sopenharmony_ci u16 pipenum = ep->pipenum; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (ep->pipenum == 0) { 53562306a36Sopenharmony_ci m66592_mdfy(m66592, M66592_PIPE0, 53662306a36Sopenharmony_ci (M66592_ISEL | M66592_CURPIPE), 53762306a36Sopenharmony_ci M66592_CFIFOSEL); 53862306a36Sopenharmony_ci m66592_write(m66592, M66592_BCLR, ep->fifoctr); 53962306a36Sopenharmony_ci pipe_start(m66592, pipenum); 54062306a36Sopenharmony_ci pipe_irq_enable(m66592, pipenum); 54162306a36Sopenharmony_ci } else { 54262306a36Sopenharmony_ci if (ep->use_dma) { 54362306a36Sopenharmony_ci m66592_bset(m66592, M66592_TRCLR, ep->fifosel); 54462306a36Sopenharmony_ci pipe_change(m66592, pipenum); 54562306a36Sopenharmony_ci m66592_bset(m66592, M66592_TRENB, ep->fifosel); 54662306a36Sopenharmony_ci m66592_write(m66592, 54762306a36Sopenharmony_ci (req->req.length + ep->ep.maxpacket - 1) 54862306a36Sopenharmony_ci / ep->ep.maxpacket, 54962306a36Sopenharmony_ci ep->fifotrn); 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci pipe_start(m66592, pipenum); /* trigger once */ 55262306a36Sopenharmony_ci pipe_irq_enable(m66592, pipenum); 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic void start_packet(struct m66592_ep *ep, struct m66592_request *req) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) 55962306a36Sopenharmony_ci start_packet_write(ep, req); 56062306a36Sopenharmony_ci else 56162306a36Sopenharmony_ci start_packet_read(ep, req); 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic void start_ep0(struct m66592_ep *ep, struct m66592_request *req) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci u16 ctsq; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci ctsq = m66592_read(ep->m66592, M66592_INTSTS0) & M66592_CTSQ; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci switch (ctsq) { 57162306a36Sopenharmony_ci case M66592_CS_RDDS: 57262306a36Sopenharmony_ci start_ep0_write(ep, req); 57362306a36Sopenharmony_ci break; 57462306a36Sopenharmony_ci case M66592_CS_WRDS: 57562306a36Sopenharmony_ci start_packet_read(ep, req); 57662306a36Sopenharmony_ci break; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci case M66592_CS_WRND: 57962306a36Sopenharmony_ci control_end(ep->m66592, 0); 58062306a36Sopenharmony_ci break; 58162306a36Sopenharmony_ci default: 58262306a36Sopenharmony_ci pr_err("start_ep0: unexpect ctsq(%x)\n", ctsq); 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic void init_controller(struct m66592 *m66592) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci unsigned int endian; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (m66592->pdata->on_chip) { 59262306a36Sopenharmony_ci if (m66592->pdata->endian) 59362306a36Sopenharmony_ci endian = 0; /* big endian */ 59462306a36Sopenharmony_ci else 59562306a36Sopenharmony_ci endian = M66592_LITTLE; /* little endian */ 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ 59862306a36Sopenharmony_ci m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG); 59962306a36Sopenharmony_ci m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); 60062306a36Sopenharmony_ci m66592_bset(m66592, M66592_USBE, M66592_SYSCFG); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* This is a workaound for SH7722 2nd cut */ 60362306a36Sopenharmony_ci m66592_bset(m66592, 0x8000, M66592_DVSTCTR); 60462306a36Sopenharmony_ci m66592_bset(m66592, 0x1000, M66592_TESTMODE); 60562306a36Sopenharmony_ci m66592_bclr(m66592, 0x8000, M66592_DVSTCTR); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci m66592_bset(m66592, M66592_INTL, M66592_INTENB1); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci m66592_write(m66592, 0, M66592_CFBCFG); 61062306a36Sopenharmony_ci m66592_write(m66592, 0, M66592_D0FBCFG); 61162306a36Sopenharmony_ci m66592_bset(m66592, endian, M66592_CFBCFG); 61262306a36Sopenharmony_ci m66592_bset(m66592, endian, M66592_D0FBCFG); 61362306a36Sopenharmony_ci } else { 61462306a36Sopenharmony_ci unsigned int clock, vif, irq_sense; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (m66592->pdata->endian) 61762306a36Sopenharmony_ci endian = M66592_BIGEND; /* big endian */ 61862306a36Sopenharmony_ci else 61962306a36Sopenharmony_ci endian = 0; /* little endian */ 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if (m66592->pdata->vif) 62262306a36Sopenharmony_ci vif = M66592_LDRV; /* 3.3v */ 62362306a36Sopenharmony_ci else 62462306a36Sopenharmony_ci vif = 0; /* 1.5v */ 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci switch (m66592->pdata->xtal) { 62762306a36Sopenharmony_ci case M66592_PLATDATA_XTAL_12MHZ: 62862306a36Sopenharmony_ci clock = M66592_XTAL12; 62962306a36Sopenharmony_ci break; 63062306a36Sopenharmony_ci case M66592_PLATDATA_XTAL_24MHZ: 63162306a36Sopenharmony_ci clock = M66592_XTAL24; 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci case M66592_PLATDATA_XTAL_48MHZ: 63462306a36Sopenharmony_ci clock = M66592_XTAL48; 63562306a36Sopenharmony_ci break; 63662306a36Sopenharmony_ci default: 63762306a36Sopenharmony_ci pr_warn("m66592-udc: xtal configuration error\n"); 63862306a36Sopenharmony_ci clock = 0; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci switch (m66592->irq_trigger) { 64262306a36Sopenharmony_ci case IRQF_TRIGGER_LOW: 64362306a36Sopenharmony_ci irq_sense = M66592_INTL; 64462306a36Sopenharmony_ci break; 64562306a36Sopenharmony_ci case IRQF_TRIGGER_FALLING: 64662306a36Sopenharmony_ci irq_sense = 0; 64762306a36Sopenharmony_ci break; 64862306a36Sopenharmony_ci default: 64962306a36Sopenharmony_ci pr_warn("m66592-udc: irq trigger config error\n"); 65062306a36Sopenharmony_ci irq_sense = 0; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci m66592_bset(m66592, 65462306a36Sopenharmony_ci (vif & M66592_LDRV) | (endian & M66592_BIGEND), 65562306a36Sopenharmony_ci M66592_PINCFG); 65662306a36Sopenharmony_ci m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ 65762306a36Sopenharmony_ci m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, 65862306a36Sopenharmony_ci M66592_SYSCFG); 65962306a36Sopenharmony_ci m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG); 66062306a36Sopenharmony_ci m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); 66162306a36Sopenharmony_ci m66592_bset(m66592, M66592_USBE, M66592_SYSCFG); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci msleep(3); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci msleep(1); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1); 67462306a36Sopenharmony_ci m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR, 67562306a36Sopenharmony_ci M66592_DMA0CFG); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic void disable_controller(struct m66592 *m66592) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci m66592_bclr(m66592, M66592_UTST, M66592_TESTMODE); 68262306a36Sopenharmony_ci if (!m66592->pdata->on_chip) { 68362306a36Sopenharmony_ci m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG); 68462306a36Sopenharmony_ci udelay(1); 68562306a36Sopenharmony_ci m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG); 68662306a36Sopenharmony_ci udelay(1); 68762306a36Sopenharmony_ci m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG); 68862306a36Sopenharmony_ci udelay(1); 68962306a36Sopenharmony_ci m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG); 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic void m66592_start_xclock(struct m66592 *m66592) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci u16 tmp; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (!m66592->pdata->on_chip) { 69862306a36Sopenharmony_ci tmp = m66592_read(m66592, M66592_SYSCFG); 69962306a36Sopenharmony_ci if (!(tmp & M66592_XCKE)) 70062306a36Sopenharmony_ci m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG); 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 70562306a36Sopenharmony_cistatic void transfer_complete(struct m66592_ep *ep, 70662306a36Sopenharmony_ci struct m66592_request *req, int status) 70762306a36Sopenharmony_ci__releases(m66592->lock) 70862306a36Sopenharmony_ci__acquires(m66592->lock) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci int restart = 0; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci if (unlikely(ep->pipenum == 0)) { 71362306a36Sopenharmony_ci if (ep->internal_ccpl) { 71462306a36Sopenharmony_ci ep->internal_ccpl = 0; 71562306a36Sopenharmony_ci return; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci list_del_init(&req->queue); 72062306a36Sopenharmony_ci if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN) 72162306a36Sopenharmony_ci req->req.status = -ESHUTDOWN; 72262306a36Sopenharmony_ci else 72362306a36Sopenharmony_ci req->req.status = status; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (!list_empty(&ep->queue)) 72662306a36Sopenharmony_ci restart = 1; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci spin_unlock(&ep->m66592->lock); 72962306a36Sopenharmony_ci usb_gadget_giveback_request(&ep->ep, &req->req); 73062306a36Sopenharmony_ci spin_lock(&ep->m66592->lock); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (restart) { 73362306a36Sopenharmony_ci req = list_entry(ep->queue.next, struct m66592_request, queue); 73462306a36Sopenharmony_ci if (ep->ep.desc) 73562306a36Sopenharmony_ci start_packet(ep, req); 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci int i; 74262306a36Sopenharmony_ci u16 tmp; 74362306a36Sopenharmony_ci unsigned bufsize; 74462306a36Sopenharmony_ci size_t size; 74562306a36Sopenharmony_ci void *buf; 74662306a36Sopenharmony_ci u16 pipenum = ep->pipenum; 74762306a36Sopenharmony_ci struct m66592 *m66592 = ep->m66592; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci pipe_change(m66592, pipenum); 75062306a36Sopenharmony_ci m66592_bset(m66592, M66592_ISEL, ep->fifosel); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci i = 0; 75362306a36Sopenharmony_ci do { 75462306a36Sopenharmony_ci tmp = m66592_read(m66592, ep->fifoctr); 75562306a36Sopenharmony_ci if (i++ > 100000) { 75662306a36Sopenharmony_ci pr_err("pipe0 is busy. maybe cpu i/o bus " 75762306a36Sopenharmony_ci "conflict. please power off this controller."); 75862306a36Sopenharmony_ci return; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci ndelay(1); 76162306a36Sopenharmony_ci } while ((tmp & M66592_FRDY) == 0); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* prepare parameters */ 76462306a36Sopenharmony_ci bufsize = get_buffer_size(m66592, pipenum); 76562306a36Sopenharmony_ci buf = req->req.buf + req->req.actual; 76662306a36Sopenharmony_ci size = min(bufsize, req->req.length - req->req.actual); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci /* write fifo */ 76962306a36Sopenharmony_ci if (req->req.buf) { 77062306a36Sopenharmony_ci if (size > 0) 77162306a36Sopenharmony_ci m66592_write_fifo(m66592, ep, buf, size); 77262306a36Sopenharmony_ci if ((size == 0) || ((size % ep->ep.maxpacket) != 0)) 77362306a36Sopenharmony_ci m66592_bset(m66592, M66592_BVAL, ep->fifoctr); 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci /* update parameters */ 77762306a36Sopenharmony_ci req->req.actual += size; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* check transfer finish */ 78062306a36Sopenharmony_ci if ((!req->req.zero && (req->req.actual == req->req.length)) 78162306a36Sopenharmony_ci || (size % ep->ep.maxpacket) 78262306a36Sopenharmony_ci || (size == 0)) { 78362306a36Sopenharmony_ci disable_irq_ready(m66592, pipenum); 78462306a36Sopenharmony_ci disable_irq_empty(m66592, pipenum); 78562306a36Sopenharmony_ci } else { 78662306a36Sopenharmony_ci disable_irq_ready(m66592, pipenum); 78762306a36Sopenharmony_ci enable_irq_empty(m66592, pipenum); 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci pipe_start(m66592, pipenum); 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci u16 tmp; 79562306a36Sopenharmony_ci unsigned bufsize; 79662306a36Sopenharmony_ci size_t size; 79762306a36Sopenharmony_ci void *buf; 79862306a36Sopenharmony_ci u16 pipenum = ep->pipenum; 79962306a36Sopenharmony_ci struct m66592 *m66592 = ep->m66592; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci pipe_change(m66592, pipenum); 80262306a36Sopenharmony_ci tmp = m66592_read(m66592, ep->fifoctr); 80362306a36Sopenharmony_ci if (unlikely((tmp & M66592_FRDY) == 0)) { 80462306a36Sopenharmony_ci pipe_stop(m66592, pipenum); 80562306a36Sopenharmony_ci pipe_irq_disable(m66592, pipenum); 80662306a36Sopenharmony_ci pr_err("write fifo not ready. pipnum=%d\n", pipenum); 80762306a36Sopenharmony_ci return; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci /* prepare parameters */ 81162306a36Sopenharmony_ci bufsize = get_buffer_size(m66592, pipenum); 81262306a36Sopenharmony_ci buf = req->req.buf + req->req.actual; 81362306a36Sopenharmony_ci size = min(bufsize, req->req.length - req->req.actual); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci /* write fifo */ 81662306a36Sopenharmony_ci if (req->req.buf) { 81762306a36Sopenharmony_ci m66592_write_fifo(m66592, ep, buf, size); 81862306a36Sopenharmony_ci if ((size == 0) 81962306a36Sopenharmony_ci || ((size % ep->ep.maxpacket) != 0) 82062306a36Sopenharmony_ci || ((bufsize != ep->ep.maxpacket) 82162306a36Sopenharmony_ci && (bufsize > size))) 82262306a36Sopenharmony_ci m66592_bset(m66592, M66592_BVAL, ep->fifoctr); 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci /* update parameters */ 82662306a36Sopenharmony_ci req->req.actual += size; 82762306a36Sopenharmony_ci /* check transfer finish */ 82862306a36Sopenharmony_ci if ((!req->req.zero && (req->req.actual == req->req.length)) 82962306a36Sopenharmony_ci || (size % ep->ep.maxpacket) 83062306a36Sopenharmony_ci || (size == 0)) { 83162306a36Sopenharmony_ci disable_irq_ready(m66592, pipenum); 83262306a36Sopenharmony_ci enable_irq_empty(m66592, pipenum); 83362306a36Sopenharmony_ci } else { 83462306a36Sopenharmony_ci disable_irq_empty(m66592, pipenum); 83562306a36Sopenharmony_ci pipe_irq_enable(m66592, pipenum); 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cistatic void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci u16 tmp; 84262306a36Sopenharmony_ci int rcv_len, bufsize, req_len; 84362306a36Sopenharmony_ci int size; 84462306a36Sopenharmony_ci void *buf; 84562306a36Sopenharmony_ci u16 pipenum = ep->pipenum; 84662306a36Sopenharmony_ci struct m66592 *m66592 = ep->m66592; 84762306a36Sopenharmony_ci int finish = 0; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci pipe_change(m66592, pipenum); 85062306a36Sopenharmony_ci tmp = m66592_read(m66592, ep->fifoctr); 85162306a36Sopenharmony_ci if (unlikely((tmp & M66592_FRDY) == 0)) { 85262306a36Sopenharmony_ci req->req.status = -EPIPE; 85362306a36Sopenharmony_ci pipe_stop(m66592, pipenum); 85462306a36Sopenharmony_ci pipe_irq_disable(m66592, pipenum); 85562306a36Sopenharmony_ci pr_err("read fifo not ready"); 85662306a36Sopenharmony_ci return; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci /* prepare parameters */ 86062306a36Sopenharmony_ci rcv_len = tmp & M66592_DTLN; 86162306a36Sopenharmony_ci bufsize = get_buffer_size(m66592, pipenum); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci buf = req->req.buf + req->req.actual; 86462306a36Sopenharmony_ci req_len = req->req.length - req->req.actual; 86562306a36Sopenharmony_ci if (rcv_len < bufsize) 86662306a36Sopenharmony_ci size = min(rcv_len, req_len); 86762306a36Sopenharmony_ci else 86862306a36Sopenharmony_ci size = min(bufsize, req_len); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* update parameters */ 87162306a36Sopenharmony_ci req->req.actual += size; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci /* check transfer finish */ 87462306a36Sopenharmony_ci if ((!req->req.zero && (req->req.actual == req->req.length)) 87562306a36Sopenharmony_ci || (size % ep->ep.maxpacket) 87662306a36Sopenharmony_ci || (size == 0)) { 87762306a36Sopenharmony_ci pipe_stop(m66592, pipenum); 87862306a36Sopenharmony_ci pipe_irq_disable(m66592, pipenum); 87962306a36Sopenharmony_ci finish = 1; 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* read fifo */ 88362306a36Sopenharmony_ci if (req->req.buf) { 88462306a36Sopenharmony_ci if (size == 0) 88562306a36Sopenharmony_ci m66592_write(m66592, M66592_BCLR, ep->fifoctr); 88662306a36Sopenharmony_ci else 88762306a36Sopenharmony_ci m66592_read_fifo(m66592, ep->fifoaddr, buf, size); 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if ((ep->pipenum != 0) && finish) 89162306a36Sopenharmony_ci transfer_complete(ep, req, 0); 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cistatic void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci u16 check; 89762306a36Sopenharmony_ci u16 pipenum; 89862306a36Sopenharmony_ci struct m66592_ep *ep; 89962306a36Sopenharmony_ci struct m66592_request *req; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) { 90262306a36Sopenharmony_ci m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS); 90362306a36Sopenharmony_ci m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE, 90462306a36Sopenharmony_ci M66592_CFIFOSEL); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci ep = &m66592->ep[0]; 90762306a36Sopenharmony_ci req = list_entry(ep->queue.next, struct m66592_request, queue); 90862306a36Sopenharmony_ci irq_packet_read(ep, req); 90962306a36Sopenharmony_ci } else { 91062306a36Sopenharmony_ci for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) { 91162306a36Sopenharmony_ci check = 1 << pipenum; 91262306a36Sopenharmony_ci if ((status & check) && (enb & check)) { 91362306a36Sopenharmony_ci m66592_write(m66592, ~check, M66592_BRDYSTS); 91462306a36Sopenharmony_ci ep = m66592->pipenum2ep[pipenum]; 91562306a36Sopenharmony_ci req = list_entry(ep->queue.next, 91662306a36Sopenharmony_ci struct m66592_request, queue); 91762306a36Sopenharmony_ci if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) 91862306a36Sopenharmony_ci irq_packet_write(ep, req); 91962306a36Sopenharmony_ci else 92062306a36Sopenharmony_ci irq_packet_read(ep, req); 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_cistatic void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci u16 tmp; 92962306a36Sopenharmony_ci u16 check; 93062306a36Sopenharmony_ci u16 pipenum; 93162306a36Sopenharmony_ci struct m66592_ep *ep; 93262306a36Sopenharmony_ci struct m66592_request *req; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if ((status & M66592_BEMP0) && (enb & M66592_BEMP0)) { 93562306a36Sopenharmony_ci m66592_write(m66592, ~M66592_BEMP0, M66592_BEMPSTS); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci ep = &m66592->ep[0]; 93862306a36Sopenharmony_ci req = list_entry(ep->queue.next, struct m66592_request, queue); 93962306a36Sopenharmony_ci irq_ep0_write(ep, req); 94062306a36Sopenharmony_ci } else { 94162306a36Sopenharmony_ci for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) { 94262306a36Sopenharmony_ci check = 1 << pipenum; 94362306a36Sopenharmony_ci if ((status & check) && (enb & check)) { 94462306a36Sopenharmony_ci m66592_write(m66592, ~check, M66592_BEMPSTS); 94562306a36Sopenharmony_ci tmp = control_reg_get(m66592, pipenum); 94662306a36Sopenharmony_ci if ((tmp & M66592_INBUFM) == 0) { 94762306a36Sopenharmony_ci disable_irq_empty(m66592, pipenum); 94862306a36Sopenharmony_ci pipe_irq_disable(m66592, pipenum); 94962306a36Sopenharmony_ci pipe_stop(m66592, pipenum); 95062306a36Sopenharmony_ci ep = m66592->pipenum2ep[pipenum]; 95162306a36Sopenharmony_ci req = list_entry(ep->queue.next, 95262306a36Sopenharmony_ci struct m66592_request, 95362306a36Sopenharmony_ci queue); 95462306a36Sopenharmony_ci if (!list_empty(&ep->queue)) 95562306a36Sopenharmony_ci transfer_complete(ep, req, 0); 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_cistatic void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) 96362306a36Sopenharmony_ci__releases(m66592->lock) 96462306a36Sopenharmony_ci__acquires(m66592->lock) 96562306a36Sopenharmony_ci{ 96662306a36Sopenharmony_ci struct m66592_ep *ep; 96762306a36Sopenharmony_ci u16 pid; 96862306a36Sopenharmony_ci u16 status = 0; 96962306a36Sopenharmony_ci u16 w_index = le16_to_cpu(ctrl->wIndex); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci switch (ctrl->bRequestType & USB_RECIP_MASK) { 97262306a36Sopenharmony_ci case USB_RECIP_DEVICE: 97362306a36Sopenharmony_ci status = 1 << USB_DEVICE_SELF_POWERED; 97462306a36Sopenharmony_ci break; 97562306a36Sopenharmony_ci case USB_RECIP_INTERFACE: 97662306a36Sopenharmony_ci status = 0; 97762306a36Sopenharmony_ci break; 97862306a36Sopenharmony_ci case USB_RECIP_ENDPOINT: 97962306a36Sopenharmony_ci ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; 98062306a36Sopenharmony_ci pid = control_reg_get_pid(m66592, ep->pipenum); 98162306a36Sopenharmony_ci if (pid == M66592_PID_STALL) 98262306a36Sopenharmony_ci status = 1 << USB_ENDPOINT_HALT; 98362306a36Sopenharmony_ci else 98462306a36Sopenharmony_ci status = 0; 98562306a36Sopenharmony_ci break; 98662306a36Sopenharmony_ci default: 98762306a36Sopenharmony_ci pipe_stall(m66592, 0); 98862306a36Sopenharmony_ci return; /* exit */ 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci m66592->ep0_data = cpu_to_le16(status); 99262306a36Sopenharmony_ci m66592->ep0_req->buf = &m66592->ep0_data; 99362306a36Sopenharmony_ci m66592->ep0_req->length = 2; 99462306a36Sopenharmony_ci /* AV: what happens if we get called again before that gets through? */ 99562306a36Sopenharmony_ci spin_unlock(&m66592->lock); 99662306a36Sopenharmony_ci m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL); 99762306a36Sopenharmony_ci spin_lock(&m66592->lock); 99862306a36Sopenharmony_ci} 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_cistatic void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci switch (ctrl->bRequestType & USB_RECIP_MASK) { 100362306a36Sopenharmony_ci case USB_RECIP_DEVICE: 100462306a36Sopenharmony_ci control_end(m66592, 1); 100562306a36Sopenharmony_ci break; 100662306a36Sopenharmony_ci case USB_RECIP_INTERFACE: 100762306a36Sopenharmony_ci control_end(m66592, 1); 100862306a36Sopenharmony_ci break; 100962306a36Sopenharmony_ci case USB_RECIP_ENDPOINT: { 101062306a36Sopenharmony_ci struct m66592_ep *ep; 101162306a36Sopenharmony_ci struct m66592_request *req; 101262306a36Sopenharmony_ci u16 w_index = le16_to_cpu(ctrl->wIndex); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; 101562306a36Sopenharmony_ci pipe_stop(m66592, ep->pipenum); 101662306a36Sopenharmony_ci control_reg_sqclr(m66592, ep->pipenum); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci control_end(m66592, 1); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci req = list_entry(ep->queue.next, 102162306a36Sopenharmony_ci struct m66592_request, queue); 102262306a36Sopenharmony_ci if (ep->busy) { 102362306a36Sopenharmony_ci ep->busy = 0; 102462306a36Sopenharmony_ci if (list_empty(&ep->queue)) 102562306a36Sopenharmony_ci break; 102662306a36Sopenharmony_ci start_packet(ep, req); 102762306a36Sopenharmony_ci } else if (!list_empty(&ep->queue)) 102862306a36Sopenharmony_ci pipe_start(m66592, ep->pipenum); 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci break; 103162306a36Sopenharmony_ci default: 103262306a36Sopenharmony_ci pipe_stall(m66592, 0); 103362306a36Sopenharmony_ci break; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_cistatic void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) 103862306a36Sopenharmony_ci{ 103962306a36Sopenharmony_ci u16 tmp; 104062306a36Sopenharmony_ci int timeout = 3000; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci switch (ctrl->bRequestType & USB_RECIP_MASK) { 104362306a36Sopenharmony_ci case USB_RECIP_DEVICE: 104462306a36Sopenharmony_ci switch (le16_to_cpu(ctrl->wValue)) { 104562306a36Sopenharmony_ci case USB_DEVICE_TEST_MODE: 104662306a36Sopenharmony_ci control_end(m66592, 1); 104762306a36Sopenharmony_ci /* Wait for the completion of status stage */ 104862306a36Sopenharmony_ci do { 104962306a36Sopenharmony_ci tmp = m66592_read(m66592, M66592_INTSTS0) & 105062306a36Sopenharmony_ci M66592_CTSQ; 105162306a36Sopenharmony_ci udelay(1); 105262306a36Sopenharmony_ci } while (tmp != M66592_CS_IDST && timeout-- > 0); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (tmp == M66592_CS_IDST) 105562306a36Sopenharmony_ci m66592_bset(m66592, 105662306a36Sopenharmony_ci le16_to_cpu(ctrl->wIndex >> 8), 105762306a36Sopenharmony_ci M66592_TESTMODE); 105862306a36Sopenharmony_ci break; 105962306a36Sopenharmony_ci default: 106062306a36Sopenharmony_ci pipe_stall(m66592, 0); 106162306a36Sopenharmony_ci break; 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci break; 106462306a36Sopenharmony_ci case USB_RECIP_INTERFACE: 106562306a36Sopenharmony_ci control_end(m66592, 1); 106662306a36Sopenharmony_ci break; 106762306a36Sopenharmony_ci case USB_RECIP_ENDPOINT: { 106862306a36Sopenharmony_ci struct m66592_ep *ep; 106962306a36Sopenharmony_ci u16 w_index = le16_to_cpu(ctrl->wIndex); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; 107262306a36Sopenharmony_ci pipe_stall(m66592, ep->pipenum); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci control_end(m66592, 1); 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci break; 107762306a36Sopenharmony_ci default: 107862306a36Sopenharmony_ci pipe_stall(m66592, 0); 107962306a36Sopenharmony_ci break; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci/* if return value is true, call class driver's setup() */ 108462306a36Sopenharmony_cistatic int setup_packet(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci u16 *p = (u16 *)ctrl; 108762306a36Sopenharmony_ci unsigned long offset = M66592_USBREQ; 108862306a36Sopenharmony_ci int i, ret = 0; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci /* read fifo */ 109162306a36Sopenharmony_ci m66592_write(m66592, ~M66592_VALID, M66592_INTSTS0); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci for (i = 0; i < 4; i++) 109462306a36Sopenharmony_ci p[i] = m66592_read(m66592, offset + i*2); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* check request */ 109762306a36Sopenharmony_ci if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 109862306a36Sopenharmony_ci switch (ctrl->bRequest) { 109962306a36Sopenharmony_ci case USB_REQ_GET_STATUS: 110062306a36Sopenharmony_ci get_status(m66592, ctrl); 110162306a36Sopenharmony_ci break; 110262306a36Sopenharmony_ci case USB_REQ_CLEAR_FEATURE: 110362306a36Sopenharmony_ci clear_feature(m66592, ctrl); 110462306a36Sopenharmony_ci break; 110562306a36Sopenharmony_ci case USB_REQ_SET_FEATURE: 110662306a36Sopenharmony_ci set_feature(m66592, ctrl); 110762306a36Sopenharmony_ci break; 110862306a36Sopenharmony_ci default: 110962306a36Sopenharmony_ci ret = 1; 111062306a36Sopenharmony_ci break; 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci } else 111362306a36Sopenharmony_ci ret = 1; 111462306a36Sopenharmony_ci return ret; 111562306a36Sopenharmony_ci} 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cistatic void m66592_update_usb_speed(struct m66592 *m66592) 111862306a36Sopenharmony_ci{ 111962306a36Sopenharmony_ci u16 speed = get_usb_speed(m66592); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci switch (speed) { 112262306a36Sopenharmony_ci case M66592_HSMODE: 112362306a36Sopenharmony_ci m66592->gadget.speed = USB_SPEED_HIGH; 112462306a36Sopenharmony_ci break; 112562306a36Sopenharmony_ci case M66592_FSMODE: 112662306a36Sopenharmony_ci m66592->gadget.speed = USB_SPEED_FULL; 112762306a36Sopenharmony_ci break; 112862306a36Sopenharmony_ci default: 112962306a36Sopenharmony_ci m66592->gadget.speed = USB_SPEED_UNKNOWN; 113062306a36Sopenharmony_ci pr_err("USB speed unknown\n"); 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic void irq_device_state(struct m66592 *m66592) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci u16 dvsq; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci dvsq = m66592_read(m66592, M66592_INTSTS0) & M66592_DVSQ; 113962306a36Sopenharmony_ci m66592_write(m66592, ~M66592_DVST, M66592_INTSTS0); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci if (dvsq == M66592_DS_DFLT) { /* bus reset */ 114262306a36Sopenharmony_ci usb_gadget_udc_reset(&m66592->gadget, m66592->driver); 114362306a36Sopenharmony_ci m66592_update_usb_speed(m66592); 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG) 114662306a36Sopenharmony_ci m66592_update_usb_speed(m66592); 114762306a36Sopenharmony_ci if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) 114862306a36Sopenharmony_ci && m66592->gadget.speed == USB_SPEED_UNKNOWN) 114962306a36Sopenharmony_ci m66592_update_usb_speed(m66592); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci m66592->old_dvsq = dvsq; 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_cistatic void irq_control_stage(struct m66592 *m66592) 115562306a36Sopenharmony_ci__releases(m66592->lock) 115662306a36Sopenharmony_ci__acquires(m66592->lock) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci struct usb_ctrlrequest ctrl; 115962306a36Sopenharmony_ci u16 ctsq; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci ctsq = m66592_read(m66592, M66592_INTSTS0) & M66592_CTSQ; 116262306a36Sopenharmony_ci m66592_write(m66592, ~M66592_CTRT, M66592_INTSTS0); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci switch (ctsq) { 116562306a36Sopenharmony_ci case M66592_CS_IDST: { 116662306a36Sopenharmony_ci struct m66592_ep *ep; 116762306a36Sopenharmony_ci struct m66592_request *req; 116862306a36Sopenharmony_ci ep = &m66592->ep[0]; 116962306a36Sopenharmony_ci req = list_entry(ep->queue.next, struct m66592_request, queue); 117062306a36Sopenharmony_ci transfer_complete(ep, req, 0); 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci break; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci case M66592_CS_RDDS: 117562306a36Sopenharmony_ci case M66592_CS_WRDS: 117662306a36Sopenharmony_ci case M66592_CS_WRND: 117762306a36Sopenharmony_ci if (setup_packet(m66592, &ctrl)) { 117862306a36Sopenharmony_ci spin_unlock(&m66592->lock); 117962306a36Sopenharmony_ci if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0) 118062306a36Sopenharmony_ci pipe_stall(m66592, 0); 118162306a36Sopenharmony_ci spin_lock(&m66592->lock); 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci break; 118462306a36Sopenharmony_ci case M66592_CS_RDSS: 118562306a36Sopenharmony_ci case M66592_CS_WRSS: 118662306a36Sopenharmony_ci control_end(m66592, 0); 118762306a36Sopenharmony_ci break; 118862306a36Sopenharmony_ci default: 118962306a36Sopenharmony_ci pr_err("ctrl_stage: unexpect ctsq(%x)\n", ctsq); 119062306a36Sopenharmony_ci break; 119162306a36Sopenharmony_ci } 119262306a36Sopenharmony_ci} 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_cistatic irqreturn_t m66592_irq(int irq, void *_m66592) 119562306a36Sopenharmony_ci{ 119662306a36Sopenharmony_ci struct m66592 *m66592 = _m66592; 119762306a36Sopenharmony_ci u16 intsts0; 119862306a36Sopenharmony_ci u16 intenb0; 119962306a36Sopenharmony_ci u16 savepipe; 120062306a36Sopenharmony_ci u16 mask0; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci spin_lock(&m66592->lock); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci intsts0 = m66592_read(m66592, M66592_INTSTS0); 120562306a36Sopenharmony_ci intenb0 = m66592_read(m66592, M66592_INTENB0); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci if (m66592->pdata->on_chip && !intsts0 && !intenb0) { 120862306a36Sopenharmony_ci /* 120962306a36Sopenharmony_ci * When USB clock stops, it cannot read register. Even if a 121062306a36Sopenharmony_ci * clock stops, the interrupt occurs. So this driver turn on 121162306a36Sopenharmony_ci * a clock by this timing and do re-reading of register. 121262306a36Sopenharmony_ci */ 121362306a36Sopenharmony_ci m66592_start_xclock(m66592); 121462306a36Sopenharmony_ci intsts0 = m66592_read(m66592, M66592_INTSTS0); 121562306a36Sopenharmony_ci intenb0 = m66592_read(m66592, M66592_INTENB0); 121662306a36Sopenharmony_ci } 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci savepipe = m66592_read(m66592, M66592_CFIFOSEL); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci mask0 = intsts0 & intenb0; 122162306a36Sopenharmony_ci if (mask0) { 122262306a36Sopenharmony_ci u16 brdysts = m66592_read(m66592, M66592_BRDYSTS); 122362306a36Sopenharmony_ci u16 bempsts = m66592_read(m66592, M66592_BEMPSTS); 122462306a36Sopenharmony_ci u16 brdyenb = m66592_read(m66592, M66592_BRDYENB); 122562306a36Sopenharmony_ci u16 bempenb = m66592_read(m66592, M66592_BEMPENB); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci if (mask0 & M66592_VBINT) { 122862306a36Sopenharmony_ci m66592_write(m66592, 0xffff & ~M66592_VBINT, 122962306a36Sopenharmony_ci M66592_INTSTS0); 123062306a36Sopenharmony_ci m66592_start_xclock(m66592); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci /* start vbus sampling */ 123362306a36Sopenharmony_ci m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0) 123462306a36Sopenharmony_ci & M66592_VBSTS; 123562306a36Sopenharmony_ci m66592->scount = M66592_MAX_SAMPLING; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci mod_timer(&m66592->timer, 123862306a36Sopenharmony_ci jiffies + msecs_to_jiffies(50)); 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci if (intsts0 & M66592_DVSQ) 124162306a36Sopenharmony_ci irq_device_state(m66592); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) 124462306a36Sopenharmony_ci && (brdysts & brdyenb)) { 124562306a36Sopenharmony_ci irq_pipe_ready(m66592, brdysts, brdyenb); 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) 124862306a36Sopenharmony_ci && (bempsts & bempenb)) { 124962306a36Sopenharmony_ci irq_pipe_empty(m66592, bempsts, bempenb); 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci if (intsts0 & M66592_CTRT) 125362306a36Sopenharmony_ci irq_control_stage(m66592); 125462306a36Sopenharmony_ci } 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci m66592_write(m66592, savepipe, M66592_CFIFOSEL); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci spin_unlock(&m66592->lock); 125962306a36Sopenharmony_ci return IRQ_HANDLED; 126062306a36Sopenharmony_ci} 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_cistatic void m66592_timer(struct timer_list *t) 126362306a36Sopenharmony_ci{ 126462306a36Sopenharmony_ci struct m66592 *m66592 = from_timer(m66592, t, timer); 126562306a36Sopenharmony_ci unsigned long flags; 126662306a36Sopenharmony_ci u16 tmp; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci spin_lock_irqsave(&m66592->lock, flags); 126962306a36Sopenharmony_ci tmp = m66592_read(m66592, M66592_SYSCFG); 127062306a36Sopenharmony_ci if (!(tmp & M66592_RCKE)) { 127162306a36Sopenharmony_ci m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG); 127262306a36Sopenharmony_ci udelay(10); 127362306a36Sopenharmony_ci m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG); 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci if (m66592->scount > 0) { 127662306a36Sopenharmony_ci tmp = m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS; 127762306a36Sopenharmony_ci if (tmp == m66592->old_vbus) { 127862306a36Sopenharmony_ci m66592->scount--; 127962306a36Sopenharmony_ci if (m66592->scount == 0) { 128062306a36Sopenharmony_ci if (tmp == M66592_VBSTS) 128162306a36Sopenharmony_ci m66592_usb_connect(m66592); 128262306a36Sopenharmony_ci else 128362306a36Sopenharmony_ci m66592_usb_disconnect(m66592); 128462306a36Sopenharmony_ci } else { 128562306a36Sopenharmony_ci mod_timer(&m66592->timer, 128662306a36Sopenharmony_ci jiffies + msecs_to_jiffies(50)); 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci } else { 128962306a36Sopenharmony_ci m66592->scount = M66592_MAX_SAMPLING; 129062306a36Sopenharmony_ci m66592->old_vbus = tmp; 129162306a36Sopenharmony_ci mod_timer(&m66592->timer, 129262306a36Sopenharmony_ci jiffies + msecs_to_jiffies(50)); 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci spin_unlock_irqrestore(&m66592->lock, flags); 129662306a36Sopenharmony_ci} 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 129962306a36Sopenharmony_cistatic int m66592_enable(struct usb_ep *_ep, 130062306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci struct m66592_ep *ep; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci ep = container_of(_ep, struct m66592_ep, ep); 130562306a36Sopenharmony_ci return alloc_pipe_config(ep, desc); 130662306a36Sopenharmony_ci} 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_cistatic int m66592_disable(struct usb_ep *_ep) 130962306a36Sopenharmony_ci{ 131062306a36Sopenharmony_ci struct m66592_ep *ep; 131162306a36Sopenharmony_ci struct m66592_request *req; 131262306a36Sopenharmony_ci unsigned long flags; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci ep = container_of(_ep, struct m66592_ep, ep); 131562306a36Sopenharmony_ci BUG_ON(!ep); 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci while (!list_empty(&ep->queue)) { 131862306a36Sopenharmony_ci req = list_entry(ep->queue.next, struct m66592_request, queue); 131962306a36Sopenharmony_ci spin_lock_irqsave(&ep->m66592->lock, flags); 132062306a36Sopenharmony_ci transfer_complete(ep, req, -ECONNRESET); 132162306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->m66592->lock, flags); 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci pipe_irq_disable(ep->m66592, ep->pipenum); 132562306a36Sopenharmony_ci return free_pipe_config(ep); 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_cistatic struct usb_request *m66592_alloc_request(struct usb_ep *_ep, 132962306a36Sopenharmony_ci gfp_t gfp_flags) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci struct m66592_request *req; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci req = kzalloc(sizeof(struct m66592_request), gfp_flags); 133462306a36Sopenharmony_ci if (!req) 133562306a36Sopenharmony_ci return NULL; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci INIT_LIST_HEAD(&req->queue); 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci return &req->req; 134062306a36Sopenharmony_ci} 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_cistatic void m66592_free_request(struct usb_ep *_ep, struct usb_request *_req) 134362306a36Sopenharmony_ci{ 134462306a36Sopenharmony_ci struct m66592_request *req; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci req = container_of(_req, struct m66592_request, req); 134762306a36Sopenharmony_ci kfree(req); 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic int m66592_queue(struct usb_ep *_ep, struct usb_request *_req, 135162306a36Sopenharmony_ci gfp_t gfp_flags) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci struct m66592_ep *ep; 135462306a36Sopenharmony_ci struct m66592_request *req; 135562306a36Sopenharmony_ci unsigned long flags; 135662306a36Sopenharmony_ci int request = 0; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci ep = container_of(_ep, struct m66592_ep, ep); 135962306a36Sopenharmony_ci req = container_of(_req, struct m66592_request, req); 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN) 136262306a36Sopenharmony_ci return -ESHUTDOWN; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci spin_lock_irqsave(&ep->m66592->lock, flags); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci if (list_empty(&ep->queue)) 136762306a36Sopenharmony_ci request = 1; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci list_add_tail(&req->queue, &ep->queue); 137062306a36Sopenharmony_ci req->req.actual = 0; 137162306a36Sopenharmony_ci req->req.status = -EINPROGRESS; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci if (ep->ep.desc == NULL) /* control */ 137462306a36Sopenharmony_ci start_ep0(ep, req); 137562306a36Sopenharmony_ci else { 137662306a36Sopenharmony_ci if (request && !ep->busy) 137762306a36Sopenharmony_ci start_packet(ep, req); 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->m66592->lock, flags); 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci return 0; 138362306a36Sopenharmony_ci} 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_cistatic int m66592_dequeue(struct usb_ep *_ep, struct usb_request *_req) 138662306a36Sopenharmony_ci{ 138762306a36Sopenharmony_ci struct m66592_ep *ep; 138862306a36Sopenharmony_ci struct m66592_request *req; 138962306a36Sopenharmony_ci unsigned long flags; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci ep = container_of(_ep, struct m66592_ep, ep); 139262306a36Sopenharmony_ci req = container_of(_req, struct m66592_request, req); 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci spin_lock_irqsave(&ep->m66592->lock, flags); 139562306a36Sopenharmony_ci if (!list_empty(&ep->queue)) 139662306a36Sopenharmony_ci transfer_complete(ep, req, -ECONNRESET); 139762306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->m66592->lock, flags); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci return 0; 140062306a36Sopenharmony_ci} 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_cistatic int m66592_set_halt(struct usb_ep *_ep, int value) 140362306a36Sopenharmony_ci{ 140462306a36Sopenharmony_ci struct m66592_ep *ep = container_of(_ep, struct m66592_ep, ep); 140562306a36Sopenharmony_ci unsigned long flags; 140662306a36Sopenharmony_ci int ret = 0; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci spin_lock_irqsave(&ep->m66592->lock, flags); 140962306a36Sopenharmony_ci if (!list_empty(&ep->queue)) { 141062306a36Sopenharmony_ci ret = -EAGAIN; 141162306a36Sopenharmony_ci } else if (value) { 141262306a36Sopenharmony_ci ep->busy = 1; 141362306a36Sopenharmony_ci pipe_stall(ep->m66592, ep->pipenum); 141462306a36Sopenharmony_ci } else { 141562306a36Sopenharmony_ci ep->busy = 0; 141662306a36Sopenharmony_ci pipe_stop(ep->m66592, ep->pipenum); 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->m66592->lock, flags); 141962306a36Sopenharmony_ci return ret; 142062306a36Sopenharmony_ci} 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_cistatic void m66592_fifo_flush(struct usb_ep *_ep) 142362306a36Sopenharmony_ci{ 142462306a36Sopenharmony_ci struct m66592_ep *ep; 142562306a36Sopenharmony_ci unsigned long flags; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci ep = container_of(_ep, struct m66592_ep, ep); 142862306a36Sopenharmony_ci spin_lock_irqsave(&ep->m66592->lock, flags); 142962306a36Sopenharmony_ci if (list_empty(&ep->queue) && !ep->busy) { 143062306a36Sopenharmony_ci pipe_stop(ep->m66592, ep->pipenum); 143162306a36Sopenharmony_ci m66592_bclr(ep->m66592, M66592_BCLR, ep->fifoctr); 143262306a36Sopenharmony_ci } 143362306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->m66592->lock, flags); 143462306a36Sopenharmony_ci} 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_cistatic const struct usb_ep_ops m66592_ep_ops = { 143762306a36Sopenharmony_ci .enable = m66592_enable, 143862306a36Sopenharmony_ci .disable = m66592_disable, 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci .alloc_request = m66592_alloc_request, 144162306a36Sopenharmony_ci .free_request = m66592_free_request, 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci .queue = m66592_queue, 144462306a36Sopenharmony_ci .dequeue = m66592_dequeue, 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci .set_halt = m66592_set_halt, 144762306a36Sopenharmony_ci .fifo_flush = m66592_fifo_flush, 144862306a36Sopenharmony_ci}; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 145162306a36Sopenharmony_cistatic int m66592_udc_start(struct usb_gadget *g, 145262306a36Sopenharmony_ci struct usb_gadget_driver *driver) 145362306a36Sopenharmony_ci{ 145462306a36Sopenharmony_ci struct m66592 *m66592 = to_m66592(g); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci /* hook up the driver */ 145762306a36Sopenharmony_ci m66592->driver = driver; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); 146062306a36Sopenharmony_ci if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) { 146162306a36Sopenharmony_ci m66592_start_xclock(m66592); 146262306a36Sopenharmony_ci /* start vbus sampling */ 146362306a36Sopenharmony_ci m66592->old_vbus = m66592_read(m66592, 146462306a36Sopenharmony_ci M66592_INTSTS0) & M66592_VBSTS; 146562306a36Sopenharmony_ci m66592->scount = M66592_MAX_SAMPLING; 146662306a36Sopenharmony_ci mod_timer(&m66592->timer, jiffies + msecs_to_jiffies(50)); 146762306a36Sopenharmony_ci } 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci return 0; 147062306a36Sopenharmony_ci} 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_cistatic int m66592_udc_stop(struct usb_gadget *g) 147362306a36Sopenharmony_ci{ 147462306a36Sopenharmony_ci struct m66592 *m66592 = to_m66592(g); 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci init_controller(m66592); 147962306a36Sopenharmony_ci disable_controller(m66592); 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci m66592->driver = NULL; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci return 0; 148462306a36Sopenharmony_ci} 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 148762306a36Sopenharmony_cistatic int m66592_get_frame(struct usb_gadget *_gadget) 148862306a36Sopenharmony_ci{ 148962306a36Sopenharmony_ci struct m66592 *m66592 = gadget_to_m66592(_gadget); 149062306a36Sopenharmony_ci return m66592_read(m66592, M66592_FRMNUM) & 0x03FF; 149162306a36Sopenharmony_ci} 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_cistatic int m66592_pullup(struct usb_gadget *gadget, int is_on) 149462306a36Sopenharmony_ci{ 149562306a36Sopenharmony_ci struct m66592 *m66592 = gadget_to_m66592(gadget); 149662306a36Sopenharmony_ci unsigned long flags; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci spin_lock_irqsave(&m66592->lock, flags); 149962306a36Sopenharmony_ci if (is_on) 150062306a36Sopenharmony_ci m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG); 150162306a36Sopenharmony_ci else 150262306a36Sopenharmony_ci m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); 150362306a36Sopenharmony_ci spin_unlock_irqrestore(&m66592->lock, flags); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci return 0; 150662306a36Sopenharmony_ci} 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_cistatic const struct usb_gadget_ops m66592_gadget_ops = { 150962306a36Sopenharmony_ci .get_frame = m66592_get_frame, 151062306a36Sopenharmony_ci .udc_start = m66592_udc_start, 151162306a36Sopenharmony_ci .udc_stop = m66592_udc_stop, 151262306a36Sopenharmony_ci .pullup = m66592_pullup, 151362306a36Sopenharmony_ci}; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_cistatic void m66592_remove(struct platform_device *pdev) 151662306a36Sopenharmony_ci{ 151762306a36Sopenharmony_ci struct m66592 *m66592 = platform_get_drvdata(pdev); 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci usb_del_gadget_udc(&m66592->gadget); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci timer_shutdown_sync(&m66592->timer); 152262306a36Sopenharmony_ci iounmap(m66592->reg); 152362306a36Sopenharmony_ci free_irq(platform_get_irq(pdev, 0), m66592); 152462306a36Sopenharmony_ci m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); 152562306a36Sopenharmony_ci if (m66592->pdata->on_chip) { 152662306a36Sopenharmony_ci clk_disable(m66592->clk); 152762306a36Sopenharmony_ci clk_put(m66592->clk); 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci kfree(m66592); 153062306a36Sopenharmony_ci} 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_cistatic void nop_completion(struct usb_ep *ep, struct usb_request *r) 153362306a36Sopenharmony_ci{ 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_cistatic int m66592_probe(struct platform_device *pdev) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci struct resource *res, *ires; 153962306a36Sopenharmony_ci void __iomem *reg = NULL; 154062306a36Sopenharmony_ci struct m66592 *m66592 = NULL; 154162306a36Sopenharmony_ci char clk_name[8]; 154262306a36Sopenharmony_ci int ret = 0; 154362306a36Sopenharmony_ci int i; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 154662306a36Sopenharmony_ci if (!res) { 154762306a36Sopenharmony_ci ret = -ENODEV; 154862306a36Sopenharmony_ci pr_err("platform_get_resource error.\n"); 154962306a36Sopenharmony_ci goto clean_up; 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 155362306a36Sopenharmony_ci if (!ires) { 155462306a36Sopenharmony_ci ret = -ENODEV; 155562306a36Sopenharmony_ci dev_err(&pdev->dev, 155662306a36Sopenharmony_ci "platform_get_resource IORESOURCE_IRQ error.\n"); 155762306a36Sopenharmony_ci goto clean_up; 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci reg = ioremap(res->start, resource_size(res)); 156162306a36Sopenharmony_ci if (reg == NULL) { 156262306a36Sopenharmony_ci ret = -ENOMEM; 156362306a36Sopenharmony_ci pr_err("ioremap error.\n"); 156462306a36Sopenharmony_ci goto clean_up; 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci if (dev_get_platdata(&pdev->dev) == NULL) { 156862306a36Sopenharmony_ci dev_err(&pdev->dev, "no platform data\n"); 156962306a36Sopenharmony_ci ret = -ENODEV; 157062306a36Sopenharmony_ci goto clean_up; 157162306a36Sopenharmony_ci } 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci /* initialize ucd */ 157462306a36Sopenharmony_ci m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL); 157562306a36Sopenharmony_ci if (m66592 == NULL) { 157662306a36Sopenharmony_ci ret = -ENOMEM; 157762306a36Sopenharmony_ci goto clean_up; 157862306a36Sopenharmony_ci } 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci m66592->pdata = dev_get_platdata(&pdev->dev); 158162306a36Sopenharmony_ci m66592->irq_trigger = ires->flags & IRQF_TRIGGER_MASK; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci spin_lock_init(&m66592->lock); 158462306a36Sopenharmony_ci platform_set_drvdata(pdev, m66592); 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci m66592->gadget.ops = &m66592_gadget_ops; 158762306a36Sopenharmony_ci m66592->gadget.max_speed = USB_SPEED_HIGH; 158862306a36Sopenharmony_ci m66592->gadget.name = udc_name; 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci timer_setup(&m66592->timer, m66592_timer, 0); 159162306a36Sopenharmony_ci m66592->reg = reg; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci ret = request_irq(ires->start, m66592_irq, IRQF_SHARED, 159462306a36Sopenharmony_ci udc_name, m66592); 159562306a36Sopenharmony_ci if (ret < 0) { 159662306a36Sopenharmony_ci pr_err("request_irq error (%d)\n", ret); 159762306a36Sopenharmony_ci goto clean_up; 159862306a36Sopenharmony_ci } 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci if (m66592->pdata->on_chip) { 160162306a36Sopenharmony_ci snprintf(clk_name, sizeof(clk_name), "usbf%d", pdev->id); 160262306a36Sopenharmony_ci m66592->clk = clk_get(&pdev->dev, clk_name); 160362306a36Sopenharmony_ci if (IS_ERR(m66592->clk)) { 160462306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot get clock \"%s\"\n", 160562306a36Sopenharmony_ci clk_name); 160662306a36Sopenharmony_ci ret = PTR_ERR(m66592->clk); 160762306a36Sopenharmony_ci goto clean_up2; 160862306a36Sopenharmony_ci } 160962306a36Sopenharmony_ci clk_enable(m66592->clk); 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci INIT_LIST_HEAD(&m66592->gadget.ep_list); 161362306a36Sopenharmony_ci m66592->gadget.ep0 = &m66592->ep[0].ep; 161462306a36Sopenharmony_ci INIT_LIST_HEAD(&m66592->gadget.ep0->ep_list); 161562306a36Sopenharmony_ci for (i = 0; i < M66592_MAX_NUM_PIPE; i++) { 161662306a36Sopenharmony_ci struct m66592_ep *ep = &m66592->ep[i]; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci if (i != 0) { 161962306a36Sopenharmony_ci INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list); 162062306a36Sopenharmony_ci list_add_tail(&m66592->ep[i].ep.ep_list, 162162306a36Sopenharmony_ci &m66592->gadget.ep_list); 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci ep->m66592 = m66592; 162462306a36Sopenharmony_ci INIT_LIST_HEAD(&ep->queue); 162562306a36Sopenharmony_ci ep->ep.name = m66592_ep_name[i]; 162662306a36Sopenharmony_ci ep->ep.ops = &m66592_ep_ops; 162762306a36Sopenharmony_ci usb_ep_set_maxpacket_limit(&ep->ep, 512); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci if (i == 0) { 163062306a36Sopenharmony_ci ep->ep.caps.type_control = true; 163162306a36Sopenharmony_ci } else { 163262306a36Sopenharmony_ci ep->ep.caps.type_iso = true; 163362306a36Sopenharmony_ci ep->ep.caps.type_bulk = true; 163462306a36Sopenharmony_ci ep->ep.caps.type_int = true; 163562306a36Sopenharmony_ci } 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci ep->ep.caps.dir_in = true; 163862306a36Sopenharmony_ci ep->ep.caps.dir_out = true; 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci usb_ep_set_maxpacket_limit(&m66592->ep[0].ep, 64); 164162306a36Sopenharmony_ci m66592->ep[0].pipenum = 0; 164262306a36Sopenharmony_ci m66592->ep[0].fifoaddr = M66592_CFIFO; 164362306a36Sopenharmony_ci m66592->ep[0].fifosel = M66592_CFIFOSEL; 164462306a36Sopenharmony_ci m66592->ep[0].fifoctr = M66592_CFIFOCTR; 164562306a36Sopenharmony_ci m66592->ep[0].fifotrn = 0; 164662306a36Sopenharmony_ci m66592->ep[0].pipectr = get_pipectr_addr(0); 164762306a36Sopenharmony_ci m66592->pipenum2ep[0] = &m66592->ep[0]; 164862306a36Sopenharmony_ci m66592->epaddr2ep[0] = &m66592->ep[0]; 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL); 165162306a36Sopenharmony_ci if (m66592->ep0_req == NULL) { 165262306a36Sopenharmony_ci ret = -ENOMEM; 165362306a36Sopenharmony_ci goto clean_up3; 165462306a36Sopenharmony_ci } 165562306a36Sopenharmony_ci m66592->ep0_req->complete = nop_completion; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci init_controller(m66592); 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget); 166062306a36Sopenharmony_ci if (ret) 166162306a36Sopenharmony_ci goto err_add_udc; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); 166462306a36Sopenharmony_ci return 0; 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_cierr_add_udc: 166762306a36Sopenharmony_ci m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); 166862306a36Sopenharmony_ci m66592->ep0_req = NULL; 166962306a36Sopenharmony_ciclean_up3: 167062306a36Sopenharmony_ci if (m66592->pdata->on_chip) { 167162306a36Sopenharmony_ci clk_disable(m66592->clk); 167262306a36Sopenharmony_ci clk_put(m66592->clk); 167362306a36Sopenharmony_ci } 167462306a36Sopenharmony_ciclean_up2: 167562306a36Sopenharmony_ci free_irq(ires->start, m66592); 167662306a36Sopenharmony_ciclean_up: 167762306a36Sopenharmony_ci if (m66592) { 167862306a36Sopenharmony_ci if (m66592->ep0_req) 167962306a36Sopenharmony_ci m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); 168062306a36Sopenharmony_ci kfree(m66592); 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci if (reg) 168362306a36Sopenharmony_ci iounmap(reg); 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci return ret; 168662306a36Sopenharmony_ci} 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 168962306a36Sopenharmony_cistatic struct platform_driver m66592_driver = { 169062306a36Sopenharmony_ci .remove_new = m66592_remove, 169162306a36Sopenharmony_ci .driver = { 169262306a36Sopenharmony_ci .name = udc_name, 169362306a36Sopenharmony_ci }, 169462306a36Sopenharmony_ci}; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_cimodule_platform_driver_probe(m66592_driver, m66592_probe); 1697