xref: /openbmc/linux/drivers/usb/gadget/udc/fusb300_udc.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
290fccb52SAndrzej Pietrasiewicz /*
390fccb52SAndrzej Pietrasiewicz  * Fusb300 UDC (USB gadget)
490fccb52SAndrzej Pietrasiewicz  *
590fccb52SAndrzej Pietrasiewicz  * Copyright (C) 2010 Faraday Technology Corp.
690fccb52SAndrzej Pietrasiewicz  *
790fccb52SAndrzej Pietrasiewicz  * Author : Yuan-hsin Chen <yhchen@faraday-tech.com>
890fccb52SAndrzej Pietrasiewicz  */
990fccb52SAndrzej Pietrasiewicz #include <linux/dma-mapping.h>
1090fccb52SAndrzej Pietrasiewicz #include <linux/err.h>
1190fccb52SAndrzej Pietrasiewicz #include <linux/interrupt.h>
1290fccb52SAndrzej Pietrasiewicz #include <linux/io.h>
1390fccb52SAndrzej Pietrasiewicz #include <linux/module.h>
1490fccb52SAndrzej Pietrasiewicz #include <linux/platform_device.h>
1590fccb52SAndrzej Pietrasiewicz #include <linux/usb/ch9.h>
1690fccb52SAndrzej Pietrasiewicz #include <linux/usb/gadget.h>
1790fccb52SAndrzej Pietrasiewicz 
1890fccb52SAndrzej Pietrasiewicz #include "fusb300_udc.h"
1990fccb52SAndrzej Pietrasiewicz 
2090fccb52SAndrzej Pietrasiewicz MODULE_DESCRIPTION("FUSB300  USB gadget driver");
2190fccb52SAndrzej Pietrasiewicz MODULE_LICENSE("GPL");
2290fccb52SAndrzej Pietrasiewicz MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>");
2390fccb52SAndrzej Pietrasiewicz MODULE_ALIAS("platform:fusb300_udc");
2490fccb52SAndrzej Pietrasiewicz 
2590fccb52SAndrzej Pietrasiewicz #define DRIVER_VERSION	"20 October 2010"
2690fccb52SAndrzej Pietrasiewicz 
2790fccb52SAndrzej Pietrasiewicz static const char udc_name[] = "fusb300_udc";
2890fccb52SAndrzej Pietrasiewicz static const char * const fusb300_ep_name[] = {
2990fccb52SAndrzej Pietrasiewicz 	"ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7", "ep8", "ep9",
3090fccb52SAndrzej Pietrasiewicz 	"ep10", "ep11", "ep12", "ep13", "ep14", "ep15"
3190fccb52SAndrzej Pietrasiewicz };
3290fccb52SAndrzej Pietrasiewicz 
3390fccb52SAndrzej Pietrasiewicz static void done(struct fusb300_ep *ep, struct fusb300_request *req,
3490fccb52SAndrzej Pietrasiewicz 		 int status);
3590fccb52SAndrzej Pietrasiewicz 
fusb300_enable_bit(struct fusb300 * fusb300,u32 offset,u32 value)3690fccb52SAndrzej Pietrasiewicz static void fusb300_enable_bit(struct fusb300 *fusb300, u32 offset,
3790fccb52SAndrzej Pietrasiewicz 			       u32 value)
3890fccb52SAndrzej Pietrasiewicz {
3990fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + offset);
4090fccb52SAndrzej Pietrasiewicz 
4190fccb52SAndrzej Pietrasiewicz 	reg |= value;
4290fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + offset);
4390fccb52SAndrzej Pietrasiewicz }
4490fccb52SAndrzej Pietrasiewicz 
fusb300_disable_bit(struct fusb300 * fusb300,u32 offset,u32 value)4590fccb52SAndrzej Pietrasiewicz static void fusb300_disable_bit(struct fusb300 *fusb300, u32 offset,
4690fccb52SAndrzej Pietrasiewicz 				u32 value)
4790fccb52SAndrzej Pietrasiewicz {
4890fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + offset);
4990fccb52SAndrzej Pietrasiewicz 
5090fccb52SAndrzej Pietrasiewicz 	reg &= ~value;
5190fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + offset);
5290fccb52SAndrzej Pietrasiewicz }
5390fccb52SAndrzej Pietrasiewicz 
5490fccb52SAndrzej Pietrasiewicz 
fusb300_ep_setting(struct fusb300_ep * ep,struct fusb300_ep_info info)5590fccb52SAndrzej Pietrasiewicz static void fusb300_ep_setting(struct fusb300_ep *ep,
5690fccb52SAndrzej Pietrasiewicz 			       struct fusb300_ep_info info)
5790fccb52SAndrzej Pietrasiewicz {
5890fccb52SAndrzej Pietrasiewicz 	ep->epnum = info.epnum;
5990fccb52SAndrzej Pietrasiewicz 	ep->type = info.type;
6090fccb52SAndrzej Pietrasiewicz }
6190fccb52SAndrzej Pietrasiewicz 
fusb300_ep_release(struct fusb300_ep * ep)6290fccb52SAndrzej Pietrasiewicz static int fusb300_ep_release(struct fusb300_ep *ep)
6390fccb52SAndrzej Pietrasiewicz {
6490fccb52SAndrzej Pietrasiewicz 	if (!ep->epnum)
6590fccb52SAndrzej Pietrasiewicz 		return 0;
6690fccb52SAndrzej Pietrasiewicz 	ep->epnum = 0;
6790fccb52SAndrzej Pietrasiewicz 	ep->stall = 0;
6890fccb52SAndrzej Pietrasiewicz 	ep->wedged = 0;
6990fccb52SAndrzej Pietrasiewicz 	return 0;
7090fccb52SAndrzej Pietrasiewicz }
7190fccb52SAndrzej Pietrasiewicz 
fusb300_set_fifo_entry(struct fusb300 * fusb300,u32 ep)7290fccb52SAndrzej Pietrasiewicz static void fusb300_set_fifo_entry(struct fusb300 *fusb300,
7390fccb52SAndrzej Pietrasiewicz 				   u32 ep)
7490fccb52SAndrzej Pietrasiewicz {
7590fccb52SAndrzej Pietrasiewicz 	u32 val = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
7690fccb52SAndrzej Pietrasiewicz 
7790fccb52SAndrzej Pietrasiewicz 	val &= ~FUSB300_EPSET1_FIFOENTRY_MSK;
7890fccb52SAndrzej Pietrasiewicz 	val |= FUSB300_EPSET1_FIFOENTRY(FUSB300_FIFO_ENTRY_NUM);
7990fccb52SAndrzej Pietrasiewicz 	iowrite32(val, fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
8090fccb52SAndrzej Pietrasiewicz }
8190fccb52SAndrzej Pietrasiewicz 
fusb300_set_start_entry(struct fusb300 * fusb300,u8 ep)8290fccb52SAndrzej Pietrasiewicz static void fusb300_set_start_entry(struct fusb300 *fusb300,
8390fccb52SAndrzej Pietrasiewicz 				    u8 ep)
8490fccb52SAndrzej Pietrasiewicz {
8590fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
8690fccb52SAndrzej Pietrasiewicz 	u32 start_entry = fusb300->fifo_entry_num * FUSB300_FIFO_ENTRY_NUM;
8790fccb52SAndrzej Pietrasiewicz 
8890fccb52SAndrzej Pietrasiewicz 	reg &= ~FUSB300_EPSET1_START_ENTRY_MSK	;
8990fccb52SAndrzej Pietrasiewicz 	reg |= FUSB300_EPSET1_START_ENTRY(start_entry);
9090fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
9190fccb52SAndrzej Pietrasiewicz 	if (fusb300->fifo_entry_num == FUSB300_MAX_FIFO_ENTRY) {
9290fccb52SAndrzej Pietrasiewicz 		fusb300->fifo_entry_num = 0;
9390fccb52SAndrzej Pietrasiewicz 		fusb300->addrofs = 0;
9490fccb52SAndrzej Pietrasiewicz 		pr_err("fifo entry is over the maximum number!\n");
9590fccb52SAndrzej Pietrasiewicz 	} else
9690fccb52SAndrzej Pietrasiewicz 		fusb300->fifo_entry_num++;
9790fccb52SAndrzej Pietrasiewicz }
9890fccb52SAndrzej Pietrasiewicz 
9990fccb52SAndrzej Pietrasiewicz /* set fusb300_set_start_entry first before fusb300_set_epaddrofs */
fusb300_set_epaddrofs(struct fusb300 * fusb300,struct fusb300_ep_info info)10090fccb52SAndrzej Pietrasiewicz static void fusb300_set_epaddrofs(struct fusb300 *fusb300,
10190fccb52SAndrzej Pietrasiewicz 				  struct fusb300_ep_info info)
10290fccb52SAndrzej Pietrasiewicz {
10390fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum));
10490fccb52SAndrzej Pietrasiewicz 
10590fccb52SAndrzej Pietrasiewicz 	reg &= ~FUSB300_EPSET2_ADDROFS_MSK;
10690fccb52SAndrzej Pietrasiewicz 	reg |= FUSB300_EPSET2_ADDROFS(fusb300->addrofs);
10790fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum));
10890fccb52SAndrzej Pietrasiewicz 	fusb300->addrofs += (info.maxpacket + 7) / 8 * FUSB300_FIFO_ENTRY_NUM;
10990fccb52SAndrzej Pietrasiewicz }
11090fccb52SAndrzej Pietrasiewicz 
ep_fifo_setting(struct fusb300 * fusb300,struct fusb300_ep_info info)11190fccb52SAndrzej Pietrasiewicz static void ep_fifo_setting(struct fusb300 *fusb300,
11290fccb52SAndrzej Pietrasiewicz 			    struct fusb300_ep_info info)
11390fccb52SAndrzej Pietrasiewicz {
11490fccb52SAndrzej Pietrasiewicz 	fusb300_set_fifo_entry(fusb300, info.epnum);
11590fccb52SAndrzej Pietrasiewicz 	fusb300_set_start_entry(fusb300, info.epnum);
11690fccb52SAndrzej Pietrasiewicz 	fusb300_set_epaddrofs(fusb300, info);
11790fccb52SAndrzej Pietrasiewicz }
11890fccb52SAndrzej Pietrasiewicz 
fusb300_set_eptype(struct fusb300 * fusb300,struct fusb300_ep_info info)11990fccb52SAndrzej Pietrasiewicz static void fusb300_set_eptype(struct fusb300 *fusb300,
12090fccb52SAndrzej Pietrasiewicz 			       struct fusb300_ep_info info)
12190fccb52SAndrzej Pietrasiewicz {
12290fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
12390fccb52SAndrzej Pietrasiewicz 
12490fccb52SAndrzej Pietrasiewicz 	reg &= ~FUSB300_EPSET1_TYPE_MSK;
12590fccb52SAndrzej Pietrasiewicz 	reg |= FUSB300_EPSET1_TYPE(info.type);
12690fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
12790fccb52SAndrzej Pietrasiewicz }
12890fccb52SAndrzej Pietrasiewicz 
fusb300_set_epdir(struct fusb300 * fusb300,struct fusb300_ep_info info)12990fccb52SAndrzej Pietrasiewicz static void fusb300_set_epdir(struct fusb300 *fusb300,
13090fccb52SAndrzej Pietrasiewicz 			      struct fusb300_ep_info info)
13190fccb52SAndrzej Pietrasiewicz {
13290fccb52SAndrzej Pietrasiewicz 	u32 reg;
13390fccb52SAndrzej Pietrasiewicz 
13490fccb52SAndrzej Pietrasiewicz 	if (!info.dir_in)
13590fccb52SAndrzej Pietrasiewicz 		return;
13690fccb52SAndrzej Pietrasiewicz 	reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
13790fccb52SAndrzej Pietrasiewicz 	reg &= ~FUSB300_EPSET1_DIR_MSK;
13890fccb52SAndrzej Pietrasiewicz 	reg |= FUSB300_EPSET1_DIRIN;
13990fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
14090fccb52SAndrzej Pietrasiewicz }
14190fccb52SAndrzej Pietrasiewicz 
fusb300_set_ep_active(struct fusb300 * fusb300,u8 ep)14290fccb52SAndrzej Pietrasiewicz static void fusb300_set_ep_active(struct fusb300 *fusb300,
14390fccb52SAndrzej Pietrasiewicz 			  u8 ep)
14490fccb52SAndrzej Pietrasiewicz {
14590fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
14690fccb52SAndrzej Pietrasiewicz 
14790fccb52SAndrzej Pietrasiewicz 	reg |= FUSB300_EPSET1_ACTEN;
14890fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
14990fccb52SAndrzej Pietrasiewicz }
15090fccb52SAndrzej Pietrasiewicz 
fusb300_set_epmps(struct fusb300 * fusb300,struct fusb300_ep_info info)15190fccb52SAndrzej Pietrasiewicz static void fusb300_set_epmps(struct fusb300 *fusb300,
15290fccb52SAndrzej Pietrasiewicz 			      struct fusb300_ep_info info)
15390fccb52SAndrzej Pietrasiewicz {
15490fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum));
15590fccb52SAndrzej Pietrasiewicz 
15690fccb52SAndrzej Pietrasiewicz 	reg &= ~FUSB300_EPSET2_MPS_MSK;
15790fccb52SAndrzej Pietrasiewicz 	reg |= FUSB300_EPSET2_MPS(info.maxpacket);
15890fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum));
15990fccb52SAndrzej Pietrasiewicz }
16090fccb52SAndrzej Pietrasiewicz 
fusb300_set_interval(struct fusb300 * fusb300,struct fusb300_ep_info info)16190fccb52SAndrzej Pietrasiewicz static void fusb300_set_interval(struct fusb300 *fusb300,
16290fccb52SAndrzej Pietrasiewicz 				 struct fusb300_ep_info info)
16390fccb52SAndrzej Pietrasiewicz {
16490fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
16590fccb52SAndrzej Pietrasiewicz 
16690fccb52SAndrzej Pietrasiewicz 	reg &= ~FUSB300_EPSET1_INTERVAL(0x7);
16790fccb52SAndrzej Pietrasiewicz 	reg |= FUSB300_EPSET1_INTERVAL(info.interval);
16890fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
16990fccb52SAndrzej Pietrasiewicz }
17090fccb52SAndrzej Pietrasiewicz 
fusb300_set_bwnum(struct fusb300 * fusb300,struct fusb300_ep_info info)17190fccb52SAndrzej Pietrasiewicz static void fusb300_set_bwnum(struct fusb300 *fusb300,
17290fccb52SAndrzej Pietrasiewicz 			      struct fusb300_ep_info info)
17390fccb52SAndrzej Pietrasiewicz {
17490fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
17590fccb52SAndrzej Pietrasiewicz 
17690fccb52SAndrzej Pietrasiewicz 	reg &= ~FUSB300_EPSET1_BWNUM(0x3);
17790fccb52SAndrzej Pietrasiewicz 	reg |= FUSB300_EPSET1_BWNUM(info.bw_num);
17890fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
17990fccb52SAndrzej Pietrasiewicz }
18090fccb52SAndrzej Pietrasiewicz 
set_ep_reg(struct fusb300 * fusb300,struct fusb300_ep_info info)18190fccb52SAndrzej Pietrasiewicz static void set_ep_reg(struct fusb300 *fusb300,
18290fccb52SAndrzej Pietrasiewicz 		      struct fusb300_ep_info info)
18390fccb52SAndrzej Pietrasiewicz {
18490fccb52SAndrzej Pietrasiewicz 	fusb300_set_eptype(fusb300, info);
18590fccb52SAndrzej Pietrasiewicz 	fusb300_set_epdir(fusb300, info);
18690fccb52SAndrzej Pietrasiewicz 	fusb300_set_epmps(fusb300, info);
18790fccb52SAndrzej Pietrasiewicz 
18890fccb52SAndrzej Pietrasiewicz 	if (info.interval)
18990fccb52SAndrzej Pietrasiewicz 		fusb300_set_interval(fusb300, info);
19090fccb52SAndrzej Pietrasiewicz 
19190fccb52SAndrzej Pietrasiewicz 	if (info.bw_num)
19290fccb52SAndrzej Pietrasiewicz 		fusb300_set_bwnum(fusb300, info);
19390fccb52SAndrzej Pietrasiewicz 
19490fccb52SAndrzej Pietrasiewicz 	fusb300_set_ep_active(fusb300, info.epnum);
19590fccb52SAndrzej Pietrasiewicz }
19690fccb52SAndrzej Pietrasiewicz 
config_ep(struct fusb300_ep * ep,const struct usb_endpoint_descriptor * desc)19790fccb52SAndrzej Pietrasiewicz static int config_ep(struct fusb300_ep *ep,
19890fccb52SAndrzej Pietrasiewicz 		     const struct usb_endpoint_descriptor *desc)
19990fccb52SAndrzej Pietrasiewicz {
20090fccb52SAndrzej Pietrasiewicz 	struct fusb300 *fusb300 = ep->fusb300;
20190fccb52SAndrzej Pietrasiewicz 	struct fusb300_ep_info info;
20290fccb52SAndrzej Pietrasiewicz 
20390fccb52SAndrzej Pietrasiewicz 	ep->ep.desc = desc;
20490fccb52SAndrzej Pietrasiewicz 
20590fccb52SAndrzej Pietrasiewicz 	info.interval = 0;
20690fccb52SAndrzej Pietrasiewicz 	info.addrofs = 0;
20790fccb52SAndrzej Pietrasiewicz 	info.bw_num = 0;
20890fccb52SAndrzej Pietrasiewicz 
20990fccb52SAndrzej Pietrasiewicz 	info.type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
21090fccb52SAndrzej Pietrasiewicz 	info.dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
21190fccb52SAndrzej Pietrasiewicz 	info.maxpacket = usb_endpoint_maxp(desc);
21290fccb52SAndrzej Pietrasiewicz 	info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
21390fccb52SAndrzej Pietrasiewicz 
21490fccb52SAndrzej Pietrasiewicz 	if ((info.type == USB_ENDPOINT_XFER_INT) ||
21590fccb52SAndrzej Pietrasiewicz 	   (info.type == USB_ENDPOINT_XFER_ISOC)) {
21690fccb52SAndrzej Pietrasiewicz 		info.interval = desc->bInterval;
21790fccb52SAndrzej Pietrasiewicz 		if (info.type == USB_ENDPOINT_XFER_ISOC)
2182f237451SFelipe Balbi 			info.bw_num = usb_endpoint_maxp_mult(desc);
21990fccb52SAndrzej Pietrasiewicz 	}
22090fccb52SAndrzej Pietrasiewicz 
22190fccb52SAndrzej Pietrasiewicz 	ep_fifo_setting(fusb300, info);
22290fccb52SAndrzej Pietrasiewicz 
22390fccb52SAndrzej Pietrasiewicz 	set_ep_reg(fusb300, info);
22490fccb52SAndrzej Pietrasiewicz 
22590fccb52SAndrzej Pietrasiewicz 	fusb300_ep_setting(ep, info);
22690fccb52SAndrzej Pietrasiewicz 
22790fccb52SAndrzej Pietrasiewicz 	fusb300->ep[info.epnum] = ep;
22890fccb52SAndrzej Pietrasiewicz 
22990fccb52SAndrzej Pietrasiewicz 	return 0;
23090fccb52SAndrzej Pietrasiewicz }
23190fccb52SAndrzej Pietrasiewicz 
fusb300_enable(struct usb_ep * _ep,const struct usb_endpoint_descriptor * desc)23290fccb52SAndrzej Pietrasiewicz static int fusb300_enable(struct usb_ep *_ep,
23390fccb52SAndrzej Pietrasiewicz 			  const struct usb_endpoint_descriptor *desc)
23490fccb52SAndrzej Pietrasiewicz {
23590fccb52SAndrzej Pietrasiewicz 	struct fusb300_ep *ep;
23690fccb52SAndrzej Pietrasiewicz 
23790fccb52SAndrzej Pietrasiewicz 	ep = container_of(_ep, struct fusb300_ep, ep);
23890fccb52SAndrzej Pietrasiewicz 
23990fccb52SAndrzej Pietrasiewicz 	if (ep->fusb300->reenum) {
24090fccb52SAndrzej Pietrasiewicz 		ep->fusb300->fifo_entry_num = 0;
24190fccb52SAndrzej Pietrasiewicz 		ep->fusb300->addrofs = 0;
24290fccb52SAndrzej Pietrasiewicz 		ep->fusb300->reenum = 0;
24390fccb52SAndrzej Pietrasiewicz 	}
24490fccb52SAndrzej Pietrasiewicz 
24590fccb52SAndrzej Pietrasiewicz 	return config_ep(ep, desc);
24690fccb52SAndrzej Pietrasiewicz }
24790fccb52SAndrzej Pietrasiewicz 
fusb300_disable(struct usb_ep * _ep)24890fccb52SAndrzej Pietrasiewicz static int fusb300_disable(struct usb_ep *_ep)
24990fccb52SAndrzej Pietrasiewicz {
25090fccb52SAndrzej Pietrasiewicz 	struct fusb300_ep *ep;
25190fccb52SAndrzej Pietrasiewicz 	struct fusb300_request *req;
25290fccb52SAndrzej Pietrasiewicz 	unsigned long flags;
25390fccb52SAndrzej Pietrasiewicz 
25490fccb52SAndrzej Pietrasiewicz 	ep = container_of(_ep, struct fusb300_ep, ep);
25590fccb52SAndrzej Pietrasiewicz 
25690fccb52SAndrzej Pietrasiewicz 	BUG_ON(!ep);
25790fccb52SAndrzej Pietrasiewicz 
25890fccb52SAndrzej Pietrasiewicz 	while (!list_empty(&ep->queue)) {
25990fccb52SAndrzej Pietrasiewicz 		req = list_entry(ep->queue.next, struct fusb300_request, queue);
26090fccb52SAndrzej Pietrasiewicz 		spin_lock_irqsave(&ep->fusb300->lock, flags);
26190fccb52SAndrzej Pietrasiewicz 		done(ep, req, -ECONNRESET);
26290fccb52SAndrzej Pietrasiewicz 		spin_unlock_irqrestore(&ep->fusb300->lock, flags);
26390fccb52SAndrzej Pietrasiewicz 	}
26490fccb52SAndrzej Pietrasiewicz 
26590fccb52SAndrzej Pietrasiewicz 	return fusb300_ep_release(ep);
26690fccb52SAndrzej Pietrasiewicz }
26790fccb52SAndrzej Pietrasiewicz 
fusb300_alloc_request(struct usb_ep * _ep,gfp_t gfp_flags)26890fccb52SAndrzej Pietrasiewicz static struct usb_request *fusb300_alloc_request(struct usb_ep *_ep,
26990fccb52SAndrzej Pietrasiewicz 						gfp_t gfp_flags)
27090fccb52SAndrzej Pietrasiewicz {
27190fccb52SAndrzej Pietrasiewicz 	struct fusb300_request *req;
27290fccb52SAndrzej Pietrasiewicz 
27390fccb52SAndrzej Pietrasiewicz 	req = kzalloc(sizeof(struct fusb300_request), gfp_flags);
27490fccb52SAndrzej Pietrasiewicz 	if (!req)
27590fccb52SAndrzej Pietrasiewicz 		return NULL;
27690fccb52SAndrzej Pietrasiewicz 	INIT_LIST_HEAD(&req->queue);
27790fccb52SAndrzej Pietrasiewicz 
27890fccb52SAndrzej Pietrasiewicz 	return &req->req;
27990fccb52SAndrzej Pietrasiewicz }
28090fccb52SAndrzej Pietrasiewicz 
fusb300_free_request(struct usb_ep * _ep,struct usb_request * _req)28190fccb52SAndrzej Pietrasiewicz static void fusb300_free_request(struct usb_ep *_ep, struct usb_request *_req)
28290fccb52SAndrzej Pietrasiewicz {
28390fccb52SAndrzej Pietrasiewicz 	struct fusb300_request *req;
28490fccb52SAndrzej Pietrasiewicz 
28590fccb52SAndrzej Pietrasiewicz 	req = container_of(_req, struct fusb300_request, req);
28690fccb52SAndrzej Pietrasiewicz 	kfree(req);
28790fccb52SAndrzej Pietrasiewicz }
28890fccb52SAndrzej Pietrasiewicz 
enable_fifo_int(struct fusb300_ep * ep)28990fccb52SAndrzej Pietrasiewicz static int enable_fifo_int(struct fusb300_ep *ep)
29090fccb52SAndrzej Pietrasiewicz {
29190fccb52SAndrzej Pietrasiewicz 	struct fusb300 *fusb300 = ep->fusb300;
29290fccb52SAndrzej Pietrasiewicz 
29390fccb52SAndrzej Pietrasiewicz 	if (ep->epnum) {
29490fccb52SAndrzej Pietrasiewicz 		fusb300_enable_bit(fusb300, FUSB300_OFFSET_IGER0,
29590fccb52SAndrzej Pietrasiewicz 			FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum));
29690fccb52SAndrzej Pietrasiewicz 	} else {
29790fccb52SAndrzej Pietrasiewicz 		pr_err("can't enable_fifo_int ep0\n");
29890fccb52SAndrzej Pietrasiewicz 		return -EINVAL;
29990fccb52SAndrzej Pietrasiewicz 	}
30090fccb52SAndrzej Pietrasiewicz 
30190fccb52SAndrzej Pietrasiewicz 	return 0;
30290fccb52SAndrzej Pietrasiewicz }
30390fccb52SAndrzej Pietrasiewicz 
disable_fifo_int(struct fusb300_ep * ep)30490fccb52SAndrzej Pietrasiewicz static int disable_fifo_int(struct fusb300_ep *ep)
30590fccb52SAndrzej Pietrasiewicz {
30690fccb52SAndrzej Pietrasiewicz 	struct fusb300 *fusb300 = ep->fusb300;
30790fccb52SAndrzej Pietrasiewicz 
30890fccb52SAndrzej Pietrasiewicz 	if (ep->epnum) {
30990fccb52SAndrzej Pietrasiewicz 		fusb300_disable_bit(fusb300, FUSB300_OFFSET_IGER0,
31090fccb52SAndrzej Pietrasiewicz 			FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum));
31190fccb52SAndrzej Pietrasiewicz 	} else {
31290fccb52SAndrzej Pietrasiewicz 		pr_err("can't disable_fifo_int ep0\n");
31390fccb52SAndrzej Pietrasiewicz 		return -EINVAL;
31490fccb52SAndrzej Pietrasiewicz 	}
31590fccb52SAndrzej Pietrasiewicz 
31690fccb52SAndrzej Pietrasiewicz 	return 0;
31790fccb52SAndrzej Pietrasiewicz }
31890fccb52SAndrzej Pietrasiewicz 
fusb300_set_cxlen(struct fusb300 * fusb300,u32 length)31990fccb52SAndrzej Pietrasiewicz static void fusb300_set_cxlen(struct fusb300 *fusb300, u32 length)
32090fccb52SAndrzej Pietrasiewicz {
32190fccb52SAndrzej Pietrasiewicz 	u32 reg;
32290fccb52SAndrzej Pietrasiewicz 
32390fccb52SAndrzej Pietrasiewicz 	reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR);
32490fccb52SAndrzej Pietrasiewicz 	reg &= ~FUSB300_CSR_LEN_MSK;
32590fccb52SAndrzej Pietrasiewicz 	reg |= FUSB300_CSR_LEN(length);
32690fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_CSR);
32790fccb52SAndrzej Pietrasiewicz }
32890fccb52SAndrzej Pietrasiewicz 
32990fccb52SAndrzej Pietrasiewicz /* write data to cx fifo */
fusb300_wrcxf(struct fusb300_ep * ep,struct fusb300_request * req)33090fccb52SAndrzej Pietrasiewicz static void fusb300_wrcxf(struct fusb300_ep *ep,
33190fccb52SAndrzej Pietrasiewicz 		   struct fusb300_request *req)
33290fccb52SAndrzej Pietrasiewicz {
33390fccb52SAndrzej Pietrasiewicz 	int i = 0;
33490fccb52SAndrzej Pietrasiewicz 	u8 *tmp;
33590fccb52SAndrzej Pietrasiewicz 	u32 data;
33690fccb52SAndrzej Pietrasiewicz 	struct fusb300 *fusb300 = ep->fusb300;
33790fccb52SAndrzej Pietrasiewicz 	u32 length = req->req.length - req->req.actual;
33890fccb52SAndrzej Pietrasiewicz 
33990fccb52SAndrzej Pietrasiewicz 	tmp = req->req.buf + req->req.actual;
34090fccb52SAndrzej Pietrasiewicz 
34190fccb52SAndrzej Pietrasiewicz 	if (length > SS_CTL_MAX_PACKET_SIZE) {
34290fccb52SAndrzej Pietrasiewicz 		fusb300_set_cxlen(fusb300, SS_CTL_MAX_PACKET_SIZE);
34390fccb52SAndrzej Pietrasiewicz 		for (i = (SS_CTL_MAX_PACKET_SIZE >> 2); i > 0; i--) {
34490fccb52SAndrzej Pietrasiewicz 			data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 |
34590fccb52SAndrzej Pietrasiewicz 				*(tmp + 3) << 24;
34690fccb52SAndrzej Pietrasiewicz 			iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
34790fccb52SAndrzej Pietrasiewicz 			tmp += 4;
34890fccb52SAndrzej Pietrasiewicz 		}
34990fccb52SAndrzej Pietrasiewicz 		req->req.actual += SS_CTL_MAX_PACKET_SIZE;
35090fccb52SAndrzej Pietrasiewicz 	} else { /* length is less than max packet size */
35190fccb52SAndrzej Pietrasiewicz 		fusb300_set_cxlen(fusb300, length);
35290fccb52SAndrzej Pietrasiewicz 		for (i = length >> 2; i > 0; i--) {
35390fccb52SAndrzej Pietrasiewicz 			data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 |
35490fccb52SAndrzej Pietrasiewicz 				*(tmp + 3) << 24;
35590fccb52SAndrzej Pietrasiewicz 			printk(KERN_DEBUG "    0x%x\n", data);
35690fccb52SAndrzej Pietrasiewicz 			iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
35790fccb52SAndrzej Pietrasiewicz 			tmp = tmp + 4;
35890fccb52SAndrzej Pietrasiewicz 		}
35990fccb52SAndrzej Pietrasiewicz 		switch (length % 4) {
36090fccb52SAndrzej Pietrasiewicz 		case 1:
36190fccb52SAndrzej Pietrasiewicz 			data = *tmp;
36290fccb52SAndrzej Pietrasiewicz 			printk(KERN_DEBUG "    0x%x\n", data);
36390fccb52SAndrzej Pietrasiewicz 			iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
36490fccb52SAndrzej Pietrasiewicz 			break;
36590fccb52SAndrzej Pietrasiewicz 		case 2:
36690fccb52SAndrzej Pietrasiewicz 			data = *tmp | *(tmp + 1) << 8;
36790fccb52SAndrzej Pietrasiewicz 			printk(KERN_DEBUG "    0x%x\n", data);
36890fccb52SAndrzej Pietrasiewicz 			iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
36990fccb52SAndrzej Pietrasiewicz 			break;
37090fccb52SAndrzej Pietrasiewicz 		case 3:
37190fccb52SAndrzej Pietrasiewicz 			data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16;
37290fccb52SAndrzej Pietrasiewicz 			printk(KERN_DEBUG "    0x%x\n", data);
37390fccb52SAndrzej Pietrasiewicz 			iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
37490fccb52SAndrzej Pietrasiewicz 			break;
37590fccb52SAndrzej Pietrasiewicz 		default:
37690fccb52SAndrzej Pietrasiewicz 			break;
37790fccb52SAndrzej Pietrasiewicz 		}
37890fccb52SAndrzej Pietrasiewicz 		req->req.actual += length;
37990fccb52SAndrzej Pietrasiewicz 	}
38090fccb52SAndrzej Pietrasiewicz }
38190fccb52SAndrzej Pietrasiewicz 
fusb300_set_epnstall(struct fusb300 * fusb300,u8 ep)38290fccb52SAndrzej Pietrasiewicz static void fusb300_set_epnstall(struct fusb300 *fusb300, u8 ep)
38390fccb52SAndrzej Pietrasiewicz {
38490fccb52SAndrzej Pietrasiewicz 	fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep),
38590fccb52SAndrzej Pietrasiewicz 		FUSB300_EPSET0_STL);
38690fccb52SAndrzej Pietrasiewicz }
38790fccb52SAndrzej Pietrasiewicz 
fusb300_clear_epnstall(struct fusb300 * fusb300,u8 ep)38890fccb52SAndrzej Pietrasiewicz static void fusb300_clear_epnstall(struct fusb300 *fusb300, u8 ep)
38990fccb52SAndrzej Pietrasiewicz {
39090fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
39190fccb52SAndrzej Pietrasiewicz 
39290fccb52SAndrzej Pietrasiewicz 	if (reg & FUSB300_EPSET0_STL) {
39390fccb52SAndrzej Pietrasiewicz 		printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep);
39490fccb52SAndrzej Pietrasiewicz 		reg |= FUSB300_EPSET0_STL_CLR;
39590fccb52SAndrzej Pietrasiewicz 		iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
39690fccb52SAndrzej Pietrasiewicz 	}
39790fccb52SAndrzej Pietrasiewicz }
39890fccb52SAndrzej Pietrasiewicz 
ep0_queue(struct fusb300_ep * ep,struct fusb300_request * req)39990fccb52SAndrzej Pietrasiewicz static void ep0_queue(struct fusb300_ep *ep, struct fusb300_request *req)
40090fccb52SAndrzej Pietrasiewicz {
40190fccb52SAndrzej Pietrasiewicz 	if (ep->fusb300->ep0_dir) { /* if IN */
40290fccb52SAndrzej Pietrasiewicz 		if (req->req.length) {
40390fccb52SAndrzej Pietrasiewicz 			fusb300_wrcxf(ep, req);
40490fccb52SAndrzej Pietrasiewicz 		} else
40590fccb52SAndrzej Pietrasiewicz 			printk(KERN_DEBUG "%s : req->req.length = 0x%x\n",
40690fccb52SAndrzej Pietrasiewicz 				__func__, req->req.length);
40790fccb52SAndrzej Pietrasiewicz 		if ((req->req.length == req->req.actual) ||
40890fccb52SAndrzej Pietrasiewicz 		    (req->req.actual < ep->ep.maxpacket))
40990fccb52SAndrzej Pietrasiewicz 			done(ep, req, 0);
41090fccb52SAndrzej Pietrasiewicz 	} else { /* OUT */
41190fccb52SAndrzej Pietrasiewicz 		if (!req->req.length)
41290fccb52SAndrzej Pietrasiewicz 			done(ep, req, 0);
41390fccb52SAndrzej Pietrasiewicz 		else
41490fccb52SAndrzej Pietrasiewicz 			fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER1,
41590fccb52SAndrzej Pietrasiewicz 				FUSB300_IGER1_CX_OUT_INT);
41690fccb52SAndrzej Pietrasiewicz 	}
41790fccb52SAndrzej Pietrasiewicz }
41890fccb52SAndrzej Pietrasiewicz 
fusb300_queue(struct usb_ep * _ep,struct usb_request * _req,gfp_t gfp_flags)41990fccb52SAndrzej Pietrasiewicz static int fusb300_queue(struct usb_ep *_ep, struct usb_request *_req,
42090fccb52SAndrzej Pietrasiewicz 			 gfp_t gfp_flags)
42190fccb52SAndrzej Pietrasiewicz {
42290fccb52SAndrzej Pietrasiewicz 	struct fusb300_ep *ep;
42390fccb52SAndrzej Pietrasiewicz 	struct fusb300_request *req;
42490fccb52SAndrzej Pietrasiewicz 	unsigned long flags;
42590fccb52SAndrzej Pietrasiewicz 	int request  = 0;
42690fccb52SAndrzej Pietrasiewicz 
42790fccb52SAndrzej Pietrasiewicz 	ep = container_of(_ep, struct fusb300_ep, ep);
42890fccb52SAndrzej Pietrasiewicz 	req = container_of(_req, struct fusb300_request, req);
42990fccb52SAndrzej Pietrasiewicz 
43090fccb52SAndrzej Pietrasiewicz 	if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN)
43190fccb52SAndrzej Pietrasiewicz 		return -ESHUTDOWN;
43290fccb52SAndrzej Pietrasiewicz 
43390fccb52SAndrzej Pietrasiewicz 	spin_lock_irqsave(&ep->fusb300->lock, flags);
43490fccb52SAndrzej Pietrasiewicz 
43590fccb52SAndrzej Pietrasiewicz 	if (list_empty(&ep->queue))
43690fccb52SAndrzej Pietrasiewicz 		request = 1;
43790fccb52SAndrzej Pietrasiewicz 
43890fccb52SAndrzej Pietrasiewicz 	list_add_tail(&req->queue, &ep->queue);
43990fccb52SAndrzej Pietrasiewicz 
44090fccb52SAndrzej Pietrasiewicz 	req->req.actual = 0;
44190fccb52SAndrzej Pietrasiewicz 	req->req.status = -EINPROGRESS;
44290fccb52SAndrzej Pietrasiewicz 
44390fccb52SAndrzej Pietrasiewicz 	if (ep->ep.desc == NULL) /* ep0 */
44490fccb52SAndrzej Pietrasiewicz 		ep0_queue(ep, req);
44590fccb52SAndrzej Pietrasiewicz 	else if (request && !ep->stall)
44690fccb52SAndrzej Pietrasiewicz 		enable_fifo_int(ep);
44790fccb52SAndrzej Pietrasiewicz 
44890fccb52SAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&ep->fusb300->lock, flags);
44990fccb52SAndrzej Pietrasiewicz 
45090fccb52SAndrzej Pietrasiewicz 	return 0;
45190fccb52SAndrzej Pietrasiewicz }
45290fccb52SAndrzej Pietrasiewicz 
fusb300_dequeue(struct usb_ep * _ep,struct usb_request * _req)45390fccb52SAndrzej Pietrasiewicz static int fusb300_dequeue(struct usb_ep *_ep, struct usb_request *_req)
45490fccb52SAndrzej Pietrasiewicz {
45590fccb52SAndrzej Pietrasiewicz 	struct fusb300_ep *ep;
45690fccb52SAndrzej Pietrasiewicz 	struct fusb300_request *req;
45790fccb52SAndrzej Pietrasiewicz 	unsigned long flags;
45890fccb52SAndrzej Pietrasiewicz 
45990fccb52SAndrzej Pietrasiewicz 	ep = container_of(_ep, struct fusb300_ep, ep);
46090fccb52SAndrzej Pietrasiewicz 	req = container_of(_req, struct fusb300_request, req);
46190fccb52SAndrzej Pietrasiewicz 
46290fccb52SAndrzej Pietrasiewicz 	spin_lock_irqsave(&ep->fusb300->lock, flags);
46390fccb52SAndrzej Pietrasiewicz 	if (!list_empty(&ep->queue))
46490fccb52SAndrzej Pietrasiewicz 		done(ep, req, -ECONNRESET);
46590fccb52SAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&ep->fusb300->lock, flags);
46690fccb52SAndrzej Pietrasiewicz 
46790fccb52SAndrzej Pietrasiewicz 	return 0;
46890fccb52SAndrzej Pietrasiewicz }
46990fccb52SAndrzej Pietrasiewicz 
fusb300_set_halt_and_wedge(struct usb_ep * _ep,int value,int wedge)47090fccb52SAndrzej Pietrasiewicz static int fusb300_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge)
47190fccb52SAndrzej Pietrasiewicz {
47290fccb52SAndrzej Pietrasiewicz 	struct fusb300_ep *ep;
47390fccb52SAndrzej Pietrasiewicz 	struct fusb300 *fusb300;
47490fccb52SAndrzej Pietrasiewicz 	unsigned long flags;
47590fccb52SAndrzej Pietrasiewicz 	int ret = 0;
47690fccb52SAndrzej Pietrasiewicz 
47790fccb52SAndrzej Pietrasiewicz 	ep = container_of(_ep, struct fusb300_ep, ep);
47890fccb52SAndrzej Pietrasiewicz 
47990fccb52SAndrzej Pietrasiewicz 	fusb300 = ep->fusb300;
48090fccb52SAndrzej Pietrasiewicz 
48190fccb52SAndrzej Pietrasiewicz 	spin_lock_irqsave(&ep->fusb300->lock, flags);
48290fccb52SAndrzej Pietrasiewicz 
48390fccb52SAndrzej Pietrasiewicz 	if (!list_empty(&ep->queue)) {
48490fccb52SAndrzej Pietrasiewicz 		ret = -EAGAIN;
48590fccb52SAndrzej Pietrasiewicz 		goto out;
48690fccb52SAndrzej Pietrasiewicz 	}
48790fccb52SAndrzej Pietrasiewicz 
48890fccb52SAndrzej Pietrasiewicz 	if (value) {
48990fccb52SAndrzej Pietrasiewicz 		fusb300_set_epnstall(fusb300, ep->epnum);
49090fccb52SAndrzej Pietrasiewicz 		ep->stall = 1;
49190fccb52SAndrzej Pietrasiewicz 		if (wedge)
49290fccb52SAndrzej Pietrasiewicz 			ep->wedged = 1;
49390fccb52SAndrzej Pietrasiewicz 	} else {
49490fccb52SAndrzej Pietrasiewicz 		fusb300_clear_epnstall(fusb300, ep->epnum);
49590fccb52SAndrzej Pietrasiewicz 		ep->stall = 0;
49690fccb52SAndrzej Pietrasiewicz 		ep->wedged = 0;
49790fccb52SAndrzej Pietrasiewicz 	}
49890fccb52SAndrzej Pietrasiewicz 
49990fccb52SAndrzej Pietrasiewicz out:
50090fccb52SAndrzej Pietrasiewicz 	spin_unlock_irqrestore(&ep->fusb300->lock, flags);
50190fccb52SAndrzej Pietrasiewicz 	return ret;
50290fccb52SAndrzej Pietrasiewicz }
50390fccb52SAndrzej Pietrasiewicz 
fusb300_set_halt(struct usb_ep * _ep,int value)50490fccb52SAndrzej Pietrasiewicz static int fusb300_set_halt(struct usb_ep *_ep, int value)
50590fccb52SAndrzej Pietrasiewicz {
50690fccb52SAndrzej Pietrasiewicz 	return fusb300_set_halt_and_wedge(_ep, value, 0);
50790fccb52SAndrzej Pietrasiewicz }
50890fccb52SAndrzej Pietrasiewicz 
fusb300_set_wedge(struct usb_ep * _ep)50990fccb52SAndrzej Pietrasiewicz static int fusb300_set_wedge(struct usb_ep *_ep)
51090fccb52SAndrzej Pietrasiewicz {
51190fccb52SAndrzej Pietrasiewicz 	return fusb300_set_halt_and_wedge(_ep, 1, 1);
51290fccb52SAndrzej Pietrasiewicz }
51390fccb52SAndrzej Pietrasiewicz 
fusb300_fifo_flush(struct usb_ep * _ep)51490fccb52SAndrzej Pietrasiewicz static void fusb300_fifo_flush(struct usb_ep *_ep)
51590fccb52SAndrzej Pietrasiewicz {
51690fccb52SAndrzej Pietrasiewicz }
51790fccb52SAndrzej Pietrasiewicz 
518977ac789SBhumika Goyal static const struct usb_ep_ops fusb300_ep_ops = {
51990fccb52SAndrzej Pietrasiewicz 	.enable		= fusb300_enable,
52090fccb52SAndrzej Pietrasiewicz 	.disable	= fusb300_disable,
52190fccb52SAndrzej Pietrasiewicz 
52290fccb52SAndrzej Pietrasiewicz 	.alloc_request	= fusb300_alloc_request,
52390fccb52SAndrzej Pietrasiewicz 	.free_request	= fusb300_free_request,
52490fccb52SAndrzej Pietrasiewicz 
52590fccb52SAndrzej Pietrasiewicz 	.queue		= fusb300_queue,
52690fccb52SAndrzej Pietrasiewicz 	.dequeue	= fusb300_dequeue,
52790fccb52SAndrzej Pietrasiewicz 
52890fccb52SAndrzej Pietrasiewicz 	.set_halt	= fusb300_set_halt,
52990fccb52SAndrzej Pietrasiewicz 	.fifo_flush	= fusb300_fifo_flush,
53090fccb52SAndrzej Pietrasiewicz 	.set_wedge	= fusb300_set_wedge,
53190fccb52SAndrzej Pietrasiewicz };
53290fccb52SAndrzej Pietrasiewicz 
53390fccb52SAndrzej Pietrasiewicz /*****************************************************************************/
fusb300_clear_int(struct fusb300 * fusb300,u32 offset,u32 value)53490fccb52SAndrzej Pietrasiewicz static void fusb300_clear_int(struct fusb300 *fusb300, u32 offset,
53590fccb52SAndrzej Pietrasiewicz 		       u32 value)
53690fccb52SAndrzej Pietrasiewicz {
53790fccb52SAndrzej Pietrasiewicz 	iowrite32(value, fusb300->reg + offset);
53890fccb52SAndrzej Pietrasiewicz }
53990fccb52SAndrzej Pietrasiewicz 
fusb300_reset(void)54090fccb52SAndrzej Pietrasiewicz static void fusb300_reset(void)
54190fccb52SAndrzej Pietrasiewicz {
54290fccb52SAndrzej Pietrasiewicz }
54390fccb52SAndrzej Pietrasiewicz 
fusb300_set_cxstall(struct fusb300 * fusb300)54490fccb52SAndrzej Pietrasiewicz static void fusb300_set_cxstall(struct fusb300 *fusb300)
54590fccb52SAndrzej Pietrasiewicz {
54690fccb52SAndrzej Pietrasiewicz 	fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR,
54790fccb52SAndrzej Pietrasiewicz 			   FUSB300_CSR_STL);
54890fccb52SAndrzej Pietrasiewicz }
54990fccb52SAndrzej Pietrasiewicz 
fusb300_set_cxdone(struct fusb300 * fusb300)55090fccb52SAndrzej Pietrasiewicz static void fusb300_set_cxdone(struct fusb300 *fusb300)
55190fccb52SAndrzej Pietrasiewicz {
55290fccb52SAndrzej Pietrasiewicz 	fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR,
55390fccb52SAndrzej Pietrasiewicz 			   FUSB300_CSR_DONE);
55490fccb52SAndrzej Pietrasiewicz }
55590fccb52SAndrzej Pietrasiewicz 
55690fccb52SAndrzej Pietrasiewicz /* read data from cx fifo */
fusb300_rdcxf(struct fusb300 * fusb300,u8 * buffer,u32 length)55790fccb52SAndrzej Pietrasiewicz static void fusb300_rdcxf(struct fusb300 *fusb300,
55890fccb52SAndrzej Pietrasiewicz 		   u8 *buffer, u32 length)
55990fccb52SAndrzej Pietrasiewicz {
56090fccb52SAndrzej Pietrasiewicz 	int i = 0;
56190fccb52SAndrzej Pietrasiewicz 	u8 *tmp;
56290fccb52SAndrzej Pietrasiewicz 	u32 data;
56390fccb52SAndrzej Pietrasiewicz 
56490fccb52SAndrzej Pietrasiewicz 	tmp = buffer;
56590fccb52SAndrzej Pietrasiewicz 
56690fccb52SAndrzej Pietrasiewicz 	for (i = (length >> 2); i > 0; i--) {
56790fccb52SAndrzej Pietrasiewicz 		data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT);
56890fccb52SAndrzej Pietrasiewicz 		printk(KERN_DEBUG "    0x%x\n", data);
56990fccb52SAndrzej Pietrasiewicz 		*tmp = data & 0xFF;
57090fccb52SAndrzej Pietrasiewicz 		*(tmp + 1) = (data >> 8) & 0xFF;
57190fccb52SAndrzej Pietrasiewicz 		*(tmp + 2) = (data >> 16) & 0xFF;
57290fccb52SAndrzej Pietrasiewicz 		*(tmp + 3) = (data >> 24) & 0xFF;
57390fccb52SAndrzej Pietrasiewicz 		tmp = tmp + 4;
57490fccb52SAndrzej Pietrasiewicz 	}
57590fccb52SAndrzej Pietrasiewicz 
57690fccb52SAndrzej Pietrasiewicz 	switch (length % 4) {
57790fccb52SAndrzej Pietrasiewicz 	case 1:
57890fccb52SAndrzej Pietrasiewicz 		data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT);
57990fccb52SAndrzej Pietrasiewicz 		printk(KERN_DEBUG "    0x%x\n", data);
58090fccb52SAndrzej Pietrasiewicz 		*tmp = data & 0xFF;
58190fccb52SAndrzej Pietrasiewicz 		break;
58290fccb52SAndrzej Pietrasiewicz 	case 2:
58390fccb52SAndrzej Pietrasiewicz 		data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT);
58490fccb52SAndrzej Pietrasiewicz 		printk(KERN_DEBUG "    0x%x\n", data);
58590fccb52SAndrzej Pietrasiewicz 		*tmp = data & 0xFF;
58690fccb52SAndrzej Pietrasiewicz 		*(tmp + 1) = (data >> 8) & 0xFF;
58790fccb52SAndrzej Pietrasiewicz 		break;
58890fccb52SAndrzej Pietrasiewicz 	case 3:
58990fccb52SAndrzej Pietrasiewicz 		data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT);
59090fccb52SAndrzej Pietrasiewicz 		printk(KERN_DEBUG "    0x%x\n", data);
59190fccb52SAndrzej Pietrasiewicz 		*tmp = data & 0xFF;
59290fccb52SAndrzej Pietrasiewicz 		*(tmp + 1) = (data >> 8) & 0xFF;
59390fccb52SAndrzej Pietrasiewicz 		*(tmp + 2) = (data >> 16) & 0xFF;
59490fccb52SAndrzej Pietrasiewicz 		break;
59590fccb52SAndrzej Pietrasiewicz 	default:
59690fccb52SAndrzej Pietrasiewicz 		break;
59790fccb52SAndrzej Pietrasiewicz 	}
59890fccb52SAndrzej Pietrasiewicz }
59990fccb52SAndrzej Pietrasiewicz 
fusb300_rdfifo(struct fusb300_ep * ep,struct fusb300_request * req,u32 length)60090fccb52SAndrzej Pietrasiewicz static void fusb300_rdfifo(struct fusb300_ep *ep,
60190fccb52SAndrzej Pietrasiewicz 			  struct fusb300_request *req,
60290fccb52SAndrzej Pietrasiewicz 			  u32 length)
60390fccb52SAndrzej Pietrasiewicz {
60490fccb52SAndrzej Pietrasiewicz 	int i = 0;
60590fccb52SAndrzej Pietrasiewicz 	u8 *tmp;
60690fccb52SAndrzej Pietrasiewicz 	u32 data, reg;
60790fccb52SAndrzej Pietrasiewicz 	struct fusb300 *fusb300 = ep->fusb300;
60890fccb52SAndrzej Pietrasiewicz 
60990fccb52SAndrzej Pietrasiewicz 	tmp = req->req.buf + req->req.actual;
61090fccb52SAndrzej Pietrasiewicz 	req->req.actual += length;
61190fccb52SAndrzej Pietrasiewicz 
61290fccb52SAndrzej Pietrasiewicz 	if (req->req.actual > req->req.length)
61390fccb52SAndrzej Pietrasiewicz 		printk(KERN_DEBUG "req->req.actual > req->req.length\n");
61490fccb52SAndrzej Pietrasiewicz 
61590fccb52SAndrzej Pietrasiewicz 	for (i = (length >> 2); i > 0; i--) {
61690fccb52SAndrzej Pietrasiewicz 		data = ioread32(fusb300->reg +
61790fccb52SAndrzej Pietrasiewicz 			FUSB300_OFFSET_EPPORT(ep->epnum));
61890fccb52SAndrzej Pietrasiewicz 		*tmp = data & 0xFF;
61990fccb52SAndrzej Pietrasiewicz 		*(tmp + 1) = (data >> 8) & 0xFF;
62090fccb52SAndrzej Pietrasiewicz 		*(tmp + 2) = (data >> 16) & 0xFF;
62190fccb52SAndrzej Pietrasiewicz 		*(tmp + 3) = (data >> 24) & 0xFF;
62290fccb52SAndrzej Pietrasiewicz 		tmp = tmp + 4;
62390fccb52SAndrzej Pietrasiewicz 	}
62490fccb52SAndrzej Pietrasiewicz 
62590fccb52SAndrzej Pietrasiewicz 	switch (length % 4) {
62690fccb52SAndrzej Pietrasiewicz 	case 1:
62790fccb52SAndrzej Pietrasiewicz 		data = ioread32(fusb300->reg +
62890fccb52SAndrzej Pietrasiewicz 			FUSB300_OFFSET_EPPORT(ep->epnum));
62990fccb52SAndrzej Pietrasiewicz 		*tmp = data & 0xFF;
63090fccb52SAndrzej Pietrasiewicz 		break;
63190fccb52SAndrzej Pietrasiewicz 	case 2:
63290fccb52SAndrzej Pietrasiewicz 		data = ioread32(fusb300->reg +
63390fccb52SAndrzej Pietrasiewicz 			FUSB300_OFFSET_EPPORT(ep->epnum));
63490fccb52SAndrzej Pietrasiewicz 		*tmp = data & 0xFF;
63590fccb52SAndrzej Pietrasiewicz 		*(tmp + 1) = (data >> 8) & 0xFF;
63690fccb52SAndrzej Pietrasiewicz 		break;
63790fccb52SAndrzej Pietrasiewicz 	case 3:
63890fccb52SAndrzej Pietrasiewicz 		data = ioread32(fusb300->reg +
63990fccb52SAndrzej Pietrasiewicz 			FUSB300_OFFSET_EPPORT(ep->epnum));
64090fccb52SAndrzej Pietrasiewicz 		*tmp = data & 0xFF;
64190fccb52SAndrzej Pietrasiewicz 		*(tmp + 1) = (data >> 8) & 0xFF;
64290fccb52SAndrzej Pietrasiewicz 		*(tmp + 2) = (data >> 16) & 0xFF;
64390fccb52SAndrzej Pietrasiewicz 		break;
64490fccb52SAndrzej Pietrasiewicz 	default:
64590fccb52SAndrzej Pietrasiewicz 		break;
64690fccb52SAndrzej Pietrasiewicz 	}
64790fccb52SAndrzej Pietrasiewicz 
64890fccb52SAndrzej Pietrasiewicz 	do {
64990fccb52SAndrzej Pietrasiewicz 		reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1);
65090fccb52SAndrzej Pietrasiewicz 		reg &= FUSB300_IGR1_SYNF0_EMPTY_INT;
65190fccb52SAndrzej Pietrasiewicz 		if (i)
65290fccb52SAndrzej Pietrasiewicz 			printk(KERN_INFO "sync fifo is not empty!\n");
65390fccb52SAndrzej Pietrasiewicz 		i++;
65490fccb52SAndrzej Pietrasiewicz 	} while (!reg);
65590fccb52SAndrzej Pietrasiewicz }
65690fccb52SAndrzej Pietrasiewicz 
fusb300_get_epnstall(struct fusb300 * fusb300,u8 ep)65790fccb52SAndrzej Pietrasiewicz static u8 fusb300_get_epnstall(struct fusb300 *fusb300, u8 ep)
65890fccb52SAndrzej Pietrasiewicz {
65990fccb52SAndrzej Pietrasiewicz 	u8 value;
66090fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
66190fccb52SAndrzej Pietrasiewicz 
66290fccb52SAndrzej Pietrasiewicz 	value = reg & FUSB300_EPSET0_STL;
66390fccb52SAndrzej Pietrasiewicz 
66490fccb52SAndrzej Pietrasiewicz 	return value;
66590fccb52SAndrzej Pietrasiewicz }
66690fccb52SAndrzej Pietrasiewicz 
fusb300_get_cxstall(struct fusb300 * fusb300)66790fccb52SAndrzej Pietrasiewicz static u8 fusb300_get_cxstall(struct fusb300 *fusb300)
66890fccb52SAndrzej Pietrasiewicz {
66990fccb52SAndrzej Pietrasiewicz 	u8 value;
67090fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR);
67190fccb52SAndrzej Pietrasiewicz 
67290fccb52SAndrzej Pietrasiewicz 	value = (reg & FUSB300_CSR_STL) >> 1;
67390fccb52SAndrzej Pietrasiewicz 
67490fccb52SAndrzej Pietrasiewicz 	return value;
67590fccb52SAndrzej Pietrasiewicz }
67690fccb52SAndrzej Pietrasiewicz 
request_error(struct fusb300 * fusb300)67790fccb52SAndrzej Pietrasiewicz static void request_error(struct fusb300 *fusb300)
67890fccb52SAndrzej Pietrasiewicz {
67990fccb52SAndrzej Pietrasiewicz 	fusb300_set_cxstall(fusb300);
68090fccb52SAndrzej Pietrasiewicz 	printk(KERN_DEBUG "request error!!\n");
68190fccb52SAndrzej Pietrasiewicz }
68290fccb52SAndrzej Pietrasiewicz 
get_status(struct fusb300 * fusb300,struct usb_ctrlrequest * ctrl)68390fccb52SAndrzej Pietrasiewicz static void get_status(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
68490fccb52SAndrzej Pietrasiewicz __releases(fusb300->lock)
68590fccb52SAndrzej Pietrasiewicz __acquires(fusb300->lock)
68690fccb52SAndrzej Pietrasiewicz {
68790fccb52SAndrzej Pietrasiewicz 	u8 ep;
68890fccb52SAndrzej Pietrasiewicz 	u16 status = 0;
68990fccb52SAndrzej Pietrasiewicz 	u16 w_index = ctrl->wIndex;
69090fccb52SAndrzej Pietrasiewicz 
69190fccb52SAndrzej Pietrasiewicz 	switch (ctrl->bRequestType & USB_RECIP_MASK) {
69290fccb52SAndrzej Pietrasiewicz 	case USB_RECIP_DEVICE:
69390fccb52SAndrzej Pietrasiewicz 		status = 1 << USB_DEVICE_SELF_POWERED;
69490fccb52SAndrzej Pietrasiewicz 		break;
69590fccb52SAndrzej Pietrasiewicz 	case USB_RECIP_INTERFACE:
69690fccb52SAndrzej Pietrasiewicz 		status = 0;
69790fccb52SAndrzej Pietrasiewicz 		break;
69890fccb52SAndrzej Pietrasiewicz 	case USB_RECIP_ENDPOINT:
69990fccb52SAndrzej Pietrasiewicz 		ep = w_index & USB_ENDPOINT_NUMBER_MASK;
70090fccb52SAndrzej Pietrasiewicz 		if (ep) {
70190fccb52SAndrzej Pietrasiewicz 			if (fusb300_get_epnstall(fusb300, ep))
70290fccb52SAndrzej Pietrasiewicz 				status = 1 << USB_ENDPOINT_HALT;
70390fccb52SAndrzej Pietrasiewicz 		} else {
70490fccb52SAndrzej Pietrasiewicz 			if (fusb300_get_cxstall(fusb300))
70590fccb52SAndrzej Pietrasiewicz 				status = 0;
70690fccb52SAndrzej Pietrasiewicz 		}
70790fccb52SAndrzej Pietrasiewicz 		break;
70890fccb52SAndrzej Pietrasiewicz 
70990fccb52SAndrzej Pietrasiewicz 	default:
71090fccb52SAndrzej Pietrasiewicz 		request_error(fusb300);
71190fccb52SAndrzej Pietrasiewicz 		return;		/* exit */
71290fccb52SAndrzej Pietrasiewicz 	}
71390fccb52SAndrzej Pietrasiewicz 
71490fccb52SAndrzej Pietrasiewicz 	fusb300->ep0_data = cpu_to_le16(status);
71590fccb52SAndrzej Pietrasiewicz 	fusb300->ep0_req->buf = &fusb300->ep0_data;
71690fccb52SAndrzej Pietrasiewicz 	fusb300->ep0_req->length = 2;
71790fccb52SAndrzej Pietrasiewicz 
71890fccb52SAndrzej Pietrasiewicz 	spin_unlock(&fusb300->lock);
71990fccb52SAndrzej Pietrasiewicz 	fusb300_queue(fusb300->gadget.ep0, fusb300->ep0_req, GFP_KERNEL);
72090fccb52SAndrzej Pietrasiewicz 	spin_lock(&fusb300->lock);
72190fccb52SAndrzej Pietrasiewicz }
72290fccb52SAndrzej Pietrasiewicz 
set_feature(struct fusb300 * fusb300,struct usb_ctrlrequest * ctrl)72390fccb52SAndrzej Pietrasiewicz static void set_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
72490fccb52SAndrzej Pietrasiewicz {
72590fccb52SAndrzej Pietrasiewicz 	u8 ep;
72690fccb52SAndrzej Pietrasiewicz 
72790fccb52SAndrzej Pietrasiewicz 	switch (ctrl->bRequestType & USB_RECIP_MASK) {
72890fccb52SAndrzej Pietrasiewicz 	case USB_RECIP_DEVICE:
72990fccb52SAndrzej Pietrasiewicz 		fusb300_set_cxdone(fusb300);
73090fccb52SAndrzej Pietrasiewicz 		break;
73190fccb52SAndrzej Pietrasiewicz 	case USB_RECIP_INTERFACE:
73290fccb52SAndrzej Pietrasiewicz 		fusb300_set_cxdone(fusb300);
73390fccb52SAndrzej Pietrasiewicz 		break;
73490fccb52SAndrzej Pietrasiewicz 	case USB_RECIP_ENDPOINT: {
73590fccb52SAndrzej Pietrasiewicz 		u16 w_index = le16_to_cpu(ctrl->wIndex);
73690fccb52SAndrzej Pietrasiewicz 
73790fccb52SAndrzej Pietrasiewicz 		ep = w_index & USB_ENDPOINT_NUMBER_MASK;
73890fccb52SAndrzej Pietrasiewicz 		if (ep)
73990fccb52SAndrzej Pietrasiewicz 			fusb300_set_epnstall(fusb300, ep);
74090fccb52SAndrzej Pietrasiewicz 		else
74190fccb52SAndrzej Pietrasiewicz 			fusb300_set_cxstall(fusb300);
74290fccb52SAndrzej Pietrasiewicz 		fusb300_set_cxdone(fusb300);
74390fccb52SAndrzej Pietrasiewicz 		}
74490fccb52SAndrzej Pietrasiewicz 		break;
74590fccb52SAndrzej Pietrasiewicz 	default:
74690fccb52SAndrzej Pietrasiewicz 		request_error(fusb300);
74790fccb52SAndrzej Pietrasiewicz 		break;
74890fccb52SAndrzej Pietrasiewicz 	}
74990fccb52SAndrzej Pietrasiewicz }
75090fccb52SAndrzej Pietrasiewicz 
fusb300_clear_seqnum(struct fusb300 * fusb300,u8 ep)75190fccb52SAndrzej Pietrasiewicz static void fusb300_clear_seqnum(struct fusb300 *fusb300, u8 ep)
75290fccb52SAndrzej Pietrasiewicz {
75390fccb52SAndrzej Pietrasiewicz 	fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep),
75490fccb52SAndrzej Pietrasiewicz 			    FUSB300_EPSET0_CLRSEQNUM);
75590fccb52SAndrzej Pietrasiewicz }
75690fccb52SAndrzej Pietrasiewicz 
clear_feature(struct fusb300 * fusb300,struct usb_ctrlrequest * ctrl)75790fccb52SAndrzej Pietrasiewicz static void clear_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
75890fccb52SAndrzej Pietrasiewicz {
75990fccb52SAndrzej Pietrasiewicz 	struct fusb300_ep *ep =
76090fccb52SAndrzej Pietrasiewicz 		fusb300->ep[ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK];
76190fccb52SAndrzej Pietrasiewicz 
76290fccb52SAndrzej Pietrasiewicz 	switch (ctrl->bRequestType & USB_RECIP_MASK) {
76390fccb52SAndrzej Pietrasiewicz 	case USB_RECIP_DEVICE:
76490fccb52SAndrzej Pietrasiewicz 		fusb300_set_cxdone(fusb300);
76590fccb52SAndrzej Pietrasiewicz 		break;
76690fccb52SAndrzej Pietrasiewicz 	case USB_RECIP_INTERFACE:
76790fccb52SAndrzej Pietrasiewicz 		fusb300_set_cxdone(fusb300);
76890fccb52SAndrzej Pietrasiewicz 		break;
76990fccb52SAndrzej Pietrasiewicz 	case USB_RECIP_ENDPOINT:
77090fccb52SAndrzej Pietrasiewicz 		if (ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK) {
77190fccb52SAndrzej Pietrasiewicz 			if (ep->wedged) {
77290fccb52SAndrzej Pietrasiewicz 				fusb300_set_cxdone(fusb300);
77390fccb52SAndrzej Pietrasiewicz 				break;
77490fccb52SAndrzej Pietrasiewicz 			}
77590fccb52SAndrzej Pietrasiewicz 			if (ep->stall) {
77690fccb52SAndrzej Pietrasiewicz 				ep->stall = 0;
77790fccb52SAndrzej Pietrasiewicz 				fusb300_clear_seqnum(fusb300, ep->epnum);
77890fccb52SAndrzej Pietrasiewicz 				fusb300_clear_epnstall(fusb300, ep->epnum);
77990fccb52SAndrzej Pietrasiewicz 				if (!list_empty(&ep->queue))
78090fccb52SAndrzej Pietrasiewicz 					enable_fifo_int(ep);
78190fccb52SAndrzej Pietrasiewicz 			}
78290fccb52SAndrzej Pietrasiewicz 		}
78390fccb52SAndrzej Pietrasiewicz 		fusb300_set_cxdone(fusb300);
78490fccb52SAndrzej Pietrasiewicz 		break;
78590fccb52SAndrzej Pietrasiewicz 	default:
78690fccb52SAndrzej Pietrasiewicz 		request_error(fusb300);
78790fccb52SAndrzej Pietrasiewicz 		break;
78890fccb52SAndrzej Pietrasiewicz 	}
78990fccb52SAndrzej Pietrasiewicz }
79090fccb52SAndrzej Pietrasiewicz 
fusb300_set_dev_addr(struct fusb300 * fusb300,u16 addr)79190fccb52SAndrzej Pietrasiewicz static void fusb300_set_dev_addr(struct fusb300 *fusb300, u16 addr)
79290fccb52SAndrzej Pietrasiewicz {
79390fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_DAR);
79490fccb52SAndrzej Pietrasiewicz 
79590fccb52SAndrzej Pietrasiewicz 	reg &= ~FUSB300_DAR_DRVADDR_MSK;
79690fccb52SAndrzej Pietrasiewicz 	reg |= FUSB300_DAR_DRVADDR(addr);
79790fccb52SAndrzej Pietrasiewicz 
79890fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_DAR);
79990fccb52SAndrzej Pietrasiewicz }
80090fccb52SAndrzej Pietrasiewicz 
set_address(struct fusb300 * fusb300,struct usb_ctrlrequest * ctrl)80190fccb52SAndrzej Pietrasiewicz static void set_address(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
80290fccb52SAndrzej Pietrasiewicz {
80390fccb52SAndrzej Pietrasiewicz 	if (ctrl->wValue >= 0x0100)
80490fccb52SAndrzej Pietrasiewicz 		request_error(fusb300);
80590fccb52SAndrzej Pietrasiewicz 	else {
80690fccb52SAndrzej Pietrasiewicz 		fusb300_set_dev_addr(fusb300, ctrl->wValue);
80790fccb52SAndrzej Pietrasiewicz 		fusb300_set_cxdone(fusb300);
80890fccb52SAndrzej Pietrasiewicz 	}
80990fccb52SAndrzej Pietrasiewicz }
81090fccb52SAndrzej Pietrasiewicz 
81190fccb52SAndrzej Pietrasiewicz #define UVC_COPY_DESCRIPTORS(mem, src) \
81290fccb52SAndrzej Pietrasiewicz 	do { \
81390fccb52SAndrzej Pietrasiewicz 		const struct usb_descriptor_header * const *__src; \
81490fccb52SAndrzej Pietrasiewicz 		for (__src = src; *__src; ++__src) { \
81590fccb52SAndrzej Pietrasiewicz 			memcpy(mem, *__src, (*__src)->bLength); \
81690fccb52SAndrzej Pietrasiewicz 			mem += (*__src)->bLength; \
81790fccb52SAndrzej Pietrasiewicz 		} \
81890fccb52SAndrzej Pietrasiewicz 	} while (0)
81990fccb52SAndrzej Pietrasiewicz 
setup_packet(struct fusb300 * fusb300,struct usb_ctrlrequest * ctrl)82090fccb52SAndrzej Pietrasiewicz static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
82190fccb52SAndrzej Pietrasiewicz {
82290fccb52SAndrzej Pietrasiewicz 	u8 *p = (u8 *)ctrl;
82390fccb52SAndrzej Pietrasiewicz 	u8 ret = 0;
82490fccb52SAndrzej Pietrasiewicz 	u8 i = 0;
82590fccb52SAndrzej Pietrasiewicz 
82690fccb52SAndrzej Pietrasiewicz 	fusb300_rdcxf(fusb300, p, 8);
82790fccb52SAndrzej Pietrasiewicz 	fusb300->ep0_dir = ctrl->bRequestType & USB_DIR_IN;
82890fccb52SAndrzej Pietrasiewicz 	fusb300->ep0_length = ctrl->wLength;
82990fccb52SAndrzej Pietrasiewicz 
83090fccb52SAndrzej Pietrasiewicz 	/* check request */
83190fccb52SAndrzej Pietrasiewicz 	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
83290fccb52SAndrzej Pietrasiewicz 		switch (ctrl->bRequest) {
83390fccb52SAndrzej Pietrasiewicz 		case USB_REQ_GET_STATUS:
83490fccb52SAndrzej Pietrasiewicz 			get_status(fusb300, ctrl);
83590fccb52SAndrzej Pietrasiewicz 			break;
83690fccb52SAndrzej Pietrasiewicz 		case USB_REQ_CLEAR_FEATURE:
83790fccb52SAndrzej Pietrasiewicz 			clear_feature(fusb300, ctrl);
83890fccb52SAndrzej Pietrasiewicz 			break;
83990fccb52SAndrzej Pietrasiewicz 		case USB_REQ_SET_FEATURE:
84090fccb52SAndrzej Pietrasiewicz 			set_feature(fusb300, ctrl);
84190fccb52SAndrzej Pietrasiewicz 			break;
84290fccb52SAndrzej Pietrasiewicz 		case USB_REQ_SET_ADDRESS:
84390fccb52SAndrzej Pietrasiewicz 			set_address(fusb300, ctrl);
84490fccb52SAndrzej Pietrasiewicz 			break;
84590fccb52SAndrzej Pietrasiewicz 		case USB_REQ_SET_CONFIGURATION:
84690fccb52SAndrzej Pietrasiewicz 			fusb300_enable_bit(fusb300, FUSB300_OFFSET_DAR,
84790fccb52SAndrzej Pietrasiewicz 					   FUSB300_DAR_SETCONFG);
84890fccb52SAndrzej Pietrasiewicz 			/* clear sequence number */
84990fccb52SAndrzej Pietrasiewicz 			for (i = 1; i <= FUSB300_MAX_NUM_EP; i++)
85090fccb52SAndrzej Pietrasiewicz 				fusb300_clear_seqnum(fusb300, i);
85190fccb52SAndrzej Pietrasiewicz 			fusb300->reenum = 1;
85290fccb52SAndrzej Pietrasiewicz 			ret = 1;
85390fccb52SAndrzej Pietrasiewicz 			break;
85490fccb52SAndrzej Pietrasiewicz 		default:
85590fccb52SAndrzej Pietrasiewicz 			ret = 1;
85690fccb52SAndrzej Pietrasiewicz 			break;
85790fccb52SAndrzej Pietrasiewicz 		}
85890fccb52SAndrzej Pietrasiewicz 	} else
85990fccb52SAndrzej Pietrasiewicz 		ret = 1;
86090fccb52SAndrzej Pietrasiewicz 
86190fccb52SAndrzej Pietrasiewicz 	return ret;
86290fccb52SAndrzej Pietrasiewicz }
86390fccb52SAndrzej Pietrasiewicz 
done(struct fusb300_ep * ep,struct fusb300_request * req,int status)86490fccb52SAndrzej Pietrasiewicz static void done(struct fusb300_ep *ep, struct fusb300_request *req,
86590fccb52SAndrzej Pietrasiewicz 		 int status)
86690fccb52SAndrzej Pietrasiewicz {
86790fccb52SAndrzej Pietrasiewicz 	list_del_init(&req->queue);
86890fccb52SAndrzej Pietrasiewicz 
86990fccb52SAndrzej Pietrasiewicz 	/* don't modify queue heads during completion callback */
87090fccb52SAndrzej Pietrasiewicz 	if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN)
87190fccb52SAndrzej Pietrasiewicz 		req->req.status = -ESHUTDOWN;
87290fccb52SAndrzej Pietrasiewicz 	else
87390fccb52SAndrzej Pietrasiewicz 		req->req.status = status;
87490fccb52SAndrzej Pietrasiewicz 
87590fccb52SAndrzej Pietrasiewicz 	spin_unlock(&ep->fusb300->lock);
876304f7e5eSMichal Sojka 	usb_gadget_giveback_request(&ep->ep, &req->req);
87790fccb52SAndrzej Pietrasiewicz 	spin_lock(&ep->fusb300->lock);
87890fccb52SAndrzej Pietrasiewicz 
87990fccb52SAndrzej Pietrasiewicz 	if (ep->epnum) {
88090fccb52SAndrzej Pietrasiewicz 		disable_fifo_int(ep);
88190fccb52SAndrzej Pietrasiewicz 		if (!list_empty(&ep->queue))
88290fccb52SAndrzej Pietrasiewicz 			enable_fifo_int(ep);
88390fccb52SAndrzej Pietrasiewicz 	} else
88490fccb52SAndrzej Pietrasiewicz 		fusb300_set_cxdone(ep->fusb300);
88590fccb52SAndrzej Pietrasiewicz }
88690fccb52SAndrzej Pietrasiewicz 
fusb300_fill_idma_prdtbl(struct fusb300_ep * ep,dma_addr_t d,u32 len)88790fccb52SAndrzej Pietrasiewicz static void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, dma_addr_t d,
88890fccb52SAndrzej Pietrasiewicz 		u32 len)
88990fccb52SAndrzej Pietrasiewicz {
89090fccb52SAndrzej Pietrasiewicz 	u32 value;
89190fccb52SAndrzej Pietrasiewicz 	u32 reg;
89290fccb52SAndrzej Pietrasiewicz 
89390fccb52SAndrzej Pietrasiewicz 	/* wait SW owner */
89490fccb52SAndrzej Pietrasiewicz 	do {
89590fccb52SAndrzej Pietrasiewicz 		reg = ioread32(ep->fusb300->reg +
89690fccb52SAndrzej Pietrasiewicz 			FUSB300_OFFSET_EPPRD_W0(ep->epnum));
89790fccb52SAndrzej Pietrasiewicz 		reg &= FUSB300_EPPRD0_H;
89890fccb52SAndrzej Pietrasiewicz 	} while (reg);
89990fccb52SAndrzej Pietrasiewicz 
90090fccb52SAndrzej Pietrasiewicz 	iowrite32(d, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W1(ep->epnum));
90190fccb52SAndrzej Pietrasiewicz 
90290fccb52SAndrzej Pietrasiewicz 	value = FUSB300_EPPRD0_BTC(len) | FUSB300_EPPRD0_H |
90390fccb52SAndrzej Pietrasiewicz 		FUSB300_EPPRD0_F | FUSB300_EPPRD0_L | FUSB300_EPPRD0_I;
90490fccb52SAndrzej Pietrasiewicz 	iowrite32(value, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W0(ep->epnum));
90590fccb52SAndrzej Pietrasiewicz 
90690fccb52SAndrzej Pietrasiewicz 	iowrite32(0x0, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W2(ep->epnum));
90790fccb52SAndrzej Pietrasiewicz 
90890fccb52SAndrzej Pietrasiewicz 	fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_EPPRDRDY,
90990fccb52SAndrzej Pietrasiewicz 		FUSB300_EPPRDR_EP_PRD_RDY(ep->epnum));
91090fccb52SAndrzej Pietrasiewicz }
91190fccb52SAndrzej Pietrasiewicz 
fusb300_wait_idma_finished(struct fusb300_ep * ep)91290fccb52SAndrzej Pietrasiewicz static void fusb300_wait_idma_finished(struct fusb300_ep *ep)
91390fccb52SAndrzej Pietrasiewicz {
91490fccb52SAndrzej Pietrasiewicz 	u32 reg;
91590fccb52SAndrzej Pietrasiewicz 
91690fccb52SAndrzej Pietrasiewicz 	do {
91790fccb52SAndrzej Pietrasiewicz 		reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR1);
91890fccb52SAndrzej Pietrasiewicz 		if ((reg & FUSB300_IGR1_VBUS_CHG_INT) ||
91990fccb52SAndrzej Pietrasiewicz 		    (reg & FUSB300_IGR1_WARM_RST_INT) ||
92090fccb52SAndrzej Pietrasiewicz 		    (reg & FUSB300_IGR1_HOT_RST_INT) ||
92190fccb52SAndrzej Pietrasiewicz 		    (reg & FUSB300_IGR1_USBRST_INT)
92290fccb52SAndrzej Pietrasiewicz 		)
92390fccb52SAndrzej Pietrasiewicz 			goto IDMA_RESET;
92490fccb52SAndrzej Pietrasiewicz 		reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR0);
92590fccb52SAndrzej Pietrasiewicz 		reg &= FUSB300_IGR0_EPn_PRD_INT(ep->epnum);
92690fccb52SAndrzej Pietrasiewicz 	} while (!reg);
92790fccb52SAndrzej Pietrasiewicz 
92890fccb52SAndrzej Pietrasiewicz 	fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0,
92990fccb52SAndrzej Pietrasiewicz 		FUSB300_IGR0_EPn_PRD_INT(ep->epnum));
93090fccb52SAndrzej Pietrasiewicz 	return;
93190fccb52SAndrzej Pietrasiewicz 
93290fccb52SAndrzej Pietrasiewicz IDMA_RESET:
93390fccb52SAndrzej Pietrasiewicz 	reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGER0);
93490fccb52SAndrzej Pietrasiewicz 	reg &= ~FUSB300_IGER0_EEPn_PRD_INT(ep->epnum);
93590fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_IGER0);
93690fccb52SAndrzej Pietrasiewicz }
93790fccb52SAndrzej Pietrasiewicz 
fusb300_set_idma(struct fusb300_ep * ep,struct fusb300_request * req)93890fccb52SAndrzej Pietrasiewicz static void fusb300_set_idma(struct fusb300_ep *ep,
93990fccb52SAndrzej Pietrasiewicz 			struct fusb300_request *req)
94090fccb52SAndrzej Pietrasiewicz {
94190fccb52SAndrzej Pietrasiewicz 	int ret;
94290fccb52SAndrzej Pietrasiewicz 
94390fccb52SAndrzej Pietrasiewicz 	ret = usb_gadget_map_request(&ep->fusb300->gadget,
94490fccb52SAndrzej Pietrasiewicz 			&req->req, DMA_TO_DEVICE);
94590fccb52SAndrzej Pietrasiewicz 	if (ret)
94690fccb52SAndrzej Pietrasiewicz 		return;
94790fccb52SAndrzej Pietrasiewicz 
94890fccb52SAndrzej Pietrasiewicz 	fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0,
94990fccb52SAndrzej Pietrasiewicz 		FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
95090fccb52SAndrzej Pietrasiewicz 
95190fccb52SAndrzej Pietrasiewicz 	fusb300_fill_idma_prdtbl(ep, req->req.dma, req->req.length);
95290fccb52SAndrzej Pietrasiewicz 	/* check idma is done */
95390fccb52SAndrzej Pietrasiewicz 	fusb300_wait_idma_finished(ep);
95490fccb52SAndrzej Pietrasiewicz 
95590fccb52SAndrzej Pietrasiewicz 	usb_gadget_unmap_request(&ep->fusb300->gadget,
95690fccb52SAndrzej Pietrasiewicz 			&req->req, DMA_TO_DEVICE);
95790fccb52SAndrzej Pietrasiewicz }
95890fccb52SAndrzej Pietrasiewicz 
in_ep_fifo_handler(struct fusb300_ep * ep)95990fccb52SAndrzej Pietrasiewicz static void in_ep_fifo_handler(struct fusb300_ep *ep)
96090fccb52SAndrzej Pietrasiewicz {
96190fccb52SAndrzej Pietrasiewicz 	struct fusb300_request *req = list_entry(ep->queue.next,
96290fccb52SAndrzej Pietrasiewicz 					struct fusb300_request, queue);
96390fccb52SAndrzej Pietrasiewicz 
96490fccb52SAndrzej Pietrasiewicz 	if (req->req.length)
96590fccb52SAndrzej Pietrasiewicz 		fusb300_set_idma(ep, req);
96690fccb52SAndrzej Pietrasiewicz 	done(ep, req, 0);
96790fccb52SAndrzej Pietrasiewicz }
96890fccb52SAndrzej Pietrasiewicz 
out_ep_fifo_handler(struct fusb300_ep * ep)96990fccb52SAndrzej Pietrasiewicz static void out_ep_fifo_handler(struct fusb300_ep *ep)
97090fccb52SAndrzej Pietrasiewicz {
97190fccb52SAndrzej Pietrasiewicz 	struct fusb300 *fusb300 = ep->fusb300;
97290fccb52SAndrzej Pietrasiewicz 	struct fusb300_request *req = list_entry(ep->queue.next,
97390fccb52SAndrzej Pietrasiewicz 						 struct fusb300_request, queue);
97490fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum));
97590fccb52SAndrzej Pietrasiewicz 	u32 length = reg & FUSB300_FFR_BYCNT;
97690fccb52SAndrzej Pietrasiewicz 
97790fccb52SAndrzej Pietrasiewicz 	fusb300_rdfifo(ep, req, length);
97890fccb52SAndrzej Pietrasiewicz 
97990fccb52SAndrzej Pietrasiewicz 	/* finish out transfer */
98090fccb52SAndrzej Pietrasiewicz 	if ((req->req.length == req->req.actual) || (length < ep->ep.maxpacket))
98190fccb52SAndrzej Pietrasiewicz 		done(ep, req, 0);
98290fccb52SAndrzej Pietrasiewicz }
98390fccb52SAndrzej Pietrasiewicz 
check_device_mode(struct fusb300 * fusb300)98490fccb52SAndrzej Pietrasiewicz static void check_device_mode(struct fusb300 *fusb300)
98590fccb52SAndrzej Pietrasiewicz {
98690fccb52SAndrzej Pietrasiewicz 	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_GCR);
98790fccb52SAndrzej Pietrasiewicz 
98890fccb52SAndrzej Pietrasiewicz 	switch (reg & FUSB300_GCR_DEVEN_MSK) {
98990fccb52SAndrzej Pietrasiewicz 	case FUSB300_GCR_DEVEN_SS:
99090fccb52SAndrzej Pietrasiewicz 		fusb300->gadget.speed = USB_SPEED_SUPER;
99190fccb52SAndrzej Pietrasiewicz 		break;
99290fccb52SAndrzej Pietrasiewicz 	case FUSB300_GCR_DEVEN_HS:
99390fccb52SAndrzej Pietrasiewicz 		fusb300->gadget.speed = USB_SPEED_HIGH;
99490fccb52SAndrzej Pietrasiewicz 		break;
99590fccb52SAndrzej Pietrasiewicz 	case FUSB300_GCR_DEVEN_FS:
99690fccb52SAndrzej Pietrasiewicz 		fusb300->gadget.speed = USB_SPEED_FULL;
99790fccb52SAndrzej Pietrasiewicz 		break;
99890fccb52SAndrzej Pietrasiewicz 	default:
99990fccb52SAndrzej Pietrasiewicz 		fusb300->gadget.speed = USB_SPEED_UNKNOWN;
100090fccb52SAndrzej Pietrasiewicz 		break;
100190fccb52SAndrzej Pietrasiewicz 	}
100290fccb52SAndrzej Pietrasiewicz 	printk(KERN_INFO "dev_mode = %d\n", (reg & FUSB300_GCR_DEVEN_MSK));
100390fccb52SAndrzej Pietrasiewicz }
100490fccb52SAndrzej Pietrasiewicz 
100590fccb52SAndrzej Pietrasiewicz 
fusb300_ep0out(struct fusb300 * fusb300)100690fccb52SAndrzej Pietrasiewicz static void fusb300_ep0out(struct fusb300 *fusb300)
100790fccb52SAndrzej Pietrasiewicz {
100890fccb52SAndrzej Pietrasiewicz 	struct fusb300_ep *ep = fusb300->ep[0];
100990fccb52SAndrzej Pietrasiewicz 	u32 reg;
101090fccb52SAndrzej Pietrasiewicz 
101190fccb52SAndrzej Pietrasiewicz 	if (!list_empty(&ep->queue)) {
101290fccb52SAndrzej Pietrasiewicz 		struct fusb300_request *req;
101390fccb52SAndrzej Pietrasiewicz 
101490fccb52SAndrzej Pietrasiewicz 		req = list_first_entry(&ep->queue,
101590fccb52SAndrzej Pietrasiewicz 			struct fusb300_request, queue);
101690fccb52SAndrzej Pietrasiewicz 		if (req->req.length)
101790fccb52SAndrzej Pietrasiewicz 			fusb300_rdcxf(ep->fusb300, req->req.buf,
101890fccb52SAndrzej Pietrasiewicz 				req->req.length);
101990fccb52SAndrzej Pietrasiewicz 		done(ep, req, 0);
102090fccb52SAndrzej Pietrasiewicz 		reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1);
102190fccb52SAndrzej Pietrasiewicz 		reg &= ~FUSB300_IGER1_CX_OUT_INT;
102290fccb52SAndrzej Pietrasiewicz 		iowrite32(reg, fusb300->reg + FUSB300_OFFSET_IGER1);
102390fccb52SAndrzej Pietrasiewicz 	} else
102490fccb52SAndrzej Pietrasiewicz 		pr_err("%s : empty queue\n", __func__);
102590fccb52SAndrzej Pietrasiewicz }
102690fccb52SAndrzej Pietrasiewicz 
fusb300_ep0in(struct fusb300 * fusb300)102790fccb52SAndrzej Pietrasiewicz static void fusb300_ep0in(struct fusb300 *fusb300)
102890fccb52SAndrzej Pietrasiewicz {
102990fccb52SAndrzej Pietrasiewicz 	struct fusb300_request *req;
103090fccb52SAndrzej Pietrasiewicz 	struct fusb300_ep *ep = fusb300->ep[0];
103190fccb52SAndrzej Pietrasiewicz 
103290fccb52SAndrzej Pietrasiewicz 	if ((!list_empty(&ep->queue)) && (fusb300->ep0_dir)) {
103390fccb52SAndrzej Pietrasiewicz 		req = list_entry(ep->queue.next,
103490fccb52SAndrzej Pietrasiewicz 				struct fusb300_request, queue);
103590fccb52SAndrzej Pietrasiewicz 		if (req->req.length)
103690fccb52SAndrzej Pietrasiewicz 			fusb300_wrcxf(ep, req);
103790fccb52SAndrzej Pietrasiewicz 		if ((req->req.length - req->req.actual) < ep->ep.maxpacket)
103890fccb52SAndrzej Pietrasiewicz 			done(ep, req, 0);
103990fccb52SAndrzej Pietrasiewicz 	} else
104090fccb52SAndrzej Pietrasiewicz 		fusb300_set_cxdone(fusb300);
104190fccb52SAndrzej Pietrasiewicz }
104290fccb52SAndrzej Pietrasiewicz 
fusb300_grp2_handler(void)104390fccb52SAndrzej Pietrasiewicz static void fusb300_grp2_handler(void)
104490fccb52SAndrzej Pietrasiewicz {
104590fccb52SAndrzej Pietrasiewicz }
104690fccb52SAndrzej Pietrasiewicz 
fusb300_grp3_handler(void)104790fccb52SAndrzej Pietrasiewicz static void fusb300_grp3_handler(void)
104890fccb52SAndrzej Pietrasiewicz {
104990fccb52SAndrzej Pietrasiewicz }
105090fccb52SAndrzej Pietrasiewicz 
fusb300_grp4_handler(void)105190fccb52SAndrzej Pietrasiewicz static void fusb300_grp4_handler(void)
105290fccb52SAndrzej Pietrasiewicz {
105390fccb52SAndrzej Pietrasiewicz }
105490fccb52SAndrzej Pietrasiewicz 
fusb300_grp5_handler(void)105590fccb52SAndrzej Pietrasiewicz static void fusb300_grp5_handler(void)
105690fccb52SAndrzej Pietrasiewicz {
105790fccb52SAndrzej Pietrasiewicz }
105890fccb52SAndrzej Pietrasiewicz 
fusb300_irq(int irq,void * _fusb300)105990fccb52SAndrzej Pietrasiewicz static irqreturn_t fusb300_irq(int irq, void *_fusb300)
106090fccb52SAndrzej Pietrasiewicz {
106190fccb52SAndrzej Pietrasiewicz 	struct fusb300 *fusb300 = _fusb300;
106290fccb52SAndrzej Pietrasiewicz 	u32 int_grp1 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1);
106390fccb52SAndrzej Pietrasiewicz 	u32 int_grp1_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1);
106490fccb52SAndrzej Pietrasiewicz 	u32 int_grp0 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR0);
106590fccb52SAndrzej Pietrasiewicz 	u32 int_grp0_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER0);
106690fccb52SAndrzej Pietrasiewicz 	struct usb_ctrlrequest ctrl;
106790fccb52SAndrzej Pietrasiewicz 	u8 in;
106890fccb52SAndrzej Pietrasiewicz 	u32 reg;
106990fccb52SAndrzej Pietrasiewicz 	int i;
107090fccb52SAndrzej Pietrasiewicz 
107190fccb52SAndrzej Pietrasiewicz 	spin_lock(&fusb300->lock);
107290fccb52SAndrzej Pietrasiewicz 
107390fccb52SAndrzej Pietrasiewicz 	int_grp1 &= int_grp1_en;
107490fccb52SAndrzej Pietrasiewicz 	int_grp0 &= int_grp0_en;
107590fccb52SAndrzej Pietrasiewicz 
107690fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_WARM_RST_INT) {
107790fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
107890fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_WARM_RST_INT);
107990fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO"fusb300_warmreset\n");
108090fccb52SAndrzej Pietrasiewicz 		fusb300_reset();
108190fccb52SAndrzej Pietrasiewicz 	}
108290fccb52SAndrzej Pietrasiewicz 
108390fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_HOT_RST_INT) {
108490fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
108590fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_HOT_RST_INT);
108690fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO"fusb300_hotreset\n");
108790fccb52SAndrzej Pietrasiewicz 		fusb300_reset();
108890fccb52SAndrzej Pietrasiewicz 	}
108990fccb52SAndrzej Pietrasiewicz 
109090fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_USBRST_INT) {
109190fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
109290fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_USBRST_INT);
109390fccb52SAndrzej Pietrasiewicz 		fusb300_reset();
109490fccb52SAndrzej Pietrasiewicz 	}
109590fccb52SAndrzej Pietrasiewicz 	/* COMABT_INT has a highest priority */
109690fccb52SAndrzej Pietrasiewicz 
109790fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_CX_COMABT_INT) {
109890fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
109990fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_CX_COMABT_INT);
110090fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO"fusb300_ep0abt\n");
110190fccb52SAndrzej Pietrasiewicz 	}
110290fccb52SAndrzej Pietrasiewicz 
110390fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_VBUS_CHG_INT) {
110490fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
110590fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_VBUS_CHG_INT);
110690fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO"fusb300_vbus_change\n");
110790fccb52SAndrzej Pietrasiewicz 	}
110890fccb52SAndrzej Pietrasiewicz 
110990fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_U3_EXIT_FAIL_INT) {
111090fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
111190fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_U3_EXIT_FAIL_INT);
111290fccb52SAndrzej Pietrasiewicz 	}
111390fccb52SAndrzej Pietrasiewicz 
111490fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_U2_EXIT_FAIL_INT) {
111590fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
111690fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_U2_EXIT_FAIL_INT);
111790fccb52SAndrzej Pietrasiewicz 	}
111890fccb52SAndrzej Pietrasiewicz 
111990fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_U1_EXIT_FAIL_INT) {
112090fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
112190fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_U1_EXIT_FAIL_INT);
112290fccb52SAndrzej Pietrasiewicz 	}
112390fccb52SAndrzej Pietrasiewicz 
112490fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_U2_ENTRY_FAIL_INT) {
112590fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
112690fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_U2_ENTRY_FAIL_INT);
112790fccb52SAndrzej Pietrasiewicz 	}
112890fccb52SAndrzej Pietrasiewicz 
112990fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_U1_ENTRY_FAIL_INT) {
113090fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
113190fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_U1_ENTRY_FAIL_INT);
113290fccb52SAndrzej Pietrasiewicz 	}
113390fccb52SAndrzej Pietrasiewicz 
113490fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_U3_EXIT_INT) {
113590fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
113690fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_U3_EXIT_INT);
113790fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "FUSB300_IGR1_U3_EXIT_INT\n");
113890fccb52SAndrzej Pietrasiewicz 	}
113990fccb52SAndrzej Pietrasiewicz 
114090fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_U2_EXIT_INT) {
114190fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
114290fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_U2_EXIT_INT);
114390fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "FUSB300_IGR1_U2_EXIT_INT\n");
114490fccb52SAndrzej Pietrasiewicz 	}
114590fccb52SAndrzej Pietrasiewicz 
114690fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_U1_EXIT_INT) {
114790fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
114890fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_U1_EXIT_INT);
114990fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "FUSB300_IGR1_U1_EXIT_INT\n");
115090fccb52SAndrzej Pietrasiewicz 	}
115190fccb52SAndrzej Pietrasiewicz 
115290fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_U3_ENTRY_INT) {
115390fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
115490fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_U3_ENTRY_INT);
115590fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "FUSB300_IGR1_U3_ENTRY_INT\n");
115690fccb52SAndrzej Pietrasiewicz 		fusb300_enable_bit(fusb300, FUSB300_OFFSET_SSCR1,
115790fccb52SAndrzej Pietrasiewicz 				   FUSB300_SSCR1_GO_U3_DONE);
115890fccb52SAndrzej Pietrasiewicz 	}
115990fccb52SAndrzej Pietrasiewicz 
116090fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_U2_ENTRY_INT) {
116190fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
116290fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_U2_ENTRY_INT);
116390fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "FUSB300_IGR1_U2_ENTRY_INT\n");
116490fccb52SAndrzej Pietrasiewicz 	}
116590fccb52SAndrzej Pietrasiewicz 
116690fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_U1_ENTRY_INT) {
116790fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
116890fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_U1_ENTRY_INT);
116990fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "FUSB300_IGR1_U1_ENTRY_INT\n");
117090fccb52SAndrzej Pietrasiewicz 	}
117190fccb52SAndrzej Pietrasiewicz 
117290fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_RESM_INT) {
117390fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
117490fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_RESM_INT);
117590fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "fusb300_resume\n");
117690fccb52SAndrzej Pietrasiewicz 	}
117790fccb52SAndrzej Pietrasiewicz 
117890fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_SUSP_INT) {
117990fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
118090fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_SUSP_INT);
118190fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "fusb300_suspend\n");
118290fccb52SAndrzej Pietrasiewicz 	}
118390fccb52SAndrzej Pietrasiewicz 
118490fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_HS_LPM_INT) {
118590fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
118690fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_HS_LPM_INT);
118790fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "fusb300_HS_LPM_INT\n");
118890fccb52SAndrzej Pietrasiewicz 	}
118990fccb52SAndrzej Pietrasiewicz 
119090fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_DEV_MODE_CHG_INT) {
119190fccb52SAndrzej Pietrasiewicz 		fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
119290fccb52SAndrzej Pietrasiewicz 				  FUSB300_IGR1_DEV_MODE_CHG_INT);
119390fccb52SAndrzej Pietrasiewicz 		check_device_mode(fusb300);
119490fccb52SAndrzej Pietrasiewicz 	}
119590fccb52SAndrzej Pietrasiewicz 
119690fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_CX_COMFAIL_INT) {
119790fccb52SAndrzej Pietrasiewicz 		fusb300_set_cxstall(fusb300);
119890fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "fusb300_ep0fail\n");
119990fccb52SAndrzej Pietrasiewicz 	}
120090fccb52SAndrzej Pietrasiewicz 
120190fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_CX_SETUP_INT) {
120290fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "fusb300_ep0setup\n");
120390fccb52SAndrzej Pietrasiewicz 		if (setup_packet(fusb300, &ctrl)) {
120490fccb52SAndrzej Pietrasiewicz 			spin_unlock(&fusb300->lock);
120590fccb52SAndrzej Pietrasiewicz 			if (fusb300->driver->setup(&fusb300->gadget, &ctrl) < 0)
120690fccb52SAndrzej Pietrasiewicz 				fusb300_set_cxstall(fusb300);
120790fccb52SAndrzej Pietrasiewicz 			spin_lock(&fusb300->lock);
120890fccb52SAndrzej Pietrasiewicz 		}
120990fccb52SAndrzej Pietrasiewicz 	}
121090fccb52SAndrzej Pietrasiewicz 
121190fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_CX_CMDEND_INT)
121290fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "fusb300_cmdend\n");
121390fccb52SAndrzej Pietrasiewicz 
121490fccb52SAndrzej Pietrasiewicz 
121590fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_CX_OUT_INT) {
121690fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "fusb300_cxout\n");
121790fccb52SAndrzej Pietrasiewicz 		fusb300_ep0out(fusb300);
121890fccb52SAndrzej Pietrasiewicz 	}
121990fccb52SAndrzej Pietrasiewicz 
122090fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_CX_IN_INT) {
122190fccb52SAndrzej Pietrasiewicz 		printk(KERN_INFO "fusb300_cxin\n");
122290fccb52SAndrzej Pietrasiewicz 		fusb300_ep0in(fusb300);
122390fccb52SAndrzej Pietrasiewicz 	}
122490fccb52SAndrzej Pietrasiewicz 
122590fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_INTGRP5)
122690fccb52SAndrzej Pietrasiewicz 		fusb300_grp5_handler();
122790fccb52SAndrzej Pietrasiewicz 
122890fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_INTGRP4)
122990fccb52SAndrzej Pietrasiewicz 		fusb300_grp4_handler();
123090fccb52SAndrzej Pietrasiewicz 
123190fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_INTGRP3)
123290fccb52SAndrzej Pietrasiewicz 		fusb300_grp3_handler();
123390fccb52SAndrzej Pietrasiewicz 
123490fccb52SAndrzej Pietrasiewicz 	if (int_grp1 & FUSB300_IGR1_INTGRP2)
123590fccb52SAndrzej Pietrasiewicz 		fusb300_grp2_handler();
123690fccb52SAndrzej Pietrasiewicz 
123790fccb52SAndrzej Pietrasiewicz 	if (int_grp0) {
123890fccb52SAndrzej Pietrasiewicz 		for (i = 1; i < FUSB300_MAX_NUM_EP; i++) {
123990fccb52SAndrzej Pietrasiewicz 			if (int_grp0 & FUSB300_IGR0_EPn_FIFO_INT(i)) {
124090fccb52SAndrzej Pietrasiewicz 				reg = ioread32(fusb300->reg +
124190fccb52SAndrzej Pietrasiewicz 					FUSB300_OFFSET_EPSET1(i));
124290fccb52SAndrzej Pietrasiewicz 				in = (reg & FUSB300_EPSET1_DIRIN) ? 1 : 0;
124390fccb52SAndrzej Pietrasiewicz 				if (in)
124490fccb52SAndrzej Pietrasiewicz 					in_ep_fifo_handler(fusb300->ep[i]);
124590fccb52SAndrzej Pietrasiewicz 				else
124690fccb52SAndrzej Pietrasiewicz 					out_ep_fifo_handler(fusb300->ep[i]);
124790fccb52SAndrzej Pietrasiewicz 			}
124890fccb52SAndrzej Pietrasiewicz 		}
124990fccb52SAndrzej Pietrasiewicz 	}
125090fccb52SAndrzej Pietrasiewicz 
125190fccb52SAndrzej Pietrasiewicz 	spin_unlock(&fusb300->lock);
125290fccb52SAndrzej Pietrasiewicz 
125390fccb52SAndrzej Pietrasiewicz 	return IRQ_HANDLED;
125490fccb52SAndrzej Pietrasiewicz }
125590fccb52SAndrzej Pietrasiewicz 
fusb300_set_u2_timeout(struct fusb300 * fusb300,u32 time)125690fccb52SAndrzej Pietrasiewicz static void fusb300_set_u2_timeout(struct fusb300 *fusb300,
125790fccb52SAndrzej Pietrasiewicz 				   u32 time)
125890fccb52SAndrzej Pietrasiewicz {
125990fccb52SAndrzej Pietrasiewicz 	u32 reg;
126090fccb52SAndrzej Pietrasiewicz 
126190fccb52SAndrzej Pietrasiewicz 	reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT);
126290fccb52SAndrzej Pietrasiewicz 	reg &= ~0xff;
126390fccb52SAndrzej Pietrasiewicz 	reg |= FUSB300_SSCR2_U2TIMEOUT(time);
126490fccb52SAndrzej Pietrasiewicz 
126590fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT);
126690fccb52SAndrzej Pietrasiewicz }
126790fccb52SAndrzej Pietrasiewicz 
fusb300_set_u1_timeout(struct fusb300 * fusb300,u32 time)126890fccb52SAndrzej Pietrasiewicz static void fusb300_set_u1_timeout(struct fusb300 *fusb300,
126990fccb52SAndrzej Pietrasiewicz 				   u32 time)
127090fccb52SAndrzej Pietrasiewicz {
127190fccb52SAndrzej Pietrasiewicz 	u32 reg;
127290fccb52SAndrzej Pietrasiewicz 
127390fccb52SAndrzej Pietrasiewicz 	reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT);
127490fccb52SAndrzej Pietrasiewicz 	reg &= ~(0xff << 8);
127590fccb52SAndrzej Pietrasiewicz 	reg |= FUSB300_SSCR2_U1TIMEOUT(time);
127690fccb52SAndrzej Pietrasiewicz 
127790fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT);
127890fccb52SAndrzej Pietrasiewicz }
127990fccb52SAndrzej Pietrasiewicz 
init_controller(struct fusb300 * fusb300)128090fccb52SAndrzej Pietrasiewicz static void init_controller(struct fusb300 *fusb300)
128190fccb52SAndrzej Pietrasiewicz {
128290fccb52SAndrzej Pietrasiewicz 	u32 reg;
128390fccb52SAndrzej Pietrasiewicz 	u32 mask = 0;
128490fccb52SAndrzej Pietrasiewicz 	u32 val = 0;
128590fccb52SAndrzej Pietrasiewicz 
128690fccb52SAndrzej Pietrasiewicz 	/* split on */
128790fccb52SAndrzej Pietrasiewicz 	mask = val = FUSB300_AHBBCR_S0_SPLIT_ON | FUSB300_AHBBCR_S1_SPLIT_ON;
128890fccb52SAndrzej Pietrasiewicz 	reg = ioread32(fusb300->reg + FUSB300_OFFSET_AHBCR);
128990fccb52SAndrzej Pietrasiewicz 	reg &= ~mask;
129090fccb52SAndrzej Pietrasiewicz 	reg |= val;
129190fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_AHBCR);
129290fccb52SAndrzej Pietrasiewicz 
129390fccb52SAndrzej Pietrasiewicz 	/* enable high-speed LPM */
129490fccb52SAndrzej Pietrasiewicz 	mask = val = FUSB300_HSCR_HS_LPM_PERMIT;
129590fccb52SAndrzej Pietrasiewicz 	reg = ioread32(fusb300->reg + FUSB300_OFFSET_HSCR);
129690fccb52SAndrzej Pietrasiewicz 	reg &= ~mask;
129790fccb52SAndrzej Pietrasiewicz 	reg |= val;
129890fccb52SAndrzej Pietrasiewicz 	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_HSCR);
129990fccb52SAndrzej Pietrasiewicz 
130090fccb52SAndrzej Pietrasiewicz 	/*set u1 u2 timmer*/
130190fccb52SAndrzej Pietrasiewicz 	fusb300_set_u2_timeout(fusb300, 0xff);
130290fccb52SAndrzej Pietrasiewicz 	fusb300_set_u1_timeout(fusb300, 0xff);
130390fccb52SAndrzej Pietrasiewicz 
130490fccb52SAndrzej Pietrasiewicz 	/* enable all grp1 interrupt */
130590fccb52SAndrzej Pietrasiewicz 	iowrite32(0xcfffff9f, fusb300->reg + FUSB300_OFFSET_IGER1);
130690fccb52SAndrzej Pietrasiewicz }
130790fccb52SAndrzej Pietrasiewicz /*------------------------------------------------------------------------*/
fusb300_udc_start(struct usb_gadget * g,struct usb_gadget_driver * driver)130890fccb52SAndrzej Pietrasiewicz static int fusb300_udc_start(struct usb_gadget *g,
130990fccb52SAndrzej Pietrasiewicz 		struct usb_gadget_driver *driver)
131090fccb52SAndrzej Pietrasiewicz {
131190fccb52SAndrzej Pietrasiewicz 	struct fusb300 *fusb300 = to_fusb300(g);
131290fccb52SAndrzej Pietrasiewicz 
131390fccb52SAndrzej Pietrasiewicz 	/* hook up the driver */
131490fccb52SAndrzej Pietrasiewicz 	fusb300->driver = driver;
131590fccb52SAndrzej Pietrasiewicz 
131690fccb52SAndrzej Pietrasiewicz 	return 0;
131790fccb52SAndrzej Pietrasiewicz }
131890fccb52SAndrzej Pietrasiewicz 
fusb300_udc_stop(struct usb_gadget * g)131922835b80SFelipe Balbi static int fusb300_udc_stop(struct usb_gadget *g)
132090fccb52SAndrzej Pietrasiewicz {
132190fccb52SAndrzej Pietrasiewicz 	struct fusb300 *fusb300 = to_fusb300(g);
132290fccb52SAndrzej Pietrasiewicz 
132390fccb52SAndrzej Pietrasiewicz 	init_controller(fusb300);
132490fccb52SAndrzej Pietrasiewicz 	fusb300->driver = NULL;
132590fccb52SAndrzej Pietrasiewicz 
132690fccb52SAndrzej Pietrasiewicz 	return 0;
132790fccb52SAndrzej Pietrasiewicz }
132890fccb52SAndrzej Pietrasiewicz /*--------------------------------------------------------------------------*/
132990fccb52SAndrzej Pietrasiewicz 
fusb300_udc_pullup(struct usb_gadget * _gadget,int is_active)133090fccb52SAndrzej Pietrasiewicz static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)
133190fccb52SAndrzej Pietrasiewicz {
133290fccb52SAndrzej Pietrasiewicz 	return 0;
133390fccb52SAndrzej Pietrasiewicz }
133490fccb52SAndrzej Pietrasiewicz 
133590fccb52SAndrzej Pietrasiewicz static const struct usb_gadget_ops fusb300_gadget_ops = {
133690fccb52SAndrzej Pietrasiewicz 	.pullup		= fusb300_udc_pullup,
133790fccb52SAndrzej Pietrasiewicz 	.udc_start	= fusb300_udc_start,
133890fccb52SAndrzej Pietrasiewicz 	.udc_stop	= fusb300_udc_stop,
133990fccb52SAndrzej Pietrasiewicz };
134090fccb52SAndrzej Pietrasiewicz 
fusb300_remove(struct platform_device * pdev)1341*a864e8f2SUwe Kleine-König static void fusb300_remove(struct platform_device *pdev)
134290fccb52SAndrzej Pietrasiewicz {
134390fccb52SAndrzej Pietrasiewicz 	struct fusb300 *fusb300 = platform_get_drvdata(pdev);
134462fd0e0aSYoung Xiao 	int i;
134590fccb52SAndrzej Pietrasiewicz 
134690fccb52SAndrzej Pietrasiewicz 	usb_del_gadget_udc(&fusb300->gadget);
134790fccb52SAndrzej Pietrasiewicz 	iounmap(fusb300->reg);
134890fccb52SAndrzej Pietrasiewicz 	free_irq(platform_get_irq(pdev, 0), fusb300);
1349a8d3392eSGaosheng Cui 	free_irq(platform_get_irq(pdev, 1), fusb300);
135090fccb52SAndrzej Pietrasiewicz 
135190fccb52SAndrzej Pietrasiewicz 	fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
135262fd0e0aSYoung Xiao 	for (i = 0; i < FUSB300_MAX_NUM_EP; i++)
135362fd0e0aSYoung Xiao 		kfree(fusb300->ep[i]);
135490fccb52SAndrzej Pietrasiewicz 	kfree(fusb300);
135590fccb52SAndrzej Pietrasiewicz }
135690fccb52SAndrzej Pietrasiewicz 
fusb300_probe(struct platform_device * pdev)135790fccb52SAndrzej Pietrasiewicz static int fusb300_probe(struct platform_device *pdev)
135890fccb52SAndrzej Pietrasiewicz {
135990fccb52SAndrzej Pietrasiewicz 	struct resource *res, *ires, *ires1;
136090fccb52SAndrzej Pietrasiewicz 	void __iomem *reg = NULL;
136190fccb52SAndrzej Pietrasiewicz 	struct fusb300 *fusb300 = NULL;
136290fccb52SAndrzej Pietrasiewicz 	struct fusb300_ep *_ep[FUSB300_MAX_NUM_EP];
136390fccb52SAndrzej Pietrasiewicz 	int ret = 0;
136490fccb52SAndrzej Pietrasiewicz 	int i;
136590fccb52SAndrzej Pietrasiewicz 
136690fccb52SAndrzej Pietrasiewicz 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
136790fccb52SAndrzej Pietrasiewicz 	if (!res) {
136890fccb52SAndrzej Pietrasiewicz 		ret = -ENODEV;
136990fccb52SAndrzej Pietrasiewicz 		pr_err("platform_get_resource error.\n");
137090fccb52SAndrzej Pietrasiewicz 		goto clean_up;
137190fccb52SAndrzej Pietrasiewicz 	}
137290fccb52SAndrzej Pietrasiewicz 
137390fccb52SAndrzej Pietrasiewicz 	ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
137490fccb52SAndrzej Pietrasiewicz 	if (!ires) {
137590fccb52SAndrzej Pietrasiewicz 		ret = -ENODEV;
137690fccb52SAndrzej Pietrasiewicz 		dev_err(&pdev->dev,
137790fccb52SAndrzej Pietrasiewicz 			"platform_get_resource IORESOURCE_IRQ error.\n");
137890fccb52SAndrzej Pietrasiewicz 		goto clean_up;
137990fccb52SAndrzej Pietrasiewicz 	}
138090fccb52SAndrzej Pietrasiewicz 
138190fccb52SAndrzej Pietrasiewicz 	ires1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
138290fccb52SAndrzej Pietrasiewicz 	if (!ires1) {
138390fccb52SAndrzej Pietrasiewicz 		ret = -ENODEV;
138490fccb52SAndrzej Pietrasiewicz 		dev_err(&pdev->dev,
138590fccb52SAndrzej Pietrasiewicz 			"platform_get_resource IORESOURCE_IRQ 1 error.\n");
138690fccb52SAndrzej Pietrasiewicz 		goto clean_up;
138790fccb52SAndrzej Pietrasiewicz 	}
138890fccb52SAndrzej Pietrasiewicz 
138990fccb52SAndrzej Pietrasiewicz 	reg = ioremap(res->start, resource_size(res));
139090fccb52SAndrzej Pietrasiewicz 	if (reg == NULL) {
139190fccb52SAndrzej Pietrasiewicz 		ret = -ENOMEM;
139290fccb52SAndrzej Pietrasiewicz 		pr_err("ioremap error.\n");
139390fccb52SAndrzej Pietrasiewicz 		goto clean_up;
139490fccb52SAndrzej Pietrasiewicz 	}
139590fccb52SAndrzej Pietrasiewicz 
139690fccb52SAndrzej Pietrasiewicz 	/* initialize udc */
139790fccb52SAndrzej Pietrasiewicz 	fusb300 = kzalloc(sizeof(struct fusb300), GFP_KERNEL);
139820e7d465SJulia Lawall 	if (fusb300 == NULL) {
139920e7d465SJulia Lawall 		ret = -ENOMEM;
140090fccb52SAndrzej Pietrasiewicz 		goto clean_up;
140120e7d465SJulia Lawall 	}
140290fccb52SAndrzej Pietrasiewicz 
140390fccb52SAndrzej Pietrasiewicz 	for (i = 0; i < FUSB300_MAX_NUM_EP; i++) {
140490fccb52SAndrzej Pietrasiewicz 		_ep[i] = kzalloc(sizeof(struct fusb300_ep), GFP_KERNEL);
140520e7d465SJulia Lawall 		if (_ep[i] == NULL) {
140620e7d465SJulia Lawall 			ret = -ENOMEM;
140790fccb52SAndrzej Pietrasiewicz 			goto clean_up;
140820e7d465SJulia Lawall 		}
140990fccb52SAndrzej Pietrasiewicz 		fusb300->ep[i] = _ep[i];
141090fccb52SAndrzej Pietrasiewicz 	}
141190fccb52SAndrzej Pietrasiewicz 
141290fccb52SAndrzej Pietrasiewicz 	spin_lock_init(&fusb300->lock);
141390fccb52SAndrzej Pietrasiewicz 
141490fccb52SAndrzej Pietrasiewicz 	platform_set_drvdata(pdev, fusb300);
141590fccb52SAndrzej Pietrasiewicz 
141690fccb52SAndrzej Pietrasiewicz 	fusb300->gadget.ops = &fusb300_gadget_ops;
141790fccb52SAndrzej Pietrasiewicz 
141890fccb52SAndrzej Pietrasiewicz 	fusb300->gadget.max_speed = USB_SPEED_HIGH;
141990fccb52SAndrzej Pietrasiewicz 	fusb300->gadget.name = udc_name;
142090fccb52SAndrzej Pietrasiewicz 	fusb300->reg = reg;
142190fccb52SAndrzej Pietrasiewicz 
142290fccb52SAndrzej Pietrasiewicz 	ret = request_irq(ires->start, fusb300_irq, IRQF_SHARED,
142390fccb52SAndrzej Pietrasiewicz 			  udc_name, fusb300);
142490fccb52SAndrzej Pietrasiewicz 	if (ret < 0) {
142590fccb52SAndrzej Pietrasiewicz 		pr_err("request_irq error (%d)\n", ret);
142690fccb52SAndrzej Pietrasiewicz 		goto clean_up;
142790fccb52SAndrzej Pietrasiewicz 	}
142890fccb52SAndrzej Pietrasiewicz 
142990fccb52SAndrzej Pietrasiewicz 	ret = request_irq(ires1->start, fusb300_irq,
143090fccb52SAndrzej Pietrasiewicz 			IRQF_SHARED, udc_name, fusb300);
143190fccb52SAndrzej Pietrasiewicz 	if (ret < 0) {
143290fccb52SAndrzej Pietrasiewicz 		pr_err("request_irq1 error (%d)\n", ret);
1433a8d3392eSGaosheng Cui 		goto err_request_irq1;
143490fccb52SAndrzej Pietrasiewicz 	}
143590fccb52SAndrzej Pietrasiewicz 
143690fccb52SAndrzej Pietrasiewicz 	INIT_LIST_HEAD(&fusb300->gadget.ep_list);
143790fccb52SAndrzej Pietrasiewicz 
143890fccb52SAndrzej Pietrasiewicz 	for (i = 0; i < FUSB300_MAX_NUM_EP ; i++) {
143990fccb52SAndrzej Pietrasiewicz 		struct fusb300_ep *ep = fusb300->ep[i];
144090fccb52SAndrzej Pietrasiewicz 
144190fccb52SAndrzej Pietrasiewicz 		if (i != 0) {
144290fccb52SAndrzej Pietrasiewicz 			INIT_LIST_HEAD(&fusb300->ep[i]->ep.ep_list);
144390fccb52SAndrzej Pietrasiewicz 			list_add_tail(&fusb300->ep[i]->ep.ep_list,
144490fccb52SAndrzej Pietrasiewicz 				     &fusb300->gadget.ep_list);
144590fccb52SAndrzej Pietrasiewicz 		}
144690fccb52SAndrzej Pietrasiewicz 		ep->fusb300 = fusb300;
144790fccb52SAndrzej Pietrasiewicz 		INIT_LIST_HEAD(&ep->queue);
144890fccb52SAndrzej Pietrasiewicz 		ep->ep.name = fusb300_ep_name[i];
144990fccb52SAndrzej Pietrasiewicz 		ep->ep.ops = &fusb300_ep_ops;
145090fccb52SAndrzej Pietrasiewicz 		usb_ep_set_maxpacket_limit(&ep->ep, HS_BULK_MAX_PACKET_SIZE);
1451455d11c9SRobert Baldyga 
1452455d11c9SRobert Baldyga 		if (i == 0) {
1453455d11c9SRobert Baldyga 			ep->ep.caps.type_control = true;
1454455d11c9SRobert Baldyga 		} else {
1455455d11c9SRobert Baldyga 			ep->ep.caps.type_iso = true;
1456455d11c9SRobert Baldyga 			ep->ep.caps.type_bulk = true;
1457455d11c9SRobert Baldyga 			ep->ep.caps.type_int = true;
1458455d11c9SRobert Baldyga 		}
1459455d11c9SRobert Baldyga 
1460455d11c9SRobert Baldyga 		ep->ep.caps.dir_in = true;
1461455d11c9SRobert Baldyga 		ep->ep.caps.dir_out = true;
146290fccb52SAndrzej Pietrasiewicz 	}
146390fccb52SAndrzej Pietrasiewicz 	usb_ep_set_maxpacket_limit(&fusb300->ep[0]->ep, HS_CTL_MAX_PACKET_SIZE);
146490fccb52SAndrzej Pietrasiewicz 	fusb300->ep[0]->epnum = 0;
146590fccb52SAndrzej Pietrasiewicz 	fusb300->gadget.ep0 = &fusb300->ep[0]->ep;
146690fccb52SAndrzej Pietrasiewicz 	INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list);
146790fccb52SAndrzej Pietrasiewicz 
146890fccb52SAndrzej Pietrasiewicz 	fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep,
146990fccb52SAndrzej Pietrasiewicz 				GFP_KERNEL);
147090fccb52SAndrzej Pietrasiewicz 	if (fusb300->ep0_req == NULL) {
147190fccb52SAndrzej Pietrasiewicz 		ret = -ENOMEM;
1472a8d3392eSGaosheng Cui 		goto err_alloc_request;
147390fccb52SAndrzej Pietrasiewicz 	}
147490fccb52SAndrzej Pietrasiewicz 
147590fccb52SAndrzej Pietrasiewicz 	init_controller(fusb300);
147690fccb52SAndrzej Pietrasiewicz 	ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget);
147790fccb52SAndrzej Pietrasiewicz 	if (ret)
147890fccb52SAndrzej Pietrasiewicz 		goto err_add_udc;
147990fccb52SAndrzej Pietrasiewicz 
148090fccb52SAndrzej Pietrasiewicz 	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
148190fccb52SAndrzej Pietrasiewicz 
148290fccb52SAndrzej Pietrasiewicz 	return 0;
148390fccb52SAndrzej Pietrasiewicz 
148490fccb52SAndrzej Pietrasiewicz err_add_udc:
148590fccb52SAndrzej Pietrasiewicz 	fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
148690fccb52SAndrzej Pietrasiewicz 
1487a8d3392eSGaosheng Cui err_alloc_request:
1488a8d3392eSGaosheng Cui 	free_irq(ires1->start, fusb300);
1489a8d3392eSGaosheng Cui 
1490a8d3392eSGaosheng Cui err_request_irq1:
149190fccb52SAndrzej Pietrasiewicz 	free_irq(ires->start, fusb300);
149290fccb52SAndrzej Pietrasiewicz 
149390fccb52SAndrzej Pietrasiewicz clean_up:
149490fccb52SAndrzej Pietrasiewicz 	if (fusb300) {
149590fccb52SAndrzej Pietrasiewicz 		if (fusb300->ep0_req)
149690fccb52SAndrzej Pietrasiewicz 			fusb300_free_request(&fusb300->ep[0]->ep,
149790fccb52SAndrzej Pietrasiewicz 				fusb300->ep0_req);
149862fd0e0aSYoung Xiao 		for (i = 0; i < FUSB300_MAX_NUM_EP; i++)
149962fd0e0aSYoung Xiao 			kfree(fusb300->ep[i]);
150090fccb52SAndrzej Pietrasiewicz 		kfree(fusb300);
150190fccb52SAndrzej Pietrasiewicz 	}
150290fccb52SAndrzej Pietrasiewicz 	if (reg)
150390fccb52SAndrzej Pietrasiewicz 		iounmap(reg);
150490fccb52SAndrzej Pietrasiewicz 
150590fccb52SAndrzej Pietrasiewicz 	return ret;
150690fccb52SAndrzej Pietrasiewicz }
150790fccb52SAndrzej Pietrasiewicz 
150890fccb52SAndrzej Pietrasiewicz static struct platform_driver fusb300_driver = {
1509*a864e8f2SUwe Kleine-König 	.remove_new =	fusb300_remove,
151090fccb52SAndrzej Pietrasiewicz 	.driver		= {
15113620ed30SCorentin Labbe 		.name =	udc_name,
151290fccb52SAndrzej Pietrasiewicz 	},
151390fccb52SAndrzej Pietrasiewicz };
151490fccb52SAndrzej Pietrasiewicz 
151590fccb52SAndrzej Pietrasiewicz module_platform_driver_probe(fusb300_driver, fusb300_probe);
1516