18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Fusb300 UDC (USB gadget)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2010 Faraday Technology Corp.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author : Yuan-hsin Chen <yhchen@faraday-tech.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
108c2ecf20Sopenharmony_ci#include <linux/err.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/io.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
158c2ecf20Sopenharmony_ci#include <linux/usb/ch9.h>
168c2ecf20Sopenharmony_ci#include <linux/usb/gadget.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "fusb300_udc.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("FUSB300  USB gadget driver");
218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>");
238c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:fusb300_udc");
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define DRIVER_VERSION	"20 October 2010"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic const char udc_name[] = "fusb300_udc";
288c2ecf20Sopenharmony_cistatic const char * const fusb300_ep_name[] = {
298c2ecf20Sopenharmony_ci	"ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7", "ep8", "ep9",
308c2ecf20Sopenharmony_ci	"ep10", "ep11", "ep12", "ep13", "ep14", "ep15"
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic void done(struct fusb300_ep *ep, struct fusb300_request *req,
348c2ecf20Sopenharmony_ci		 int status);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic void fusb300_enable_bit(struct fusb300 *fusb300, u32 offset,
378c2ecf20Sopenharmony_ci			       u32 value)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + offset);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	reg |= value;
428c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + offset);
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic void fusb300_disable_bit(struct fusb300 *fusb300, u32 offset,
468c2ecf20Sopenharmony_ci				u32 value)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + offset);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	reg &= ~value;
518c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + offset);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic void fusb300_ep_setting(struct fusb300_ep *ep,
568c2ecf20Sopenharmony_ci			       struct fusb300_ep_info info)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	ep->epnum = info.epnum;
598c2ecf20Sopenharmony_ci	ep->type = info.type;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic int fusb300_ep_release(struct fusb300_ep *ep)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	if (!ep->epnum)
658c2ecf20Sopenharmony_ci		return 0;
668c2ecf20Sopenharmony_ci	ep->epnum = 0;
678c2ecf20Sopenharmony_ci	ep->stall = 0;
688c2ecf20Sopenharmony_ci	ep->wedged = 0;
698c2ecf20Sopenharmony_ci	return 0;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic void fusb300_set_fifo_entry(struct fusb300 *fusb300,
738c2ecf20Sopenharmony_ci				   u32 ep)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	u32 val = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	val &= ~FUSB300_EPSET1_FIFOENTRY_MSK;
788c2ecf20Sopenharmony_ci	val |= FUSB300_EPSET1_FIFOENTRY(FUSB300_FIFO_ENTRY_NUM);
798c2ecf20Sopenharmony_ci	iowrite32(val, fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic void fusb300_set_start_entry(struct fusb300 *fusb300,
838c2ecf20Sopenharmony_ci				    u8 ep)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
868c2ecf20Sopenharmony_ci	u32 start_entry = fusb300->fifo_entry_num * FUSB300_FIFO_ENTRY_NUM;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	reg &= ~FUSB300_EPSET1_START_ENTRY_MSK	;
898c2ecf20Sopenharmony_ci	reg |= FUSB300_EPSET1_START_ENTRY(start_entry);
908c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
918c2ecf20Sopenharmony_ci	if (fusb300->fifo_entry_num == FUSB300_MAX_FIFO_ENTRY) {
928c2ecf20Sopenharmony_ci		fusb300->fifo_entry_num = 0;
938c2ecf20Sopenharmony_ci		fusb300->addrofs = 0;
948c2ecf20Sopenharmony_ci		pr_err("fifo entry is over the maximum number!\n");
958c2ecf20Sopenharmony_ci	} else
968c2ecf20Sopenharmony_ci		fusb300->fifo_entry_num++;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/* set fusb300_set_start_entry first before fusb300_set_epaddrofs */
1008c2ecf20Sopenharmony_cistatic void fusb300_set_epaddrofs(struct fusb300 *fusb300,
1018c2ecf20Sopenharmony_ci				  struct fusb300_ep_info info)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum));
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	reg &= ~FUSB300_EPSET2_ADDROFS_MSK;
1068c2ecf20Sopenharmony_ci	reg |= FUSB300_EPSET2_ADDROFS(fusb300->addrofs);
1078c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum));
1088c2ecf20Sopenharmony_ci	fusb300->addrofs += (info.maxpacket + 7) / 8 * FUSB300_FIFO_ENTRY_NUM;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic void ep_fifo_setting(struct fusb300 *fusb300,
1128c2ecf20Sopenharmony_ci			    struct fusb300_ep_info info)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	fusb300_set_fifo_entry(fusb300, info.epnum);
1158c2ecf20Sopenharmony_ci	fusb300_set_start_entry(fusb300, info.epnum);
1168c2ecf20Sopenharmony_ci	fusb300_set_epaddrofs(fusb300, info);
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic void fusb300_set_eptype(struct fusb300 *fusb300,
1208c2ecf20Sopenharmony_ci			       struct fusb300_ep_info info)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	reg &= ~FUSB300_EPSET1_TYPE_MSK;
1258c2ecf20Sopenharmony_ci	reg |= FUSB300_EPSET1_TYPE(info.type);
1268c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic void fusb300_set_epdir(struct fusb300 *fusb300,
1308c2ecf20Sopenharmony_ci			      struct fusb300_ep_info info)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	u32 reg;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	if (!info.dir_in)
1358c2ecf20Sopenharmony_ci		return;
1368c2ecf20Sopenharmony_ci	reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
1378c2ecf20Sopenharmony_ci	reg &= ~FUSB300_EPSET1_DIR_MSK;
1388c2ecf20Sopenharmony_ci	reg |= FUSB300_EPSET1_DIRIN;
1398c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic void fusb300_set_ep_active(struct fusb300 *fusb300,
1438c2ecf20Sopenharmony_ci			  u8 ep)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	reg |= FUSB300_EPSET1_ACTEN;
1488c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic void fusb300_set_epmps(struct fusb300 *fusb300,
1528c2ecf20Sopenharmony_ci			      struct fusb300_ep_info info)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum));
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	reg &= ~FUSB300_EPSET2_MPS_MSK;
1578c2ecf20Sopenharmony_ci	reg |= FUSB300_EPSET2_MPS(info.maxpacket);
1588c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum));
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic void fusb300_set_interval(struct fusb300 *fusb300,
1628c2ecf20Sopenharmony_ci				 struct fusb300_ep_info info)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	reg &= ~FUSB300_EPSET1_INTERVAL(0x7);
1678c2ecf20Sopenharmony_ci	reg |= FUSB300_EPSET1_INTERVAL(info.interval);
1688c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic void fusb300_set_bwnum(struct fusb300 *fusb300,
1728c2ecf20Sopenharmony_ci			      struct fusb300_ep_info info)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	reg &= ~FUSB300_EPSET1_BWNUM(0x3);
1778c2ecf20Sopenharmony_ci	reg |= FUSB300_EPSET1_BWNUM(info.bw_num);
1788c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic void set_ep_reg(struct fusb300 *fusb300,
1828c2ecf20Sopenharmony_ci		      struct fusb300_ep_info info)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	fusb300_set_eptype(fusb300, info);
1858c2ecf20Sopenharmony_ci	fusb300_set_epdir(fusb300, info);
1868c2ecf20Sopenharmony_ci	fusb300_set_epmps(fusb300, info);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (info.interval)
1898c2ecf20Sopenharmony_ci		fusb300_set_interval(fusb300, info);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	if (info.bw_num)
1928c2ecf20Sopenharmony_ci		fusb300_set_bwnum(fusb300, info);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	fusb300_set_ep_active(fusb300, info.epnum);
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int config_ep(struct fusb300_ep *ep,
1988c2ecf20Sopenharmony_ci		     const struct usb_endpoint_descriptor *desc)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct fusb300 *fusb300 = ep->fusb300;
2018c2ecf20Sopenharmony_ci	struct fusb300_ep_info info;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	ep->ep.desc = desc;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	info.interval = 0;
2068c2ecf20Sopenharmony_ci	info.addrofs = 0;
2078c2ecf20Sopenharmony_ci	info.bw_num = 0;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	info.type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
2108c2ecf20Sopenharmony_ci	info.dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
2118c2ecf20Sopenharmony_ci	info.maxpacket = usb_endpoint_maxp(desc);
2128c2ecf20Sopenharmony_ci	info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	if ((info.type == USB_ENDPOINT_XFER_INT) ||
2158c2ecf20Sopenharmony_ci	   (info.type == USB_ENDPOINT_XFER_ISOC)) {
2168c2ecf20Sopenharmony_ci		info.interval = desc->bInterval;
2178c2ecf20Sopenharmony_ci		if (info.type == USB_ENDPOINT_XFER_ISOC)
2188c2ecf20Sopenharmony_ci			info.bw_num = usb_endpoint_maxp_mult(desc);
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	ep_fifo_setting(fusb300, info);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	set_ep_reg(fusb300, info);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	fusb300_ep_setting(ep, info);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	fusb300->ep[info.epnum] = ep;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	return 0;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic int fusb300_enable(struct usb_ep *_ep,
2338c2ecf20Sopenharmony_ci			  const struct usb_endpoint_descriptor *desc)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct fusb300_ep *ep;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	ep = container_of(_ep, struct fusb300_ep, ep);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if (ep->fusb300->reenum) {
2408c2ecf20Sopenharmony_ci		ep->fusb300->fifo_entry_num = 0;
2418c2ecf20Sopenharmony_ci		ep->fusb300->addrofs = 0;
2428c2ecf20Sopenharmony_ci		ep->fusb300->reenum = 0;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return config_ep(ep, desc);
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic int fusb300_disable(struct usb_ep *_ep)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	struct fusb300_ep *ep;
2518c2ecf20Sopenharmony_ci	struct fusb300_request *req;
2528c2ecf20Sopenharmony_ci	unsigned long flags;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	ep = container_of(_ep, struct fusb300_ep, ep);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	BUG_ON(!ep);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	while (!list_empty(&ep->queue)) {
2598c2ecf20Sopenharmony_ci		req = list_entry(ep->queue.next, struct fusb300_request, queue);
2608c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ep->fusb300->lock, flags);
2618c2ecf20Sopenharmony_ci		done(ep, req, -ECONNRESET);
2628c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ep->fusb300->lock, flags);
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	return fusb300_ep_release(ep);
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic struct usb_request *fusb300_alloc_request(struct usb_ep *_ep,
2698c2ecf20Sopenharmony_ci						gfp_t gfp_flags)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	struct fusb300_request *req;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	req = kzalloc(sizeof(struct fusb300_request), gfp_flags);
2748c2ecf20Sopenharmony_ci	if (!req)
2758c2ecf20Sopenharmony_ci		return NULL;
2768c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&req->queue);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	return &req->req;
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic void fusb300_free_request(struct usb_ep *_ep, struct usb_request *_req)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	struct fusb300_request *req;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	req = container_of(_req, struct fusb300_request, req);
2868c2ecf20Sopenharmony_ci	kfree(req);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic int enable_fifo_int(struct fusb300_ep *ep)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct fusb300 *fusb300 = ep->fusb300;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (ep->epnum) {
2948c2ecf20Sopenharmony_ci		fusb300_enable_bit(fusb300, FUSB300_OFFSET_IGER0,
2958c2ecf20Sopenharmony_ci			FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum));
2968c2ecf20Sopenharmony_ci	} else {
2978c2ecf20Sopenharmony_ci		pr_err("can't enable_fifo_int ep0\n");
2988c2ecf20Sopenharmony_ci		return -EINVAL;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	return 0;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic int disable_fifo_int(struct fusb300_ep *ep)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct fusb300 *fusb300 = ep->fusb300;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if (ep->epnum) {
3098c2ecf20Sopenharmony_ci		fusb300_disable_bit(fusb300, FUSB300_OFFSET_IGER0,
3108c2ecf20Sopenharmony_ci			FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum));
3118c2ecf20Sopenharmony_ci	} else {
3128c2ecf20Sopenharmony_ci		pr_err("can't disable_fifo_int ep0\n");
3138c2ecf20Sopenharmony_ci		return -EINVAL;
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	return 0;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic void fusb300_set_cxlen(struct fusb300 *fusb300, u32 length)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	u32 reg;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR);
3248c2ecf20Sopenharmony_ci	reg &= ~FUSB300_CSR_LEN_MSK;
3258c2ecf20Sopenharmony_ci	reg |= FUSB300_CSR_LEN(length);
3268c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_CSR);
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci/* write data to cx fifo */
3308c2ecf20Sopenharmony_cistatic void fusb300_wrcxf(struct fusb300_ep *ep,
3318c2ecf20Sopenharmony_ci		   struct fusb300_request *req)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	int i = 0;
3348c2ecf20Sopenharmony_ci	u8 *tmp;
3358c2ecf20Sopenharmony_ci	u32 data;
3368c2ecf20Sopenharmony_ci	struct fusb300 *fusb300 = ep->fusb300;
3378c2ecf20Sopenharmony_ci	u32 length = req->req.length - req->req.actual;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	tmp = req->req.buf + req->req.actual;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	if (length > SS_CTL_MAX_PACKET_SIZE) {
3428c2ecf20Sopenharmony_ci		fusb300_set_cxlen(fusb300, SS_CTL_MAX_PACKET_SIZE);
3438c2ecf20Sopenharmony_ci		for (i = (SS_CTL_MAX_PACKET_SIZE >> 2); i > 0; i--) {
3448c2ecf20Sopenharmony_ci			data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 |
3458c2ecf20Sopenharmony_ci				*(tmp + 3) << 24;
3468c2ecf20Sopenharmony_ci			iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
3478c2ecf20Sopenharmony_ci			tmp += 4;
3488c2ecf20Sopenharmony_ci		}
3498c2ecf20Sopenharmony_ci		req->req.actual += SS_CTL_MAX_PACKET_SIZE;
3508c2ecf20Sopenharmony_ci	} else { /* length is less than max packet size */
3518c2ecf20Sopenharmony_ci		fusb300_set_cxlen(fusb300, length);
3528c2ecf20Sopenharmony_ci		for (i = length >> 2; i > 0; i--) {
3538c2ecf20Sopenharmony_ci			data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 |
3548c2ecf20Sopenharmony_ci				*(tmp + 3) << 24;
3558c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "    0x%x\n", data);
3568c2ecf20Sopenharmony_ci			iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
3578c2ecf20Sopenharmony_ci			tmp = tmp + 4;
3588c2ecf20Sopenharmony_ci		}
3598c2ecf20Sopenharmony_ci		switch (length % 4) {
3608c2ecf20Sopenharmony_ci		case 1:
3618c2ecf20Sopenharmony_ci			data = *tmp;
3628c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "    0x%x\n", data);
3638c2ecf20Sopenharmony_ci			iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
3648c2ecf20Sopenharmony_ci			break;
3658c2ecf20Sopenharmony_ci		case 2:
3668c2ecf20Sopenharmony_ci			data = *tmp | *(tmp + 1) << 8;
3678c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "    0x%x\n", data);
3688c2ecf20Sopenharmony_ci			iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
3698c2ecf20Sopenharmony_ci			break;
3708c2ecf20Sopenharmony_ci		case 3:
3718c2ecf20Sopenharmony_ci			data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16;
3728c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "    0x%x\n", data);
3738c2ecf20Sopenharmony_ci			iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
3748c2ecf20Sopenharmony_ci			break;
3758c2ecf20Sopenharmony_ci		default:
3768c2ecf20Sopenharmony_ci			break;
3778c2ecf20Sopenharmony_ci		}
3788c2ecf20Sopenharmony_ci		req->req.actual += length;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic void fusb300_set_epnstall(struct fusb300 *fusb300, u8 ep)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep),
3858c2ecf20Sopenharmony_ci		FUSB300_EPSET0_STL);
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_cistatic void fusb300_clear_epnstall(struct fusb300 *fusb300, u8 ep)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	if (reg & FUSB300_EPSET0_STL) {
3938c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep);
3948c2ecf20Sopenharmony_ci		reg |= FUSB300_EPSET0_STL_CLR;
3958c2ecf20Sopenharmony_ci		iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
3968c2ecf20Sopenharmony_ci	}
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic void ep0_queue(struct fusb300_ep *ep, struct fusb300_request *req)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	if (ep->fusb300->ep0_dir) { /* if IN */
4028c2ecf20Sopenharmony_ci		if (req->req.length) {
4038c2ecf20Sopenharmony_ci			fusb300_wrcxf(ep, req);
4048c2ecf20Sopenharmony_ci		} else
4058c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "%s : req->req.length = 0x%x\n",
4068c2ecf20Sopenharmony_ci				__func__, req->req.length);
4078c2ecf20Sopenharmony_ci		if ((req->req.length == req->req.actual) ||
4088c2ecf20Sopenharmony_ci		    (req->req.actual < ep->ep.maxpacket))
4098c2ecf20Sopenharmony_ci			done(ep, req, 0);
4108c2ecf20Sopenharmony_ci	} else { /* OUT */
4118c2ecf20Sopenharmony_ci		if (!req->req.length)
4128c2ecf20Sopenharmony_ci			done(ep, req, 0);
4138c2ecf20Sopenharmony_ci		else
4148c2ecf20Sopenharmony_ci			fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER1,
4158c2ecf20Sopenharmony_ci				FUSB300_IGER1_CX_OUT_INT);
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic int fusb300_queue(struct usb_ep *_ep, struct usb_request *_req,
4208c2ecf20Sopenharmony_ci			 gfp_t gfp_flags)
4218c2ecf20Sopenharmony_ci{
4228c2ecf20Sopenharmony_ci	struct fusb300_ep *ep;
4238c2ecf20Sopenharmony_ci	struct fusb300_request *req;
4248c2ecf20Sopenharmony_ci	unsigned long flags;
4258c2ecf20Sopenharmony_ci	int request  = 0;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	ep = container_of(_ep, struct fusb300_ep, ep);
4288c2ecf20Sopenharmony_ci	req = container_of(_req, struct fusb300_request, req);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN)
4318c2ecf20Sopenharmony_ci		return -ESHUTDOWN;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ep->fusb300->lock, flags);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	if (list_empty(&ep->queue))
4368c2ecf20Sopenharmony_ci		request = 1;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	list_add_tail(&req->queue, &ep->queue);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	req->req.actual = 0;
4418c2ecf20Sopenharmony_ci	req->req.status = -EINPROGRESS;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	if (ep->ep.desc == NULL) /* ep0 */
4448c2ecf20Sopenharmony_ci		ep0_queue(ep, req);
4458c2ecf20Sopenharmony_ci	else if (request && !ep->stall)
4468c2ecf20Sopenharmony_ci		enable_fifo_int(ep);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ep->fusb300->lock, flags);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	return 0;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic int fusb300_dequeue(struct usb_ep *_ep, struct usb_request *_req)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	struct fusb300_ep *ep;
4568c2ecf20Sopenharmony_ci	struct fusb300_request *req;
4578c2ecf20Sopenharmony_ci	unsigned long flags;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	ep = container_of(_ep, struct fusb300_ep, ep);
4608c2ecf20Sopenharmony_ci	req = container_of(_req, struct fusb300_request, req);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ep->fusb300->lock, flags);
4638c2ecf20Sopenharmony_ci	if (!list_empty(&ep->queue))
4648c2ecf20Sopenharmony_ci		done(ep, req, -ECONNRESET);
4658c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ep->fusb300->lock, flags);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	return 0;
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic int fusb300_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	struct fusb300_ep *ep;
4738c2ecf20Sopenharmony_ci	struct fusb300 *fusb300;
4748c2ecf20Sopenharmony_ci	unsigned long flags;
4758c2ecf20Sopenharmony_ci	int ret = 0;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	ep = container_of(_ep, struct fusb300_ep, ep);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	fusb300 = ep->fusb300;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ep->fusb300->lock, flags);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	if (!list_empty(&ep->queue)) {
4848c2ecf20Sopenharmony_ci		ret = -EAGAIN;
4858c2ecf20Sopenharmony_ci		goto out;
4868c2ecf20Sopenharmony_ci	}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if (value) {
4898c2ecf20Sopenharmony_ci		fusb300_set_epnstall(fusb300, ep->epnum);
4908c2ecf20Sopenharmony_ci		ep->stall = 1;
4918c2ecf20Sopenharmony_ci		if (wedge)
4928c2ecf20Sopenharmony_ci			ep->wedged = 1;
4938c2ecf20Sopenharmony_ci	} else {
4948c2ecf20Sopenharmony_ci		fusb300_clear_epnstall(fusb300, ep->epnum);
4958c2ecf20Sopenharmony_ci		ep->stall = 0;
4968c2ecf20Sopenharmony_ci		ep->wedged = 0;
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ciout:
5008c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ep->fusb300->lock, flags);
5018c2ecf20Sopenharmony_ci	return ret;
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic int fusb300_set_halt(struct usb_ep *_ep, int value)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	return fusb300_set_halt_and_wedge(_ep, value, 0);
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic int fusb300_set_wedge(struct usb_ep *_ep)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	return fusb300_set_halt_and_wedge(_ep, 1, 1);
5128c2ecf20Sopenharmony_ci}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_cistatic void fusb300_fifo_flush(struct usb_ep *_ep)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic const struct usb_ep_ops fusb300_ep_ops = {
5198c2ecf20Sopenharmony_ci	.enable		= fusb300_enable,
5208c2ecf20Sopenharmony_ci	.disable	= fusb300_disable,
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	.alloc_request	= fusb300_alloc_request,
5238c2ecf20Sopenharmony_ci	.free_request	= fusb300_free_request,
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	.queue		= fusb300_queue,
5268c2ecf20Sopenharmony_ci	.dequeue	= fusb300_dequeue,
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	.set_halt	= fusb300_set_halt,
5298c2ecf20Sopenharmony_ci	.fifo_flush	= fusb300_fifo_flush,
5308c2ecf20Sopenharmony_ci	.set_wedge	= fusb300_set_wedge,
5318c2ecf20Sopenharmony_ci};
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci/*****************************************************************************/
5348c2ecf20Sopenharmony_cistatic void fusb300_clear_int(struct fusb300 *fusb300, u32 offset,
5358c2ecf20Sopenharmony_ci		       u32 value)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	iowrite32(value, fusb300->reg + offset);
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic void fusb300_reset(void)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic void fusb300_set_cxstall(struct fusb300 *fusb300)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR,
5478c2ecf20Sopenharmony_ci			   FUSB300_CSR_STL);
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_cistatic void fusb300_set_cxdone(struct fusb300 *fusb300)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR,
5538c2ecf20Sopenharmony_ci			   FUSB300_CSR_DONE);
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci/* read data from cx fifo */
5578c2ecf20Sopenharmony_cistatic void fusb300_rdcxf(struct fusb300 *fusb300,
5588c2ecf20Sopenharmony_ci		   u8 *buffer, u32 length)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	int i = 0;
5618c2ecf20Sopenharmony_ci	u8 *tmp;
5628c2ecf20Sopenharmony_ci	u32 data;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	tmp = buffer;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	for (i = (length >> 2); i > 0; i--) {
5678c2ecf20Sopenharmony_ci		data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT);
5688c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "    0x%x\n", data);
5698c2ecf20Sopenharmony_ci		*tmp = data & 0xFF;
5708c2ecf20Sopenharmony_ci		*(tmp + 1) = (data >> 8) & 0xFF;
5718c2ecf20Sopenharmony_ci		*(tmp + 2) = (data >> 16) & 0xFF;
5728c2ecf20Sopenharmony_ci		*(tmp + 3) = (data >> 24) & 0xFF;
5738c2ecf20Sopenharmony_ci		tmp = tmp + 4;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	switch (length % 4) {
5778c2ecf20Sopenharmony_ci	case 1:
5788c2ecf20Sopenharmony_ci		data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT);
5798c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "    0x%x\n", data);
5808c2ecf20Sopenharmony_ci		*tmp = data & 0xFF;
5818c2ecf20Sopenharmony_ci		break;
5828c2ecf20Sopenharmony_ci	case 2:
5838c2ecf20Sopenharmony_ci		data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT);
5848c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "    0x%x\n", data);
5858c2ecf20Sopenharmony_ci		*tmp = data & 0xFF;
5868c2ecf20Sopenharmony_ci		*(tmp + 1) = (data >> 8) & 0xFF;
5878c2ecf20Sopenharmony_ci		break;
5888c2ecf20Sopenharmony_ci	case 3:
5898c2ecf20Sopenharmony_ci		data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT);
5908c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "    0x%x\n", data);
5918c2ecf20Sopenharmony_ci		*tmp = data & 0xFF;
5928c2ecf20Sopenharmony_ci		*(tmp + 1) = (data >> 8) & 0xFF;
5938c2ecf20Sopenharmony_ci		*(tmp + 2) = (data >> 16) & 0xFF;
5948c2ecf20Sopenharmony_ci		break;
5958c2ecf20Sopenharmony_ci	default:
5968c2ecf20Sopenharmony_ci		break;
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cistatic void fusb300_rdfifo(struct fusb300_ep *ep,
6018c2ecf20Sopenharmony_ci			  struct fusb300_request *req,
6028c2ecf20Sopenharmony_ci			  u32 length)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	int i = 0;
6058c2ecf20Sopenharmony_ci	u8 *tmp;
6068c2ecf20Sopenharmony_ci	u32 data, reg;
6078c2ecf20Sopenharmony_ci	struct fusb300 *fusb300 = ep->fusb300;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	tmp = req->req.buf + req->req.actual;
6108c2ecf20Sopenharmony_ci	req->req.actual += length;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	if (req->req.actual > req->req.length)
6138c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "req->req.actual > req->req.length\n");
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	for (i = (length >> 2); i > 0; i--) {
6168c2ecf20Sopenharmony_ci		data = ioread32(fusb300->reg +
6178c2ecf20Sopenharmony_ci			FUSB300_OFFSET_EPPORT(ep->epnum));
6188c2ecf20Sopenharmony_ci		*tmp = data & 0xFF;
6198c2ecf20Sopenharmony_ci		*(tmp + 1) = (data >> 8) & 0xFF;
6208c2ecf20Sopenharmony_ci		*(tmp + 2) = (data >> 16) & 0xFF;
6218c2ecf20Sopenharmony_ci		*(tmp + 3) = (data >> 24) & 0xFF;
6228c2ecf20Sopenharmony_ci		tmp = tmp + 4;
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	switch (length % 4) {
6268c2ecf20Sopenharmony_ci	case 1:
6278c2ecf20Sopenharmony_ci		data = ioread32(fusb300->reg +
6288c2ecf20Sopenharmony_ci			FUSB300_OFFSET_EPPORT(ep->epnum));
6298c2ecf20Sopenharmony_ci		*tmp = data & 0xFF;
6308c2ecf20Sopenharmony_ci		break;
6318c2ecf20Sopenharmony_ci	case 2:
6328c2ecf20Sopenharmony_ci		data = ioread32(fusb300->reg +
6338c2ecf20Sopenharmony_ci			FUSB300_OFFSET_EPPORT(ep->epnum));
6348c2ecf20Sopenharmony_ci		*tmp = data & 0xFF;
6358c2ecf20Sopenharmony_ci		*(tmp + 1) = (data >> 8) & 0xFF;
6368c2ecf20Sopenharmony_ci		break;
6378c2ecf20Sopenharmony_ci	case 3:
6388c2ecf20Sopenharmony_ci		data = ioread32(fusb300->reg +
6398c2ecf20Sopenharmony_ci			FUSB300_OFFSET_EPPORT(ep->epnum));
6408c2ecf20Sopenharmony_ci		*tmp = data & 0xFF;
6418c2ecf20Sopenharmony_ci		*(tmp + 1) = (data >> 8) & 0xFF;
6428c2ecf20Sopenharmony_ci		*(tmp + 2) = (data >> 16) & 0xFF;
6438c2ecf20Sopenharmony_ci		break;
6448c2ecf20Sopenharmony_ci	default:
6458c2ecf20Sopenharmony_ci		break;
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	do {
6498c2ecf20Sopenharmony_ci		reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1);
6508c2ecf20Sopenharmony_ci		reg &= FUSB300_IGR1_SYNF0_EMPTY_INT;
6518c2ecf20Sopenharmony_ci		if (i)
6528c2ecf20Sopenharmony_ci			printk(KERN_INFO "sync fifo is not empty!\n");
6538c2ecf20Sopenharmony_ci		i++;
6548c2ecf20Sopenharmony_ci	} while (!reg);
6558c2ecf20Sopenharmony_ci}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_cistatic u8 fusb300_get_epnstall(struct fusb300 *fusb300, u8 ep)
6588c2ecf20Sopenharmony_ci{
6598c2ecf20Sopenharmony_ci	u8 value;
6608c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	value = reg & FUSB300_EPSET0_STL;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	return value;
6658c2ecf20Sopenharmony_ci}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_cistatic u8 fusb300_get_cxstall(struct fusb300 *fusb300)
6688c2ecf20Sopenharmony_ci{
6698c2ecf20Sopenharmony_ci	u8 value;
6708c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	value = (reg & FUSB300_CSR_STL) >> 1;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	return value;
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_cistatic void request_error(struct fusb300 *fusb300)
6788c2ecf20Sopenharmony_ci{
6798c2ecf20Sopenharmony_ci	fusb300_set_cxstall(fusb300);
6808c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "request error!!\n");
6818c2ecf20Sopenharmony_ci}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_cistatic void get_status(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
6848c2ecf20Sopenharmony_ci__releases(fusb300->lock)
6858c2ecf20Sopenharmony_ci__acquires(fusb300->lock)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	u8 ep;
6888c2ecf20Sopenharmony_ci	u16 status = 0;
6898c2ecf20Sopenharmony_ci	u16 w_index = ctrl->wIndex;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	switch (ctrl->bRequestType & USB_RECIP_MASK) {
6928c2ecf20Sopenharmony_ci	case USB_RECIP_DEVICE:
6938c2ecf20Sopenharmony_ci		status = 1 << USB_DEVICE_SELF_POWERED;
6948c2ecf20Sopenharmony_ci		break;
6958c2ecf20Sopenharmony_ci	case USB_RECIP_INTERFACE:
6968c2ecf20Sopenharmony_ci		status = 0;
6978c2ecf20Sopenharmony_ci		break;
6988c2ecf20Sopenharmony_ci	case USB_RECIP_ENDPOINT:
6998c2ecf20Sopenharmony_ci		ep = w_index & USB_ENDPOINT_NUMBER_MASK;
7008c2ecf20Sopenharmony_ci		if (ep) {
7018c2ecf20Sopenharmony_ci			if (fusb300_get_epnstall(fusb300, ep))
7028c2ecf20Sopenharmony_ci				status = 1 << USB_ENDPOINT_HALT;
7038c2ecf20Sopenharmony_ci		} else {
7048c2ecf20Sopenharmony_ci			if (fusb300_get_cxstall(fusb300))
7058c2ecf20Sopenharmony_ci				status = 0;
7068c2ecf20Sopenharmony_ci		}
7078c2ecf20Sopenharmony_ci		break;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	default:
7108c2ecf20Sopenharmony_ci		request_error(fusb300);
7118c2ecf20Sopenharmony_ci		return;		/* exit */
7128c2ecf20Sopenharmony_ci	}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	fusb300->ep0_data = cpu_to_le16(status);
7158c2ecf20Sopenharmony_ci	fusb300->ep0_req->buf = &fusb300->ep0_data;
7168c2ecf20Sopenharmony_ci	fusb300->ep0_req->length = 2;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	spin_unlock(&fusb300->lock);
7198c2ecf20Sopenharmony_ci	fusb300_queue(fusb300->gadget.ep0, fusb300->ep0_req, GFP_KERNEL);
7208c2ecf20Sopenharmony_ci	spin_lock(&fusb300->lock);
7218c2ecf20Sopenharmony_ci}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_cistatic void set_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
7248c2ecf20Sopenharmony_ci{
7258c2ecf20Sopenharmony_ci	u8 ep;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	switch (ctrl->bRequestType & USB_RECIP_MASK) {
7288c2ecf20Sopenharmony_ci	case USB_RECIP_DEVICE:
7298c2ecf20Sopenharmony_ci		fusb300_set_cxdone(fusb300);
7308c2ecf20Sopenharmony_ci		break;
7318c2ecf20Sopenharmony_ci	case USB_RECIP_INTERFACE:
7328c2ecf20Sopenharmony_ci		fusb300_set_cxdone(fusb300);
7338c2ecf20Sopenharmony_ci		break;
7348c2ecf20Sopenharmony_ci	case USB_RECIP_ENDPOINT: {
7358c2ecf20Sopenharmony_ci		u16 w_index = le16_to_cpu(ctrl->wIndex);
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci		ep = w_index & USB_ENDPOINT_NUMBER_MASK;
7388c2ecf20Sopenharmony_ci		if (ep)
7398c2ecf20Sopenharmony_ci			fusb300_set_epnstall(fusb300, ep);
7408c2ecf20Sopenharmony_ci		else
7418c2ecf20Sopenharmony_ci			fusb300_set_cxstall(fusb300);
7428c2ecf20Sopenharmony_ci		fusb300_set_cxdone(fusb300);
7438c2ecf20Sopenharmony_ci		}
7448c2ecf20Sopenharmony_ci		break;
7458c2ecf20Sopenharmony_ci	default:
7468c2ecf20Sopenharmony_ci		request_error(fusb300);
7478c2ecf20Sopenharmony_ci		break;
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_cistatic void fusb300_clear_seqnum(struct fusb300 *fusb300, u8 ep)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep),
7548c2ecf20Sopenharmony_ci			    FUSB300_EPSET0_CLRSEQNUM);
7558c2ecf20Sopenharmony_ci}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_cistatic void clear_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
7588c2ecf20Sopenharmony_ci{
7598c2ecf20Sopenharmony_ci	struct fusb300_ep *ep =
7608c2ecf20Sopenharmony_ci		fusb300->ep[ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK];
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	switch (ctrl->bRequestType & USB_RECIP_MASK) {
7638c2ecf20Sopenharmony_ci	case USB_RECIP_DEVICE:
7648c2ecf20Sopenharmony_ci		fusb300_set_cxdone(fusb300);
7658c2ecf20Sopenharmony_ci		break;
7668c2ecf20Sopenharmony_ci	case USB_RECIP_INTERFACE:
7678c2ecf20Sopenharmony_ci		fusb300_set_cxdone(fusb300);
7688c2ecf20Sopenharmony_ci		break;
7698c2ecf20Sopenharmony_ci	case USB_RECIP_ENDPOINT:
7708c2ecf20Sopenharmony_ci		if (ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK) {
7718c2ecf20Sopenharmony_ci			if (ep->wedged) {
7728c2ecf20Sopenharmony_ci				fusb300_set_cxdone(fusb300);
7738c2ecf20Sopenharmony_ci				break;
7748c2ecf20Sopenharmony_ci			}
7758c2ecf20Sopenharmony_ci			if (ep->stall) {
7768c2ecf20Sopenharmony_ci				ep->stall = 0;
7778c2ecf20Sopenharmony_ci				fusb300_clear_seqnum(fusb300, ep->epnum);
7788c2ecf20Sopenharmony_ci				fusb300_clear_epnstall(fusb300, ep->epnum);
7798c2ecf20Sopenharmony_ci				if (!list_empty(&ep->queue))
7808c2ecf20Sopenharmony_ci					enable_fifo_int(ep);
7818c2ecf20Sopenharmony_ci			}
7828c2ecf20Sopenharmony_ci		}
7838c2ecf20Sopenharmony_ci		fusb300_set_cxdone(fusb300);
7848c2ecf20Sopenharmony_ci		break;
7858c2ecf20Sopenharmony_ci	default:
7868c2ecf20Sopenharmony_ci		request_error(fusb300);
7878c2ecf20Sopenharmony_ci		break;
7888c2ecf20Sopenharmony_ci	}
7898c2ecf20Sopenharmony_ci}
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_cistatic void fusb300_set_dev_addr(struct fusb300 *fusb300, u16 addr)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_DAR);
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	reg &= ~FUSB300_DAR_DRVADDR_MSK;
7968c2ecf20Sopenharmony_ci	reg |= FUSB300_DAR_DRVADDR(addr);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_DAR);
7998c2ecf20Sopenharmony_ci}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_cistatic void set_address(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	if (ctrl->wValue >= 0x0100)
8048c2ecf20Sopenharmony_ci		request_error(fusb300);
8058c2ecf20Sopenharmony_ci	else {
8068c2ecf20Sopenharmony_ci		fusb300_set_dev_addr(fusb300, ctrl->wValue);
8078c2ecf20Sopenharmony_ci		fusb300_set_cxdone(fusb300);
8088c2ecf20Sopenharmony_ci	}
8098c2ecf20Sopenharmony_ci}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci#define UVC_COPY_DESCRIPTORS(mem, src) \
8128c2ecf20Sopenharmony_ci	do { \
8138c2ecf20Sopenharmony_ci		const struct usb_descriptor_header * const *__src; \
8148c2ecf20Sopenharmony_ci		for (__src = src; *__src; ++__src) { \
8158c2ecf20Sopenharmony_ci			memcpy(mem, *__src, (*__src)->bLength); \
8168c2ecf20Sopenharmony_ci			mem += (*__src)->bLength; \
8178c2ecf20Sopenharmony_ci		} \
8188c2ecf20Sopenharmony_ci	} while (0)
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_cistatic int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	u8 *p = (u8 *)ctrl;
8238c2ecf20Sopenharmony_ci	u8 ret = 0;
8248c2ecf20Sopenharmony_ci	u8 i = 0;
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	fusb300_rdcxf(fusb300, p, 8);
8278c2ecf20Sopenharmony_ci	fusb300->ep0_dir = ctrl->bRequestType & USB_DIR_IN;
8288c2ecf20Sopenharmony_ci	fusb300->ep0_length = ctrl->wLength;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	/* check request */
8318c2ecf20Sopenharmony_ci	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
8328c2ecf20Sopenharmony_ci		switch (ctrl->bRequest) {
8338c2ecf20Sopenharmony_ci		case USB_REQ_GET_STATUS:
8348c2ecf20Sopenharmony_ci			get_status(fusb300, ctrl);
8358c2ecf20Sopenharmony_ci			break;
8368c2ecf20Sopenharmony_ci		case USB_REQ_CLEAR_FEATURE:
8378c2ecf20Sopenharmony_ci			clear_feature(fusb300, ctrl);
8388c2ecf20Sopenharmony_ci			break;
8398c2ecf20Sopenharmony_ci		case USB_REQ_SET_FEATURE:
8408c2ecf20Sopenharmony_ci			set_feature(fusb300, ctrl);
8418c2ecf20Sopenharmony_ci			break;
8428c2ecf20Sopenharmony_ci		case USB_REQ_SET_ADDRESS:
8438c2ecf20Sopenharmony_ci			set_address(fusb300, ctrl);
8448c2ecf20Sopenharmony_ci			break;
8458c2ecf20Sopenharmony_ci		case USB_REQ_SET_CONFIGURATION:
8468c2ecf20Sopenharmony_ci			fusb300_enable_bit(fusb300, FUSB300_OFFSET_DAR,
8478c2ecf20Sopenharmony_ci					   FUSB300_DAR_SETCONFG);
8488c2ecf20Sopenharmony_ci			/* clear sequence number */
8498c2ecf20Sopenharmony_ci			for (i = 1; i <= FUSB300_MAX_NUM_EP; i++)
8508c2ecf20Sopenharmony_ci				fusb300_clear_seqnum(fusb300, i);
8518c2ecf20Sopenharmony_ci			fusb300->reenum = 1;
8528c2ecf20Sopenharmony_ci			ret = 1;
8538c2ecf20Sopenharmony_ci			break;
8548c2ecf20Sopenharmony_ci		default:
8558c2ecf20Sopenharmony_ci			ret = 1;
8568c2ecf20Sopenharmony_ci			break;
8578c2ecf20Sopenharmony_ci		}
8588c2ecf20Sopenharmony_ci	} else
8598c2ecf20Sopenharmony_ci		ret = 1;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	return ret;
8628c2ecf20Sopenharmony_ci}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_cistatic void done(struct fusb300_ep *ep, struct fusb300_request *req,
8658c2ecf20Sopenharmony_ci		 int status)
8668c2ecf20Sopenharmony_ci{
8678c2ecf20Sopenharmony_ci	list_del_init(&req->queue);
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	/* don't modify queue heads during completion callback */
8708c2ecf20Sopenharmony_ci	if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN)
8718c2ecf20Sopenharmony_ci		req->req.status = -ESHUTDOWN;
8728c2ecf20Sopenharmony_ci	else
8738c2ecf20Sopenharmony_ci		req->req.status = status;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	spin_unlock(&ep->fusb300->lock);
8768c2ecf20Sopenharmony_ci	usb_gadget_giveback_request(&ep->ep, &req->req);
8778c2ecf20Sopenharmony_ci	spin_lock(&ep->fusb300->lock);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	if (ep->epnum) {
8808c2ecf20Sopenharmony_ci		disable_fifo_int(ep);
8818c2ecf20Sopenharmony_ci		if (!list_empty(&ep->queue))
8828c2ecf20Sopenharmony_ci			enable_fifo_int(ep);
8838c2ecf20Sopenharmony_ci	} else
8848c2ecf20Sopenharmony_ci		fusb300_set_cxdone(ep->fusb300);
8858c2ecf20Sopenharmony_ci}
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_cistatic void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, dma_addr_t d,
8888c2ecf20Sopenharmony_ci		u32 len)
8898c2ecf20Sopenharmony_ci{
8908c2ecf20Sopenharmony_ci	u32 value;
8918c2ecf20Sopenharmony_ci	u32 reg;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	/* wait SW owner */
8948c2ecf20Sopenharmony_ci	do {
8958c2ecf20Sopenharmony_ci		reg = ioread32(ep->fusb300->reg +
8968c2ecf20Sopenharmony_ci			FUSB300_OFFSET_EPPRD_W0(ep->epnum));
8978c2ecf20Sopenharmony_ci		reg &= FUSB300_EPPRD0_H;
8988c2ecf20Sopenharmony_ci	} while (reg);
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	iowrite32(d, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W1(ep->epnum));
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	value = FUSB300_EPPRD0_BTC(len) | FUSB300_EPPRD0_H |
9038c2ecf20Sopenharmony_ci		FUSB300_EPPRD0_F | FUSB300_EPPRD0_L | FUSB300_EPPRD0_I;
9048c2ecf20Sopenharmony_ci	iowrite32(value, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W0(ep->epnum));
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	iowrite32(0x0, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W2(ep->epnum));
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_EPPRDRDY,
9098c2ecf20Sopenharmony_ci		FUSB300_EPPRDR_EP_PRD_RDY(ep->epnum));
9108c2ecf20Sopenharmony_ci}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_cistatic void fusb300_wait_idma_finished(struct fusb300_ep *ep)
9138c2ecf20Sopenharmony_ci{
9148c2ecf20Sopenharmony_ci	u32 reg;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	do {
9178c2ecf20Sopenharmony_ci		reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR1);
9188c2ecf20Sopenharmony_ci		if ((reg & FUSB300_IGR1_VBUS_CHG_INT) ||
9198c2ecf20Sopenharmony_ci		    (reg & FUSB300_IGR1_WARM_RST_INT) ||
9208c2ecf20Sopenharmony_ci		    (reg & FUSB300_IGR1_HOT_RST_INT) ||
9218c2ecf20Sopenharmony_ci		    (reg & FUSB300_IGR1_USBRST_INT)
9228c2ecf20Sopenharmony_ci		)
9238c2ecf20Sopenharmony_ci			goto IDMA_RESET;
9248c2ecf20Sopenharmony_ci		reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR0);
9258c2ecf20Sopenharmony_ci		reg &= FUSB300_IGR0_EPn_PRD_INT(ep->epnum);
9268c2ecf20Sopenharmony_ci	} while (!reg);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0,
9298c2ecf20Sopenharmony_ci		FUSB300_IGR0_EPn_PRD_INT(ep->epnum));
9308c2ecf20Sopenharmony_ci	return;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ciIDMA_RESET:
9338c2ecf20Sopenharmony_ci	reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGER0);
9348c2ecf20Sopenharmony_ci	reg &= ~FUSB300_IGER0_EEPn_PRD_INT(ep->epnum);
9358c2ecf20Sopenharmony_ci	iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_IGER0);
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cistatic void fusb300_set_idma(struct fusb300_ep *ep,
9398c2ecf20Sopenharmony_ci			struct fusb300_request *req)
9408c2ecf20Sopenharmony_ci{
9418c2ecf20Sopenharmony_ci	int ret;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	ret = usb_gadget_map_request(&ep->fusb300->gadget,
9448c2ecf20Sopenharmony_ci			&req->req, DMA_TO_DEVICE);
9458c2ecf20Sopenharmony_ci	if (ret)
9468c2ecf20Sopenharmony_ci		return;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0,
9498c2ecf20Sopenharmony_ci		FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	fusb300_fill_idma_prdtbl(ep, req->req.dma, req->req.length);
9528c2ecf20Sopenharmony_ci	/* check idma is done */
9538c2ecf20Sopenharmony_ci	fusb300_wait_idma_finished(ep);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	usb_gadget_unmap_request(&ep->fusb300->gadget,
9568c2ecf20Sopenharmony_ci			&req->req, DMA_TO_DEVICE);
9578c2ecf20Sopenharmony_ci}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_cistatic void in_ep_fifo_handler(struct fusb300_ep *ep)
9608c2ecf20Sopenharmony_ci{
9618c2ecf20Sopenharmony_ci	struct fusb300_request *req = list_entry(ep->queue.next,
9628c2ecf20Sopenharmony_ci					struct fusb300_request, queue);
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	if (req->req.length)
9658c2ecf20Sopenharmony_ci		fusb300_set_idma(ep, req);
9668c2ecf20Sopenharmony_ci	done(ep, req, 0);
9678c2ecf20Sopenharmony_ci}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_cistatic void out_ep_fifo_handler(struct fusb300_ep *ep)
9708c2ecf20Sopenharmony_ci{
9718c2ecf20Sopenharmony_ci	struct fusb300 *fusb300 = ep->fusb300;
9728c2ecf20Sopenharmony_ci	struct fusb300_request *req = list_entry(ep->queue.next,
9738c2ecf20Sopenharmony_ci						 struct fusb300_request, queue);
9748c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum));
9758c2ecf20Sopenharmony_ci	u32 length = reg & FUSB300_FFR_BYCNT;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	fusb300_rdfifo(ep, req, length);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	/* finish out transfer */
9808c2ecf20Sopenharmony_ci	if ((req->req.length == req->req.actual) || (length < ep->ep.maxpacket))
9818c2ecf20Sopenharmony_ci		done(ep, req, 0);
9828c2ecf20Sopenharmony_ci}
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_cistatic void check_device_mode(struct fusb300 *fusb300)
9858c2ecf20Sopenharmony_ci{
9868c2ecf20Sopenharmony_ci	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_GCR);
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	switch (reg & FUSB300_GCR_DEVEN_MSK) {
9898c2ecf20Sopenharmony_ci	case FUSB300_GCR_DEVEN_SS:
9908c2ecf20Sopenharmony_ci		fusb300->gadget.speed = USB_SPEED_SUPER;
9918c2ecf20Sopenharmony_ci		break;
9928c2ecf20Sopenharmony_ci	case FUSB300_GCR_DEVEN_HS:
9938c2ecf20Sopenharmony_ci		fusb300->gadget.speed = USB_SPEED_HIGH;
9948c2ecf20Sopenharmony_ci		break;
9958c2ecf20Sopenharmony_ci	case FUSB300_GCR_DEVEN_FS:
9968c2ecf20Sopenharmony_ci		fusb300->gadget.speed = USB_SPEED_FULL;
9978c2ecf20Sopenharmony_ci		break;
9988c2ecf20Sopenharmony_ci	default:
9998c2ecf20Sopenharmony_ci		fusb300->gadget.speed = USB_SPEED_UNKNOWN;
10008c2ecf20Sopenharmony_ci		break;
10018c2ecf20Sopenharmony_ci	}
10028c2ecf20Sopenharmony_ci	printk(KERN_INFO "dev_mode = %d\n", (reg & FUSB300_GCR_DEVEN_MSK));
10038c2ecf20Sopenharmony_ci}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_cistatic void fusb300_ep0out(struct fusb300 *fusb300)
10078c2ecf20Sopenharmony_ci{
10088c2ecf20Sopenharmony_ci	struct fusb300_ep *ep = fusb300->ep[0];
10098c2ecf20Sopenharmony_ci	u32 reg;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	if (!list_empty(&ep->queue)) {
10128c2ecf20Sopenharmony_ci		struct fusb300_request *req;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci		req = list_first_entry(&ep->queue,
10158c2ecf20Sopenharmony_ci			struct fusb300_request, queue);
10168c2ecf20Sopenharmony_ci		if (req->req.length)
10178c2ecf20Sopenharmony_ci			fusb300_rdcxf(ep->fusb300, req->req.buf,
10188c2ecf20Sopenharmony_ci				req->req.length);
10198c2ecf20Sopenharmony_ci		done(ep, req, 0);
10208c2ecf20Sopenharmony_ci		reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1);
10218c2ecf20Sopenharmony_ci		reg &= ~FUSB300_IGER1_CX_OUT_INT;
10228c2ecf20Sopenharmony_ci		iowrite32(reg, fusb300->reg + FUSB300_OFFSET_IGER1);
10238c2ecf20Sopenharmony_ci	} else
10248c2ecf20Sopenharmony_ci		pr_err("%s : empty queue\n", __func__);
10258c2ecf20Sopenharmony_ci}
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_cistatic void fusb300_ep0in(struct fusb300 *fusb300)
10288c2ecf20Sopenharmony_ci{
10298c2ecf20Sopenharmony_ci	struct fusb300_request *req;
10308c2ecf20Sopenharmony_ci	struct fusb300_ep *ep = fusb300->ep[0];
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	if ((!list_empty(&ep->queue)) && (fusb300->ep0_dir)) {
10338c2ecf20Sopenharmony_ci		req = list_entry(ep->queue.next,
10348c2ecf20Sopenharmony_ci				struct fusb300_request, queue);
10358c2ecf20Sopenharmony_ci		if (req->req.length)
10368c2ecf20Sopenharmony_ci			fusb300_wrcxf(ep, req);
10378c2ecf20Sopenharmony_ci		if ((req->req.length - req->req.actual) < ep->ep.maxpacket)
10388c2ecf20Sopenharmony_ci			done(ep, req, 0);
10398c2ecf20Sopenharmony_ci	} else
10408c2ecf20Sopenharmony_ci		fusb300_set_cxdone(fusb300);
10418c2ecf20Sopenharmony_ci}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_cistatic void fusb300_grp2_handler(void)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_cistatic void fusb300_grp3_handler(void)
10488c2ecf20Sopenharmony_ci{
10498c2ecf20Sopenharmony_ci}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_cistatic void fusb300_grp4_handler(void)
10528c2ecf20Sopenharmony_ci{
10538c2ecf20Sopenharmony_ci}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_cistatic void fusb300_grp5_handler(void)
10568c2ecf20Sopenharmony_ci{
10578c2ecf20Sopenharmony_ci}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_cistatic irqreturn_t fusb300_irq(int irq, void *_fusb300)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	struct fusb300 *fusb300 = _fusb300;
10628c2ecf20Sopenharmony_ci	u32 int_grp1 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1);
10638c2ecf20Sopenharmony_ci	u32 int_grp1_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1);
10648c2ecf20Sopenharmony_ci	u32 int_grp0 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR0);
10658c2ecf20Sopenharmony_ci	u32 int_grp0_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER0);
10668c2ecf20Sopenharmony_ci	struct usb_ctrlrequest ctrl;
10678c2ecf20Sopenharmony_ci	u8 in;
10688c2ecf20Sopenharmony_ci	u32 reg;
10698c2ecf20Sopenharmony_ci	int i;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	spin_lock(&fusb300->lock);
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	int_grp1 &= int_grp1_en;
10748c2ecf20Sopenharmony_ci	int_grp0 &= int_grp0_en;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_WARM_RST_INT) {
10778c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
10788c2ecf20Sopenharmony_ci				  FUSB300_IGR1_WARM_RST_INT);
10798c2ecf20Sopenharmony_ci		printk(KERN_INFO"fusb300_warmreset\n");
10808c2ecf20Sopenharmony_ci		fusb300_reset();
10818c2ecf20Sopenharmony_ci	}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_HOT_RST_INT) {
10848c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
10858c2ecf20Sopenharmony_ci				  FUSB300_IGR1_HOT_RST_INT);
10868c2ecf20Sopenharmony_ci		printk(KERN_INFO"fusb300_hotreset\n");
10878c2ecf20Sopenharmony_ci		fusb300_reset();
10888c2ecf20Sopenharmony_ci	}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_USBRST_INT) {
10918c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
10928c2ecf20Sopenharmony_ci				  FUSB300_IGR1_USBRST_INT);
10938c2ecf20Sopenharmony_ci		fusb300_reset();
10948c2ecf20Sopenharmony_ci	}
10958c2ecf20Sopenharmony_ci	/* COMABT_INT has a highest priority */
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_CX_COMABT_INT) {
10988c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
10998c2ecf20Sopenharmony_ci				  FUSB300_IGR1_CX_COMABT_INT);
11008c2ecf20Sopenharmony_ci		printk(KERN_INFO"fusb300_ep0abt\n");
11018c2ecf20Sopenharmony_ci	}
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_VBUS_CHG_INT) {
11048c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11058c2ecf20Sopenharmony_ci				  FUSB300_IGR1_VBUS_CHG_INT);
11068c2ecf20Sopenharmony_ci		printk(KERN_INFO"fusb300_vbus_change\n");
11078c2ecf20Sopenharmony_ci	}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_U3_EXIT_FAIL_INT) {
11108c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11118c2ecf20Sopenharmony_ci				  FUSB300_IGR1_U3_EXIT_FAIL_INT);
11128c2ecf20Sopenharmony_ci	}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_U2_EXIT_FAIL_INT) {
11158c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11168c2ecf20Sopenharmony_ci				  FUSB300_IGR1_U2_EXIT_FAIL_INT);
11178c2ecf20Sopenharmony_ci	}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_U1_EXIT_FAIL_INT) {
11208c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11218c2ecf20Sopenharmony_ci				  FUSB300_IGR1_U1_EXIT_FAIL_INT);
11228c2ecf20Sopenharmony_ci	}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_U2_ENTRY_FAIL_INT) {
11258c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11268c2ecf20Sopenharmony_ci				  FUSB300_IGR1_U2_ENTRY_FAIL_INT);
11278c2ecf20Sopenharmony_ci	}
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_U1_ENTRY_FAIL_INT) {
11308c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11318c2ecf20Sopenharmony_ci				  FUSB300_IGR1_U1_ENTRY_FAIL_INT);
11328c2ecf20Sopenharmony_ci	}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_U3_EXIT_INT) {
11358c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11368c2ecf20Sopenharmony_ci				  FUSB300_IGR1_U3_EXIT_INT);
11378c2ecf20Sopenharmony_ci		printk(KERN_INFO "FUSB300_IGR1_U3_EXIT_INT\n");
11388c2ecf20Sopenharmony_ci	}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_U2_EXIT_INT) {
11418c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11428c2ecf20Sopenharmony_ci				  FUSB300_IGR1_U2_EXIT_INT);
11438c2ecf20Sopenharmony_ci		printk(KERN_INFO "FUSB300_IGR1_U2_EXIT_INT\n");
11448c2ecf20Sopenharmony_ci	}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_U1_EXIT_INT) {
11478c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11488c2ecf20Sopenharmony_ci				  FUSB300_IGR1_U1_EXIT_INT);
11498c2ecf20Sopenharmony_ci		printk(KERN_INFO "FUSB300_IGR1_U1_EXIT_INT\n");
11508c2ecf20Sopenharmony_ci	}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_U3_ENTRY_INT) {
11538c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11548c2ecf20Sopenharmony_ci				  FUSB300_IGR1_U3_ENTRY_INT);
11558c2ecf20Sopenharmony_ci		printk(KERN_INFO "FUSB300_IGR1_U3_ENTRY_INT\n");
11568c2ecf20Sopenharmony_ci		fusb300_enable_bit(fusb300, FUSB300_OFFSET_SSCR1,
11578c2ecf20Sopenharmony_ci				   FUSB300_SSCR1_GO_U3_DONE);
11588c2ecf20Sopenharmony_ci	}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_U2_ENTRY_INT) {
11618c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11628c2ecf20Sopenharmony_ci				  FUSB300_IGR1_U2_ENTRY_INT);
11638c2ecf20Sopenharmony_ci		printk(KERN_INFO "FUSB300_IGR1_U2_ENTRY_INT\n");
11648c2ecf20Sopenharmony_ci	}
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_U1_ENTRY_INT) {
11678c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11688c2ecf20Sopenharmony_ci				  FUSB300_IGR1_U1_ENTRY_INT);
11698c2ecf20Sopenharmony_ci		printk(KERN_INFO "FUSB300_IGR1_U1_ENTRY_INT\n");
11708c2ecf20Sopenharmony_ci	}
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_RESM_INT) {
11738c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11748c2ecf20Sopenharmony_ci				  FUSB300_IGR1_RESM_INT);
11758c2ecf20Sopenharmony_ci		printk(KERN_INFO "fusb300_resume\n");
11768c2ecf20Sopenharmony_ci	}
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_SUSP_INT) {
11798c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11808c2ecf20Sopenharmony_ci				  FUSB300_IGR1_SUSP_INT);
11818c2ecf20Sopenharmony_ci		printk(KERN_INFO "fusb300_suspend\n");
11828c2ecf20Sopenharmony_ci	}
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_HS_LPM_INT) {
11858c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11868c2ecf20Sopenharmony_ci				  FUSB300_IGR1_HS_LPM_INT);
11878c2ecf20Sopenharmony_ci		printk(KERN_INFO "fusb300_HS_LPM_INT\n");
11888c2ecf20Sopenharmony_ci	}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_DEV_MODE_CHG_INT) {
11918c2ecf20Sopenharmony_ci		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
11928c2ecf20Sopenharmony_ci				  FUSB300_IGR1_DEV_MODE_CHG_INT);
11938c2ecf20Sopenharmony_ci		check_device_mode(fusb300);
11948c2ecf20Sopenharmony_ci	}
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_CX_COMFAIL_INT) {
11978c2ecf20Sopenharmony_ci		fusb300_set_cxstall(fusb300);
11988c2ecf20Sopenharmony_ci		printk(KERN_INFO "fusb300_ep0fail\n");
11998c2ecf20Sopenharmony_ci	}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_CX_SETUP_INT) {
12028c2ecf20Sopenharmony_ci		printk(KERN_INFO "fusb300_ep0setup\n");
12038c2ecf20Sopenharmony_ci		if (setup_packet(fusb300, &ctrl)) {
12048c2ecf20Sopenharmony_ci			spin_unlock(&fusb300->lock);
12058c2ecf20Sopenharmony_ci			if (fusb300->driver->setup(&fusb300->gadget, &ctrl) < 0)
12068c2ecf20Sopenharmony_ci				fusb300_set_cxstall(fusb300);
12078c2ecf20Sopenharmony_ci			spin_lock(&fusb300->lock);
12088c2ecf20Sopenharmony_ci		}
12098c2ecf20Sopenharmony_ci	}
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_CX_CMDEND_INT)
12128c2ecf20Sopenharmony_ci		printk(KERN_INFO "fusb300_cmdend\n");
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_CX_OUT_INT) {
12168c2ecf20Sopenharmony_ci		printk(KERN_INFO "fusb300_cxout\n");
12178c2ecf20Sopenharmony_ci		fusb300_ep0out(fusb300);
12188c2ecf20Sopenharmony_ci	}
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_CX_IN_INT) {
12218c2ecf20Sopenharmony_ci		printk(KERN_INFO "fusb300_cxin\n");
12228c2ecf20Sopenharmony_ci		fusb300_ep0in(fusb300);
12238c2ecf20Sopenharmony_ci	}
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_INTGRP5)
12268c2ecf20Sopenharmony_ci		fusb300_grp5_handler();
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_INTGRP4)
12298c2ecf20Sopenharmony_ci		fusb300_grp4_handler();
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_INTGRP3)
12328c2ecf20Sopenharmony_ci		fusb300_grp3_handler();
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	if (int_grp1 & FUSB300_IGR1_INTGRP2)
12358c2ecf20Sopenharmony_ci		fusb300_grp2_handler();
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	if (int_grp0) {
12388c2ecf20Sopenharmony_ci		for (i = 1; i < FUSB300_MAX_NUM_EP; i++) {
12398c2ecf20Sopenharmony_ci			if (int_grp0 & FUSB300_IGR0_EPn_FIFO_INT(i)) {
12408c2ecf20Sopenharmony_ci				reg = ioread32(fusb300->reg +
12418c2ecf20Sopenharmony_ci					FUSB300_OFFSET_EPSET1(i));
12428c2ecf20Sopenharmony_ci				in = (reg & FUSB300_EPSET1_DIRIN) ? 1 : 0;
12438c2ecf20Sopenharmony_ci				if (in)
12448c2ecf20Sopenharmony_ci					in_ep_fifo_handler(fusb300->ep[i]);
12458c2ecf20Sopenharmony_ci				else
12468c2ecf20Sopenharmony_ci					out_ep_fifo_handler(fusb300->ep[i]);
12478c2ecf20Sopenharmony_ci			}
12488c2ecf20Sopenharmony_ci		}
12498c2ecf20Sopenharmony_ci	}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	spin_unlock(&fusb300->lock);
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
12548c2ecf20Sopenharmony_ci}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_cistatic void fusb300_set_u2_timeout(struct fusb300 *fusb300,
12578c2ecf20Sopenharmony_ci				   u32 time)
12588c2ecf20Sopenharmony_ci{
12598c2ecf20Sopenharmony_ci	u32 reg;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT);
12628c2ecf20Sopenharmony_ci	reg &= ~0xff;
12638c2ecf20Sopenharmony_ci	reg |= FUSB300_SSCR2_U2TIMEOUT(time);
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT);
12668c2ecf20Sopenharmony_ci}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_cistatic void fusb300_set_u1_timeout(struct fusb300 *fusb300,
12698c2ecf20Sopenharmony_ci				   u32 time)
12708c2ecf20Sopenharmony_ci{
12718c2ecf20Sopenharmony_ci	u32 reg;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT);
12748c2ecf20Sopenharmony_ci	reg &= ~(0xff << 8);
12758c2ecf20Sopenharmony_ci	reg |= FUSB300_SSCR2_U1TIMEOUT(time);
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT);
12788c2ecf20Sopenharmony_ci}
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_cistatic void init_controller(struct fusb300 *fusb300)
12818c2ecf20Sopenharmony_ci{
12828c2ecf20Sopenharmony_ci	u32 reg;
12838c2ecf20Sopenharmony_ci	u32 mask = 0;
12848c2ecf20Sopenharmony_ci	u32 val = 0;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	/* split on */
12878c2ecf20Sopenharmony_ci	mask = val = FUSB300_AHBBCR_S0_SPLIT_ON | FUSB300_AHBBCR_S1_SPLIT_ON;
12888c2ecf20Sopenharmony_ci	reg = ioread32(fusb300->reg + FUSB300_OFFSET_AHBCR);
12898c2ecf20Sopenharmony_ci	reg &= ~mask;
12908c2ecf20Sopenharmony_ci	reg |= val;
12918c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_AHBCR);
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	/* enable high-speed LPM */
12948c2ecf20Sopenharmony_ci	mask = val = FUSB300_HSCR_HS_LPM_PERMIT;
12958c2ecf20Sopenharmony_ci	reg = ioread32(fusb300->reg + FUSB300_OFFSET_HSCR);
12968c2ecf20Sopenharmony_ci	reg &= ~mask;
12978c2ecf20Sopenharmony_ci	reg |= val;
12988c2ecf20Sopenharmony_ci	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_HSCR);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	/*set u1 u2 timmer*/
13018c2ecf20Sopenharmony_ci	fusb300_set_u2_timeout(fusb300, 0xff);
13028c2ecf20Sopenharmony_ci	fusb300_set_u1_timeout(fusb300, 0xff);
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	/* enable all grp1 interrupt */
13058c2ecf20Sopenharmony_ci	iowrite32(0xcfffff9f, fusb300->reg + FUSB300_OFFSET_IGER1);
13068c2ecf20Sopenharmony_ci}
13078c2ecf20Sopenharmony_ci/*------------------------------------------------------------------------*/
13088c2ecf20Sopenharmony_cistatic int fusb300_udc_start(struct usb_gadget *g,
13098c2ecf20Sopenharmony_ci		struct usb_gadget_driver *driver)
13108c2ecf20Sopenharmony_ci{
13118c2ecf20Sopenharmony_ci	struct fusb300 *fusb300 = to_fusb300(g);
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	/* hook up the driver */
13148c2ecf20Sopenharmony_ci	driver->driver.bus = NULL;
13158c2ecf20Sopenharmony_ci	fusb300->driver = driver;
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	return 0;
13188c2ecf20Sopenharmony_ci}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_cistatic int fusb300_udc_stop(struct usb_gadget *g)
13218c2ecf20Sopenharmony_ci{
13228c2ecf20Sopenharmony_ci	struct fusb300 *fusb300 = to_fusb300(g);
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	init_controller(fusb300);
13258c2ecf20Sopenharmony_ci	fusb300->driver = NULL;
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	return 0;
13288c2ecf20Sopenharmony_ci}
13298c2ecf20Sopenharmony_ci/*--------------------------------------------------------------------------*/
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_cistatic int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)
13328c2ecf20Sopenharmony_ci{
13338c2ecf20Sopenharmony_ci	return 0;
13348c2ecf20Sopenharmony_ci}
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_cistatic const struct usb_gadget_ops fusb300_gadget_ops = {
13378c2ecf20Sopenharmony_ci	.pullup		= fusb300_udc_pullup,
13388c2ecf20Sopenharmony_ci	.udc_start	= fusb300_udc_start,
13398c2ecf20Sopenharmony_ci	.udc_stop	= fusb300_udc_stop,
13408c2ecf20Sopenharmony_ci};
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_cistatic int fusb300_remove(struct platform_device *pdev)
13438c2ecf20Sopenharmony_ci{
13448c2ecf20Sopenharmony_ci	struct fusb300 *fusb300 = platform_get_drvdata(pdev);
13458c2ecf20Sopenharmony_ci	int i;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	usb_del_gadget_udc(&fusb300->gadget);
13488c2ecf20Sopenharmony_ci	iounmap(fusb300->reg);
13498c2ecf20Sopenharmony_ci	free_irq(platform_get_irq(pdev, 0), fusb300);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
13528c2ecf20Sopenharmony_ci	for (i = 0; i < FUSB300_MAX_NUM_EP; i++)
13538c2ecf20Sopenharmony_ci		kfree(fusb300->ep[i]);
13548c2ecf20Sopenharmony_ci	kfree(fusb300);
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	return 0;
13578c2ecf20Sopenharmony_ci}
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_cistatic int fusb300_probe(struct platform_device *pdev)
13608c2ecf20Sopenharmony_ci{
13618c2ecf20Sopenharmony_ci	struct resource *res, *ires, *ires1;
13628c2ecf20Sopenharmony_ci	void __iomem *reg = NULL;
13638c2ecf20Sopenharmony_ci	struct fusb300 *fusb300 = NULL;
13648c2ecf20Sopenharmony_ci	struct fusb300_ep *_ep[FUSB300_MAX_NUM_EP];
13658c2ecf20Sopenharmony_ci	int ret = 0;
13668c2ecf20Sopenharmony_ci	int i;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
13698c2ecf20Sopenharmony_ci	if (!res) {
13708c2ecf20Sopenharmony_ci		ret = -ENODEV;
13718c2ecf20Sopenharmony_ci		pr_err("platform_get_resource error.\n");
13728c2ecf20Sopenharmony_ci		goto clean_up;
13738c2ecf20Sopenharmony_ci	}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
13768c2ecf20Sopenharmony_ci	if (!ires) {
13778c2ecf20Sopenharmony_ci		ret = -ENODEV;
13788c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
13798c2ecf20Sopenharmony_ci			"platform_get_resource IORESOURCE_IRQ error.\n");
13808c2ecf20Sopenharmony_ci		goto clean_up;
13818c2ecf20Sopenharmony_ci	}
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	ires1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
13848c2ecf20Sopenharmony_ci	if (!ires1) {
13858c2ecf20Sopenharmony_ci		ret = -ENODEV;
13868c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
13878c2ecf20Sopenharmony_ci			"platform_get_resource IORESOURCE_IRQ 1 error.\n");
13888c2ecf20Sopenharmony_ci		goto clean_up;
13898c2ecf20Sopenharmony_ci	}
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	reg = ioremap(res->start, resource_size(res));
13928c2ecf20Sopenharmony_ci	if (reg == NULL) {
13938c2ecf20Sopenharmony_ci		ret = -ENOMEM;
13948c2ecf20Sopenharmony_ci		pr_err("ioremap error.\n");
13958c2ecf20Sopenharmony_ci		goto clean_up;
13968c2ecf20Sopenharmony_ci	}
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	/* initialize udc */
13998c2ecf20Sopenharmony_ci	fusb300 = kzalloc(sizeof(struct fusb300), GFP_KERNEL);
14008c2ecf20Sopenharmony_ci	if (fusb300 == NULL) {
14018c2ecf20Sopenharmony_ci		ret = -ENOMEM;
14028c2ecf20Sopenharmony_ci		goto clean_up;
14038c2ecf20Sopenharmony_ci	}
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	for (i = 0; i < FUSB300_MAX_NUM_EP; i++) {
14068c2ecf20Sopenharmony_ci		_ep[i] = kzalloc(sizeof(struct fusb300_ep), GFP_KERNEL);
14078c2ecf20Sopenharmony_ci		if (_ep[i] == NULL) {
14088c2ecf20Sopenharmony_ci			ret = -ENOMEM;
14098c2ecf20Sopenharmony_ci			goto clean_up;
14108c2ecf20Sopenharmony_ci		}
14118c2ecf20Sopenharmony_ci		fusb300->ep[i] = _ep[i];
14128c2ecf20Sopenharmony_ci	}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	spin_lock_init(&fusb300->lock);
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, fusb300);
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	fusb300->gadget.ops = &fusb300_gadget_ops;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	fusb300->gadget.max_speed = USB_SPEED_HIGH;
14218c2ecf20Sopenharmony_ci	fusb300->gadget.name = udc_name;
14228c2ecf20Sopenharmony_ci	fusb300->reg = reg;
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	ret = request_irq(ires->start, fusb300_irq, IRQF_SHARED,
14258c2ecf20Sopenharmony_ci			  udc_name, fusb300);
14268c2ecf20Sopenharmony_ci	if (ret < 0) {
14278c2ecf20Sopenharmony_ci		pr_err("request_irq error (%d)\n", ret);
14288c2ecf20Sopenharmony_ci		goto clean_up;
14298c2ecf20Sopenharmony_ci	}
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	ret = request_irq(ires1->start, fusb300_irq,
14328c2ecf20Sopenharmony_ci			IRQF_SHARED, udc_name, fusb300);
14338c2ecf20Sopenharmony_ci	if (ret < 0) {
14348c2ecf20Sopenharmony_ci		pr_err("request_irq1 error (%d)\n", ret);
14358c2ecf20Sopenharmony_ci		goto clean_up;
14368c2ecf20Sopenharmony_ci	}
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&fusb300->gadget.ep_list);
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	for (i = 0; i < FUSB300_MAX_NUM_EP ; i++) {
14418c2ecf20Sopenharmony_ci		struct fusb300_ep *ep = fusb300->ep[i];
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci		if (i != 0) {
14448c2ecf20Sopenharmony_ci			INIT_LIST_HEAD(&fusb300->ep[i]->ep.ep_list);
14458c2ecf20Sopenharmony_ci			list_add_tail(&fusb300->ep[i]->ep.ep_list,
14468c2ecf20Sopenharmony_ci				     &fusb300->gadget.ep_list);
14478c2ecf20Sopenharmony_ci		}
14488c2ecf20Sopenharmony_ci		ep->fusb300 = fusb300;
14498c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ep->queue);
14508c2ecf20Sopenharmony_ci		ep->ep.name = fusb300_ep_name[i];
14518c2ecf20Sopenharmony_ci		ep->ep.ops = &fusb300_ep_ops;
14528c2ecf20Sopenharmony_ci		usb_ep_set_maxpacket_limit(&ep->ep, HS_BULK_MAX_PACKET_SIZE);
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci		if (i == 0) {
14558c2ecf20Sopenharmony_ci			ep->ep.caps.type_control = true;
14568c2ecf20Sopenharmony_ci		} else {
14578c2ecf20Sopenharmony_ci			ep->ep.caps.type_iso = true;
14588c2ecf20Sopenharmony_ci			ep->ep.caps.type_bulk = true;
14598c2ecf20Sopenharmony_ci			ep->ep.caps.type_int = true;
14608c2ecf20Sopenharmony_ci		}
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci		ep->ep.caps.dir_in = true;
14638c2ecf20Sopenharmony_ci		ep->ep.caps.dir_out = true;
14648c2ecf20Sopenharmony_ci	}
14658c2ecf20Sopenharmony_ci	usb_ep_set_maxpacket_limit(&fusb300->ep[0]->ep, HS_CTL_MAX_PACKET_SIZE);
14668c2ecf20Sopenharmony_ci	fusb300->ep[0]->epnum = 0;
14678c2ecf20Sopenharmony_ci	fusb300->gadget.ep0 = &fusb300->ep[0]->ep;
14688c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list);
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep,
14718c2ecf20Sopenharmony_ci				GFP_KERNEL);
14728c2ecf20Sopenharmony_ci	if (fusb300->ep0_req == NULL) {
14738c2ecf20Sopenharmony_ci		ret = -ENOMEM;
14748c2ecf20Sopenharmony_ci		goto clean_up3;
14758c2ecf20Sopenharmony_ci	}
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	init_controller(fusb300);
14788c2ecf20Sopenharmony_ci	ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget);
14798c2ecf20Sopenharmony_ci	if (ret)
14808c2ecf20Sopenharmony_ci		goto err_add_udc;
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	return 0;
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_cierr_add_udc:
14878c2ecf20Sopenharmony_ci	fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ciclean_up3:
14908c2ecf20Sopenharmony_ci	free_irq(ires->start, fusb300);
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ciclean_up:
14938c2ecf20Sopenharmony_ci	if (fusb300) {
14948c2ecf20Sopenharmony_ci		if (fusb300->ep0_req)
14958c2ecf20Sopenharmony_ci			fusb300_free_request(&fusb300->ep[0]->ep,
14968c2ecf20Sopenharmony_ci				fusb300->ep0_req);
14978c2ecf20Sopenharmony_ci		for (i = 0; i < FUSB300_MAX_NUM_EP; i++)
14988c2ecf20Sopenharmony_ci			kfree(fusb300->ep[i]);
14998c2ecf20Sopenharmony_ci		kfree(fusb300);
15008c2ecf20Sopenharmony_ci	}
15018c2ecf20Sopenharmony_ci	if (reg)
15028c2ecf20Sopenharmony_ci		iounmap(reg);
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	return ret;
15058c2ecf20Sopenharmony_ci}
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_cistatic struct platform_driver fusb300_driver = {
15088c2ecf20Sopenharmony_ci	.remove =	fusb300_remove,
15098c2ecf20Sopenharmony_ci	.driver		= {
15108c2ecf20Sopenharmony_ci		.name =	udc_name,
15118c2ecf20Sopenharmony_ci	},
15128c2ecf20Sopenharmony_ci};
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_cimodule_platform_driver_probe(fusb300_driver, fusb300_probe);
1515