162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for the NXP ISP1761 device controller
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2021 Linaro, Rui Miguel Silva
662306a36Sopenharmony_ci * Copyright 2014 Ideas on Board Oy
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Contacts:
962306a36Sopenharmony_ci *	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
1062306a36Sopenharmony_ci *	Rui Miguel Silva <rui.silva@linaro.org>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/interrupt.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/list.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/timer.h>
2062306a36Sopenharmony_ci#include <linux/usb.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "isp1760-core.h"
2362306a36Sopenharmony_ci#include "isp1760-regs.h"
2462306a36Sopenharmony_ci#include "isp1760-udc.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define ISP1760_VBUS_POLL_INTERVAL	msecs_to_jiffies(500)
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistruct isp1760_request {
2962306a36Sopenharmony_ci	struct usb_request req;
3062306a36Sopenharmony_ci	struct list_head queue;
3162306a36Sopenharmony_ci	struct isp1760_ep *ep;
3262306a36Sopenharmony_ci	unsigned int packet_size;
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic inline struct isp1760_udc *gadget_to_udc(struct usb_gadget *gadget)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	return container_of(gadget, struct isp1760_udc, gadget);
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic inline struct isp1760_ep *ep_to_udc_ep(struct usb_ep *ep)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	return container_of(ep, struct isp1760_ep, ep);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic inline struct isp1760_request *req_to_udc_req(struct usb_request *req)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	return container_of(req, struct isp1760_request, req);
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic u32 isp1760_udc_read(struct isp1760_udc *udc, u16 field)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	return isp1760_field_read(udc->fields, field);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic void isp1760_udc_write(struct isp1760_udc *udc, u16 field, u32 val)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	isp1760_field_write(udc->fields, field, val);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic u32 isp1760_udc_read_raw(struct isp1760_udc *udc, u16 reg)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	__le32 val;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	regmap_raw_read(udc->regs, reg, &val, 4);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	return le32_to_cpu(val);
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic u16 isp1760_udc_read_raw16(struct isp1760_udc *udc, u16 reg)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	__le16 val;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	regmap_raw_read(udc->regs, reg, &val, 2);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return le16_to_cpu(val);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic void isp1760_udc_write_raw(struct isp1760_udc *udc, u16 reg, u32 val)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	__le32 val_le = cpu_to_le32(val);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	regmap_raw_write(udc->regs, reg, &val_le, 4);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic void isp1760_udc_write_raw16(struct isp1760_udc *udc, u16 reg, u16 val)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	__le16 val_le = cpu_to_le16(val);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	regmap_raw_write(udc->regs, reg, &val_le, 2);
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic void isp1760_udc_set(struct isp1760_udc *udc, u32 field)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	isp1760_udc_write(udc, field, 0xFFFFFFFF);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic void isp1760_udc_clear(struct isp1760_udc *udc, u32 field)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	isp1760_udc_write(udc, field, 0);
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic bool isp1760_udc_is_set(struct isp1760_udc *udc, u32 field)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	return !!isp1760_udc_read(udc, field);
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
10762306a36Sopenharmony_ci * Endpoint Management
10862306a36Sopenharmony_ci */
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic struct isp1760_ep *isp1760_udc_find_ep(struct isp1760_udc *udc,
11162306a36Sopenharmony_ci					      u16 index)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	unsigned int i;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (index == 0)
11662306a36Sopenharmony_ci		return &udc->ep[0];
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	for (i = 1; i < ARRAY_SIZE(udc->ep); ++i) {
11962306a36Sopenharmony_ci		if (udc->ep[i].addr == index)
12062306a36Sopenharmony_ci			return udc->ep[i].desc ? &udc->ep[i] : NULL;
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	return NULL;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic void __isp1760_udc_select_ep(struct isp1760_udc *udc,
12762306a36Sopenharmony_ci				    struct isp1760_ep *ep, int dir)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	isp1760_udc_write(udc, DC_ENDPIDX, ep->addr & USB_ENDPOINT_NUMBER_MASK);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	if (dir == USB_DIR_IN)
13262306a36Sopenharmony_ci		isp1760_udc_set(udc, DC_EPDIR);
13362306a36Sopenharmony_ci	else
13462306a36Sopenharmony_ci		isp1760_udc_clear(udc, DC_EPDIR);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/**
13862306a36Sopenharmony_ci * isp1760_udc_select_ep - Select an endpoint for register access
13962306a36Sopenharmony_ci * @ep: The endpoint
14062306a36Sopenharmony_ci * @udc: Reference to the device controller
14162306a36Sopenharmony_ci *
14262306a36Sopenharmony_ci * The ISP1761 endpoint registers are banked. This function selects the target
14362306a36Sopenharmony_ci * endpoint for banked register access. The selection remains valid until the
14462306a36Sopenharmony_ci * next call to this function, the next direct access to the EPINDEX register
14562306a36Sopenharmony_ci * or the next reset, whichever comes first.
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci * Called with the UDC spinlock held.
14862306a36Sopenharmony_ci */
14962306a36Sopenharmony_cistatic void isp1760_udc_select_ep(struct isp1760_udc *udc,
15062306a36Sopenharmony_ci				  struct isp1760_ep *ep)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	__isp1760_udc_select_ep(udc, ep, ep->addr & USB_ENDPOINT_DIR_MASK);
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/* Called with the UDC spinlock held. */
15662306a36Sopenharmony_cistatic void isp1760_udc_ctrl_send_status(struct isp1760_ep *ep, int dir)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct isp1760_udc *udc = ep->udc;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/*
16162306a36Sopenharmony_ci	 * Proceed to the status stage. The status stage data packet flows in
16262306a36Sopenharmony_ci	 * the direction opposite to the data stage data packets, we thus need
16362306a36Sopenharmony_ci	 * to select the OUT/IN endpoint for IN/OUT transfers.
16462306a36Sopenharmony_ci	 */
16562306a36Sopenharmony_ci	if (dir == USB_DIR_IN)
16662306a36Sopenharmony_ci		isp1760_udc_clear(udc, DC_EPDIR);
16762306a36Sopenharmony_ci	else
16862306a36Sopenharmony_ci		isp1760_udc_set(udc, DC_EPDIR);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	isp1760_udc_write(udc, DC_ENDPIDX, 1);
17162306a36Sopenharmony_ci	isp1760_udc_set(udc, DC_STATUS);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/*
17462306a36Sopenharmony_ci	 * The hardware will terminate the request automatically and go back to
17562306a36Sopenharmony_ci	 * the setup stage without notifying us.
17662306a36Sopenharmony_ci	 */
17762306a36Sopenharmony_ci	udc->ep0_state = ISP1760_CTRL_SETUP;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/* Called without the UDC spinlock held. */
18162306a36Sopenharmony_cistatic void isp1760_udc_request_complete(struct isp1760_ep *ep,
18262306a36Sopenharmony_ci					 struct isp1760_request *req,
18362306a36Sopenharmony_ci					 int status)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct isp1760_udc *udc = ep->udc;
18662306a36Sopenharmony_ci	unsigned long flags;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	dev_dbg(ep->udc->isp->dev, "completing request %p with status %d\n",
18962306a36Sopenharmony_ci		req, status);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	req->ep = NULL;
19262306a36Sopenharmony_ci	req->req.status = status;
19362306a36Sopenharmony_ci	req->req.complete(&ep->ep, &req->req);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	/*
19862306a36Sopenharmony_ci	 * When completing control OUT requests, move to the status stage after
19962306a36Sopenharmony_ci	 * calling the request complete callback. This gives the gadget an
20062306a36Sopenharmony_ci	 * opportunity to stall the control transfer if needed.
20162306a36Sopenharmony_ci	 */
20262306a36Sopenharmony_ci	if (status == 0 && ep->addr == 0 && udc->ep0_dir == USB_DIR_OUT)
20362306a36Sopenharmony_ci		isp1760_udc_ctrl_send_status(ep, USB_DIR_OUT);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic void isp1760_udc_ctrl_send_stall(struct isp1760_ep *ep)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct isp1760_udc *udc = ep->udc;
21162306a36Sopenharmony_ci	unsigned long flags;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	dev_dbg(ep->udc->isp->dev, "%s(ep%02x)\n", __func__, ep->addr);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	/* Stall both the IN and OUT endpoints. */
21862306a36Sopenharmony_ci	__isp1760_udc_select_ep(udc, ep, USB_DIR_OUT);
21962306a36Sopenharmony_ci	isp1760_udc_set(udc, DC_STALL);
22062306a36Sopenharmony_ci	__isp1760_udc_select_ep(udc, ep, USB_DIR_IN);
22162306a36Sopenharmony_ci	isp1760_udc_set(udc, DC_STALL);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/* A protocol stall completes the control transaction. */
22462306a36Sopenharmony_ci	udc->ep0_state = ISP1760_CTRL_SETUP;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
23062306a36Sopenharmony_ci * Data Endpoints
23162306a36Sopenharmony_ci */
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci/* Called with the UDC spinlock held. */
23462306a36Sopenharmony_cistatic bool isp1760_udc_receive(struct isp1760_ep *ep,
23562306a36Sopenharmony_ci				struct isp1760_request *req)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	struct isp1760_udc *udc = ep->udc;
23862306a36Sopenharmony_ci	unsigned int len;
23962306a36Sopenharmony_ci	u32 *buf;
24062306a36Sopenharmony_ci	int i;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	isp1760_udc_select_ep(udc, ep);
24362306a36Sopenharmony_ci	len = isp1760_udc_read(udc, DC_BUFLEN);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	dev_dbg(udc->isp->dev, "%s: received %u bytes (%u/%u done)\n",
24662306a36Sopenharmony_ci		__func__, len, req->req.actual, req->req.length);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	len = min(len, req->req.length - req->req.actual);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (!len) {
25162306a36Sopenharmony_ci		/*
25262306a36Sopenharmony_ci		 * There's no data to be read from the FIFO, acknowledge the RX
25362306a36Sopenharmony_ci		 * interrupt by clearing the buffer.
25462306a36Sopenharmony_ci		 *
25562306a36Sopenharmony_ci		 * TODO: What if another packet arrives in the meantime ? The
25662306a36Sopenharmony_ci		 * datasheet doesn't clearly document how this should be
25762306a36Sopenharmony_ci		 * handled.
25862306a36Sopenharmony_ci		 */
25962306a36Sopenharmony_ci		isp1760_udc_set(udc, DC_CLBUF);
26062306a36Sopenharmony_ci		return false;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	buf = req->req.buf + req->req.actual;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/*
26662306a36Sopenharmony_ci	 * Make sure not to read more than one extra byte, otherwise data from
26762306a36Sopenharmony_ci	 * the next packet might be removed from the FIFO.
26862306a36Sopenharmony_ci	 */
26962306a36Sopenharmony_ci	for (i = len; i > 2; i -= 4, ++buf)
27062306a36Sopenharmony_ci		*buf = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT);
27162306a36Sopenharmony_ci	if (i > 0)
27262306a36Sopenharmony_ci		*(u16 *)buf = isp1760_udc_read_raw16(udc, ISP176x_DC_DATAPORT);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	req->req.actual += len;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	/*
27762306a36Sopenharmony_ci	 * TODO: The short_not_ok flag isn't supported yet, but isn't used by
27862306a36Sopenharmony_ci	 * any gadget driver either.
27962306a36Sopenharmony_ci	 */
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	dev_dbg(udc->isp->dev,
28262306a36Sopenharmony_ci		"%s: req %p actual/length %u/%u maxpacket %u packet size %u\n",
28362306a36Sopenharmony_ci		__func__, req, req->req.actual, req->req.length, ep->maxpacket,
28462306a36Sopenharmony_ci		len);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	ep->rx_pending = false;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/*
28962306a36Sopenharmony_ci	 * Complete the request if all data has been received or if a short
29062306a36Sopenharmony_ci	 * packet has been received.
29162306a36Sopenharmony_ci	 */
29262306a36Sopenharmony_ci	if (req->req.actual == req->req.length || len < ep->maxpacket) {
29362306a36Sopenharmony_ci		list_del(&req->queue);
29462306a36Sopenharmony_ci		return true;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return false;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic void isp1760_udc_transmit(struct isp1760_ep *ep,
30162306a36Sopenharmony_ci				 struct isp1760_request *req)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct isp1760_udc *udc = ep->udc;
30462306a36Sopenharmony_ci	u32 *buf = req->req.buf + req->req.actual;
30562306a36Sopenharmony_ci	int i;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	req->packet_size = min(req->req.length - req->req.actual,
30862306a36Sopenharmony_ci			       ep->maxpacket);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	dev_dbg(udc->isp->dev, "%s: transferring %u bytes (%u/%u done)\n",
31162306a36Sopenharmony_ci		__func__, req->packet_size, req->req.actual,
31262306a36Sopenharmony_ci		req->req.length);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	__isp1760_udc_select_ep(udc, ep, USB_DIR_IN);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (req->packet_size)
31762306a36Sopenharmony_ci		isp1760_udc_write(udc, DC_BUFLEN, req->packet_size);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/*
32062306a36Sopenharmony_ci	 * Make sure not to write more than one extra byte, otherwise extra data
32162306a36Sopenharmony_ci	 * will stay in the FIFO and will be transmitted during the next control
32262306a36Sopenharmony_ci	 * request. The endpoint control CLBUF bit is supposed to allow flushing
32362306a36Sopenharmony_ci	 * the FIFO for this kind of conditions, but doesn't seem to work.
32462306a36Sopenharmony_ci	 */
32562306a36Sopenharmony_ci	for (i = req->packet_size; i > 2; i -= 4, ++buf)
32662306a36Sopenharmony_ci		isp1760_udc_write_raw(udc, ISP176x_DC_DATAPORT, *buf);
32762306a36Sopenharmony_ci	if (i > 0)
32862306a36Sopenharmony_ci		isp1760_udc_write_raw16(udc, ISP176x_DC_DATAPORT, *(u16 *)buf);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (ep->addr == 0)
33162306a36Sopenharmony_ci		isp1760_udc_set(udc, DC_DSEN);
33262306a36Sopenharmony_ci	if (!req->packet_size)
33362306a36Sopenharmony_ci		isp1760_udc_set(udc, DC_VENDP);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic void isp1760_ep_rx_ready(struct isp1760_ep *ep)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct isp1760_udc *udc = ep->udc;
33962306a36Sopenharmony_ci	struct isp1760_request *req;
34062306a36Sopenharmony_ci	bool complete;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	spin_lock(&udc->lock);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (ep->addr == 0 && udc->ep0_state != ISP1760_CTRL_DATA_OUT) {
34562306a36Sopenharmony_ci		spin_unlock(&udc->lock);
34662306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s: invalid ep0 state %u\n", __func__,
34762306a36Sopenharmony_ci			udc->ep0_state);
34862306a36Sopenharmony_ci		return;
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (ep->addr != 0 && !ep->desc) {
35262306a36Sopenharmony_ci		spin_unlock(&udc->lock);
35362306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s: ep%02x is disabled\n", __func__,
35462306a36Sopenharmony_ci			ep->addr);
35562306a36Sopenharmony_ci		return;
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (list_empty(&ep->queue)) {
35962306a36Sopenharmony_ci		ep->rx_pending = true;
36062306a36Sopenharmony_ci		spin_unlock(&udc->lock);
36162306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s: ep%02x (%p) has no request queued\n",
36262306a36Sopenharmony_ci			__func__, ep->addr, ep);
36362306a36Sopenharmony_ci		return;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	req = list_first_entry(&ep->queue, struct isp1760_request,
36762306a36Sopenharmony_ci			       queue);
36862306a36Sopenharmony_ci	complete = isp1760_udc_receive(ep, req);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	spin_unlock(&udc->lock);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (complete)
37362306a36Sopenharmony_ci		isp1760_udc_request_complete(ep, req, 0);
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic void isp1760_ep_tx_complete(struct isp1760_ep *ep)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	struct isp1760_udc *udc = ep->udc;
37962306a36Sopenharmony_ci	struct isp1760_request *complete = NULL;
38062306a36Sopenharmony_ci	struct isp1760_request *req;
38162306a36Sopenharmony_ci	bool need_zlp;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	spin_lock(&udc->lock);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	if (ep->addr == 0 && udc->ep0_state != ISP1760_CTRL_DATA_IN) {
38662306a36Sopenharmony_ci		spin_unlock(&udc->lock);
38762306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "TX IRQ: invalid endpoint state %u\n",
38862306a36Sopenharmony_ci			udc->ep0_state);
38962306a36Sopenharmony_ci		return;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (list_empty(&ep->queue)) {
39362306a36Sopenharmony_ci		/*
39462306a36Sopenharmony_ci		 * This can happen for the control endpoint when the reply to
39562306a36Sopenharmony_ci		 * the GET_STATUS IN control request is sent directly by the
39662306a36Sopenharmony_ci		 * setup IRQ handler. Just proceed to the status stage.
39762306a36Sopenharmony_ci		 */
39862306a36Sopenharmony_ci		if (ep->addr == 0) {
39962306a36Sopenharmony_ci			isp1760_udc_ctrl_send_status(ep, USB_DIR_IN);
40062306a36Sopenharmony_ci			spin_unlock(&udc->lock);
40162306a36Sopenharmony_ci			return;
40262306a36Sopenharmony_ci		}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci		spin_unlock(&udc->lock);
40562306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s: ep%02x has no request queued\n",
40662306a36Sopenharmony_ci			__func__, ep->addr);
40762306a36Sopenharmony_ci		return;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	req = list_first_entry(&ep->queue, struct isp1760_request,
41162306a36Sopenharmony_ci			       queue);
41262306a36Sopenharmony_ci	req->req.actual += req->packet_size;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	need_zlp = req->req.actual == req->req.length &&
41562306a36Sopenharmony_ci		   !(req->req.length % ep->maxpacket) &&
41662306a36Sopenharmony_ci		   req->packet_size && req->req.zero;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	dev_dbg(udc->isp->dev,
41962306a36Sopenharmony_ci		"TX IRQ: req %p actual/length %u/%u maxpacket %u packet size %u zero %u need zlp %u\n",
42062306a36Sopenharmony_ci		 req, req->req.actual, req->req.length, ep->maxpacket,
42162306a36Sopenharmony_ci		 req->packet_size, req->req.zero, need_zlp);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/*
42462306a36Sopenharmony_ci	 * Complete the request if all data has been sent and we don't need to
42562306a36Sopenharmony_ci	 * transmit a zero length packet.
42662306a36Sopenharmony_ci	 */
42762306a36Sopenharmony_ci	if (req->req.actual == req->req.length && !need_zlp) {
42862306a36Sopenharmony_ci		complete = req;
42962306a36Sopenharmony_ci		list_del(&req->queue);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		if (ep->addr == 0)
43262306a36Sopenharmony_ci			isp1760_udc_ctrl_send_status(ep, USB_DIR_IN);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		if (!list_empty(&ep->queue))
43562306a36Sopenharmony_ci			req = list_first_entry(&ep->queue,
43662306a36Sopenharmony_ci					       struct isp1760_request, queue);
43762306a36Sopenharmony_ci		else
43862306a36Sopenharmony_ci			req = NULL;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	/*
44262306a36Sopenharmony_ci	 * Transmit the next packet or start the next request, if any.
44362306a36Sopenharmony_ci	 *
44462306a36Sopenharmony_ci	 * TODO: If the endpoint is stalled the next request shouldn't be
44562306a36Sopenharmony_ci	 * started, but what about the next packet ?
44662306a36Sopenharmony_ci	 */
44762306a36Sopenharmony_ci	if (req)
44862306a36Sopenharmony_ci		isp1760_udc_transmit(ep, req);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	spin_unlock(&udc->lock);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (complete)
45362306a36Sopenharmony_ci		isp1760_udc_request_complete(ep, complete, 0);
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic int __isp1760_udc_set_halt(struct isp1760_ep *ep, bool halt)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	struct isp1760_udc *udc = ep->udc;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	dev_dbg(udc->isp->dev, "%s: %s halt on ep%02x\n", __func__,
46162306a36Sopenharmony_ci		halt ? "set" : "clear", ep->addr);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (ep->desc && usb_endpoint_xfer_isoc(ep->desc)) {
46462306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s: ep%02x is isochronous\n", __func__,
46562306a36Sopenharmony_ci			ep->addr);
46662306a36Sopenharmony_ci		return -EINVAL;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	isp1760_udc_select_ep(udc, ep);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (halt)
47262306a36Sopenharmony_ci		isp1760_udc_set(udc, DC_STALL);
47362306a36Sopenharmony_ci	else
47462306a36Sopenharmony_ci		isp1760_udc_clear(udc, DC_STALL);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	if (ep->addr == 0) {
47762306a36Sopenharmony_ci		/* When halting the control endpoint, stall both IN and OUT. */
47862306a36Sopenharmony_ci		__isp1760_udc_select_ep(udc, ep, USB_DIR_IN);
47962306a36Sopenharmony_ci		if (halt)
48062306a36Sopenharmony_ci			isp1760_udc_set(udc, DC_STALL);
48162306a36Sopenharmony_ci		else
48262306a36Sopenharmony_ci			isp1760_udc_clear(udc, DC_STALL);
48362306a36Sopenharmony_ci	} else if (!halt) {
48462306a36Sopenharmony_ci		/* Reset the data PID by cycling the endpoint enable bit. */
48562306a36Sopenharmony_ci		isp1760_udc_clear(udc, DC_EPENABLE);
48662306a36Sopenharmony_ci		isp1760_udc_set(udc, DC_EPENABLE);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci		/*
48962306a36Sopenharmony_ci		 * Disabling the endpoint emptied the transmit FIFO, fill it
49062306a36Sopenharmony_ci		 * again if a request is pending.
49162306a36Sopenharmony_ci		 *
49262306a36Sopenharmony_ci		 * TODO: Does the gadget framework require synchronizatino with
49362306a36Sopenharmony_ci		 * the TX IRQ handler ?
49462306a36Sopenharmony_ci		 */
49562306a36Sopenharmony_ci		if ((ep->addr & USB_DIR_IN) && !list_empty(&ep->queue)) {
49662306a36Sopenharmony_ci			struct isp1760_request *req;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci			req = list_first_entry(&ep->queue,
49962306a36Sopenharmony_ci					       struct isp1760_request, queue);
50062306a36Sopenharmony_ci			isp1760_udc_transmit(ep, req);
50162306a36Sopenharmony_ci		}
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	ep->halted = halt;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	return 0;
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
51062306a36Sopenharmony_ci * Control Endpoint
51162306a36Sopenharmony_ci */
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic int isp1760_udc_get_status(struct isp1760_udc *udc,
51462306a36Sopenharmony_ci				  const struct usb_ctrlrequest *req)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	struct isp1760_ep *ep;
51762306a36Sopenharmony_ci	u16 status;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	if (req->wLength != cpu_to_le16(2) || req->wValue != cpu_to_le16(0))
52062306a36Sopenharmony_ci		return -EINVAL;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	switch (req->bRequestType) {
52362306a36Sopenharmony_ci	case USB_DIR_IN | USB_RECIP_DEVICE:
52462306a36Sopenharmony_ci		status = udc->devstatus;
52562306a36Sopenharmony_ci		break;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	case USB_DIR_IN | USB_RECIP_INTERFACE:
52862306a36Sopenharmony_ci		status = 0;
52962306a36Sopenharmony_ci		break;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	case USB_DIR_IN | USB_RECIP_ENDPOINT:
53262306a36Sopenharmony_ci		ep = isp1760_udc_find_ep(udc, le16_to_cpu(req->wIndex));
53362306a36Sopenharmony_ci		if (!ep)
53462306a36Sopenharmony_ci			return -EINVAL;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		status = 0;
53762306a36Sopenharmony_ci		if (ep->halted)
53862306a36Sopenharmony_ci			status |= 1 << USB_ENDPOINT_HALT;
53962306a36Sopenharmony_ci		break;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	default:
54262306a36Sopenharmony_ci		return -EINVAL;
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	isp1760_udc_set(udc, DC_EPDIR);
54662306a36Sopenharmony_ci	isp1760_udc_write(udc, DC_ENDPIDX, 1);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	isp1760_udc_write(udc, DC_BUFLEN, 2);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	isp1760_udc_write_raw16(udc, ISP176x_DC_DATAPORT, status);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	isp1760_udc_set(udc, DC_DSEN);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	dev_dbg(udc->isp->dev, "%s: status 0x%04x\n", __func__, status);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	return 0;
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic int isp1760_udc_set_address(struct isp1760_udc *udc, u16 addr)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	if (addr > 127) {
56262306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "invalid device address %u\n", addr);
56362306a36Sopenharmony_ci		return -EINVAL;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	if (udc->gadget.state != USB_STATE_DEFAULT &&
56762306a36Sopenharmony_ci	    udc->gadget.state != USB_STATE_ADDRESS) {
56862306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "can't set address in state %u\n",
56962306a36Sopenharmony_ci			udc->gadget.state);
57062306a36Sopenharmony_ci		return -EINVAL;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	usb_gadget_set_state(&udc->gadget, addr ? USB_STATE_ADDRESS :
57462306a36Sopenharmony_ci			     USB_STATE_DEFAULT);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	isp1760_udc_write(udc, DC_DEVADDR, addr);
57762306a36Sopenharmony_ci	isp1760_udc_set(udc, DC_DEVEN);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	spin_lock(&udc->lock);
58062306a36Sopenharmony_ci	isp1760_udc_ctrl_send_status(&udc->ep[0], USB_DIR_OUT);
58162306a36Sopenharmony_ci	spin_unlock(&udc->lock);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	return 0;
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic bool isp1760_ep0_setup_standard(struct isp1760_udc *udc,
58762306a36Sopenharmony_ci				       struct usb_ctrlrequest *req)
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	bool stall;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	switch (req->bRequest) {
59262306a36Sopenharmony_ci	case USB_REQ_GET_STATUS:
59362306a36Sopenharmony_ci		return isp1760_udc_get_status(udc, req);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	case USB_REQ_CLEAR_FEATURE:
59662306a36Sopenharmony_ci		switch (req->bRequestType) {
59762306a36Sopenharmony_ci		case USB_DIR_OUT | USB_RECIP_DEVICE: {
59862306a36Sopenharmony_ci			/* TODO: Handle remote wakeup feature. */
59962306a36Sopenharmony_ci			return true;
60062306a36Sopenharmony_ci		}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		case USB_DIR_OUT | USB_RECIP_ENDPOINT: {
60362306a36Sopenharmony_ci			u16 index = le16_to_cpu(req->wIndex);
60462306a36Sopenharmony_ci			struct isp1760_ep *ep;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci			if (req->wLength != cpu_to_le16(0) ||
60762306a36Sopenharmony_ci			    req->wValue != cpu_to_le16(USB_ENDPOINT_HALT))
60862306a36Sopenharmony_ci				return true;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci			ep = isp1760_udc_find_ep(udc, index);
61162306a36Sopenharmony_ci			if (!ep)
61262306a36Sopenharmony_ci				return true;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci			spin_lock(&udc->lock);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci			/*
61762306a36Sopenharmony_ci			 * If the endpoint is wedged only the gadget can clear
61862306a36Sopenharmony_ci			 * the halt feature. Pretend success in that case, but
61962306a36Sopenharmony_ci			 * keep the endpoint halted.
62062306a36Sopenharmony_ci			 */
62162306a36Sopenharmony_ci			if (!ep->wedged)
62262306a36Sopenharmony_ci				stall = __isp1760_udc_set_halt(ep, false);
62362306a36Sopenharmony_ci			else
62462306a36Sopenharmony_ci				stall = false;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci			if (!stall)
62762306a36Sopenharmony_ci				isp1760_udc_ctrl_send_status(&udc->ep[0],
62862306a36Sopenharmony_ci							     USB_DIR_OUT);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci			spin_unlock(&udc->lock);
63162306a36Sopenharmony_ci			return stall;
63262306a36Sopenharmony_ci		}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		default:
63562306a36Sopenharmony_ci			return true;
63662306a36Sopenharmony_ci		}
63762306a36Sopenharmony_ci		break;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	case USB_REQ_SET_FEATURE:
64062306a36Sopenharmony_ci		switch (req->bRequestType) {
64162306a36Sopenharmony_ci		case USB_DIR_OUT | USB_RECIP_DEVICE: {
64262306a36Sopenharmony_ci			/* TODO: Handle remote wakeup and test mode features */
64362306a36Sopenharmony_ci			return true;
64462306a36Sopenharmony_ci		}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci		case USB_DIR_OUT | USB_RECIP_ENDPOINT: {
64762306a36Sopenharmony_ci			u16 index = le16_to_cpu(req->wIndex);
64862306a36Sopenharmony_ci			struct isp1760_ep *ep;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci			if (req->wLength != cpu_to_le16(0) ||
65162306a36Sopenharmony_ci			    req->wValue != cpu_to_le16(USB_ENDPOINT_HALT))
65262306a36Sopenharmony_ci				return true;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci			ep = isp1760_udc_find_ep(udc, index);
65562306a36Sopenharmony_ci			if (!ep)
65662306a36Sopenharmony_ci				return true;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci			spin_lock(&udc->lock);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci			stall = __isp1760_udc_set_halt(ep, true);
66162306a36Sopenharmony_ci			if (!stall)
66262306a36Sopenharmony_ci				isp1760_udc_ctrl_send_status(&udc->ep[0],
66362306a36Sopenharmony_ci							     USB_DIR_OUT);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci			spin_unlock(&udc->lock);
66662306a36Sopenharmony_ci			return stall;
66762306a36Sopenharmony_ci		}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci		default:
67062306a36Sopenharmony_ci			return true;
67162306a36Sopenharmony_ci		}
67262306a36Sopenharmony_ci		break;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	case USB_REQ_SET_ADDRESS:
67562306a36Sopenharmony_ci		if (req->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
67662306a36Sopenharmony_ci			return true;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci		return isp1760_udc_set_address(udc, le16_to_cpu(req->wValue));
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	case USB_REQ_SET_CONFIGURATION:
68162306a36Sopenharmony_ci		if (req->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
68262306a36Sopenharmony_ci			return true;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci		if (udc->gadget.state != USB_STATE_ADDRESS &&
68562306a36Sopenharmony_ci		    udc->gadget.state != USB_STATE_CONFIGURED)
68662306a36Sopenharmony_ci			return true;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci		stall = udc->driver->setup(&udc->gadget, req) < 0;
68962306a36Sopenharmony_ci		if (stall)
69062306a36Sopenharmony_ci			return true;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci		usb_gadget_set_state(&udc->gadget, req->wValue ?
69362306a36Sopenharmony_ci				     USB_STATE_CONFIGURED : USB_STATE_ADDRESS);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci		/*
69662306a36Sopenharmony_ci		 * SET_CONFIGURATION (and SET_INTERFACE) must reset the halt
69762306a36Sopenharmony_ci		 * feature on all endpoints. There is however no need to do so
69862306a36Sopenharmony_ci		 * explicitly here as the gadget driver will disable and
69962306a36Sopenharmony_ci		 * reenable endpoints, clearing the halt feature.
70062306a36Sopenharmony_ci		 */
70162306a36Sopenharmony_ci		return false;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	default:
70462306a36Sopenharmony_ci		return udc->driver->setup(&udc->gadget, req) < 0;
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic void isp1760_ep0_setup(struct isp1760_udc *udc)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	union {
71162306a36Sopenharmony_ci		struct usb_ctrlrequest r;
71262306a36Sopenharmony_ci		u32 data[2];
71362306a36Sopenharmony_ci	} req;
71462306a36Sopenharmony_ci	unsigned int count;
71562306a36Sopenharmony_ci	bool stall = false;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	spin_lock(&udc->lock);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	isp1760_udc_set(udc, DC_EP0SETUP);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	count = isp1760_udc_read(udc, DC_BUFLEN);
72262306a36Sopenharmony_ci	if (count != sizeof(req)) {
72362306a36Sopenharmony_ci		spin_unlock(&udc->lock);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci		dev_err(udc->isp->dev, "invalid length %u for setup packet\n",
72662306a36Sopenharmony_ci			count);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci		isp1760_udc_ctrl_send_stall(&udc->ep[0]);
72962306a36Sopenharmony_ci		return;
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	req.data[0] = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT);
73362306a36Sopenharmony_ci	req.data[1] = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	if (udc->ep0_state != ISP1760_CTRL_SETUP) {
73662306a36Sopenharmony_ci		spin_unlock(&udc->lock);
73762306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "unexpected SETUP packet\n");
73862306a36Sopenharmony_ci		return;
73962306a36Sopenharmony_ci	}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	/* Move to the data stage. */
74262306a36Sopenharmony_ci	if (!req.r.wLength)
74362306a36Sopenharmony_ci		udc->ep0_state = ISP1760_CTRL_STATUS;
74462306a36Sopenharmony_ci	else if (req.r.bRequestType & USB_DIR_IN)
74562306a36Sopenharmony_ci		udc->ep0_state = ISP1760_CTRL_DATA_IN;
74662306a36Sopenharmony_ci	else
74762306a36Sopenharmony_ci		udc->ep0_state = ISP1760_CTRL_DATA_OUT;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	udc->ep0_dir = req.r.bRequestType & USB_DIR_IN;
75062306a36Sopenharmony_ci	udc->ep0_length = le16_to_cpu(req.r.wLength);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	spin_unlock(&udc->lock);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	dev_dbg(udc->isp->dev,
75562306a36Sopenharmony_ci		"%s: bRequestType 0x%02x bRequest 0x%02x wValue 0x%04x wIndex 0x%04x wLength 0x%04x\n",
75662306a36Sopenharmony_ci		__func__, req.r.bRequestType, req.r.bRequest,
75762306a36Sopenharmony_ci		le16_to_cpu(req.r.wValue), le16_to_cpu(req.r.wIndex),
75862306a36Sopenharmony_ci		le16_to_cpu(req.r.wLength));
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if ((req.r.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
76162306a36Sopenharmony_ci		stall = isp1760_ep0_setup_standard(udc, &req.r);
76262306a36Sopenharmony_ci	else
76362306a36Sopenharmony_ci		stall = udc->driver->setup(&udc->gadget, &req.r) < 0;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	if (stall)
76662306a36Sopenharmony_ci		isp1760_udc_ctrl_send_stall(&udc->ep[0]);
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
77062306a36Sopenharmony_ci * Gadget Endpoint Operations
77162306a36Sopenharmony_ci */
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_cistatic int isp1760_ep_enable(struct usb_ep *ep,
77462306a36Sopenharmony_ci			     const struct usb_endpoint_descriptor *desc)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	struct isp1760_ep *uep = ep_to_udc_ep(ep);
77762306a36Sopenharmony_ci	struct isp1760_udc *udc = uep->udc;
77862306a36Sopenharmony_ci	unsigned long flags;
77962306a36Sopenharmony_ci	unsigned int type;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	dev_dbg(uep->udc->isp->dev, "%s\n", __func__);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	/*
78462306a36Sopenharmony_ci	 * Validate the descriptor. The control endpoint can't be enabled
78562306a36Sopenharmony_ci	 * manually.
78662306a36Sopenharmony_ci	 */
78762306a36Sopenharmony_ci	if (desc->bDescriptorType != USB_DT_ENDPOINT ||
78862306a36Sopenharmony_ci	    desc->bEndpointAddress == 0 ||
78962306a36Sopenharmony_ci	    desc->bEndpointAddress != uep->addr ||
79062306a36Sopenharmony_ci	    le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket) {
79162306a36Sopenharmony_ci		dev_dbg(udc->isp->dev,
79262306a36Sopenharmony_ci			"%s: invalid descriptor type %u addr %02x ep addr %02x max packet size %u/%u\n",
79362306a36Sopenharmony_ci			__func__, desc->bDescriptorType,
79462306a36Sopenharmony_ci			desc->bEndpointAddress, uep->addr,
79562306a36Sopenharmony_ci			le16_to_cpu(desc->wMaxPacketSize), ep->maxpacket);
79662306a36Sopenharmony_ci		return -EINVAL;
79762306a36Sopenharmony_ci	}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	switch (usb_endpoint_type(desc)) {
80062306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_ISOC:
80162306a36Sopenharmony_ci		type = ISP176x_DC_ENDPTYP_ISOC;
80262306a36Sopenharmony_ci		break;
80362306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_BULK:
80462306a36Sopenharmony_ci		type = ISP176x_DC_ENDPTYP_BULK;
80562306a36Sopenharmony_ci		break;
80662306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_INT:
80762306a36Sopenharmony_ci		type = ISP176x_DC_ENDPTYP_INTERRUPT;
80862306a36Sopenharmony_ci		break;
80962306a36Sopenharmony_ci	case USB_ENDPOINT_XFER_CONTROL:
81062306a36Sopenharmony_ci	default:
81162306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s: control endpoints unsupported\n",
81262306a36Sopenharmony_ci			__func__);
81362306a36Sopenharmony_ci		return -EINVAL;
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	uep->desc = desc;
81962306a36Sopenharmony_ci	uep->maxpacket = le16_to_cpu(desc->wMaxPacketSize);
82062306a36Sopenharmony_ci	uep->rx_pending = false;
82162306a36Sopenharmony_ci	uep->halted = false;
82262306a36Sopenharmony_ci	uep->wedged = false;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	isp1760_udc_select_ep(udc, uep);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	isp1760_udc_write(udc, DC_FFOSZ, uep->maxpacket);
82762306a36Sopenharmony_ci	isp1760_udc_write(udc, DC_BUFLEN, uep->maxpacket);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	isp1760_udc_write(udc, DC_ENDPTYP, type);
83062306a36Sopenharmony_ci	isp1760_udc_set(udc, DC_EPENABLE);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	return 0;
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_cistatic int isp1760_ep_disable(struct usb_ep *ep)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	struct isp1760_ep *uep = ep_to_udc_ep(ep);
84062306a36Sopenharmony_ci	struct isp1760_udc *udc = uep->udc;
84162306a36Sopenharmony_ci	struct isp1760_request *req, *nreq;
84262306a36Sopenharmony_ci	LIST_HEAD(req_list);
84362306a36Sopenharmony_ci	unsigned long flags;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	dev_dbg(udc->isp->dev, "%s\n", __func__);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	if (!uep->desc) {
85062306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s: endpoint not enabled\n", __func__);
85162306a36Sopenharmony_ci		spin_unlock_irqrestore(&udc->lock, flags);
85262306a36Sopenharmony_ci		return -EINVAL;
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	uep->desc = NULL;
85662306a36Sopenharmony_ci	uep->maxpacket = 0;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	isp1760_udc_select_ep(udc, uep);
85962306a36Sopenharmony_ci	isp1760_udc_clear(udc, DC_EPENABLE);
86062306a36Sopenharmony_ci	isp1760_udc_clear(udc, DC_ENDPTYP);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	/* TODO Synchronize with the IRQ handler */
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	list_splice_init(&uep->queue, &req_list);
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	list_for_each_entry_safe(req, nreq, &req_list, queue) {
86962306a36Sopenharmony_ci		list_del(&req->queue);
87062306a36Sopenharmony_ci		isp1760_udc_request_complete(uep, req, -ESHUTDOWN);
87162306a36Sopenharmony_ci	}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	return 0;
87462306a36Sopenharmony_ci}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_cistatic struct usb_request *isp1760_ep_alloc_request(struct usb_ep *ep,
87762306a36Sopenharmony_ci						    gfp_t gfp_flags)
87862306a36Sopenharmony_ci{
87962306a36Sopenharmony_ci	struct isp1760_request *req;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	req = kzalloc(sizeof(*req), gfp_flags);
88262306a36Sopenharmony_ci	if (!req)
88362306a36Sopenharmony_ci		return NULL;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	return &req->req;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_cistatic void isp1760_ep_free_request(struct usb_ep *ep, struct usb_request *_req)
88962306a36Sopenharmony_ci{
89062306a36Sopenharmony_ci	struct isp1760_request *req = req_to_udc_req(_req);
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	kfree(req);
89362306a36Sopenharmony_ci}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_cistatic int isp1760_ep_queue(struct usb_ep *ep, struct usb_request *_req,
89662306a36Sopenharmony_ci			    gfp_t gfp_flags)
89762306a36Sopenharmony_ci{
89862306a36Sopenharmony_ci	struct isp1760_request *req = req_to_udc_req(_req);
89962306a36Sopenharmony_ci	struct isp1760_ep *uep = ep_to_udc_ep(ep);
90062306a36Sopenharmony_ci	struct isp1760_udc *udc = uep->udc;
90162306a36Sopenharmony_ci	bool complete = false;
90262306a36Sopenharmony_ci	unsigned long flags;
90362306a36Sopenharmony_ci	int ret = 0;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	_req->status = -EINPROGRESS;
90662306a36Sopenharmony_ci	_req->actual = 0;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	dev_dbg(udc->isp->dev,
91162306a36Sopenharmony_ci		"%s: req %p (%u bytes%s) ep %p(0x%02x)\n", __func__, _req,
91262306a36Sopenharmony_ci		_req->length, _req->zero ? " (zlp)" : "", uep, uep->addr);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	req->ep = uep;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	if (uep->addr == 0) {
91762306a36Sopenharmony_ci		if (_req->length != udc->ep0_length &&
91862306a36Sopenharmony_ci		    udc->ep0_state != ISP1760_CTRL_DATA_IN) {
91962306a36Sopenharmony_ci			dev_dbg(udc->isp->dev,
92062306a36Sopenharmony_ci				"%s: invalid length %u for req %p\n",
92162306a36Sopenharmony_ci				__func__, _req->length, req);
92262306a36Sopenharmony_ci			ret = -EINVAL;
92362306a36Sopenharmony_ci			goto done;
92462306a36Sopenharmony_ci		}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci		switch (udc->ep0_state) {
92762306a36Sopenharmony_ci		case ISP1760_CTRL_DATA_IN:
92862306a36Sopenharmony_ci			dev_dbg(udc->isp->dev, "%s: transmitting req %p\n",
92962306a36Sopenharmony_ci				__func__, req);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci			list_add_tail(&req->queue, &uep->queue);
93262306a36Sopenharmony_ci			isp1760_udc_transmit(uep, req);
93362306a36Sopenharmony_ci			break;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci		case ISP1760_CTRL_DATA_OUT:
93662306a36Sopenharmony_ci			list_add_tail(&req->queue, &uep->queue);
93762306a36Sopenharmony_ci			__isp1760_udc_select_ep(udc, uep, USB_DIR_OUT);
93862306a36Sopenharmony_ci			isp1760_udc_set(udc, DC_DSEN);
93962306a36Sopenharmony_ci			break;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci		case ISP1760_CTRL_STATUS:
94262306a36Sopenharmony_ci			complete = true;
94362306a36Sopenharmony_ci			break;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci		default:
94662306a36Sopenharmony_ci			dev_dbg(udc->isp->dev, "%s: invalid ep0 state\n",
94762306a36Sopenharmony_ci				__func__);
94862306a36Sopenharmony_ci			ret = -EINVAL;
94962306a36Sopenharmony_ci			break;
95062306a36Sopenharmony_ci		}
95162306a36Sopenharmony_ci	} else if (uep->desc) {
95262306a36Sopenharmony_ci		bool empty = list_empty(&uep->queue);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci		list_add_tail(&req->queue, &uep->queue);
95562306a36Sopenharmony_ci		if ((uep->addr & USB_DIR_IN) && !uep->halted && empty)
95662306a36Sopenharmony_ci			isp1760_udc_transmit(uep, req);
95762306a36Sopenharmony_ci		else if (!(uep->addr & USB_DIR_IN) && uep->rx_pending)
95862306a36Sopenharmony_ci			complete = isp1760_udc_receive(uep, req);
95962306a36Sopenharmony_ci	} else {
96062306a36Sopenharmony_ci		dev_dbg(udc->isp->dev,
96162306a36Sopenharmony_ci			"%s: can't queue request to disabled ep%02x\n",
96262306a36Sopenharmony_ci			__func__, uep->addr);
96362306a36Sopenharmony_ci		ret = -ESHUTDOWN;
96462306a36Sopenharmony_ci	}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_cidone:
96762306a36Sopenharmony_ci	if (ret < 0)
96862306a36Sopenharmony_ci		req->ep = NULL;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	if (complete)
97362306a36Sopenharmony_ci		isp1760_udc_request_complete(uep, req, 0);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	return ret;
97662306a36Sopenharmony_ci}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_cistatic int isp1760_ep_dequeue(struct usb_ep *ep, struct usb_request *_req)
97962306a36Sopenharmony_ci{
98062306a36Sopenharmony_ci	struct isp1760_request *req = req_to_udc_req(_req);
98162306a36Sopenharmony_ci	struct isp1760_ep *uep = ep_to_udc_ep(ep);
98262306a36Sopenharmony_ci	struct isp1760_udc *udc = uep->udc;
98362306a36Sopenharmony_ci	unsigned long flags;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	dev_dbg(uep->udc->isp->dev, "%s(ep%02x)\n", __func__, uep->addr);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	if (req->ep != uep)
99062306a36Sopenharmony_ci		req = NULL;
99162306a36Sopenharmony_ci	else
99262306a36Sopenharmony_ci		list_del(&req->queue);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	if (!req)
99762306a36Sopenharmony_ci		return -EINVAL;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	isp1760_udc_request_complete(uep, req, -ECONNRESET);
100062306a36Sopenharmony_ci	return 0;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cistatic int __isp1760_ep_set_halt(struct isp1760_ep *uep, bool stall, bool wedge)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	struct isp1760_udc *udc = uep->udc;
100662306a36Sopenharmony_ci	int ret;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (!uep->addr) {
100962306a36Sopenharmony_ci		/*
101062306a36Sopenharmony_ci		 * Halting the control endpoint is only valid as a delayed error
101162306a36Sopenharmony_ci		 * response to a SETUP packet. Make sure EP0 is in the right
101262306a36Sopenharmony_ci		 * stage and that the gadget isn't trying to clear the halt
101362306a36Sopenharmony_ci		 * condition.
101462306a36Sopenharmony_ci		 */
101562306a36Sopenharmony_ci		if (WARN_ON(udc->ep0_state == ISP1760_CTRL_SETUP || !stall ||
101662306a36Sopenharmony_ci			     wedge)) {
101762306a36Sopenharmony_ci			return -EINVAL;
101862306a36Sopenharmony_ci		}
101962306a36Sopenharmony_ci	}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	if (uep->addr && !uep->desc) {
102262306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s: ep%02x is disabled\n", __func__,
102362306a36Sopenharmony_ci			uep->addr);
102462306a36Sopenharmony_ci		return -EINVAL;
102562306a36Sopenharmony_ci	}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (uep->addr & USB_DIR_IN) {
102862306a36Sopenharmony_ci		/* Refuse to halt IN endpoints with active transfers. */
102962306a36Sopenharmony_ci		if (!list_empty(&uep->queue)) {
103062306a36Sopenharmony_ci			dev_dbg(udc->isp->dev,
103162306a36Sopenharmony_ci				"%s: ep%02x has request pending\n", __func__,
103262306a36Sopenharmony_ci				uep->addr);
103362306a36Sopenharmony_ci			return -EAGAIN;
103462306a36Sopenharmony_ci		}
103562306a36Sopenharmony_ci	}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	ret = __isp1760_udc_set_halt(uep, stall);
103862306a36Sopenharmony_ci	if (ret < 0)
103962306a36Sopenharmony_ci		return ret;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	if (!uep->addr) {
104262306a36Sopenharmony_ci		/*
104362306a36Sopenharmony_ci		 * Stalling EP0 completes the control transaction, move back to
104462306a36Sopenharmony_ci		 * the SETUP state.
104562306a36Sopenharmony_ci		 */
104662306a36Sopenharmony_ci		udc->ep0_state = ISP1760_CTRL_SETUP;
104762306a36Sopenharmony_ci		return 0;
104862306a36Sopenharmony_ci	}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	if (wedge)
105162306a36Sopenharmony_ci		uep->wedged = true;
105262306a36Sopenharmony_ci	else if (!stall)
105362306a36Sopenharmony_ci		uep->wedged = false;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	return 0;
105662306a36Sopenharmony_ci}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_cistatic int isp1760_ep_set_halt(struct usb_ep *ep, int value)
105962306a36Sopenharmony_ci{
106062306a36Sopenharmony_ci	struct isp1760_ep *uep = ep_to_udc_ep(ep);
106162306a36Sopenharmony_ci	unsigned long flags;
106262306a36Sopenharmony_ci	int ret;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	dev_dbg(uep->udc->isp->dev, "%s: %s halt on ep%02x\n", __func__,
106562306a36Sopenharmony_ci		value ? "set" : "clear", uep->addr);
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	spin_lock_irqsave(&uep->udc->lock, flags);
106862306a36Sopenharmony_ci	ret = __isp1760_ep_set_halt(uep, value, false);
106962306a36Sopenharmony_ci	spin_unlock_irqrestore(&uep->udc->lock, flags);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	return ret;
107262306a36Sopenharmony_ci}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_cistatic int isp1760_ep_set_wedge(struct usb_ep *ep)
107562306a36Sopenharmony_ci{
107662306a36Sopenharmony_ci	struct isp1760_ep *uep = ep_to_udc_ep(ep);
107762306a36Sopenharmony_ci	unsigned long flags;
107862306a36Sopenharmony_ci	int ret;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	dev_dbg(uep->udc->isp->dev, "%s: set wedge on ep%02x)\n", __func__,
108162306a36Sopenharmony_ci		uep->addr);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	spin_lock_irqsave(&uep->udc->lock, flags);
108462306a36Sopenharmony_ci	ret = __isp1760_ep_set_halt(uep, true, true);
108562306a36Sopenharmony_ci	spin_unlock_irqrestore(&uep->udc->lock, flags);
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	return ret;
108862306a36Sopenharmony_ci}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_cistatic void isp1760_ep_fifo_flush(struct usb_ep *ep)
109162306a36Sopenharmony_ci{
109262306a36Sopenharmony_ci	struct isp1760_ep *uep = ep_to_udc_ep(ep);
109362306a36Sopenharmony_ci	struct isp1760_udc *udc = uep->udc;
109462306a36Sopenharmony_ci	unsigned long flags;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	isp1760_udc_select_ep(udc, uep);
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	/*
110162306a36Sopenharmony_ci	 * Set the CLBUF bit twice to flush both buffers in case double
110262306a36Sopenharmony_ci	 * buffering is enabled.
110362306a36Sopenharmony_ci	 */
110462306a36Sopenharmony_ci	isp1760_udc_set(udc, DC_CLBUF);
110562306a36Sopenharmony_ci	isp1760_udc_set(udc, DC_CLBUF);
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_cistatic const struct usb_ep_ops isp1760_ep_ops = {
111162306a36Sopenharmony_ci	.enable = isp1760_ep_enable,
111262306a36Sopenharmony_ci	.disable = isp1760_ep_disable,
111362306a36Sopenharmony_ci	.alloc_request = isp1760_ep_alloc_request,
111462306a36Sopenharmony_ci	.free_request = isp1760_ep_free_request,
111562306a36Sopenharmony_ci	.queue = isp1760_ep_queue,
111662306a36Sopenharmony_ci	.dequeue = isp1760_ep_dequeue,
111762306a36Sopenharmony_ci	.set_halt = isp1760_ep_set_halt,
111862306a36Sopenharmony_ci	.set_wedge = isp1760_ep_set_wedge,
111962306a36Sopenharmony_ci	.fifo_flush = isp1760_ep_fifo_flush,
112062306a36Sopenharmony_ci};
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
112362306a36Sopenharmony_ci * Device States
112462306a36Sopenharmony_ci */
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci/* Called with the UDC spinlock held. */
112762306a36Sopenharmony_cistatic void isp1760_udc_connect(struct isp1760_udc *udc)
112862306a36Sopenharmony_ci{
112962306a36Sopenharmony_ci	usb_gadget_set_state(&udc->gadget, USB_STATE_POWERED);
113062306a36Sopenharmony_ci	mod_timer(&udc->vbus_timer, jiffies + ISP1760_VBUS_POLL_INTERVAL);
113162306a36Sopenharmony_ci}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci/* Called with the UDC spinlock held. */
113462306a36Sopenharmony_cistatic void isp1760_udc_disconnect(struct isp1760_udc *udc)
113562306a36Sopenharmony_ci{
113662306a36Sopenharmony_ci	if (udc->gadget.state < USB_STATE_POWERED)
113762306a36Sopenharmony_ci		return;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	dev_dbg(udc->isp->dev, "Device disconnected in state %u\n",
114062306a36Sopenharmony_ci		 udc->gadget.state);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	udc->gadget.speed = USB_SPEED_UNKNOWN;
114362306a36Sopenharmony_ci	usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	if (udc->driver->disconnect)
114662306a36Sopenharmony_ci		udc->driver->disconnect(&udc->gadget);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	del_timer(&udc->vbus_timer);
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	/* TODO Reset all endpoints ? */
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_cistatic void isp1760_udc_init_hw(struct isp1760_udc *udc)
115462306a36Sopenharmony_ci{
115562306a36Sopenharmony_ci	u32 intconf = udc->is_isp1763 ? ISP1763_DC_INTCONF : ISP176x_DC_INTCONF;
115662306a36Sopenharmony_ci	u32 intena = udc->is_isp1763 ? ISP1763_DC_INTENABLE :
115762306a36Sopenharmony_ci						ISP176x_DC_INTENABLE;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	/*
116062306a36Sopenharmony_ci	 * The device controller currently shares its interrupt with the host
116162306a36Sopenharmony_ci	 * controller, the DC_IRQ polarity and signaling mode are ignored. Set
116262306a36Sopenharmony_ci	 * the to active-low level-triggered.
116362306a36Sopenharmony_ci	 *
116462306a36Sopenharmony_ci	 * Configure the control, in and out pipes to generate interrupts on
116562306a36Sopenharmony_ci	 * ACK tokens only (and NYET for the out pipe). The default
116662306a36Sopenharmony_ci	 * configuration also generates an interrupt on the first NACK token.
116762306a36Sopenharmony_ci	 */
116862306a36Sopenharmony_ci	isp1760_reg_write(udc->regs, intconf,
116962306a36Sopenharmony_ci			  ISP176x_DC_CDBGMOD_ACK | ISP176x_DC_DDBGMODIN_ACK |
117062306a36Sopenharmony_ci			  ISP176x_DC_DDBGMODOUT_ACK);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	isp1760_reg_write(udc->regs, intena, DC_IEPRXTX(7) |
117362306a36Sopenharmony_ci			  DC_IEPRXTX(6) | DC_IEPRXTX(5) | DC_IEPRXTX(4) |
117462306a36Sopenharmony_ci			  DC_IEPRXTX(3) | DC_IEPRXTX(2) | DC_IEPRXTX(1) |
117562306a36Sopenharmony_ci			  DC_IEPRXTX(0) | ISP176x_DC_IEP0SETUP |
117662306a36Sopenharmony_ci			  ISP176x_DC_IEVBUS | ISP176x_DC_IERESM |
117762306a36Sopenharmony_ci			  ISP176x_DC_IESUSP | ISP176x_DC_IEHS_STA |
117862306a36Sopenharmony_ci			  ISP176x_DC_IEBRST);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	if (udc->connected)
118162306a36Sopenharmony_ci		isp1760_set_pullup(udc->isp, true);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	isp1760_udc_set(udc, DC_DEVEN);
118462306a36Sopenharmony_ci}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_cistatic void isp1760_udc_reset(struct isp1760_udc *udc)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	unsigned long flags;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	/*
119362306a36Sopenharmony_ci	 * The bus reset has reset most registers to their default value,
119462306a36Sopenharmony_ci	 * reinitialize the UDC hardware.
119562306a36Sopenharmony_ci	 */
119662306a36Sopenharmony_ci	isp1760_udc_init_hw(udc);
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	udc->ep0_state = ISP1760_CTRL_SETUP;
119962306a36Sopenharmony_ci	udc->gadget.speed = USB_SPEED_FULL;
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	usb_gadget_udc_reset(&udc->gadget, udc->driver);
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
120462306a36Sopenharmony_ci}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_cistatic void isp1760_udc_suspend(struct isp1760_udc *udc)
120762306a36Sopenharmony_ci{
120862306a36Sopenharmony_ci	if (udc->gadget.state < USB_STATE_DEFAULT)
120962306a36Sopenharmony_ci		return;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	if (udc->driver->suspend)
121262306a36Sopenharmony_ci		udc->driver->suspend(&udc->gadget);
121362306a36Sopenharmony_ci}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cistatic void isp1760_udc_resume(struct isp1760_udc *udc)
121662306a36Sopenharmony_ci{
121762306a36Sopenharmony_ci	if (udc->gadget.state < USB_STATE_DEFAULT)
121862306a36Sopenharmony_ci		return;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	if (udc->driver->resume)
122162306a36Sopenharmony_ci		udc->driver->resume(&udc->gadget);
122262306a36Sopenharmony_ci}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
122562306a36Sopenharmony_ci * Gadget Operations
122662306a36Sopenharmony_ci */
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic int isp1760_udc_get_frame(struct usb_gadget *gadget)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	struct isp1760_udc *udc = gadget_to_udc(gadget);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	return isp1760_udc_read(udc, DC_FRAMENUM);
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_cistatic int isp1760_udc_wakeup(struct usb_gadget *gadget)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct isp1760_udc *udc = gadget_to_udc(gadget);
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	dev_dbg(udc->isp->dev, "%s\n", __func__);
124062306a36Sopenharmony_ci	return -ENOTSUPP;
124162306a36Sopenharmony_ci}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_cistatic int isp1760_udc_set_selfpowered(struct usb_gadget *gadget,
124462306a36Sopenharmony_ci				       int is_selfpowered)
124562306a36Sopenharmony_ci{
124662306a36Sopenharmony_ci	struct isp1760_udc *udc = gadget_to_udc(gadget);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	if (is_selfpowered)
124962306a36Sopenharmony_ci		udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
125062306a36Sopenharmony_ci	else
125162306a36Sopenharmony_ci		udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	return 0;
125462306a36Sopenharmony_ci}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_cistatic int isp1760_udc_pullup(struct usb_gadget *gadget, int is_on)
125762306a36Sopenharmony_ci{
125862306a36Sopenharmony_ci	struct isp1760_udc *udc = gadget_to_udc(gadget);
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	isp1760_set_pullup(udc->isp, is_on);
126162306a36Sopenharmony_ci	udc->connected = is_on;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	return 0;
126462306a36Sopenharmony_ci}
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_cistatic int isp1760_udc_start(struct usb_gadget *gadget,
126762306a36Sopenharmony_ci			     struct usb_gadget_driver *driver)
126862306a36Sopenharmony_ci{
126962306a36Sopenharmony_ci	struct isp1760_udc *udc = gadget_to_udc(gadget);
127062306a36Sopenharmony_ci	unsigned long flags;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	/* The hardware doesn't support low speed. */
127362306a36Sopenharmony_ci	if (driver->max_speed < USB_SPEED_FULL) {
127462306a36Sopenharmony_ci		dev_err(udc->isp->dev, "Invalid gadget driver\n");
127562306a36Sopenharmony_ci		return -EINVAL;
127662306a36Sopenharmony_ci	}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	if (udc->driver) {
128162306a36Sopenharmony_ci		dev_err(udc->isp->dev, "UDC already has a gadget driver\n");
128262306a36Sopenharmony_ci		spin_unlock_irqrestore(&udc->lock, flags);
128362306a36Sopenharmony_ci		return -EBUSY;
128462306a36Sopenharmony_ci	}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	udc->driver = driver;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	dev_dbg(udc->isp->dev, "starting UDC with driver %s\n",
129162306a36Sopenharmony_ci		driver->function);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	udc->devstatus = 0;
129462306a36Sopenharmony_ci	udc->connected = true;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED);
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	/* DMA isn't supported yet, don't enable the DMA clock. */
129962306a36Sopenharmony_ci	isp1760_udc_set(udc, DC_GLINTENA);
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	isp1760_udc_init_hw(udc);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	dev_dbg(udc->isp->dev, "UDC started with driver %s\n",
130462306a36Sopenharmony_ci		driver->function);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	return 0;
130762306a36Sopenharmony_ci}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_cistatic int isp1760_udc_stop(struct usb_gadget *gadget)
131062306a36Sopenharmony_ci{
131162306a36Sopenharmony_ci	struct isp1760_udc *udc = gadget_to_udc(gadget);
131262306a36Sopenharmony_ci	u32 mode_reg = udc->is_isp1763 ? ISP1763_DC_MODE : ISP176x_DC_MODE;
131362306a36Sopenharmony_ci	unsigned long flags;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	dev_dbg(udc->isp->dev, "%s\n", __func__);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	del_timer_sync(&udc->vbus_timer);
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	isp1760_reg_write(udc->regs, mode_reg, 0);
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
132262306a36Sopenharmony_ci	udc->driver = NULL;
132362306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	return 0;
132662306a36Sopenharmony_ci}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_cistatic const struct usb_gadget_ops isp1760_udc_ops = {
132962306a36Sopenharmony_ci	.get_frame = isp1760_udc_get_frame,
133062306a36Sopenharmony_ci	.wakeup = isp1760_udc_wakeup,
133162306a36Sopenharmony_ci	.set_selfpowered = isp1760_udc_set_selfpowered,
133262306a36Sopenharmony_ci	.pullup = isp1760_udc_pullup,
133362306a36Sopenharmony_ci	.udc_start = isp1760_udc_start,
133462306a36Sopenharmony_ci	.udc_stop = isp1760_udc_stop,
133562306a36Sopenharmony_ci};
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
133862306a36Sopenharmony_ci * Interrupt Handling
133962306a36Sopenharmony_ci */
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_cistatic u32 isp1760_udc_irq_get_status(struct isp1760_udc *udc)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	u32 status;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	if (udc->is_isp1763) {
134662306a36Sopenharmony_ci		status = isp1760_reg_read(udc->regs, ISP1763_DC_INTERRUPT)
134762306a36Sopenharmony_ci			& isp1760_reg_read(udc->regs, ISP1763_DC_INTENABLE);
134862306a36Sopenharmony_ci		isp1760_reg_write(udc->regs, ISP1763_DC_INTERRUPT, status);
134962306a36Sopenharmony_ci	} else {
135062306a36Sopenharmony_ci		status = isp1760_reg_read(udc->regs, ISP176x_DC_INTERRUPT)
135162306a36Sopenharmony_ci			& isp1760_reg_read(udc->regs, ISP176x_DC_INTENABLE);
135262306a36Sopenharmony_ci		isp1760_reg_write(udc->regs, ISP176x_DC_INTERRUPT, status);
135362306a36Sopenharmony_ci	}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	return status;
135662306a36Sopenharmony_ci}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_cistatic irqreturn_t isp1760_udc_irq(int irq, void *dev)
135962306a36Sopenharmony_ci{
136062306a36Sopenharmony_ci	struct isp1760_udc *udc = dev;
136162306a36Sopenharmony_ci	unsigned int i;
136262306a36Sopenharmony_ci	u32 status;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	status = isp1760_udc_irq_get_status(udc);
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	if (status & ISP176x_DC_IEVBUS) {
136762306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s(VBUS)\n", __func__);
136862306a36Sopenharmony_ci		/* The VBUS interrupt is only triggered when VBUS appears. */
136962306a36Sopenharmony_ci		spin_lock(&udc->lock);
137062306a36Sopenharmony_ci		isp1760_udc_connect(udc);
137162306a36Sopenharmony_ci		spin_unlock(&udc->lock);
137262306a36Sopenharmony_ci	}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	if (status & ISP176x_DC_IEBRST) {
137562306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s(BRST)\n", __func__);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci		isp1760_udc_reset(udc);
137862306a36Sopenharmony_ci	}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	for (i = 0; i <= 7; ++i) {
138162306a36Sopenharmony_ci		struct isp1760_ep *ep = &udc->ep[i*2];
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci		if (status & DC_IEPTX(i)) {
138462306a36Sopenharmony_ci			dev_dbg(udc->isp->dev, "%s(EPTX%u)\n", __func__, i);
138562306a36Sopenharmony_ci			isp1760_ep_tx_complete(ep);
138662306a36Sopenharmony_ci		}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci		if (status & DC_IEPRX(i)) {
138962306a36Sopenharmony_ci			dev_dbg(udc->isp->dev, "%s(EPRX%u)\n", __func__, i);
139062306a36Sopenharmony_ci			isp1760_ep_rx_ready(i ? ep - 1 : ep);
139162306a36Sopenharmony_ci		}
139262306a36Sopenharmony_ci	}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	if (status & ISP176x_DC_IEP0SETUP) {
139562306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s(EP0SETUP)\n", __func__);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci		isp1760_ep0_setup(udc);
139862306a36Sopenharmony_ci	}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	if (status & ISP176x_DC_IERESM) {
140162306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s(RESM)\n", __func__);
140262306a36Sopenharmony_ci		isp1760_udc_resume(udc);
140362306a36Sopenharmony_ci	}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	if (status & ISP176x_DC_IESUSP) {
140662306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s(SUSP)\n", __func__);
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci		spin_lock(&udc->lock);
140962306a36Sopenharmony_ci		if (!isp1760_udc_is_set(udc, DC_VBUSSTAT))
141062306a36Sopenharmony_ci			isp1760_udc_disconnect(udc);
141162306a36Sopenharmony_ci		else
141262306a36Sopenharmony_ci			isp1760_udc_suspend(udc);
141362306a36Sopenharmony_ci		spin_unlock(&udc->lock);
141462306a36Sopenharmony_ci	}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	if (status & ISP176x_DC_IEHS_STA) {
141762306a36Sopenharmony_ci		dev_dbg(udc->isp->dev, "%s(HS_STA)\n", __func__);
141862306a36Sopenharmony_ci		udc->gadget.speed = USB_SPEED_HIGH;
141962306a36Sopenharmony_ci	}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	return status ? IRQ_HANDLED : IRQ_NONE;
142262306a36Sopenharmony_ci}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_cistatic void isp1760_udc_vbus_poll(struct timer_list *t)
142562306a36Sopenharmony_ci{
142662306a36Sopenharmony_ci	struct isp1760_udc *udc = from_timer(udc, t, vbus_timer);
142762306a36Sopenharmony_ci	unsigned long flags;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	if (!(isp1760_udc_is_set(udc, DC_VBUSSTAT)))
143262306a36Sopenharmony_ci		isp1760_udc_disconnect(udc);
143362306a36Sopenharmony_ci	else if (udc->gadget.state >= USB_STATE_POWERED)
143462306a36Sopenharmony_ci		mod_timer(&udc->vbus_timer,
143562306a36Sopenharmony_ci			  jiffies + ISP1760_VBUS_POLL_INTERVAL);
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
143862306a36Sopenharmony_ci}
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
144162306a36Sopenharmony_ci * Registration
144262306a36Sopenharmony_ci */
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_cistatic void isp1760_udc_init_eps(struct isp1760_udc *udc)
144562306a36Sopenharmony_ci{
144662306a36Sopenharmony_ci	unsigned int i;
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	INIT_LIST_HEAD(&udc->gadget.ep_list);
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(udc->ep); ++i) {
145162306a36Sopenharmony_ci		struct isp1760_ep *ep = &udc->ep[i];
145262306a36Sopenharmony_ci		unsigned int ep_num = (i + 1) / 2;
145362306a36Sopenharmony_ci		bool is_in = !(i & 1);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci		ep->udc = udc;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci		INIT_LIST_HEAD(&ep->queue);
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci		ep->addr = (ep_num && is_in ? USB_DIR_IN : USB_DIR_OUT)
146062306a36Sopenharmony_ci			 | ep_num;
146162306a36Sopenharmony_ci		ep->desc = NULL;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci		sprintf(ep->name, "ep%u%s", ep_num,
146462306a36Sopenharmony_ci			ep_num ? (is_in ? "in" : "out") : "");
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci		ep->ep.ops = &isp1760_ep_ops;
146762306a36Sopenharmony_ci		ep->ep.name = ep->name;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci		/*
147062306a36Sopenharmony_ci		 * Hardcode the maximum packet sizes for now, to 64 bytes for
147162306a36Sopenharmony_ci		 * the control endpoint and 512 bytes for all other endpoints.
147262306a36Sopenharmony_ci		 * This fits in the 8kB FIFO without double-buffering.
147362306a36Sopenharmony_ci		 */
147462306a36Sopenharmony_ci		if (ep_num == 0) {
147562306a36Sopenharmony_ci			usb_ep_set_maxpacket_limit(&ep->ep, 64);
147662306a36Sopenharmony_ci			ep->ep.caps.type_control = true;
147762306a36Sopenharmony_ci			ep->ep.caps.dir_in = true;
147862306a36Sopenharmony_ci			ep->ep.caps.dir_out = true;
147962306a36Sopenharmony_ci			ep->maxpacket = 64;
148062306a36Sopenharmony_ci			udc->gadget.ep0 = &ep->ep;
148162306a36Sopenharmony_ci		} else {
148262306a36Sopenharmony_ci			usb_ep_set_maxpacket_limit(&ep->ep, 512);
148362306a36Sopenharmony_ci			ep->ep.caps.type_iso = true;
148462306a36Sopenharmony_ci			ep->ep.caps.type_bulk = true;
148562306a36Sopenharmony_ci			ep->ep.caps.type_int = true;
148662306a36Sopenharmony_ci			ep->maxpacket = 0;
148762306a36Sopenharmony_ci			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
148862306a36Sopenharmony_ci		}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci		if (is_in)
149162306a36Sopenharmony_ci			ep->ep.caps.dir_in = true;
149262306a36Sopenharmony_ci		else
149362306a36Sopenharmony_ci			ep->ep.caps.dir_out = true;
149462306a36Sopenharmony_ci	}
149562306a36Sopenharmony_ci}
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_cistatic int isp1760_udc_init(struct isp1760_udc *udc)
149862306a36Sopenharmony_ci{
149962306a36Sopenharmony_ci	u32 mode_reg = udc->is_isp1763 ? ISP1763_DC_MODE : ISP176x_DC_MODE;
150062306a36Sopenharmony_ci	u16 scratch;
150162306a36Sopenharmony_ci	u32 chipid;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	/*
150462306a36Sopenharmony_ci	 * Check that the controller is present by writing to the scratch
150562306a36Sopenharmony_ci	 * register, modifying the bus pattern by reading from the chip ID
150662306a36Sopenharmony_ci	 * register, and reading the scratch register value back. The chip ID
150762306a36Sopenharmony_ci	 * and scratch register contents must match the expected values.
150862306a36Sopenharmony_ci	 */
150962306a36Sopenharmony_ci	isp1760_udc_write(udc, DC_SCRATCH, 0xbabe);
151062306a36Sopenharmony_ci	chipid = isp1760_udc_read(udc, DC_CHIP_ID_HIGH) << 16;
151162306a36Sopenharmony_ci	chipid |= isp1760_udc_read(udc, DC_CHIP_ID_LOW);
151262306a36Sopenharmony_ci	scratch = isp1760_udc_read(udc, DC_SCRATCH);
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	if (scratch != 0xbabe) {
151562306a36Sopenharmony_ci		dev_err(udc->isp->dev,
151662306a36Sopenharmony_ci			"udc: scratch test failed (0x%04x/0x%08x)\n",
151762306a36Sopenharmony_ci			scratch, chipid);
151862306a36Sopenharmony_ci		return -ENODEV;
151962306a36Sopenharmony_ci	}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	if (chipid != 0x00011582 && chipid != 0x00158210 &&
152262306a36Sopenharmony_ci	    chipid != 0x00176320) {
152362306a36Sopenharmony_ci		dev_err(udc->isp->dev, "udc: invalid chip ID 0x%08x\n", chipid);
152462306a36Sopenharmony_ci		return -ENODEV;
152562306a36Sopenharmony_ci	}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	/* Reset the device controller. */
152862306a36Sopenharmony_ci	isp1760_udc_set(udc, DC_SFRESET);
152962306a36Sopenharmony_ci	usleep_range(10000, 11000);
153062306a36Sopenharmony_ci	isp1760_reg_write(udc->regs, mode_reg, 0);
153162306a36Sopenharmony_ci	usleep_range(10000, 11000);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	return 0;
153462306a36Sopenharmony_ci}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ciint isp1760_udc_register(struct isp1760_device *isp, int irq,
153762306a36Sopenharmony_ci			 unsigned long irqflags)
153862306a36Sopenharmony_ci{
153962306a36Sopenharmony_ci	struct isp1760_udc *udc = &isp->udc;
154062306a36Sopenharmony_ci	int ret;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	udc->irq = -1;
154362306a36Sopenharmony_ci	udc->isp = isp;
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	spin_lock_init(&udc->lock);
154662306a36Sopenharmony_ci	timer_setup(&udc->vbus_timer, isp1760_udc_vbus_poll, 0);
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	ret = isp1760_udc_init(udc);
154962306a36Sopenharmony_ci	if (ret < 0)
155062306a36Sopenharmony_ci		return ret;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	udc->irqname = kasprintf(GFP_KERNEL, "%s (udc)", dev_name(isp->dev));
155362306a36Sopenharmony_ci	if (!udc->irqname)
155462306a36Sopenharmony_ci		return -ENOMEM;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | irqflags,
155762306a36Sopenharmony_ci			  udc->irqname, udc);
155862306a36Sopenharmony_ci	if (ret < 0)
155962306a36Sopenharmony_ci		goto error;
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	udc->irq = irq;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	/*
156462306a36Sopenharmony_ci	 * Initialize the gadget static fields and register its device. Gadget
156562306a36Sopenharmony_ci	 * fields that vary during the life time of the gadget are initialized
156662306a36Sopenharmony_ci	 * by the UDC core.
156762306a36Sopenharmony_ci	 */
156862306a36Sopenharmony_ci	udc->gadget.ops = &isp1760_udc_ops;
156962306a36Sopenharmony_ci	udc->gadget.speed = USB_SPEED_UNKNOWN;
157062306a36Sopenharmony_ci	udc->gadget.max_speed = USB_SPEED_HIGH;
157162306a36Sopenharmony_ci	udc->gadget.name = "isp1761_udc";
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	isp1760_udc_init_eps(udc);
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	ret = usb_add_gadget_udc(isp->dev, &udc->gadget);
157662306a36Sopenharmony_ci	if (ret < 0)
157762306a36Sopenharmony_ci		goto error;
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	return 0;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_cierror:
158262306a36Sopenharmony_ci	if (udc->irq >= 0)
158362306a36Sopenharmony_ci		free_irq(udc->irq, udc);
158462306a36Sopenharmony_ci	kfree(udc->irqname);
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	return ret;
158762306a36Sopenharmony_ci}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_civoid isp1760_udc_unregister(struct isp1760_device *isp)
159062306a36Sopenharmony_ci{
159162306a36Sopenharmony_ci	struct isp1760_udc *udc = &isp->udc;
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	if (!udc->isp)
159462306a36Sopenharmony_ci		return;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	usb_del_gadget_udc(&udc->gadget);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	free_irq(udc->irq, udc);
159962306a36Sopenharmony_ci	kfree(udc->irqname);
160062306a36Sopenharmony_ci}
1601