162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * MAX3420 Device Controller driver for USB.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Jaswinder Singh Brar <jaswinder.singh@linaro.org>
662306a36Sopenharmony_ci * (C) Copyright 2019-2020 Linaro Ltd
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Based on:
962306a36Sopenharmony_ci *	o MAX3420E datasheet
1062306a36Sopenharmony_ci *		https://datasheets.maximintegrated.com/en/ds/MAX3420E.pdf
1162306a36Sopenharmony_ci *	o MAX342{0,1}E Programming Guides
1262306a36Sopenharmony_ci *		https://pdfserv.maximintegrated.com/en/an/AN3598.pdf
1362306a36Sopenharmony_ci *		https://pdfserv.maximintegrated.com/en/an/AN3785.pdf
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/delay.h>
1762306a36Sopenharmony_ci#include <linux/device.h>
1862306a36Sopenharmony_ci#include <linux/interrupt.h>
1962306a36Sopenharmony_ci#include <linux/io.h>
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/bitfield.h>
2262306a36Sopenharmony_ci#include <linux/of.h>
2362306a36Sopenharmony_ci#include <linux/of_irq.h>
2462306a36Sopenharmony_ci#include <linux/prefetch.h>
2562306a36Sopenharmony_ci#include <linux/usb/ch9.h>
2662306a36Sopenharmony_ci#include <linux/usb/gadget.h>
2762306a36Sopenharmony_ci#include <linux/spi/spi.h>
2862306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define MAX3420_MAX_EPS		4
3162306a36Sopenharmony_ci#define MAX3420_EP_MAX_PACKET		64  /* Same for all Endpoints */
3262306a36Sopenharmony_ci#define MAX3420_EPNAME_SIZE		16  /* Buffer size for endpoint name */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define MAX3420_ACKSTAT		BIT(0)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define MAX3420_SPI_DIR_RD	0	/* read register from MAX3420 */
3762306a36Sopenharmony_ci#define MAX3420_SPI_DIR_WR	1	/* write register to MAX3420 */
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* SPI commands: */
4062306a36Sopenharmony_ci#define MAX3420_SPI_DIR_SHIFT	1
4162306a36Sopenharmony_ci#define MAX3420_SPI_REG_SHIFT	3
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define MAX3420_REG_EP0FIFO	0
4462306a36Sopenharmony_ci#define MAX3420_REG_EP1FIFO	1
4562306a36Sopenharmony_ci#define MAX3420_REG_EP2FIFO	2
4662306a36Sopenharmony_ci#define MAX3420_REG_EP3FIFO	3
4762306a36Sopenharmony_ci#define MAX3420_REG_SUDFIFO	4
4862306a36Sopenharmony_ci#define MAX3420_REG_EP0BC	5
4962306a36Sopenharmony_ci#define MAX3420_REG_EP1BC	6
5062306a36Sopenharmony_ci#define MAX3420_REG_EP2BC	7
5162306a36Sopenharmony_ci#define MAX3420_REG_EP3BC	8
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define MAX3420_REG_EPSTALLS	9
5462306a36Sopenharmony_ci	#define ACKSTAT		BIT(6)
5562306a36Sopenharmony_ci	#define STLSTAT		BIT(5)
5662306a36Sopenharmony_ci	#define STLEP3IN	BIT(4)
5762306a36Sopenharmony_ci	#define STLEP2IN	BIT(3)
5862306a36Sopenharmony_ci	#define STLEP1OUT	BIT(2)
5962306a36Sopenharmony_ci	#define STLEP0OUT	BIT(1)
6062306a36Sopenharmony_ci	#define STLEP0IN	BIT(0)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define MAX3420_REG_CLRTOGS	10
6362306a36Sopenharmony_ci	#define EP3DISAB	BIT(7)
6462306a36Sopenharmony_ci	#define EP2DISAB	BIT(6)
6562306a36Sopenharmony_ci	#define EP1DISAB	BIT(5)
6662306a36Sopenharmony_ci	#define CTGEP3IN	BIT(4)
6762306a36Sopenharmony_ci	#define CTGEP2IN	BIT(3)
6862306a36Sopenharmony_ci	#define CTGEP1OUT	BIT(2)
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define MAX3420_REG_EPIRQ	11
7162306a36Sopenharmony_ci#define MAX3420_REG_EPIEN	12
7262306a36Sopenharmony_ci	#define SUDAVIRQ	BIT(5)
7362306a36Sopenharmony_ci	#define IN3BAVIRQ	BIT(4)
7462306a36Sopenharmony_ci	#define IN2BAVIRQ	BIT(3)
7562306a36Sopenharmony_ci	#define OUT1DAVIRQ	BIT(2)
7662306a36Sopenharmony_ci	#define OUT0DAVIRQ	BIT(1)
7762306a36Sopenharmony_ci	#define IN0BAVIRQ	BIT(0)
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define MAX3420_REG_USBIRQ	13
8062306a36Sopenharmony_ci#define MAX3420_REG_USBIEN	14
8162306a36Sopenharmony_ci	#define OSCOKIRQ	BIT(0)
8262306a36Sopenharmony_ci	#define RWUDNIRQ	BIT(1)
8362306a36Sopenharmony_ci	#define BUSACTIRQ	BIT(2)
8462306a36Sopenharmony_ci	#define URESIRQ		BIT(3)
8562306a36Sopenharmony_ci	#define SUSPIRQ		BIT(4)
8662306a36Sopenharmony_ci	#define NOVBUSIRQ	BIT(5)
8762306a36Sopenharmony_ci	#define VBUSIRQ		BIT(6)
8862306a36Sopenharmony_ci	#define URESDNIRQ	BIT(7)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#define MAX3420_REG_USBCTL	15
9162306a36Sopenharmony_ci	#define HOSCSTEN	BIT(7)
9262306a36Sopenharmony_ci	#define VBGATE		BIT(6)
9362306a36Sopenharmony_ci	#define CHIPRES		BIT(5)
9462306a36Sopenharmony_ci	#define PWRDOWN		BIT(4)
9562306a36Sopenharmony_ci	#define CONNECT		BIT(3)
9662306a36Sopenharmony_ci	#define SIGRWU		BIT(2)
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define MAX3420_REG_CPUCTL	16
9962306a36Sopenharmony_ci	#define IE		BIT(0)
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#define MAX3420_REG_PINCTL	17
10262306a36Sopenharmony_ci	#define EP3INAK		BIT(7)
10362306a36Sopenharmony_ci	#define EP2INAK		BIT(6)
10462306a36Sopenharmony_ci	#define EP0INAK		BIT(5)
10562306a36Sopenharmony_ci	#define FDUPSPI		BIT(4)
10662306a36Sopenharmony_ci	#define INTLEVEL	BIT(3)
10762306a36Sopenharmony_ci	#define POSINT		BIT(2)
10862306a36Sopenharmony_ci	#define GPXB		BIT(1)
10962306a36Sopenharmony_ci	#define GPXA		BIT(0)
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define MAX3420_REG_REVISION	18
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define MAX3420_REG_FNADDR	19
11462306a36Sopenharmony_ci	#define FNADDR_MASK	0x7f
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci#define MAX3420_REG_IOPINS	20
11762306a36Sopenharmony_ci#define MAX3420_REG_IOPINS2	21
11862306a36Sopenharmony_ci#define MAX3420_REG_GPINIRQ	22
11962306a36Sopenharmony_ci#define MAX3420_REG_GPINIEN	23
12062306a36Sopenharmony_ci#define MAX3420_REG_GPINPOL	24
12162306a36Sopenharmony_ci#define MAX3420_REG_HIRQ	25
12262306a36Sopenharmony_ci#define MAX3420_REG_HIEN	26
12362306a36Sopenharmony_ci#define MAX3420_REG_MODE	27
12462306a36Sopenharmony_ci#define MAX3420_REG_PERADDR	28
12562306a36Sopenharmony_ci#define MAX3420_REG_HCTL	29
12662306a36Sopenharmony_ci#define MAX3420_REG_HXFR	30
12762306a36Sopenharmony_ci#define MAX3420_REG_HRSL	31
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci#define ENABLE_IRQ	BIT(0)
13062306a36Sopenharmony_ci#define IOPIN_UPDATE	BIT(1)
13162306a36Sopenharmony_ci#define REMOTE_WAKEUP	BIT(2)
13262306a36Sopenharmony_ci#define CONNECT_HOST	GENMASK(4, 3)
13362306a36Sopenharmony_ci#define	HCONNECT	(1 << 3)
13462306a36Sopenharmony_ci#define	HDISCONNECT	(3 << 3)
13562306a36Sopenharmony_ci#define UDC_START	GENMASK(6, 5)
13662306a36Sopenharmony_ci#define	START		(1 << 5)
13762306a36Sopenharmony_ci#define	STOP		(3 << 5)
13862306a36Sopenharmony_ci#define ENABLE_EP	GENMASK(8, 7)
13962306a36Sopenharmony_ci#define	ENABLE		(1 << 7)
14062306a36Sopenharmony_ci#define	DISABLE		(3 << 7)
14162306a36Sopenharmony_ci#define STALL_EP	GENMASK(10, 9)
14262306a36Sopenharmony_ci#define	STALL		(1 << 9)
14362306a36Sopenharmony_ci#define	UNSTALL		(3 << 9)
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#define MAX3420_CMD(c)		FIELD_PREP(GENMASK(7, 3), c)
14662306a36Sopenharmony_ci#define MAX3420_SPI_CMD_RD(c)	(MAX3420_CMD(c) | (0 << 1))
14762306a36Sopenharmony_ci#define MAX3420_SPI_CMD_WR(c)	(MAX3420_CMD(c) | (1 << 1))
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistruct max3420_req {
15062306a36Sopenharmony_ci	struct usb_request usb_req;
15162306a36Sopenharmony_ci	struct list_head queue;
15262306a36Sopenharmony_ci	struct max3420_ep *ep;
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistruct max3420_ep {
15662306a36Sopenharmony_ci	struct usb_ep ep_usb;
15762306a36Sopenharmony_ci	struct max3420_udc *udc;
15862306a36Sopenharmony_ci	struct list_head queue;
15962306a36Sopenharmony_ci	char name[MAX3420_EPNAME_SIZE];
16062306a36Sopenharmony_ci	unsigned int maxpacket;
16162306a36Sopenharmony_ci	spinlock_t lock;
16262306a36Sopenharmony_ci	int halted;
16362306a36Sopenharmony_ci	u32 todo;
16462306a36Sopenharmony_ci	int id;
16562306a36Sopenharmony_ci};
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistruct max3420_udc {
16862306a36Sopenharmony_ci	struct usb_gadget gadget;
16962306a36Sopenharmony_ci	struct max3420_ep ep[MAX3420_MAX_EPS];
17062306a36Sopenharmony_ci	struct usb_gadget_driver *driver;
17162306a36Sopenharmony_ci	struct task_struct *thread_task;
17262306a36Sopenharmony_ci	int remote_wkp, is_selfpowered;
17362306a36Sopenharmony_ci	bool vbus_active, softconnect;
17462306a36Sopenharmony_ci	struct usb_ctrlrequest setup;
17562306a36Sopenharmony_ci	struct mutex spi_bus_mutex;
17662306a36Sopenharmony_ci	struct max3420_req ep0req;
17762306a36Sopenharmony_ci	struct spi_device *spi;
17862306a36Sopenharmony_ci	struct device *dev;
17962306a36Sopenharmony_ci	spinlock_t lock;
18062306a36Sopenharmony_ci	bool suspended;
18162306a36Sopenharmony_ci	u8 ep0buf[64];
18262306a36Sopenharmony_ci	u32 todo;
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci#define to_max3420_req(r)	container_of((r), struct max3420_req, usb_req)
18662306a36Sopenharmony_ci#define to_max3420_ep(e)	container_of((e), struct max3420_ep, ep_usb)
18762306a36Sopenharmony_ci#define to_udc(g)		container_of((g), struct max3420_udc, gadget)
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci#define DRIVER_DESC     "MAX3420 USB Device-Mode Driver"
19062306a36Sopenharmony_cistatic const char driver_name[] = "max3420-udc";
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/* Control endpoint configuration.*/
19362306a36Sopenharmony_cistatic const struct usb_endpoint_descriptor ep0_desc = {
19462306a36Sopenharmony_ci	.bEndpointAddress	= USB_DIR_OUT,
19562306a36Sopenharmony_ci	.bmAttributes		= USB_ENDPOINT_XFER_CONTROL,
19662306a36Sopenharmony_ci	.wMaxPacketSize		= cpu_to_le16(MAX3420_EP_MAX_PACKET),
19762306a36Sopenharmony_ci};
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic void spi_ack_ctrl(struct max3420_udc *udc)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct spi_device *spi = udc->spi;
20262306a36Sopenharmony_ci	struct spi_transfer transfer;
20362306a36Sopenharmony_ci	struct spi_message msg;
20462306a36Sopenharmony_ci	u8 txdata[1];
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	memset(&transfer, 0, sizeof(transfer));
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	spi_message_init(&msg);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	txdata[0] = MAX3420_ACKSTAT;
21162306a36Sopenharmony_ci	transfer.tx_buf = txdata;
21262306a36Sopenharmony_ci	transfer.len = 1;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	spi_message_add_tail(&transfer, &msg);
21562306a36Sopenharmony_ci	spi_sync(spi, &msg);
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic u8 spi_rd8_ack(struct max3420_udc *udc, u8 reg, int actstat)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct spi_device *spi = udc->spi;
22162306a36Sopenharmony_ci	struct spi_transfer transfer;
22262306a36Sopenharmony_ci	struct spi_message msg;
22362306a36Sopenharmony_ci	u8 txdata[2], rxdata[2];
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	memset(&transfer, 0, sizeof(transfer));
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	spi_message_init(&msg);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	txdata[0] = MAX3420_SPI_CMD_RD(reg) | (actstat ? MAX3420_ACKSTAT : 0);
23062306a36Sopenharmony_ci	transfer.tx_buf = txdata;
23162306a36Sopenharmony_ci	transfer.rx_buf = rxdata;
23262306a36Sopenharmony_ci	transfer.len = 2;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	spi_message_add_tail(&transfer, &msg);
23562306a36Sopenharmony_ci	spi_sync(spi, &msg);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	return rxdata[1];
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic u8 spi_rd8(struct max3420_udc *udc, u8 reg)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	return spi_rd8_ack(udc, reg, 0);
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic void spi_wr8_ack(struct max3420_udc *udc, u8 reg, u8 val, int actstat)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	struct spi_device *spi = udc->spi;
24862306a36Sopenharmony_ci	struct spi_transfer transfer;
24962306a36Sopenharmony_ci	struct spi_message msg;
25062306a36Sopenharmony_ci	u8 txdata[2];
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	memset(&transfer, 0, sizeof(transfer));
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	spi_message_init(&msg);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	txdata[0] = MAX3420_SPI_CMD_WR(reg) | (actstat ? MAX3420_ACKSTAT : 0);
25762306a36Sopenharmony_ci	txdata[1] = val;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	transfer.tx_buf = txdata;
26062306a36Sopenharmony_ci	transfer.len = 2;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	spi_message_add_tail(&transfer, &msg);
26362306a36Sopenharmony_ci	spi_sync(spi, &msg);
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic void spi_wr8(struct max3420_udc *udc, u8 reg, u8 val)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	spi_wr8_ack(udc, reg, val, 0);
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic void spi_rd_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct spi_device *spi = udc->spi;
27462306a36Sopenharmony_ci	struct spi_transfer transfer;
27562306a36Sopenharmony_ci	struct spi_message msg;
27662306a36Sopenharmony_ci	u8 local_buf[MAX3420_EP_MAX_PACKET + 1] = {};
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	memset(&transfer, 0, sizeof(transfer));
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	spi_message_init(&msg);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	local_buf[0] = MAX3420_SPI_CMD_RD(reg);
28362306a36Sopenharmony_ci	transfer.tx_buf = &local_buf[0];
28462306a36Sopenharmony_ci	transfer.rx_buf = &local_buf[0];
28562306a36Sopenharmony_ci	transfer.len = len + 1;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	spi_message_add_tail(&transfer, &msg);
28862306a36Sopenharmony_ci	spi_sync(spi, &msg);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	memcpy(buf, &local_buf[1], len);
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic void spi_wr_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct spi_device *spi = udc->spi;
29662306a36Sopenharmony_ci	struct spi_transfer transfer;
29762306a36Sopenharmony_ci	struct spi_message msg;
29862306a36Sopenharmony_ci	u8 local_buf[MAX3420_EP_MAX_PACKET + 1] = {};
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	memset(&transfer, 0, sizeof(transfer));
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	spi_message_init(&msg);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	local_buf[0] = MAX3420_SPI_CMD_WR(reg);
30562306a36Sopenharmony_ci	memcpy(&local_buf[1], buf, len);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	transfer.tx_buf = local_buf;
30862306a36Sopenharmony_ci	transfer.len = len + 1;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	spi_message_add_tail(&transfer, &msg);
31162306a36Sopenharmony_ci	spi_sync(spi, &msg);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic int spi_max3420_enable(struct max3420_ep *ep)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct max3420_udc *udc = ep->udc;
31762306a36Sopenharmony_ci	unsigned long flags;
31862306a36Sopenharmony_ci	u8 epdis, epien;
31962306a36Sopenharmony_ci	int todo;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
32262306a36Sopenharmony_ci	todo = ep->todo & ENABLE_EP;
32362306a36Sopenharmony_ci	ep->todo &= ~ENABLE_EP;
32462306a36Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	if (!todo || ep->id == 0)
32762306a36Sopenharmony_ci		return false;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	epien = spi_rd8(udc, MAX3420_REG_EPIEN);
33062306a36Sopenharmony_ci	epdis = spi_rd8(udc, MAX3420_REG_CLRTOGS);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (todo == ENABLE) {
33362306a36Sopenharmony_ci		epdis &= ~BIT(ep->id + 4);
33462306a36Sopenharmony_ci		epien |= BIT(ep->id + 1);
33562306a36Sopenharmony_ci	} else {
33662306a36Sopenharmony_ci		epdis |= BIT(ep->id + 4);
33762306a36Sopenharmony_ci		epien &= ~BIT(ep->id + 1);
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_CLRTOGS, epdis);
34162306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_EPIEN, epien);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	return true;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic int spi_max3420_stall(struct max3420_ep *ep)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct max3420_udc *udc = ep->udc;
34962306a36Sopenharmony_ci	unsigned long flags;
35062306a36Sopenharmony_ci	u8 epstalls;
35162306a36Sopenharmony_ci	int todo;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
35462306a36Sopenharmony_ci	todo = ep->todo & STALL_EP;
35562306a36Sopenharmony_ci	ep->todo &= ~STALL_EP;
35662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (!todo || ep->id == 0)
35962306a36Sopenharmony_ci		return false;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	epstalls = spi_rd8(udc, MAX3420_REG_EPSTALLS);
36262306a36Sopenharmony_ci	if (todo == STALL) {
36362306a36Sopenharmony_ci		ep->halted = 1;
36462306a36Sopenharmony_ci		epstalls |= BIT(ep->id + 1);
36562306a36Sopenharmony_ci	} else {
36662306a36Sopenharmony_ci		u8 clrtogs;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci		ep->halted = 0;
36962306a36Sopenharmony_ci		epstalls &= ~BIT(ep->id + 1);
37062306a36Sopenharmony_ci		clrtogs = spi_rd8(udc, MAX3420_REG_CLRTOGS);
37162306a36Sopenharmony_ci		clrtogs |= BIT(ep->id + 1);
37262306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_CLRTOGS, clrtogs);
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_EPSTALLS, epstalls | ACKSTAT);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	return true;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic int spi_max3420_rwkup(struct max3420_udc *udc)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	unsigned long flags;
38262306a36Sopenharmony_ci	int wake_remote;
38362306a36Sopenharmony_ci	u8 usbctl;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
38662306a36Sopenharmony_ci	wake_remote = udc->todo & REMOTE_WAKEUP;
38762306a36Sopenharmony_ci	udc->todo &= ~REMOTE_WAKEUP;
38862306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (!wake_remote || !udc->suspended)
39162306a36Sopenharmony_ci		return false;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* Set Remote-WkUp Signal*/
39462306a36Sopenharmony_ci	usbctl = spi_rd8(udc, MAX3420_REG_USBCTL);
39562306a36Sopenharmony_ci	usbctl |= SIGRWU;
39662306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_USBCTL, usbctl);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	msleep_interruptible(5);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* Clear Remote-WkUp Signal*/
40162306a36Sopenharmony_ci	usbctl = spi_rd8(udc, MAX3420_REG_USBCTL);
40262306a36Sopenharmony_ci	usbctl &= ~SIGRWU;
40362306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_USBCTL, usbctl);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	udc->suspended = false;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	return true;
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic void max3420_nuke(struct max3420_ep *ep, int status);
41162306a36Sopenharmony_cistatic void __max3420_stop(struct max3420_udc *udc)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	u8 val;
41462306a36Sopenharmony_ci	int i;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	/* clear all pending requests */
41762306a36Sopenharmony_ci	for (i = 1; i < MAX3420_MAX_EPS; i++)
41862306a36Sopenharmony_ci		max3420_nuke(&udc->ep[i], -ECONNRESET);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* Disable IRQ to CPU */
42162306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_CPUCTL, 0);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	val = spi_rd8(udc, MAX3420_REG_USBCTL);
42462306a36Sopenharmony_ci	val |= PWRDOWN;
42562306a36Sopenharmony_ci	if (udc->is_selfpowered)
42662306a36Sopenharmony_ci		val &= ~HOSCSTEN;
42762306a36Sopenharmony_ci	else
42862306a36Sopenharmony_ci		val |= HOSCSTEN;
42962306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_USBCTL, val);
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic void __max3420_start(struct max3420_udc *udc)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	u8 val;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	/* Need this delay if bus-powered,
43762306a36Sopenharmony_ci	 * but even for self-powered it helps stability
43862306a36Sopenharmony_ci	 */
43962306a36Sopenharmony_ci	msleep_interruptible(250);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	/* configure SPI */
44262306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_PINCTL, FDUPSPI);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	/* Chip Reset */
44562306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_USBCTL, CHIPRES);
44662306a36Sopenharmony_ci	msleep_interruptible(5);
44762306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_USBCTL, 0);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	/* Poll for OSC to stabilize */
45062306a36Sopenharmony_ci	while (1) {
45162306a36Sopenharmony_ci		val = spi_rd8(udc, MAX3420_REG_USBIRQ);
45262306a36Sopenharmony_ci		if (val & OSCOKIRQ)
45362306a36Sopenharmony_ci			break;
45462306a36Sopenharmony_ci		cond_resched();
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	/* Enable PULL-UP only when Vbus detected */
45862306a36Sopenharmony_ci	val = spi_rd8(udc, MAX3420_REG_USBCTL);
45962306a36Sopenharmony_ci	val |= VBGATE | CONNECT;
46062306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_USBCTL, val);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	val = URESDNIRQ | URESIRQ;
46362306a36Sopenharmony_ci	if (udc->is_selfpowered)
46462306a36Sopenharmony_ci		val |= NOVBUSIRQ;
46562306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_USBIEN, val);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	/* Enable only EP0 interrupts */
46862306a36Sopenharmony_ci	val = IN0BAVIRQ | OUT0DAVIRQ | SUDAVIRQ;
46962306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_EPIEN, val);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* Enable IRQ to CPU */
47262306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_CPUCTL, IE);
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic int max3420_start(struct max3420_udc *udc)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	unsigned long flags;
47862306a36Sopenharmony_ci	int todo;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
48162306a36Sopenharmony_ci	todo = udc->todo & UDC_START;
48262306a36Sopenharmony_ci	udc->todo &= ~UDC_START;
48362306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (!todo)
48662306a36Sopenharmony_ci		return false;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	if (udc->vbus_active && udc->softconnect)
48962306a36Sopenharmony_ci		__max3420_start(udc);
49062306a36Sopenharmony_ci	else
49162306a36Sopenharmony_ci		__max3420_stop(udc);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	return true;
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic irqreturn_t max3420_vbus_handler(int irq, void *dev_id)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct max3420_udc *udc = dev_id;
49962306a36Sopenharmony_ci	unsigned long flags;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
50262306a36Sopenharmony_ci	/* its a vbus change interrupt */
50362306a36Sopenharmony_ci	udc->vbus_active = !udc->vbus_active;
50462306a36Sopenharmony_ci	udc->todo |= UDC_START;
50562306a36Sopenharmony_ci	usb_udc_vbus_handler(&udc->gadget, udc->vbus_active);
50662306a36Sopenharmony_ci	usb_gadget_set_state(&udc->gadget, udc->vbus_active
50762306a36Sopenharmony_ci			     ? USB_STATE_POWERED : USB_STATE_NOTATTACHED);
50862306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	if (udc->thread_task)
51162306a36Sopenharmony_ci		wake_up_process(udc->thread_task);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	return IRQ_HANDLED;
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic irqreturn_t max3420_irq_handler(int irq, void *dev_id)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	struct max3420_udc *udc = dev_id;
51962306a36Sopenharmony_ci	struct spi_device *spi = udc->spi;
52062306a36Sopenharmony_ci	unsigned long flags;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
52362306a36Sopenharmony_ci	if ((udc->todo & ENABLE_IRQ) == 0) {
52462306a36Sopenharmony_ci		disable_irq_nosync(spi->irq);
52562306a36Sopenharmony_ci		udc->todo |= ENABLE_IRQ;
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (udc->thread_task)
53062306a36Sopenharmony_ci		wake_up_process(udc->thread_task);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	return IRQ_HANDLED;
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic void max3420_getstatus(struct max3420_udc *udc)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	struct max3420_ep *ep;
53862306a36Sopenharmony_ci	u16 status = 0;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	switch (udc->setup.bRequestType & USB_RECIP_MASK) {
54162306a36Sopenharmony_ci	case USB_RECIP_DEVICE:
54262306a36Sopenharmony_ci		/* Get device status */
54362306a36Sopenharmony_ci		status = udc->gadget.is_selfpowered << USB_DEVICE_SELF_POWERED;
54462306a36Sopenharmony_ci		status |= (udc->remote_wkp << USB_DEVICE_REMOTE_WAKEUP);
54562306a36Sopenharmony_ci		break;
54662306a36Sopenharmony_ci	case USB_RECIP_INTERFACE:
54762306a36Sopenharmony_ci		if (udc->driver->setup(&udc->gadget, &udc->setup) < 0)
54862306a36Sopenharmony_ci			goto stall;
54962306a36Sopenharmony_ci		break;
55062306a36Sopenharmony_ci	case USB_RECIP_ENDPOINT:
55162306a36Sopenharmony_ci		ep = &udc->ep[udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK];
55262306a36Sopenharmony_ci		if (udc->setup.wIndex & USB_DIR_IN) {
55362306a36Sopenharmony_ci			if (!ep->ep_usb.caps.dir_in)
55462306a36Sopenharmony_ci				goto stall;
55562306a36Sopenharmony_ci		} else {
55662306a36Sopenharmony_ci			if (!ep->ep_usb.caps.dir_out)
55762306a36Sopenharmony_ci				goto stall;
55862306a36Sopenharmony_ci		}
55962306a36Sopenharmony_ci		if (ep->halted)
56062306a36Sopenharmony_ci			status = 1 << USB_ENDPOINT_HALT;
56162306a36Sopenharmony_ci		break;
56262306a36Sopenharmony_ci	default:
56362306a36Sopenharmony_ci		goto stall;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	status = cpu_to_le16(status);
56762306a36Sopenharmony_ci	spi_wr_buf(udc, MAX3420_REG_EP0FIFO, &status, 2);
56862306a36Sopenharmony_ci	spi_wr8_ack(udc, MAX3420_REG_EP0BC, 2, 1);
56962306a36Sopenharmony_ci	return;
57062306a36Sopenharmony_cistall:
57162306a36Sopenharmony_ci	dev_err(udc->dev, "Can't respond to getstatus request\n");
57262306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_EPSTALLS, STLEP0IN | STLEP0OUT | STLSTAT);
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic void max3420_set_clear_feature(struct max3420_udc *udc)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	struct max3420_ep *ep;
57862306a36Sopenharmony_ci	int set = udc->setup.bRequest == USB_REQ_SET_FEATURE;
57962306a36Sopenharmony_ci	unsigned long flags;
58062306a36Sopenharmony_ci	int id;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	switch (udc->setup.bRequestType) {
58362306a36Sopenharmony_ci	case USB_RECIP_DEVICE:
58462306a36Sopenharmony_ci		if (udc->setup.wValue != USB_DEVICE_REMOTE_WAKEUP)
58562306a36Sopenharmony_ci			break;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci		if (udc->setup.bRequest == USB_REQ_SET_FEATURE)
58862306a36Sopenharmony_ci			udc->remote_wkp = 1;
58962306a36Sopenharmony_ci		else
59062306a36Sopenharmony_ci			udc->remote_wkp = 0;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci		return spi_ack_ctrl(udc);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	case USB_RECIP_ENDPOINT:
59562306a36Sopenharmony_ci		if (udc->setup.wValue != USB_ENDPOINT_HALT)
59662306a36Sopenharmony_ci			break;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci		id = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK;
59962306a36Sopenharmony_ci		ep = &udc->ep[id];
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci		spin_lock_irqsave(&ep->lock, flags);
60262306a36Sopenharmony_ci		ep->todo &= ~STALL_EP;
60362306a36Sopenharmony_ci		if (set)
60462306a36Sopenharmony_ci			ep->todo |= STALL;
60562306a36Sopenharmony_ci		else
60662306a36Sopenharmony_ci			ep->todo |= UNSTALL;
60762306a36Sopenharmony_ci		spin_unlock_irqrestore(&ep->lock, flags);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci		spi_max3420_stall(ep);
61062306a36Sopenharmony_ci		return;
61162306a36Sopenharmony_ci	default:
61262306a36Sopenharmony_ci		break;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	dev_err(udc->dev, "Can't respond to SET/CLEAR FEATURE\n");
61662306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_EPSTALLS, STLEP0IN | STLEP0OUT | STLSTAT);
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cistatic void max3420_handle_setup(struct max3420_udc *udc)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	struct usb_ctrlrequest setup;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	spi_rd_buf(udc, MAX3420_REG_SUDFIFO, (void *)&setup, 8);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	udc->setup = setup;
62662306a36Sopenharmony_ci	udc->setup.wValue = cpu_to_le16(setup.wValue);
62762306a36Sopenharmony_ci	udc->setup.wIndex = cpu_to_le16(setup.wIndex);
62862306a36Sopenharmony_ci	udc->setup.wLength = cpu_to_le16(setup.wLength);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	switch (udc->setup.bRequest) {
63162306a36Sopenharmony_ci	case USB_REQ_GET_STATUS:
63262306a36Sopenharmony_ci		/* Data+Status phase form udc */
63362306a36Sopenharmony_ci		if ((udc->setup.bRequestType &
63462306a36Sopenharmony_ci				(USB_DIR_IN | USB_TYPE_MASK)) !=
63562306a36Sopenharmony_ci				(USB_DIR_IN | USB_TYPE_STANDARD)) {
63662306a36Sopenharmony_ci			break;
63762306a36Sopenharmony_ci		}
63862306a36Sopenharmony_ci		return max3420_getstatus(udc);
63962306a36Sopenharmony_ci	case USB_REQ_SET_ADDRESS:
64062306a36Sopenharmony_ci		/* Status phase from udc */
64162306a36Sopenharmony_ci		if (udc->setup.bRequestType != (USB_DIR_OUT |
64262306a36Sopenharmony_ci				USB_TYPE_STANDARD | USB_RECIP_DEVICE)) {
64362306a36Sopenharmony_ci			break;
64462306a36Sopenharmony_ci		}
64562306a36Sopenharmony_ci		spi_rd8_ack(udc, MAX3420_REG_FNADDR, 1);
64662306a36Sopenharmony_ci		dev_dbg(udc->dev, "Assigned Address=%d\n", udc->setup.wValue);
64762306a36Sopenharmony_ci		return;
64862306a36Sopenharmony_ci	case USB_REQ_CLEAR_FEATURE:
64962306a36Sopenharmony_ci	case USB_REQ_SET_FEATURE:
65062306a36Sopenharmony_ci		/* Requests with no data phase, status phase from udc */
65162306a36Sopenharmony_ci		if ((udc->setup.bRequestType & USB_TYPE_MASK)
65262306a36Sopenharmony_ci				!= USB_TYPE_STANDARD)
65362306a36Sopenharmony_ci			break;
65462306a36Sopenharmony_ci		return max3420_set_clear_feature(udc);
65562306a36Sopenharmony_ci	default:
65662306a36Sopenharmony_ci		break;
65762306a36Sopenharmony_ci	}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	if (udc->driver->setup(&udc->gadget, &setup) < 0) {
66062306a36Sopenharmony_ci		/* Stall EP0 */
66162306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_EPSTALLS,
66262306a36Sopenharmony_ci			STLEP0IN | STLEP0OUT | STLSTAT);
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistatic void max3420_req_done(struct max3420_req *req, int status)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	struct max3420_ep *ep = req->ep;
66962306a36Sopenharmony_ci	struct max3420_udc *udc = ep->udc;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	if (req->usb_req.status == -EINPROGRESS)
67262306a36Sopenharmony_ci		req->usb_req.status = status;
67362306a36Sopenharmony_ci	else
67462306a36Sopenharmony_ci		status = req->usb_req.status;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	if (status && status != -ESHUTDOWN)
67762306a36Sopenharmony_ci		dev_err(udc->dev, "%s done %p, status %d\n",
67862306a36Sopenharmony_ci			ep->ep_usb.name, req, status);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (req->usb_req.complete)
68162306a36Sopenharmony_ci		req->usb_req.complete(&ep->ep_usb, &req->usb_req);
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_cistatic int max3420_do_data(struct max3420_udc *udc, int ep_id, int in)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	struct max3420_ep *ep = &udc->ep[ep_id];
68762306a36Sopenharmony_ci	struct max3420_req *req;
68862306a36Sopenharmony_ci	int done, length, psz;
68962306a36Sopenharmony_ci	void *buf;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	if (list_empty(&ep->queue))
69262306a36Sopenharmony_ci		return false;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	req = list_first_entry(&ep->queue, struct max3420_req, queue);
69562306a36Sopenharmony_ci	buf = req->usb_req.buf + req->usb_req.actual;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	psz = ep->ep_usb.maxpacket;
69862306a36Sopenharmony_ci	length = req->usb_req.length - req->usb_req.actual;
69962306a36Sopenharmony_ci	length = min(length, psz);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	if (length == 0) {
70262306a36Sopenharmony_ci		done = 1;
70362306a36Sopenharmony_ci		goto xfer_done;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	done = 0;
70762306a36Sopenharmony_ci	if (in) {
70862306a36Sopenharmony_ci		prefetch(buf);
70962306a36Sopenharmony_ci		spi_wr_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length);
71062306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_EP0BC + ep_id, length);
71162306a36Sopenharmony_ci		if (length < psz)
71262306a36Sopenharmony_ci			done = 1;
71362306a36Sopenharmony_ci	} else {
71462306a36Sopenharmony_ci		psz = spi_rd8(udc, MAX3420_REG_EP0BC + ep_id);
71562306a36Sopenharmony_ci		length = min(length, psz);
71662306a36Sopenharmony_ci		prefetchw(buf);
71762306a36Sopenharmony_ci		spi_rd_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length);
71862306a36Sopenharmony_ci		if (length < ep->ep_usb.maxpacket)
71962306a36Sopenharmony_ci			done = 1;
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	req->usb_req.actual += length;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	if (req->usb_req.actual == req->usb_req.length)
72562306a36Sopenharmony_ci		done = 1;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cixfer_done:
72862306a36Sopenharmony_ci	if (done) {
72962306a36Sopenharmony_ci		unsigned long flags;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci		spin_lock_irqsave(&ep->lock, flags);
73262306a36Sopenharmony_ci		list_del_init(&req->queue);
73362306a36Sopenharmony_ci		spin_unlock_irqrestore(&ep->lock, flags);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci		if (ep_id == 0)
73662306a36Sopenharmony_ci			spi_ack_ctrl(udc);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci		max3420_req_done(req, 0);
73962306a36Sopenharmony_ci	}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	return true;
74262306a36Sopenharmony_ci}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_cistatic int max3420_handle_irqs(struct max3420_udc *udc)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	u8 epien, epirq, usbirq, usbien, reg[4];
74762306a36Sopenharmony_ci	bool ret = false;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 4);
75062306a36Sopenharmony_ci	epirq = reg[0];
75162306a36Sopenharmony_ci	epien = reg[1];
75262306a36Sopenharmony_ci	usbirq = reg[2];
75362306a36Sopenharmony_ci	usbien = reg[3];
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	usbirq &= usbien;
75662306a36Sopenharmony_ci	epirq &= epien;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	if (epirq & SUDAVIRQ) {
75962306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_EPIRQ, SUDAVIRQ);
76062306a36Sopenharmony_ci		max3420_handle_setup(udc);
76162306a36Sopenharmony_ci		return true;
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	if (usbirq & VBUSIRQ) {
76562306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_USBIRQ, VBUSIRQ);
76662306a36Sopenharmony_ci		dev_dbg(udc->dev, "Cable plugged in\n");
76762306a36Sopenharmony_ci		return true;
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	if (usbirq & NOVBUSIRQ) {
77162306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_USBIRQ, NOVBUSIRQ);
77262306a36Sopenharmony_ci		dev_dbg(udc->dev, "Cable pulled out\n");
77362306a36Sopenharmony_ci		return true;
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	if (usbirq & URESIRQ) {
77762306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_USBIRQ, URESIRQ);
77862306a36Sopenharmony_ci		dev_dbg(udc->dev, "USB Reset - Start\n");
77962306a36Sopenharmony_ci		return true;
78062306a36Sopenharmony_ci	}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	if (usbirq & URESDNIRQ) {
78362306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_USBIRQ, URESDNIRQ);
78462306a36Sopenharmony_ci		dev_dbg(udc->dev, "USB Reset - END\n");
78562306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_USBIEN, URESDNIRQ | URESIRQ);
78662306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_EPIEN, SUDAVIRQ | IN0BAVIRQ
78762306a36Sopenharmony_ci			| OUT0DAVIRQ);
78862306a36Sopenharmony_ci		return true;
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (usbirq & SUSPIRQ) {
79262306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_USBIRQ, SUSPIRQ);
79362306a36Sopenharmony_ci		dev_dbg(udc->dev, "USB Suspend - Enter\n");
79462306a36Sopenharmony_ci		udc->suspended = true;
79562306a36Sopenharmony_ci		return true;
79662306a36Sopenharmony_ci	}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	if (usbirq & BUSACTIRQ) {
79962306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_USBIRQ, BUSACTIRQ);
80062306a36Sopenharmony_ci		dev_dbg(udc->dev, "USB Suspend - Exit\n");
80162306a36Sopenharmony_ci		udc->suspended = false;
80262306a36Sopenharmony_ci		return true;
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	if (usbirq & RWUDNIRQ) {
80662306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_USBIRQ, RWUDNIRQ);
80762306a36Sopenharmony_ci		dev_dbg(udc->dev, "Asked Host to wakeup\n");
80862306a36Sopenharmony_ci		return true;
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	if (usbirq & OSCOKIRQ) {
81262306a36Sopenharmony_ci		spi_wr8(udc, MAX3420_REG_USBIRQ, OSCOKIRQ);
81362306a36Sopenharmony_ci		dev_dbg(udc->dev, "Osc stabilized, start work\n");
81462306a36Sopenharmony_ci		return true;
81562306a36Sopenharmony_ci	}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	if (epirq & OUT0DAVIRQ && max3420_do_data(udc, 0, 0)) {
81862306a36Sopenharmony_ci		spi_wr8_ack(udc, MAX3420_REG_EPIRQ, OUT0DAVIRQ, 1);
81962306a36Sopenharmony_ci		ret = true;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	if (epirq & IN0BAVIRQ && max3420_do_data(udc, 0, 1))
82362306a36Sopenharmony_ci		ret = true;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	if (epirq & OUT1DAVIRQ && max3420_do_data(udc, 1, 0)) {
82662306a36Sopenharmony_ci		spi_wr8_ack(udc, MAX3420_REG_EPIRQ, OUT1DAVIRQ, 1);
82762306a36Sopenharmony_ci		ret = true;
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	if (epirq & IN2BAVIRQ && max3420_do_data(udc, 2, 1))
83162306a36Sopenharmony_ci		ret = true;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	if (epirq & IN3BAVIRQ && max3420_do_data(udc, 3, 1))
83462306a36Sopenharmony_ci		ret = true;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	return ret;
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic int max3420_thread(void *dev_id)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	struct max3420_udc *udc = dev_id;
84262306a36Sopenharmony_ci	struct spi_device *spi = udc->spi;
84362306a36Sopenharmony_ci	int i, loop_again = 1;
84462306a36Sopenharmony_ci	unsigned long flags;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	while (!kthread_should_stop()) {
84762306a36Sopenharmony_ci		if (!loop_again) {
84862306a36Sopenharmony_ci			ktime_t kt = ns_to_ktime(1000 * 1000 * 250); /* 250ms */
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci			set_current_state(TASK_INTERRUPTIBLE);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci			spin_lock_irqsave(&udc->lock, flags);
85362306a36Sopenharmony_ci			if (udc->todo & ENABLE_IRQ) {
85462306a36Sopenharmony_ci				enable_irq(spi->irq);
85562306a36Sopenharmony_ci				udc->todo &= ~ENABLE_IRQ;
85662306a36Sopenharmony_ci			}
85762306a36Sopenharmony_ci			spin_unlock_irqrestore(&udc->lock, flags);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci			schedule_hrtimeout(&kt, HRTIMER_MODE_REL);
86062306a36Sopenharmony_ci		}
86162306a36Sopenharmony_ci		loop_again = 0;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		mutex_lock(&udc->spi_bus_mutex);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci		/* If bus-vbus_active and disconnected */
86662306a36Sopenharmony_ci		if (!udc->vbus_active || !udc->softconnect)
86762306a36Sopenharmony_ci			goto loop;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci		if (max3420_start(udc)) {
87062306a36Sopenharmony_ci			loop_again = 1;
87162306a36Sopenharmony_ci			goto loop;
87262306a36Sopenharmony_ci		}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci		if (max3420_handle_irqs(udc)) {
87562306a36Sopenharmony_ci			loop_again = 1;
87662306a36Sopenharmony_ci			goto loop;
87762306a36Sopenharmony_ci		}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci		if (spi_max3420_rwkup(udc)) {
88062306a36Sopenharmony_ci			loop_again = 1;
88162306a36Sopenharmony_ci			goto loop;
88262306a36Sopenharmony_ci		}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci		max3420_do_data(udc, 0, 1); /* get done with the EP0 ZLP */
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci		for (i = 1; i < MAX3420_MAX_EPS; i++) {
88762306a36Sopenharmony_ci			struct max3420_ep *ep = &udc->ep[i];
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci			if (spi_max3420_enable(ep))
89062306a36Sopenharmony_ci				loop_again = 1;
89162306a36Sopenharmony_ci			if (spi_max3420_stall(ep))
89262306a36Sopenharmony_ci				loop_again = 1;
89362306a36Sopenharmony_ci		}
89462306a36Sopenharmony_ciloop:
89562306a36Sopenharmony_ci		mutex_unlock(&udc->spi_bus_mutex);
89662306a36Sopenharmony_ci	}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	set_current_state(TASK_RUNNING);
89962306a36Sopenharmony_ci	dev_info(udc->dev, "SPI thread exiting\n");
90062306a36Sopenharmony_ci	return 0;
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_cistatic int max3420_ep_set_halt(struct usb_ep *_ep, int stall)
90462306a36Sopenharmony_ci{
90562306a36Sopenharmony_ci	struct max3420_ep *ep = to_max3420_ep(_ep);
90662306a36Sopenharmony_ci	struct max3420_udc *udc = ep->udc;
90762306a36Sopenharmony_ci	unsigned long flags;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	ep->todo &= ~STALL_EP;
91262306a36Sopenharmony_ci	if (stall)
91362306a36Sopenharmony_ci		ep->todo |= STALL;
91462306a36Sopenharmony_ci	else
91562306a36Sopenharmony_ci		ep->todo |= UNSTALL;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	wake_up_process(udc->thread_task);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	dev_dbg(udc->dev, "%sStall %s\n", stall ? "" : "Un", ep->name);
92262306a36Sopenharmony_ci	return 0;
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_cistatic int __max3420_ep_enable(struct max3420_ep *ep,
92662306a36Sopenharmony_ci			       const struct usb_endpoint_descriptor *desc)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	unsigned int maxp = usb_endpoint_maxp(desc);
92962306a36Sopenharmony_ci	unsigned long flags;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
93262306a36Sopenharmony_ci	ep->ep_usb.desc = desc;
93362306a36Sopenharmony_ci	ep->ep_usb.maxpacket = maxp;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	ep->todo &= ~ENABLE_EP;
93662306a36Sopenharmony_ci	ep->todo |= ENABLE;
93762306a36Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	return 0;
94062306a36Sopenharmony_ci}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_cistatic int max3420_ep_enable(struct usb_ep *_ep,
94362306a36Sopenharmony_ci			     const struct usb_endpoint_descriptor *desc)
94462306a36Sopenharmony_ci{
94562306a36Sopenharmony_ci	struct max3420_ep *ep = to_max3420_ep(_ep);
94662306a36Sopenharmony_ci	struct max3420_udc *udc = ep->udc;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	__max3420_ep_enable(ep, desc);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	wake_up_process(udc->thread_task);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	return 0;
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_cistatic void max3420_nuke(struct max3420_ep *ep, int status)
95662306a36Sopenharmony_ci{
95762306a36Sopenharmony_ci	struct max3420_req *req, *r;
95862306a36Sopenharmony_ci	unsigned long flags;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	list_for_each_entry_safe(req, r, &ep->queue, queue) {
96362306a36Sopenharmony_ci		list_del_init(&req->queue);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci		spin_unlock_irqrestore(&ep->lock, flags);
96662306a36Sopenharmony_ci		max3420_req_done(req, status);
96762306a36Sopenharmony_ci		spin_lock_irqsave(&ep->lock, flags);
96862306a36Sopenharmony_ci	}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
97162306a36Sopenharmony_ci}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_cistatic void __max3420_ep_disable(struct max3420_ep *ep)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	struct max3420_udc *udc = ep->udc;
97662306a36Sopenharmony_ci	unsigned long flags;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	ep->ep_usb.desc = NULL;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	ep->todo &= ~ENABLE_EP;
98362306a36Sopenharmony_ci	ep->todo |= DISABLE;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	dev_dbg(udc->dev, "Disabled %s\n", ep->name);
98862306a36Sopenharmony_ci}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cistatic int max3420_ep_disable(struct usb_ep *_ep)
99162306a36Sopenharmony_ci{
99262306a36Sopenharmony_ci	struct max3420_ep *ep = to_max3420_ep(_ep);
99362306a36Sopenharmony_ci	struct max3420_udc *udc = ep->udc;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	max3420_nuke(ep, -ESHUTDOWN);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	__max3420_ep_disable(ep);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	wake_up_process(udc->thread_task);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	return 0;
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_cistatic struct usb_request *max3420_alloc_request(struct usb_ep *_ep,
100562306a36Sopenharmony_ci						 gfp_t gfp_flags)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	struct max3420_ep *ep = to_max3420_ep(_ep);
100862306a36Sopenharmony_ci	struct max3420_req *req;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	req = kzalloc(sizeof(*req), gfp_flags);
101162306a36Sopenharmony_ci	if (!req)
101262306a36Sopenharmony_ci		return NULL;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	req->ep = ep;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	return &req->usb_req;
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_cistatic void max3420_free_request(struct usb_ep *_ep, struct usb_request *_req)
102062306a36Sopenharmony_ci{
102162306a36Sopenharmony_ci	kfree(to_max3420_req(_req));
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic int max3420_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
102562306a36Sopenharmony_ci			    gfp_t ignored)
102662306a36Sopenharmony_ci{
102762306a36Sopenharmony_ci	struct max3420_req *req = to_max3420_req(_req);
102862306a36Sopenharmony_ci	struct max3420_ep *ep  = to_max3420_ep(_ep);
102962306a36Sopenharmony_ci	struct max3420_udc *udc = ep->udc;
103062306a36Sopenharmony_ci	unsigned long flags;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	_req->status = -EINPROGRESS;
103362306a36Sopenharmony_ci	_req->actual = 0;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
103662306a36Sopenharmony_ci	list_add_tail(&req->queue, &ep->queue);
103762306a36Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	wake_up_process(udc->thread_task);
104062306a36Sopenharmony_ci	return 0;
104162306a36Sopenharmony_ci}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_cistatic int max3420_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
104462306a36Sopenharmony_ci{
104562306a36Sopenharmony_ci	struct max3420_req *t = NULL;
104662306a36Sopenharmony_ci	struct max3420_req *req = to_max3420_req(_req);
104762306a36Sopenharmony_ci	struct max3420_req *iter;
104862306a36Sopenharmony_ci	struct max3420_ep *ep = to_max3420_ep(_ep);
104962306a36Sopenharmony_ci	unsigned long flags;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	/* Pluck the descriptor from queue */
105462306a36Sopenharmony_ci	list_for_each_entry(iter, &ep->queue, queue) {
105562306a36Sopenharmony_ci		if (iter != req)
105662306a36Sopenharmony_ci			continue;
105762306a36Sopenharmony_ci		list_del_init(&req->queue);
105862306a36Sopenharmony_ci		t = iter;
105962306a36Sopenharmony_ci		break;
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	if (t)
106562306a36Sopenharmony_ci		max3420_req_done(req, -ECONNRESET);
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	return 0;
106862306a36Sopenharmony_ci}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_cistatic const struct usb_ep_ops max3420_ep_ops = {
107162306a36Sopenharmony_ci	.enable		= max3420_ep_enable,
107262306a36Sopenharmony_ci	.disable	= max3420_ep_disable,
107362306a36Sopenharmony_ci	.alloc_request	= max3420_alloc_request,
107462306a36Sopenharmony_ci	.free_request	= max3420_free_request,
107562306a36Sopenharmony_ci	.queue		= max3420_ep_queue,
107662306a36Sopenharmony_ci	.dequeue	= max3420_ep_dequeue,
107762306a36Sopenharmony_ci	.set_halt	= max3420_ep_set_halt,
107862306a36Sopenharmony_ci};
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_cistatic int max3420_wakeup(struct usb_gadget *gadget)
108162306a36Sopenharmony_ci{
108262306a36Sopenharmony_ci	struct max3420_udc *udc = to_udc(gadget);
108362306a36Sopenharmony_ci	unsigned long flags;
108462306a36Sopenharmony_ci	int ret = -EINVAL;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	/* Only if wakeup allowed by host */
108962306a36Sopenharmony_ci	if (udc->remote_wkp) {
109062306a36Sopenharmony_ci		udc->todo |= REMOTE_WAKEUP;
109162306a36Sopenharmony_ci		ret = 0;
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	if (udc->thread_task)
109762306a36Sopenharmony_ci		wake_up_process(udc->thread_task);
109862306a36Sopenharmony_ci	return ret;
109962306a36Sopenharmony_ci}
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_cistatic int max3420_udc_start(struct usb_gadget *gadget,
110262306a36Sopenharmony_ci			     struct usb_gadget_driver *driver)
110362306a36Sopenharmony_ci{
110462306a36Sopenharmony_ci	struct max3420_udc *udc = to_udc(gadget);
110562306a36Sopenharmony_ci	unsigned long flags;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
110862306a36Sopenharmony_ci	/* hook up the driver */
110962306a36Sopenharmony_ci	udc->driver = driver;
111062306a36Sopenharmony_ci	udc->gadget.speed = USB_SPEED_FULL;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	udc->gadget.is_selfpowered = udc->is_selfpowered;
111362306a36Sopenharmony_ci	udc->remote_wkp = 0;
111462306a36Sopenharmony_ci	udc->softconnect = true;
111562306a36Sopenharmony_ci	udc->todo |= UDC_START;
111662306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	if (udc->thread_task)
111962306a36Sopenharmony_ci		wake_up_process(udc->thread_task);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	return 0;
112262306a36Sopenharmony_ci}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_cistatic int max3420_udc_stop(struct usb_gadget *gadget)
112562306a36Sopenharmony_ci{
112662306a36Sopenharmony_ci	struct max3420_udc *udc = to_udc(gadget);
112762306a36Sopenharmony_ci	unsigned long flags;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
113062306a36Sopenharmony_ci	udc->is_selfpowered = udc->gadget.is_selfpowered;
113162306a36Sopenharmony_ci	udc->gadget.speed = USB_SPEED_UNKNOWN;
113262306a36Sopenharmony_ci	udc->driver = NULL;
113362306a36Sopenharmony_ci	udc->softconnect = false;
113462306a36Sopenharmony_ci	udc->todo |= UDC_START;
113562306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	if (udc->thread_task)
113862306a36Sopenharmony_ci		wake_up_process(udc->thread_task);
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	return 0;
114162306a36Sopenharmony_ci}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_cistatic const struct usb_gadget_ops max3420_udc_ops = {
114462306a36Sopenharmony_ci	.udc_start	= max3420_udc_start,
114562306a36Sopenharmony_ci	.udc_stop	= max3420_udc_stop,
114662306a36Sopenharmony_ci	.wakeup		= max3420_wakeup,
114762306a36Sopenharmony_ci};
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_cistatic void max3420_eps_init(struct max3420_udc *udc)
115062306a36Sopenharmony_ci{
115162306a36Sopenharmony_ci	int idx;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	INIT_LIST_HEAD(&udc->gadget.ep_list);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	for (idx = 0; idx < MAX3420_MAX_EPS; idx++) {
115662306a36Sopenharmony_ci		struct max3420_ep *ep = &udc->ep[idx];
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci		spin_lock_init(&ep->lock);
115962306a36Sopenharmony_ci		INIT_LIST_HEAD(&ep->queue);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci		ep->udc = udc;
116262306a36Sopenharmony_ci		ep->id = idx;
116362306a36Sopenharmony_ci		ep->halted = 0;
116462306a36Sopenharmony_ci		ep->maxpacket = 0;
116562306a36Sopenharmony_ci		ep->ep_usb.name = ep->name;
116662306a36Sopenharmony_ci		ep->ep_usb.ops = &max3420_ep_ops;
116762306a36Sopenharmony_ci		usb_ep_set_maxpacket_limit(&ep->ep_usb, MAX3420_EP_MAX_PACKET);
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci		if (idx == 0) { /* For EP0 */
117062306a36Sopenharmony_ci			ep->ep_usb.desc = &ep0_desc;
117162306a36Sopenharmony_ci			ep->ep_usb.maxpacket = usb_endpoint_maxp(&ep0_desc);
117262306a36Sopenharmony_ci			ep->ep_usb.caps.type_control = true;
117362306a36Sopenharmony_ci			ep->ep_usb.caps.dir_in = true;
117462306a36Sopenharmony_ci			ep->ep_usb.caps.dir_out = true;
117562306a36Sopenharmony_ci			snprintf(ep->name, MAX3420_EPNAME_SIZE, "ep0");
117662306a36Sopenharmony_ci			continue;
117762306a36Sopenharmony_ci		}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci		if (idx == 1) { /* EP1 is OUT */
118062306a36Sopenharmony_ci			ep->ep_usb.caps.dir_in = false;
118162306a36Sopenharmony_ci			ep->ep_usb.caps.dir_out = true;
118262306a36Sopenharmony_ci			snprintf(ep->name, MAX3420_EPNAME_SIZE, "ep1-bulk-out");
118362306a36Sopenharmony_ci		} else { /* EP2 & EP3 are IN */
118462306a36Sopenharmony_ci			ep->ep_usb.caps.dir_in = true;
118562306a36Sopenharmony_ci			ep->ep_usb.caps.dir_out = false;
118662306a36Sopenharmony_ci			snprintf(ep->name, MAX3420_EPNAME_SIZE,
118762306a36Sopenharmony_ci				 "ep%d-bulk-in", idx);
118862306a36Sopenharmony_ci		}
118962306a36Sopenharmony_ci		ep->ep_usb.caps.type_iso = false;
119062306a36Sopenharmony_ci		ep->ep_usb.caps.type_int = false;
119162306a36Sopenharmony_ci		ep->ep_usb.caps.type_bulk = true;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci		list_add_tail(&ep->ep_usb.ep_list,
119462306a36Sopenharmony_ci			      &udc->gadget.ep_list);
119562306a36Sopenharmony_ci	}
119662306a36Sopenharmony_ci}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_cistatic int max3420_probe(struct spi_device *spi)
119962306a36Sopenharmony_ci{
120062306a36Sopenharmony_ci	struct max3420_udc *udc;
120162306a36Sopenharmony_ci	int err, irq;
120262306a36Sopenharmony_ci	u8 reg[8];
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) {
120562306a36Sopenharmony_ci		dev_err(&spi->dev, "UDC needs full duplex to work\n");
120662306a36Sopenharmony_ci		return -EINVAL;
120762306a36Sopenharmony_ci	}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	spi->mode = SPI_MODE_3;
121062306a36Sopenharmony_ci	spi->bits_per_word = 8;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	err = spi_setup(spi);
121362306a36Sopenharmony_ci	if (err) {
121462306a36Sopenharmony_ci		dev_err(&spi->dev, "Unable to setup SPI bus\n");
121562306a36Sopenharmony_ci		return -EFAULT;
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	udc = devm_kzalloc(&spi->dev, sizeof(*udc), GFP_KERNEL);
121962306a36Sopenharmony_ci	if (!udc)
122062306a36Sopenharmony_ci		return -ENOMEM;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	udc->spi = spi;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	udc->remote_wkp = 0;
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	/* Setup gadget structure */
122762306a36Sopenharmony_ci	udc->gadget.ops = &max3420_udc_ops;
122862306a36Sopenharmony_ci	udc->gadget.max_speed = USB_SPEED_FULL;
122962306a36Sopenharmony_ci	udc->gadget.speed = USB_SPEED_UNKNOWN;
123062306a36Sopenharmony_ci	udc->gadget.ep0 = &udc->ep[0].ep_usb;
123162306a36Sopenharmony_ci	udc->gadget.name = driver_name;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	spin_lock_init(&udc->lock);
123462306a36Sopenharmony_ci	mutex_init(&udc->spi_bus_mutex);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	udc->ep0req.ep = &udc->ep[0];
123762306a36Sopenharmony_ci	udc->ep0req.usb_req.buf = udc->ep0buf;
123862306a36Sopenharmony_ci	INIT_LIST_HEAD(&udc->ep0req.queue);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	/* setup Endpoints */
124162306a36Sopenharmony_ci	max3420_eps_init(udc);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	/* configure SPI */
124462306a36Sopenharmony_ci	spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8);
124562306a36Sopenharmony_ci	spi_wr8(udc, MAX3420_REG_PINCTL, FDUPSPI);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	err = usb_add_gadget_udc(&spi->dev, &udc->gadget);
124862306a36Sopenharmony_ci	if (err)
124962306a36Sopenharmony_ci		return err;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	udc->dev = &udc->gadget.dev;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	spi_set_drvdata(spi, udc);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	irq = of_irq_get_byname(spi->dev.of_node, "udc");
125662306a36Sopenharmony_ci	err = devm_request_irq(&spi->dev, irq, max3420_irq_handler, 0,
125762306a36Sopenharmony_ci			       "max3420", udc);
125862306a36Sopenharmony_ci	if (err < 0)
125962306a36Sopenharmony_ci		goto del_gadget;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	udc->thread_task = kthread_create(max3420_thread, udc,
126262306a36Sopenharmony_ci					  "max3420-thread");
126362306a36Sopenharmony_ci	if (IS_ERR(udc->thread_task)) {
126462306a36Sopenharmony_ci		err = PTR_ERR(udc->thread_task);
126562306a36Sopenharmony_ci		goto del_gadget;
126662306a36Sopenharmony_ci	}
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	irq = of_irq_get_byname(spi->dev.of_node, "vbus");
126962306a36Sopenharmony_ci	if (irq <= 0) { /* no vbus irq implies self-powered design */
127062306a36Sopenharmony_ci		udc->is_selfpowered = 1;
127162306a36Sopenharmony_ci		udc->vbus_active = true;
127262306a36Sopenharmony_ci		udc->todo |= UDC_START;
127362306a36Sopenharmony_ci		usb_udc_vbus_handler(&udc->gadget, udc->vbus_active);
127462306a36Sopenharmony_ci		usb_gadget_set_state(&udc->gadget, USB_STATE_POWERED);
127562306a36Sopenharmony_ci		max3420_start(udc);
127662306a36Sopenharmony_ci	} else {
127762306a36Sopenharmony_ci		udc->is_selfpowered = 0;
127862306a36Sopenharmony_ci		/* Detect current vbus status */
127962306a36Sopenharmony_ci		spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8);
128062306a36Sopenharmony_ci		if (reg[7] != 0xff)
128162306a36Sopenharmony_ci			udc->vbus_active = true;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci		err = devm_request_irq(&spi->dev, irq,
128462306a36Sopenharmony_ci				       max3420_vbus_handler, 0, "vbus", udc);
128562306a36Sopenharmony_ci		if (err < 0)
128662306a36Sopenharmony_ci			goto del_gadget;
128762306a36Sopenharmony_ci	}
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	return 0;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_cidel_gadget:
129262306a36Sopenharmony_ci	usb_del_gadget_udc(&udc->gadget);
129362306a36Sopenharmony_ci	return err;
129462306a36Sopenharmony_ci}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_cistatic void max3420_remove(struct spi_device *spi)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	struct max3420_udc *udc = spi_get_drvdata(spi);
129962306a36Sopenharmony_ci	unsigned long flags;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	usb_del_gadget_udc(&udc->gadget);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	spin_lock_irqsave(&udc->lock, flags);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	kthread_stop(udc->thread_task);
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	spin_unlock_irqrestore(&udc->lock, flags);
130862306a36Sopenharmony_ci}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_cistatic const struct of_device_id max3420_udc_of_match[] = {
131162306a36Sopenharmony_ci	{ .compatible = "maxim,max3420-udc"},
131262306a36Sopenharmony_ci	{ .compatible = "maxim,max3421-udc"},
131362306a36Sopenharmony_ci	{},
131462306a36Sopenharmony_ci};
131562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, max3420_udc_of_match);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_cistatic struct spi_driver max3420_driver = {
131862306a36Sopenharmony_ci	.driver = {
131962306a36Sopenharmony_ci		.name = "max3420-udc",
132062306a36Sopenharmony_ci		.of_match_table = max3420_udc_of_match,
132162306a36Sopenharmony_ci	},
132262306a36Sopenharmony_ci	.probe = max3420_probe,
132362306a36Sopenharmony_ci	.remove = max3420_remove,
132462306a36Sopenharmony_ci};
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_cimodule_spi_driver(max3420_driver);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
132962306a36Sopenharmony_ciMODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>");
133062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1331