148ba02b2SJassi Brar // SPDX-License-Identifier: GPL-2.0+ 248ba02b2SJassi Brar /* 348ba02b2SJassi Brar * MAX3420 Device Controller driver for USB. 448ba02b2SJassi Brar * 548ba02b2SJassi Brar * Author: Jaswinder Singh Brar <jaswinder.singh@linaro.org> 648ba02b2SJassi Brar * (C) Copyright 2019-2020 Linaro Ltd 748ba02b2SJassi Brar * 848ba02b2SJassi Brar * Based on: 948ba02b2SJassi Brar * o MAX3420E datasheet 1010fadd5eSAlexander A. Klimov * https://datasheets.maximintegrated.com/en/ds/MAX3420E.pdf 1148ba02b2SJassi Brar * o MAX342{0,1}E Programming Guides 1248ba02b2SJassi Brar * https://pdfserv.maximintegrated.com/en/an/AN3598.pdf 1348ba02b2SJassi Brar * https://pdfserv.maximintegrated.com/en/an/AN3785.pdf 1448ba02b2SJassi Brar */ 1548ba02b2SJassi Brar 1648ba02b2SJassi Brar #include <linux/delay.h> 1748ba02b2SJassi Brar #include <linux/device.h> 1848ba02b2SJassi Brar #include <linux/interrupt.h> 1948ba02b2SJassi Brar #include <linux/io.h> 2048ba02b2SJassi Brar #include <linux/module.h> 2148ba02b2SJassi Brar #include <linux/bitfield.h> 2248ba02b2SJassi Brar #include <linux/of_address.h> 2348ba02b2SJassi Brar #include <linux/of_device.h> 2448ba02b2SJassi Brar #include <linux/of_platform.h> 2548ba02b2SJassi Brar #include <linux/of_irq.h> 2648ba02b2SJassi Brar #include <linux/prefetch.h> 2748ba02b2SJassi Brar #include <linux/usb/ch9.h> 2848ba02b2SJassi Brar #include <linux/usb/gadget.h> 2948ba02b2SJassi Brar #include <linux/spi/spi.h> 3048ba02b2SJassi Brar #include <linux/gpio/consumer.h> 3148ba02b2SJassi Brar 3248ba02b2SJassi Brar #define MAX3420_MAX_EPS 4 3348ba02b2SJassi Brar #define MAX3420_EP_MAX_PACKET 64 /* Same for all Endpoints */ 3448ba02b2SJassi Brar #define MAX3420_EPNAME_SIZE 16 /* Buffer size for endpoint name */ 3548ba02b2SJassi Brar 3648ba02b2SJassi Brar #define MAX3420_ACKSTAT BIT(0) 3748ba02b2SJassi Brar 3848ba02b2SJassi Brar #define MAX3420_SPI_DIR_RD 0 /* read register from MAX3420 */ 3948ba02b2SJassi Brar #define MAX3420_SPI_DIR_WR 1 /* write register to MAX3420 */ 4048ba02b2SJassi Brar 4148ba02b2SJassi Brar /* SPI commands: */ 4248ba02b2SJassi Brar #define MAX3420_SPI_DIR_SHIFT 1 4348ba02b2SJassi Brar #define MAX3420_SPI_REG_SHIFT 3 4448ba02b2SJassi Brar 4548ba02b2SJassi Brar #define MAX3420_REG_EP0FIFO 0 4648ba02b2SJassi Brar #define MAX3420_REG_EP1FIFO 1 4748ba02b2SJassi Brar #define MAX3420_REG_EP2FIFO 2 4848ba02b2SJassi Brar #define MAX3420_REG_EP3FIFO 3 4948ba02b2SJassi Brar #define MAX3420_REG_SUDFIFO 4 5048ba02b2SJassi Brar #define MAX3420_REG_EP0BC 5 5148ba02b2SJassi Brar #define MAX3420_REG_EP1BC 6 5248ba02b2SJassi Brar #define MAX3420_REG_EP2BC 7 5348ba02b2SJassi Brar #define MAX3420_REG_EP3BC 8 5448ba02b2SJassi Brar 5548ba02b2SJassi Brar #define MAX3420_REG_EPSTALLS 9 5648ba02b2SJassi Brar #define ACKSTAT BIT(6) 5748ba02b2SJassi Brar #define STLSTAT BIT(5) 5848ba02b2SJassi Brar #define STLEP3IN BIT(4) 5948ba02b2SJassi Brar #define STLEP2IN BIT(3) 6048ba02b2SJassi Brar #define STLEP1OUT BIT(2) 6148ba02b2SJassi Brar #define STLEP0OUT BIT(1) 6248ba02b2SJassi Brar #define STLEP0IN BIT(0) 6348ba02b2SJassi Brar 6448ba02b2SJassi Brar #define MAX3420_REG_CLRTOGS 10 6548ba02b2SJassi Brar #define EP3DISAB BIT(7) 6648ba02b2SJassi Brar #define EP2DISAB BIT(6) 6748ba02b2SJassi Brar #define EP1DISAB BIT(5) 6848ba02b2SJassi Brar #define CTGEP3IN BIT(4) 6948ba02b2SJassi Brar #define CTGEP2IN BIT(3) 7048ba02b2SJassi Brar #define CTGEP1OUT BIT(2) 7148ba02b2SJassi Brar 7248ba02b2SJassi Brar #define MAX3420_REG_EPIRQ 11 7348ba02b2SJassi Brar #define MAX3420_REG_EPIEN 12 7448ba02b2SJassi Brar #define SUDAVIRQ BIT(5) 7548ba02b2SJassi Brar #define IN3BAVIRQ BIT(4) 7648ba02b2SJassi Brar #define IN2BAVIRQ BIT(3) 7748ba02b2SJassi Brar #define OUT1DAVIRQ BIT(2) 7848ba02b2SJassi Brar #define OUT0DAVIRQ BIT(1) 7948ba02b2SJassi Brar #define IN0BAVIRQ BIT(0) 8048ba02b2SJassi Brar 8148ba02b2SJassi Brar #define MAX3420_REG_USBIRQ 13 8248ba02b2SJassi Brar #define MAX3420_REG_USBIEN 14 8348ba02b2SJassi Brar #define OSCOKIRQ BIT(0) 8448ba02b2SJassi Brar #define RWUDNIRQ BIT(1) 8548ba02b2SJassi Brar #define BUSACTIRQ BIT(2) 8648ba02b2SJassi Brar #define URESIRQ BIT(3) 8748ba02b2SJassi Brar #define SUSPIRQ BIT(4) 8848ba02b2SJassi Brar #define NOVBUSIRQ BIT(5) 8948ba02b2SJassi Brar #define VBUSIRQ BIT(6) 9048ba02b2SJassi Brar #define URESDNIRQ BIT(7) 9148ba02b2SJassi Brar 9248ba02b2SJassi Brar #define MAX3420_REG_USBCTL 15 9348ba02b2SJassi Brar #define HOSCSTEN BIT(7) 9448ba02b2SJassi Brar #define VBGATE BIT(6) 9548ba02b2SJassi Brar #define CHIPRES BIT(5) 9648ba02b2SJassi Brar #define PWRDOWN BIT(4) 9748ba02b2SJassi Brar #define CONNECT BIT(3) 9848ba02b2SJassi Brar #define SIGRWU BIT(2) 9948ba02b2SJassi Brar 10048ba02b2SJassi Brar #define MAX3420_REG_CPUCTL 16 10148ba02b2SJassi Brar #define IE BIT(0) 10248ba02b2SJassi Brar 10348ba02b2SJassi Brar #define MAX3420_REG_PINCTL 17 10448ba02b2SJassi Brar #define EP3INAK BIT(7) 10548ba02b2SJassi Brar #define EP2INAK BIT(6) 10648ba02b2SJassi Brar #define EP0INAK BIT(5) 10748ba02b2SJassi Brar #define FDUPSPI BIT(4) 10848ba02b2SJassi Brar #define INTLEVEL BIT(3) 10948ba02b2SJassi Brar #define POSINT BIT(2) 11048ba02b2SJassi Brar #define GPXB BIT(1) 11148ba02b2SJassi Brar #define GPXA BIT(0) 11248ba02b2SJassi Brar 11348ba02b2SJassi Brar #define MAX3420_REG_REVISION 18 11448ba02b2SJassi Brar 11548ba02b2SJassi Brar #define MAX3420_REG_FNADDR 19 11648ba02b2SJassi Brar #define FNADDR_MASK 0x7f 11748ba02b2SJassi Brar 11848ba02b2SJassi Brar #define MAX3420_REG_IOPINS 20 11948ba02b2SJassi Brar #define MAX3420_REG_IOPINS2 21 12048ba02b2SJassi Brar #define MAX3420_REG_GPINIRQ 22 12148ba02b2SJassi Brar #define MAX3420_REG_GPINIEN 23 12248ba02b2SJassi Brar #define MAX3420_REG_GPINPOL 24 12348ba02b2SJassi Brar #define MAX3420_REG_HIRQ 25 12448ba02b2SJassi Brar #define MAX3420_REG_HIEN 26 12548ba02b2SJassi Brar #define MAX3420_REG_MODE 27 12648ba02b2SJassi Brar #define MAX3420_REG_PERADDR 28 12748ba02b2SJassi Brar #define MAX3420_REG_HCTL 29 12848ba02b2SJassi Brar #define MAX3420_REG_HXFR 30 12948ba02b2SJassi Brar #define MAX3420_REG_HRSL 31 13048ba02b2SJassi Brar 13148ba02b2SJassi Brar #define ENABLE_IRQ BIT(0) 13248ba02b2SJassi Brar #define IOPIN_UPDATE BIT(1) 13348ba02b2SJassi Brar #define REMOTE_WAKEUP BIT(2) 13448ba02b2SJassi Brar #define CONNECT_HOST GENMASK(4, 3) 13548ba02b2SJassi Brar #define HCONNECT (1 << 3) 13648ba02b2SJassi Brar #define HDISCONNECT (3 << 3) 13748ba02b2SJassi Brar #define UDC_START GENMASK(6, 5) 13848ba02b2SJassi Brar #define START (1 << 5) 13948ba02b2SJassi Brar #define STOP (3 << 5) 14048ba02b2SJassi Brar #define ENABLE_EP GENMASK(8, 7) 14148ba02b2SJassi Brar #define ENABLE (1 << 7) 14248ba02b2SJassi Brar #define DISABLE (3 << 7) 14348ba02b2SJassi Brar #define STALL_EP GENMASK(10, 9) 14448ba02b2SJassi Brar #define STALL (1 << 9) 14548ba02b2SJassi Brar #define UNSTALL (3 << 9) 14648ba02b2SJassi Brar 14748ba02b2SJassi Brar #define MAX3420_CMD(c) FIELD_PREP(GENMASK(7, 3), c) 14848ba02b2SJassi Brar #define MAX3420_SPI_CMD_RD(c) (MAX3420_CMD(c) | (0 << 1)) 14948ba02b2SJassi Brar #define MAX3420_SPI_CMD_WR(c) (MAX3420_CMD(c) | (1 << 1)) 15048ba02b2SJassi Brar 15148ba02b2SJassi Brar struct max3420_req { 15248ba02b2SJassi Brar struct usb_request usb_req; 15348ba02b2SJassi Brar struct list_head queue; 15448ba02b2SJassi Brar struct max3420_ep *ep; 15548ba02b2SJassi Brar }; 15648ba02b2SJassi Brar 15748ba02b2SJassi Brar struct max3420_ep { 15848ba02b2SJassi Brar struct usb_ep ep_usb; 15948ba02b2SJassi Brar struct max3420_udc *udc; 16048ba02b2SJassi Brar struct list_head queue; 16148ba02b2SJassi Brar char name[MAX3420_EPNAME_SIZE]; 16248ba02b2SJassi Brar unsigned int maxpacket; 16348ba02b2SJassi Brar spinlock_t lock; 16448ba02b2SJassi Brar int halted; 16548ba02b2SJassi Brar u32 todo; 16648ba02b2SJassi Brar int id; 16748ba02b2SJassi Brar }; 16848ba02b2SJassi Brar 16948ba02b2SJassi Brar struct max3420_udc { 17048ba02b2SJassi Brar struct usb_gadget gadget; 17148ba02b2SJassi Brar struct max3420_ep ep[MAX3420_MAX_EPS]; 17248ba02b2SJassi Brar struct usb_gadget_driver *driver; 17348ba02b2SJassi Brar struct task_struct *thread_task; 17448ba02b2SJassi Brar int remote_wkp, is_selfpowered; 17548ba02b2SJassi Brar bool vbus_active, softconnect; 17648ba02b2SJassi Brar struct usb_ctrlrequest setup; 17748ba02b2SJassi Brar struct mutex spi_bus_mutex; 17848ba02b2SJassi Brar struct max3420_req ep0req; 17948ba02b2SJassi Brar struct spi_device *spi; 18048ba02b2SJassi Brar struct device *dev; 18148ba02b2SJassi Brar spinlock_t lock; 18248ba02b2SJassi Brar bool suspended; 18348ba02b2SJassi Brar u8 ep0buf[64]; 18448ba02b2SJassi Brar u32 todo; 18548ba02b2SJassi Brar }; 18648ba02b2SJassi Brar 18748ba02b2SJassi Brar #define to_max3420_req(r) container_of((r), struct max3420_req, usb_req) 18848ba02b2SJassi Brar #define to_max3420_ep(e) container_of((e), struct max3420_ep, ep_usb) 18948ba02b2SJassi Brar #define to_udc(g) container_of((g), struct max3420_udc, gadget) 19048ba02b2SJassi Brar 19148ba02b2SJassi Brar #define DRIVER_DESC "MAX3420 USB Device-Mode Driver" 19248ba02b2SJassi Brar static const char driver_name[] = "max3420-udc"; 19348ba02b2SJassi Brar 19448ba02b2SJassi Brar /* Control endpoint configuration.*/ 19548ba02b2SJassi Brar static const struct usb_endpoint_descriptor ep0_desc = { 19648ba02b2SJassi Brar .bEndpointAddress = USB_DIR_OUT, 19748ba02b2SJassi Brar .bmAttributes = USB_ENDPOINT_XFER_CONTROL, 19848ba02b2SJassi Brar .wMaxPacketSize = cpu_to_le16(MAX3420_EP_MAX_PACKET), 19948ba02b2SJassi Brar }; 20048ba02b2SJassi Brar 20148ba02b2SJassi Brar static void spi_ack_ctrl(struct max3420_udc *udc) 20248ba02b2SJassi Brar { 20348ba02b2SJassi Brar struct spi_device *spi = udc->spi; 20448ba02b2SJassi Brar struct spi_transfer transfer; 20548ba02b2SJassi Brar struct spi_message msg; 20648ba02b2SJassi Brar u8 txdata[1]; 20748ba02b2SJassi Brar 20848ba02b2SJassi Brar memset(&transfer, 0, sizeof(transfer)); 20948ba02b2SJassi Brar 21048ba02b2SJassi Brar spi_message_init(&msg); 21148ba02b2SJassi Brar 21248ba02b2SJassi Brar txdata[0] = MAX3420_ACKSTAT; 21348ba02b2SJassi Brar transfer.tx_buf = txdata; 21448ba02b2SJassi Brar transfer.len = 1; 21548ba02b2SJassi Brar 21648ba02b2SJassi Brar spi_message_add_tail(&transfer, &msg); 21748ba02b2SJassi Brar spi_sync(spi, &msg); 21848ba02b2SJassi Brar } 21948ba02b2SJassi Brar 22048ba02b2SJassi Brar static u8 spi_rd8_ack(struct max3420_udc *udc, u8 reg, int actstat) 22148ba02b2SJassi Brar { 22248ba02b2SJassi Brar struct spi_device *spi = udc->spi; 22348ba02b2SJassi Brar struct spi_transfer transfer; 22448ba02b2SJassi Brar struct spi_message msg; 22548ba02b2SJassi Brar u8 txdata[2], rxdata[2]; 22648ba02b2SJassi Brar 22748ba02b2SJassi Brar memset(&transfer, 0, sizeof(transfer)); 22848ba02b2SJassi Brar 22948ba02b2SJassi Brar spi_message_init(&msg); 23048ba02b2SJassi Brar 23148ba02b2SJassi Brar txdata[0] = MAX3420_SPI_CMD_RD(reg) | (actstat ? MAX3420_ACKSTAT : 0); 23248ba02b2SJassi Brar transfer.tx_buf = txdata; 23348ba02b2SJassi Brar transfer.rx_buf = rxdata; 23448ba02b2SJassi Brar transfer.len = 2; 23548ba02b2SJassi Brar 23648ba02b2SJassi Brar spi_message_add_tail(&transfer, &msg); 23748ba02b2SJassi Brar spi_sync(spi, &msg); 23848ba02b2SJassi Brar 23948ba02b2SJassi Brar return rxdata[1]; 24048ba02b2SJassi Brar } 24148ba02b2SJassi Brar 24248ba02b2SJassi Brar static u8 spi_rd8(struct max3420_udc *udc, u8 reg) 24348ba02b2SJassi Brar { 24448ba02b2SJassi Brar return spi_rd8_ack(udc, reg, 0); 24548ba02b2SJassi Brar } 24648ba02b2SJassi Brar 24748ba02b2SJassi Brar static void spi_wr8_ack(struct max3420_udc *udc, u8 reg, u8 val, int actstat) 24848ba02b2SJassi Brar { 24948ba02b2SJassi Brar struct spi_device *spi = udc->spi; 25048ba02b2SJassi Brar struct spi_transfer transfer; 25148ba02b2SJassi Brar struct spi_message msg; 25248ba02b2SJassi Brar u8 txdata[2]; 25348ba02b2SJassi Brar 25448ba02b2SJassi Brar memset(&transfer, 0, sizeof(transfer)); 25548ba02b2SJassi Brar 25648ba02b2SJassi Brar spi_message_init(&msg); 25748ba02b2SJassi Brar 25848ba02b2SJassi Brar txdata[0] = MAX3420_SPI_CMD_WR(reg) | (actstat ? MAX3420_ACKSTAT : 0); 25948ba02b2SJassi Brar txdata[1] = val; 26048ba02b2SJassi Brar 26148ba02b2SJassi Brar transfer.tx_buf = txdata; 26248ba02b2SJassi Brar transfer.len = 2; 26348ba02b2SJassi Brar 26448ba02b2SJassi Brar spi_message_add_tail(&transfer, &msg); 26548ba02b2SJassi Brar spi_sync(spi, &msg); 26648ba02b2SJassi Brar } 26748ba02b2SJassi Brar 26848ba02b2SJassi Brar static void spi_wr8(struct max3420_udc *udc, u8 reg, u8 val) 26948ba02b2SJassi Brar { 27048ba02b2SJassi Brar spi_wr8_ack(udc, reg, val, 0); 27148ba02b2SJassi Brar } 27248ba02b2SJassi Brar 27348ba02b2SJassi Brar static void spi_rd_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len) 27448ba02b2SJassi Brar { 27548ba02b2SJassi Brar struct spi_device *spi = udc->spi; 27648ba02b2SJassi Brar struct spi_transfer transfer; 27748ba02b2SJassi Brar struct spi_message msg; 27848ba02b2SJassi Brar u8 local_buf[MAX3420_EP_MAX_PACKET + 1] = {}; 27948ba02b2SJassi Brar 28048ba02b2SJassi Brar memset(&transfer, 0, sizeof(transfer)); 28148ba02b2SJassi Brar 28248ba02b2SJassi Brar spi_message_init(&msg); 28348ba02b2SJassi Brar 28448ba02b2SJassi Brar local_buf[0] = MAX3420_SPI_CMD_RD(reg); 28548ba02b2SJassi Brar transfer.tx_buf = &local_buf[0]; 28648ba02b2SJassi Brar transfer.rx_buf = &local_buf[0]; 28748ba02b2SJassi Brar transfer.len = len + 1; 28848ba02b2SJassi Brar 28948ba02b2SJassi Brar spi_message_add_tail(&transfer, &msg); 29048ba02b2SJassi Brar spi_sync(spi, &msg); 29148ba02b2SJassi Brar 29248ba02b2SJassi Brar memcpy(buf, &local_buf[1], len); 29348ba02b2SJassi Brar } 29448ba02b2SJassi Brar 29548ba02b2SJassi Brar static void spi_wr_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len) 29648ba02b2SJassi Brar { 29748ba02b2SJassi Brar struct spi_device *spi = udc->spi; 29848ba02b2SJassi Brar struct spi_transfer transfer; 29948ba02b2SJassi Brar struct spi_message msg; 30048ba02b2SJassi Brar u8 local_buf[MAX3420_EP_MAX_PACKET + 1] = {}; 30148ba02b2SJassi Brar 30248ba02b2SJassi Brar memset(&transfer, 0, sizeof(transfer)); 30348ba02b2SJassi Brar 30448ba02b2SJassi Brar spi_message_init(&msg); 30548ba02b2SJassi Brar 30648ba02b2SJassi Brar local_buf[0] = MAX3420_SPI_CMD_WR(reg); 30748ba02b2SJassi Brar memcpy(&local_buf[1], buf, len); 30848ba02b2SJassi Brar 30948ba02b2SJassi Brar transfer.tx_buf = local_buf; 31048ba02b2SJassi Brar transfer.len = len + 1; 31148ba02b2SJassi Brar 31248ba02b2SJassi Brar spi_message_add_tail(&transfer, &msg); 31348ba02b2SJassi Brar spi_sync(spi, &msg); 31448ba02b2SJassi Brar } 31548ba02b2SJassi Brar 31648ba02b2SJassi Brar static int spi_max3420_enable(struct max3420_ep *ep) 31748ba02b2SJassi Brar { 31848ba02b2SJassi Brar struct max3420_udc *udc = ep->udc; 31948ba02b2SJassi Brar unsigned long flags; 32048ba02b2SJassi Brar u8 epdis, epien; 32148ba02b2SJassi Brar int todo; 32248ba02b2SJassi Brar 32348ba02b2SJassi Brar spin_lock_irqsave(&ep->lock, flags); 32448ba02b2SJassi Brar todo = ep->todo & ENABLE_EP; 32548ba02b2SJassi Brar ep->todo &= ~ENABLE_EP; 32648ba02b2SJassi Brar spin_unlock_irqrestore(&ep->lock, flags); 32748ba02b2SJassi Brar 32848ba02b2SJassi Brar if (!todo || ep->id == 0) 32948ba02b2SJassi Brar return false; 33048ba02b2SJassi Brar 33148ba02b2SJassi Brar epien = spi_rd8(udc, MAX3420_REG_EPIEN); 33248ba02b2SJassi Brar epdis = spi_rd8(udc, MAX3420_REG_CLRTOGS); 33348ba02b2SJassi Brar 33448ba02b2SJassi Brar if (todo == ENABLE) { 33548ba02b2SJassi Brar epdis &= ~BIT(ep->id + 4); 33648ba02b2SJassi Brar epien |= BIT(ep->id + 1); 33748ba02b2SJassi Brar } else { 33848ba02b2SJassi Brar epdis |= BIT(ep->id + 4); 33948ba02b2SJassi Brar epien &= ~BIT(ep->id + 1); 34048ba02b2SJassi Brar } 34148ba02b2SJassi Brar 34248ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_CLRTOGS, epdis); 34348ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_EPIEN, epien); 34448ba02b2SJassi Brar 34548ba02b2SJassi Brar return true; 34648ba02b2SJassi Brar } 34748ba02b2SJassi Brar 34848ba02b2SJassi Brar static int spi_max3420_stall(struct max3420_ep *ep) 34948ba02b2SJassi Brar { 35048ba02b2SJassi Brar struct max3420_udc *udc = ep->udc; 35148ba02b2SJassi Brar unsigned long flags; 35248ba02b2SJassi Brar u8 epstalls; 35348ba02b2SJassi Brar int todo; 35448ba02b2SJassi Brar 35548ba02b2SJassi Brar spin_lock_irqsave(&ep->lock, flags); 35648ba02b2SJassi Brar todo = ep->todo & STALL_EP; 35748ba02b2SJassi Brar ep->todo &= ~STALL_EP; 35848ba02b2SJassi Brar spin_unlock_irqrestore(&ep->lock, flags); 35948ba02b2SJassi Brar 36048ba02b2SJassi Brar if (!todo || ep->id == 0) 36148ba02b2SJassi Brar return false; 36248ba02b2SJassi Brar 36348ba02b2SJassi Brar epstalls = spi_rd8(udc, MAX3420_REG_EPSTALLS); 36448ba02b2SJassi Brar if (todo == STALL) { 36548ba02b2SJassi Brar ep->halted = 1; 36648ba02b2SJassi Brar epstalls |= BIT(ep->id + 1); 36748ba02b2SJassi Brar } else { 36848ba02b2SJassi Brar u8 clrtogs; 36948ba02b2SJassi Brar 37048ba02b2SJassi Brar ep->halted = 0; 37148ba02b2SJassi Brar epstalls &= ~BIT(ep->id + 1); 37248ba02b2SJassi Brar clrtogs = spi_rd8(udc, MAX3420_REG_CLRTOGS); 37348ba02b2SJassi Brar clrtogs |= BIT(ep->id + 1); 37448ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_CLRTOGS, clrtogs); 37548ba02b2SJassi Brar } 37648ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_EPSTALLS, epstalls | ACKSTAT); 37748ba02b2SJassi Brar 37848ba02b2SJassi Brar return true; 37948ba02b2SJassi Brar } 38048ba02b2SJassi Brar 38148ba02b2SJassi Brar static int spi_max3420_rwkup(struct max3420_udc *udc) 38248ba02b2SJassi Brar { 38348ba02b2SJassi Brar unsigned long flags; 38448ba02b2SJassi Brar int wake_remote; 38548ba02b2SJassi Brar u8 usbctl; 38648ba02b2SJassi Brar 38748ba02b2SJassi Brar spin_lock_irqsave(&udc->lock, flags); 38848ba02b2SJassi Brar wake_remote = udc->todo & REMOTE_WAKEUP; 38948ba02b2SJassi Brar udc->todo &= ~REMOTE_WAKEUP; 39048ba02b2SJassi Brar spin_unlock_irqrestore(&udc->lock, flags); 39148ba02b2SJassi Brar 39248ba02b2SJassi Brar if (!wake_remote || !udc->suspended) 39348ba02b2SJassi Brar return false; 39448ba02b2SJassi Brar 39548ba02b2SJassi Brar /* Set Remote-WkUp Signal*/ 39648ba02b2SJassi Brar usbctl = spi_rd8(udc, MAX3420_REG_USBCTL); 39748ba02b2SJassi Brar usbctl |= SIGRWU; 39848ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBCTL, usbctl); 39948ba02b2SJassi Brar 40048ba02b2SJassi Brar msleep_interruptible(5); 40148ba02b2SJassi Brar 40248ba02b2SJassi Brar /* Clear Remote-WkUp Signal*/ 40348ba02b2SJassi Brar usbctl = spi_rd8(udc, MAX3420_REG_USBCTL); 40448ba02b2SJassi Brar usbctl &= ~SIGRWU; 40548ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBCTL, usbctl); 40648ba02b2SJassi Brar 40748ba02b2SJassi Brar udc->suspended = false; 40848ba02b2SJassi Brar 40948ba02b2SJassi Brar return true; 41048ba02b2SJassi Brar } 41148ba02b2SJassi Brar 41248ba02b2SJassi Brar static void max3420_nuke(struct max3420_ep *ep, int status); 41348ba02b2SJassi Brar static void __max3420_stop(struct max3420_udc *udc) 41448ba02b2SJassi Brar { 41548ba02b2SJassi Brar u8 val; 41648ba02b2SJassi Brar int i; 41748ba02b2SJassi Brar 41848ba02b2SJassi Brar /* clear all pending requests */ 41948ba02b2SJassi Brar for (i = 1; i < MAX3420_MAX_EPS; i++) 42048ba02b2SJassi Brar max3420_nuke(&udc->ep[i], -ECONNRESET); 42148ba02b2SJassi Brar 42248ba02b2SJassi Brar /* Disable IRQ to CPU */ 42348ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_CPUCTL, 0); 42448ba02b2SJassi Brar 42548ba02b2SJassi Brar val = spi_rd8(udc, MAX3420_REG_USBCTL); 42648ba02b2SJassi Brar val |= PWRDOWN; 42748ba02b2SJassi Brar if (udc->is_selfpowered) 42848ba02b2SJassi Brar val &= ~HOSCSTEN; 42948ba02b2SJassi Brar else 43048ba02b2SJassi Brar val |= HOSCSTEN; 43148ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBCTL, val); 43248ba02b2SJassi Brar } 43348ba02b2SJassi Brar 43448ba02b2SJassi Brar static void __max3420_start(struct max3420_udc *udc) 43548ba02b2SJassi Brar { 43648ba02b2SJassi Brar u8 val; 43748ba02b2SJassi Brar 43848ba02b2SJassi Brar /* Need this delay if bus-powered, 43948ba02b2SJassi Brar * but even for self-powered it helps stability 44048ba02b2SJassi Brar */ 44148ba02b2SJassi Brar msleep_interruptible(250); 44248ba02b2SJassi Brar 44348ba02b2SJassi Brar /* configure SPI */ 44448ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_PINCTL, FDUPSPI); 44548ba02b2SJassi Brar 44648ba02b2SJassi Brar /* Chip Reset */ 44748ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBCTL, CHIPRES); 44848ba02b2SJassi Brar msleep_interruptible(5); 44948ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBCTL, 0); 45048ba02b2SJassi Brar 45148ba02b2SJassi Brar /* Poll for OSC to stabilize */ 45248ba02b2SJassi Brar while (1) { 45348ba02b2SJassi Brar val = spi_rd8(udc, MAX3420_REG_USBIRQ); 45448ba02b2SJassi Brar if (val & OSCOKIRQ) 45548ba02b2SJassi Brar break; 45648ba02b2SJassi Brar cond_resched(); 45748ba02b2SJassi Brar } 45848ba02b2SJassi Brar 45948ba02b2SJassi Brar /* Enable PULL-UP only when Vbus detected */ 46048ba02b2SJassi Brar val = spi_rd8(udc, MAX3420_REG_USBCTL); 46148ba02b2SJassi Brar val |= VBGATE | CONNECT; 46248ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBCTL, val); 46348ba02b2SJassi Brar 46448ba02b2SJassi Brar val = URESDNIRQ | URESIRQ; 46548ba02b2SJassi Brar if (udc->is_selfpowered) 46648ba02b2SJassi Brar val |= NOVBUSIRQ; 46748ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBIEN, val); 46848ba02b2SJassi Brar 46948ba02b2SJassi Brar /* Enable only EP0 interrupts */ 47048ba02b2SJassi Brar val = IN0BAVIRQ | OUT0DAVIRQ | SUDAVIRQ; 47148ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_EPIEN, val); 47248ba02b2SJassi Brar 47348ba02b2SJassi Brar /* Enable IRQ to CPU */ 47448ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_CPUCTL, IE); 47548ba02b2SJassi Brar } 47648ba02b2SJassi Brar 47748ba02b2SJassi Brar static int max3420_start(struct max3420_udc *udc) 47848ba02b2SJassi Brar { 47948ba02b2SJassi Brar unsigned long flags; 48048ba02b2SJassi Brar int todo; 48148ba02b2SJassi Brar 48248ba02b2SJassi Brar spin_lock_irqsave(&udc->lock, flags); 48348ba02b2SJassi Brar todo = udc->todo & UDC_START; 48448ba02b2SJassi Brar udc->todo &= ~UDC_START; 48548ba02b2SJassi Brar spin_unlock_irqrestore(&udc->lock, flags); 48648ba02b2SJassi Brar 48748ba02b2SJassi Brar if (!todo) 48848ba02b2SJassi Brar return false; 48948ba02b2SJassi Brar 49048ba02b2SJassi Brar if (udc->vbus_active && udc->softconnect) 49148ba02b2SJassi Brar __max3420_start(udc); 49248ba02b2SJassi Brar else 49348ba02b2SJassi Brar __max3420_stop(udc); 49448ba02b2SJassi Brar 49548ba02b2SJassi Brar return true; 49648ba02b2SJassi Brar } 49748ba02b2SJassi Brar 49848ba02b2SJassi Brar static irqreturn_t max3420_vbus_handler(int irq, void *dev_id) 49948ba02b2SJassi Brar { 50048ba02b2SJassi Brar struct max3420_udc *udc = dev_id; 50148ba02b2SJassi Brar unsigned long flags; 50248ba02b2SJassi Brar 50348ba02b2SJassi Brar spin_lock_irqsave(&udc->lock, flags); 50448ba02b2SJassi Brar /* its a vbus change interrupt */ 50548ba02b2SJassi Brar udc->vbus_active = !udc->vbus_active; 50648ba02b2SJassi Brar udc->todo |= UDC_START; 50748ba02b2SJassi Brar usb_udc_vbus_handler(&udc->gadget, udc->vbus_active); 50848ba02b2SJassi Brar usb_gadget_set_state(&udc->gadget, udc->vbus_active 50948ba02b2SJassi Brar ? USB_STATE_POWERED : USB_STATE_NOTATTACHED); 51048ba02b2SJassi Brar spin_unlock_irqrestore(&udc->lock, flags); 51148ba02b2SJassi Brar 51237aadc68SPeter Zijlstra if (udc->thread_task) 51348ba02b2SJassi Brar wake_up_process(udc->thread_task); 51448ba02b2SJassi Brar 51548ba02b2SJassi Brar return IRQ_HANDLED; 51648ba02b2SJassi Brar } 51748ba02b2SJassi Brar 51848ba02b2SJassi Brar static irqreturn_t max3420_irq_handler(int irq, void *dev_id) 51948ba02b2SJassi Brar { 52048ba02b2SJassi Brar struct max3420_udc *udc = dev_id; 52148ba02b2SJassi Brar struct spi_device *spi = udc->spi; 52248ba02b2SJassi Brar unsigned long flags; 52348ba02b2SJassi Brar 52448ba02b2SJassi Brar spin_lock_irqsave(&udc->lock, flags); 52548ba02b2SJassi Brar if ((udc->todo & ENABLE_IRQ) == 0) { 52648ba02b2SJassi Brar disable_irq_nosync(spi->irq); 52748ba02b2SJassi Brar udc->todo |= ENABLE_IRQ; 52848ba02b2SJassi Brar } 52948ba02b2SJassi Brar spin_unlock_irqrestore(&udc->lock, flags); 53048ba02b2SJassi Brar 53137aadc68SPeter Zijlstra if (udc->thread_task) 53248ba02b2SJassi Brar wake_up_process(udc->thread_task); 53348ba02b2SJassi Brar 53448ba02b2SJassi Brar return IRQ_HANDLED; 53548ba02b2SJassi Brar } 53648ba02b2SJassi Brar 53748ba02b2SJassi Brar static void max3420_getstatus(struct max3420_udc *udc) 53848ba02b2SJassi Brar { 53948ba02b2SJassi Brar struct max3420_ep *ep; 54048ba02b2SJassi Brar u16 status = 0; 54148ba02b2SJassi Brar 54248ba02b2SJassi Brar switch (udc->setup.bRequestType & USB_RECIP_MASK) { 54348ba02b2SJassi Brar case USB_RECIP_DEVICE: 54448ba02b2SJassi Brar /* Get device status */ 54548ba02b2SJassi Brar status = udc->gadget.is_selfpowered << USB_DEVICE_SELF_POWERED; 54648ba02b2SJassi Brar status |= (udc->remote_wkp << USB_DEVICE_REMOTE_WAKEUP); 54748ba02b2SJassi Brar break; 54848ba02b2SJassi Brar case USB_RECIP_INTERFACE: 54948ba02b2SJassi Brar if (udc->driver->setup(&udc->gadget, &udc->setup) < 0) 55048ba02b2SJassi Brar goto stall; 55148ba02b2SJassi Brar break; 55248ba02b2SJassi Brar case USB_RECIP_ENDPOINT: 55348ba02b2SJassi Brar ep = &udc->ep[udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK]; 55448ba02b2SJassi Brar if (udc->setup.wIndex & USB_DIR_IN) { 55548ba02b2SJassi Brar if (!ep->ep_usb.caps.dir_in) 55648ba02b2SJassi Brar goto stall; 55748ba02b2SJassi Brar } else { 55848ba02b2SJassi Brar if (!ep->ep_usb.caps.dir_out) 55948ba02b2SJassi Brar goto stall; 56048ba02b2SJassi Brar } 56148ba02b2SJassi Brar if (ep->halted) 56248ba02b2SJassi Brar status = 1 << USB_ENDPOINT_HALT; 56348ba02b2SJassi Brar break; 56448ba02b2SJassi Brar default: 56548ba02b2SJassi Brar goto stall; 56648ba02b2SJassi Brar } 56748ba02b2SJassi Brar 56848ba02b2SJassi Brar status = cpu_to_le16(status); 56948ba02b2SJassi Brar spi_wr_buf(udc, MAX3420_REG_EP0FIFO, &status, 2); 57048ba02b2SJassi Brar spi_wr8_ack(udc, MAX3420_REG_EP0BC, 2, 1); 57148ba02b2SJassi Brar return; 57248ba02b2SJassi Brar stall: 57348ba02b2SJassi Brar dev_err(udc->dev, "Can't respond to getstatus request\n"); 57448ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_EPSTALLS, STLEP0IN | STLEP0OUT | STLSTAT); 57548ba02b2SJassi Brar } 57648ba02b2SJassi Brar 57748ba02b2SJassi Brar static void max3420_set_clear_feature(struct max3420_udc *udc) 57848ba02b2SJassi Brar { 57948ba02b2SJassi Brar struct max3420_ep *ep; 58048ba02b2SJassi Brar int set = udc->setup.bRequest == USB_REQ_SET_FEATURE; 58148ba02b2SJassi Brar unsigned long flags; 58248ba02b2SJassi Brar int id; 58348ba02b2SJassi Brar 58448ba02b2SJassi Brar switch (udc->setup.bRequestType) { 58548ba02b2SJassi Brar case USB_RECIP_DEVICE: 58648ba02b2SJassi Brar if (udc->setup.wValue != USB_DEVICE_REMOTE_WAKEUP) 58748ba02b2SJassi Brar break; 58848ba02b2SJassi Brar 58948ba02b2SJassi Brar if (udc->setup.bRequest == USB_REQ_SET_FEATURE) 59048ba02b2SJassi Brar udc->remote_wkp = 1; 59148ba02b2SJassi Brar else 59248ba02b2SJassi Brar udc->remote_wkp = 0; 59348ba02b2SJassi Brar 59448ba02b2SJassi Brar return spi_ack_ctrl(udc); 59548ba02b2SJassi Brar 59648ba02b2SJassi Brar case USB_RECIP_ENDPOINT: 59748ba02b2SJassi Brar if (udc->setup.wValue != USB_ENDPOINT_HALT) 59848ba02b2SJassi Brar break; 59948ba02b2SJassi Brar 60048ba02b2SJassi Brar id = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK; 60148ba02b2SJassi Brar ep = &udc->ep[id]; 60248ba02b2SJassi Brar 60348ba02b2SJassi Brar spin_lock_irqsave(&ep->lock, flags); 60448ba02b2SJassi Brar ep->todo &= ~STALL_EP; 60548ba02b2SJassi Brar if (set) 60648ba02b2SJassi Brar ep->todo |= STALL; 60748ba02b2SJassi Brar else 60848ba02b2SJassi Brar ep->todo |= UNSTALL; 60948ba02b2SJassi Brar spin_unlock_irqrestore(&ep->lock, flags); 61048ba02b2SJassi Brar 61148ba02b2SJassi Brar spi_max3420_stall(ep); 61248ba02b2SJassi Brar return; 61348ba02b2SJassi Brar default: 61448ba02b2SJassi Brar break; 61548ba02b2SJassi Brar } 61648ba02b2SJassi Brar 61748ba02b2SJassi Brar dev_err(udc->dev, "Can't respond to SET/CLEAR FEATURE\n"); 61848ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_EPSTALLS, STLEP0IN | STLEP0OUT | STLSTAT); 61948ba02b2SJassi Brar } 62048ba02b2SJassi Brar 62148ba02b2SJassi Brar static void max3420_handle_setup(struct max3420_udc *udc) 62248ba02b2SJassi Brar { 62348ba02b2SJassi Brar struct usb_ctrlrequest setup; 62448ba02b2SJassi Brar 62548ba02b2SJassi Brar spi_rd_buf(udc, MAX3420_REG_SUDFIFO, (void *)&setup, 8); 62648ba02b2SJassi Brar 62748ba02b2SJassi Brar udc->setup = setup; 62848ba02b2SJassi Brar udc->setup.wValue = cpu_to_le16(setup.wValue); 62948ba02b2SJassi Brar udc->setup.wIndex = cpu_to_le16(setup.wIndex); 63048ba02b2SJassi Brar udc->setup.wLength = cpu_to_le16(setup.wLength); 63148ba02b2SJassi Brar 63248ba02b2SJassi Brar switch (udc->setup.bRequest) { 63348ba02b2SJassi Brar case USB_REQ_GET_STATUS: 63448ba02b2SJassi Brar /* Data+Status phase form udc */ 63548ba02b2SJassi Brar if ((udc->setup.bRequestType & 63648ba02b2SJassi Brar (USB_DIR_IN | USB_TYPE_MASK)) != 63748ba02b2SJassi Brar (USB_DIR_IN | USB_TYPE_STANDARD)) { 63848ba02b2SJassi Brar break; 63948ba02b2SJassi Brar } 64048ba02b2SJassi Brar return max3420_getstatus(udc); 64148ba02b2SJassi Brar case USB_REQ_SET_ADDRESS: 64248ba02b2SJassi Brar /* Status phase from udc */ 64348ba02b2SJassi Brar if (udc->setup.bRequestType != (USB_DIR_OUT | 64448ba02b2SJassi Brar USB_TYPE_STANDARD | USB_RECIP_DEVICE)) { 64548ba02b2SJassi Brar break; 64648ba02b2SJassi Brar } 6471a4f38a6SLee Jones spi_rd8_ack(udc, MAX3420_REG_FNADDR, 1); 64848ba02b2SJassi Brar dev_dbg(udc->dev, "Assigned Address=%d\n", udc->setup.wValue); 64948ba02b2SJassi Brar return; 65048ba02b2SJassi Brar case USB_REQ_CLEAR_FEATURE: 65148ba02b2SJassi Brar case USB_REQ_SET_FEATURE: 65248ba02b2SJassi Brar /* Requests with no data phase, status phase from udc */ 65348ba02b2SJassi Brar if ((udc->setup.bRequestType & USB_TYPE_MASK) 65448ba02b2SJassi Brar != USB_TYPE_STANDARD) 65548ba02b2SJassi Brar break; 65648ba02b2SJassi Brar return max3420_set_clear_feature(udc); 65748ba02b2SJassi Brar default: 65848ba02b2SJassi Brar break; 65948ba02b2SJassi Brar } 66048ba02b2SJassi Brar 66148ba02b2SJassi Brar if (udc->driver->setup(&udc->gadget, &setup) < 0) { 66248ba02b2SJassi Brar /* Stall EP0 */ 66348ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_EPSTALLS, 66448ba02b2SJassi Brar STLEP0IN | STLEP0OUT | STLSTAT); 66548ba02b2SJassi Brar } 66648ba02b2SJassi Brar } 66748ba02b2SJassi Brar 66848ba02b2SJassi Brar static void max3420_req_done(struct max3420_req *req, int status) 66948ba02b2SJassi Brar { 67048ba02b2SJassi Brar struct max3420_ep *ep = req->ep; 67148ba02b2SJassi Brar struct max3420_udc *udc = ep->udc; 67248ba02b2SJassi Brar 67348ba02b2SJassi Brar if (req->usb_req.status == -EINPROGRESS) 67448ba02b2SJassi Brar req->usb_req.status = status; 67548ba02b2SJassi Brar else 67648ba02b2SJassi Brar status = req->usb_req.status; 67748ba02b2SJassi Brar 67848ba02b2SJassi Brar if (status && status != -ESHUTDOWN) 67948ba02b2SJassi Brar dev_err(udc->dev, "%s done %p, status %d\n", 68048ba02b2SJassi Brar ep->ep_usb.name, req, status); 68148ba02b2SJassi Brar 68248ba02b2SJassi Brar if (req->usb_req.complete) 68348ba02b2SJassi Brar req->usb_req.complete(&ep->ep_usb, &req->usb_req); 68448ba02b2SJassi Brar } 68548ba02b2SJassi Brar 68648ba02b2SJassi Brar static int max3420_do_data(struct max3420_udc *udc, int ep_id, int in) 68748ba02b2SJassi Brar { 68848ba02b2SJassi Brar struct max3420_ep *ep = &udc->ep[ep_id]; 68948ba02b2SJassi Brar struct max3420_req *req; 69048ba02b2SJassi Brar int done, length, psz; 69148ba02b2SJassi Brar void *buf; 69248ba02b2SJassi Brar 69348ba02b2SJassi Brar if (list_empty(&ep->queue)) 69448ba02b2SJassi Brar return false; 69548ba02b2SJassi Brar 69648ba02b2SJassi Brar req = list_first_entry(&ep->queue, struct max3420_req, queue); 69748ba02b2SJassi Brar buf = req->usb_req.buf + req->usb_req.actual; 69848ba02b2SJassi Brar 69948ba02b2SJassi Brar psz = ep->ep_usb.maxpacket; 70048ba02b2SJassi Brar length = req->usb_req.length - req->usb_req.actual; 70148ba02b2SJassi Brar length = min(length, psz); 70248ba02b2SJassi Brar 70348ba02b2SJassi Brar if (length == 0) { 70448ba02b2SJassi Brar done = 1; 70548ba02b2SJassi Brar goto xfer_done; 70648ba02b2SJassi Brar } 70748ba02b2SJassi Brar 70848ba02b2SJassi Brar done = 0; 70948ba02b2SJassi Brar if (in) { 71048ba02b2SJassi Brar prefetch(buf); 71148ba02b2SJassi Brar spi_wr_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length); 71248ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_EP0BC + ep_id, length); 71348ba02b2SJassi Brar if (length < psz) 71448ba02b2SJassi Brar done = 1; 71548ba02b2SJassi Brar } else { 71648ba02b2SJassi Brar psz = spi_rd8(udc, MAX3420_REG_EP0BC + ep_id); 71748ba02b2SJassi Brar length = min(length, psz); 71848ba02b2SJassi Brar prefetchw(buf); 71948ba02b2SJassi Brar spi_rd_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length); 72048ba02b2SJassi Brar if (length < ep->ep_usb.maxpacket) 72148ba02b2SJassi Brar done = 1; 72248ba02b2SJassi Brar } 72348ba02b2SJassi Brar 72448ba02b2SJassi Brar req->usb_req.actual += length; 72548ba02b2SJassi Brar 72648ba02b2SJassi Brar if (req->usb_req.actual == req->usb_req.length) 72748ba02b2SJassi Brar done = 1; 72848ba02b2SJassi Brar 72948ba02b2SJassi Brar xfer_done: 73048ba02b2SJassi Brar if (done) { 73148ba02b2SJassi Brar unsigned long flags; 73248ba02b2SJassi Brar 73348ba02b2SJassi Brar spin_lock_irqsave(&ep->lock, flags); 73448ba02b2SJassi Brar list_del_init(&req->queue); 73548ba02b2SJassi Brar spin_unlock_irqrestore(&ep->lock, flags); 73648ba02b2SJassi Brar 73748ba02b2SJassi Brar if (ep_id == 0) 73848ba02b2SJassi Brar spi_ack_ctrl(udc); 73948ba02b2SJassi Brar 74048ba02b2SJassi Brar max3420_req_done(req, 0); 74148ba02b2SJassi Brar } 74248ba02b2SJassi Brar 74348ba02b2SJassi Brar return true; 74448ba02b2SJassi Brar } 74548ba02b2SJassi Brar 74648ba02b2SJassi Brar static int max3420_handle_irqs(struct max3420_udc *udc) 74748ba02b2SJassi Brar { 74848ba02b2SJassi Brar u8 epien, epirq, usbirq, usbien, reg[4]; 74948ba02b2SJassi Brar bool ret = false; 75048ba02b2SJassi Brar 75148ba02b2SJassi Brar spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 4); 75248ba02b2SJassi Brar epirq = reg[0]; 75348ba02b2SJassi Brar epien = reg[1]; 75448ba02b2SJassi Brar usbirq = reg[2]; 75548ba02b2SJassi Brar usbien = reg[3]; 75648ba02b2SJassi Brar 75748ba02b2SJassi Brar usbirq &= usbien; 75848ba02b2SJassi Brar epirq &= epien; 75948ba02b2SJassi Brar 76048ba02b2SJassi Brar if (epirq & SUDAVIRQ) { 76148ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_EPIRQ, SUDAVIRQ); 76248ba02b2SJassi Brar max3420_handle_setup(udc); 76348ba02b2SJassi Brar return true; 76448ba02b2SJassi Brar } 76548ba02b2SJassi Brar 76648ba02b2SJassi Brar if (usbirq & VBUSIRQ) { 76748ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBIRQ, VBUSIRQ); 76848ba02b2SJassi Brar dev_dbg(udc->dev, "Cable plugged in\n"); 76948ba02b2SJassi Brar return true; 77048ba02b2SJassi Brar } 77148ba02b2SJassi Brar 77248ba02b2SJassi Brar if (usbirq & NOVBUSIRQ) { 77348ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBIRQ, NOVBUSIRQ); 77448ba02b2SJassi Brar dev_dbg(udc->dev, "Cable pulled out\n"); 77548ba02b2SJassi Brar return true; 77648ba02b2SJassi Brar } 77748ba02b2SJassi Brar 77848ba02b2SJassi Brar if (usbirq & URESIRQ) { 77948ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBIRQ, URESIRQ); 78048ba02b2SJassi Brar dev_dbg(udc->dev, "USB Reset - Start\n"); 78148ba02b2SJassi Brar return true; 78248ba02b2SJassi Brar } 78348ba02b2SJassi Brar 78448ba02b2SJassi Brar if (usbirq & URESDNIRQ) { 78548ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBIRQ, URESDNIRQ); 78648ba02b2SJassi Brar dev_dbg(udc->dev, "USB Reset - END\n"); 78748ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBIEN, URESDNIRQ | URESIRQ); 78848ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_EPIEN, SUDAVIRQ | IN0BAVIRQ 78948ba02b2SJassi Brar | OUT0DAVIRQ); 79048ba02b2SJassi Brar return true; 79148ba02b2SJassi Brar } 79248ba02b2SJassi Brar 79348ba02b2SJassi Brar if (usbirq & SUSPIRQ) { 79448ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBIRQ, SUSPIRQ); 79548ba02b2SJassi Brar dev_dbg(udc->dev, "USB Suspend - Enter\n"); 79648ba02b2SJassi Brar udc->suspended = true; 79748ba02b2SJassi Brar return true; 79848ba02b2SJassi Brar } 79948ba02b2SJassi Brar 80048ba02b2SJassi Brar if (usbirq & BUSACTIRQ) { 80148ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBIRQ, BUSACTIRQ); 80248ba02b2SJassi Brar dev_dbg(udc->dev, "USB Suspend - Exit\n"); 80348ba02b2SJassi Brar udc->suspended = false; 80448ba02b2SJassi Brar return true; 80548ba02b2SJassi Brar } 80648ba02b2SJassi Brar 80748ba02b2SJassi Brar if (usbirq & RWUDNIRQ) { 80848ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBIRQ, RWUDNIRQ); 80948ba02b2SJassi Brar dev_dbg(udc->dev, "Asked Host to wakeup\n"); 81048ba02b2SJassi Brar return true; 81148ba02b2SJassi Brar } 81248ba02b2SJassi Brar 81348ba02b2SJassi Brar if (usbirq & OSCOKIRQ) { 81448ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_USBIRQ, OSCOKIRQ); 81548ba02b2SJassi Brar dev_dbg(udc->dev, "Osc stabilized, start work\n"); 81648ba02b2SJassi Brar return true; 81748ba02b2SJassi Brar } 81848ba02b2SJassi Brar 81948ba02b2SJassi Brar if (epirq & OUT0DAVIRQ && max3420_do_data(udc, 0, 0)) { 82048ba02b2SJassi Brar spi_wr8_ack(udc, MAX3420_REG_EPIRQ, OUT0DAVIRQ, 1); 82148ba02b2SJassi Brar ret = true; 82248ba02b2SJassi Brar } 82348ba02b2SJassi Brar 82448ba02b2SJassi Brar if (epirq & IN0BAVIRQ && max3420_do_data(udc, 0, 1)) 82548ba02b2SJassi Brar ret = true; 82648ba02b2SJassi Brar 82748ba02b2SJassi Brar if (epirq & OUT1DAVIRQ && max3420_do_data(udc, 1, 0)) { 82848ba02b2SJassi Brar spi_wr8_ack(udc, MAX3420_REG_EPIRQ, OUT1DAVIRQ, 1); 82948ba02b2SJassi Brar ret = true; 83048ba02b2SJassi Brar } 83148ba02b2SJassi Brar 83248ba02b2SJassi Brar if (epirq & IN2BAVIRQ && max3420_do_data(udc, 2, 1)) 83348ba02b2SJassi Brar ret = true; 83448ba02b2SJassi Brar 83548ba02b2SJassi Brar if (epirq & IN3BAVIRQ && max3420_do_data(udc, 3, 1)) 83648ba02b2SJassi Brar ret = true; 83748ba02b2SJassi Brar 83848ba02b2SJassi Brar return ret; 83948ba02b2SJassi Brar } 84048ba02b2SJassi Brar 84148ba02b2SJassi Brar static int max3420_thread(void *dev_id) 84248ba02b2SJassi Brar { 84348ba02b2SJassi Brar struct max3420_udc *udc = dev_id; 84448ba02b2SJassi Brar struct spi_device *spi = udc->spi; 84548ba02b2SJassi Brar int i, loop_again = 1; 84648ba02b2SJassi Brar unsigned long flags; 84748ba02b2SJassi Brar 84848ba02b2SJassi Brar while (!kthread_should_stop()) { 84948ba02b2SJassi Brar if (!loop_again) { 85048ba02b2SJassi Brar ktime_t kt = ns_to_ktime(1000 * 1000 * 250); /* 250ms */ 85148ba02b2SJassi Brar 85248ba02b2SJassi Brar set_current_state(TASK_INTERRUPTIBLE); 85348ba02b2SJassi Brar 85448ba02b2SJassi Brar spin_lock_irqsave(&udc->lock, flags); 85548ba02b2SJassi Brar if (udc->todo & ENABLE_IRQ) { 85648ba02b2SJassi Brar enable_irq(spi->irq); 85748ba02b2SJassi Brar udc->todo &= ~ENABLE_IRQ; 85848ba02b2SJassi Brar } 85948ba02b2SJassi Brar spin_unlock_irqrestore(&udc->lock, flags); 86048ba02b2SJassi Brar 86148ba02b2SJassi Brar schedule_hrtimeout(&kt, HRTIMER_MODE_REL); 86248ba02b2SJassi Brar } 86348ba02b2SJassi Brar loop_again = 0; 86448ba02b2SJassi Brar 86548ba02b2SJassi Brar mutex_lock(&udc->spi_bus_mutex); 86648ba02b2SJassi Brar 86748ba02b2SJassi Brar /* If bus-vbus_active and disconnected */ 86848ba02b2SJassi Brar if (!udc->vbus_active || !udc->softconnect) 86948ba02b2SJassi Brar goto loop; 87048ba02b2SJassi Brar 87148ba02b2SJassi Brar if (max3420_start(udc)) { 87248ba02b2SJassi Brar loop_again = 1; 87348ba02b2SJassi Brar goto loop; 87448ba02b2SJassi Brar } 87548ba02b2SJassi Brar 87648ba02b2SJassi Brar if (max3420_handle_irqs(udc)) { 87748ba02b2SJassi Brar loop_again = 1; 87848ba02b2SJassi Brar goto loop; 87948ba02b2SJassi Brar } 88048ba02b2SJassi Brar 88148ba02b2SJassi Brar if (spi_max3420_rwkup(udc)) { 88248ba02b2SJassi Brar loop_again = 1; 88348ba02b2SJassi Brar goto loop; 88448ba02b2SJassi Brar } 88548ba02b2SJassi Brar 88648ba02b2SJassi Brar max3420_do_data(udc, 0, 1); /* get done with the EP0 ZLP */ 88748ba02b2SJassi Brar 88848ba02b2SJassi Brar for (i = 1; i < MAX3420_MAX_EPS; i++) { 88948ba02b2SJassi Brar struct max3420_ep *ep = &udc->ep[i]; 89048ba02b2SJassi Brar 89148ba02b2SJassi Brar if (spi_max3420_enable(ep)) 89248ba02b2SJassi Brar loop_again = 1; 89348ba02b2SJassi Brar if (spi_max3420_stall(ep)) 89448ba02b2SJassi Brar loop_again = 1; 89548ba02b2SJassi Brar } 89648ba02b2SJassi Brar loop: 89748ba02b2SJassi Brar mutex_unlock(&udc->spi_bus_mutex); 89848ba02b2SJassi Brar } 89948ba02b2SJassi Brar 90048ba02b2SJassi Brar set_current_state(TASK_RUNNING); 90182b3fba2SChristophe JAILLET dev_info(udc->dev, "SPI thread exiting\n"); 90248ba02b2SJassi Brar return 0; 90348ba02b2SJassi Brar } 90448ba02b2SJassi Brar 90548ba02b2SJassi Brar static int max3420_ep_set_halt(struct usb_ep *_ep, int stall) 90648ba02b2SJassi Brar { 90748ba02b2SJassi Brar struct max3420_ep *ep = to_max3420_ep(_ep); 90848ba02b2SJassi Brar struct max3420_udc *udc = ep->udc; 90948ba02b2SJassi Brar unsigned long flags; 91048ba02b2SJassi Brar 91148ba02b2SJassi Brar spin_lock_irqsave(&ep->lock, flags); 91248ba02b2SJassi Brar 91348ba02b2SJassi Brar ep->todo &= ~STALL_EP; 91448ba02b2SJassi Brar if (stall) 91548ba02b2SJassi Brar ep->todo |= STALL; 91648ba02b2SJassi Brar else 91748ba02b2SJassi Brar ep->todo |= UNSTALL; 91848ba02b2SJassi Brar 91948ba02b2SJassi Brar spin_unlock_irqrestore(&ep->lock, flags); 92048ba02b2SJassi Brar 92148ba02b2SJassi Brar wake_up_process(udc->thread_task); 92248ba02b2SJassi Brar 92348ba02b2SJassi Brar dev_dbg(udc->dev, "%sStall %s\n", stall ? "" : "Un", ep->name); 92448ba02b2SJassi Brar return 0; 92548ba02b2SJassi Brar } 92648ba02b2SJassi Brar 92748ba02b2SJassi Brar static int __max3420_ep_enable(struct max3420_ep *ep, 92848ba02b2SJassi Brar const struct usb_endpoint_descriptor *desc) 92948ba02b2SJassi Brar { 93048ba02b2SJassi Brar unsigned int maxp = usb_endpoint_maxp(desc); 93148ba02b2SJassi Brar unsigned long flags; 93248ba02b2SJassi Brar 93348ba02b2SJassi Brar spin_lock_irqsave(&ep->lock, flags); 93448ba02b2SJassi Brar ep->ep_usb.desc = desc; 93548ba02b2SJassi Brar ep->ep_usb.maxpacket = maxp; 93648ba02b2SJassi Brar 93748ba02b2SJassi Brar ep->todo &= ~ENABLE_EP; 93848ba02b2SJassi Brar ep->todo |= ENABLE; 93948ba02b2SJassi Brar spin_unlock_irqrestore(&ep->lock, flags); 94048ba02b2SJassi Brar 94148ba02b2SJassi Brar return 0; 94248ba02b2SJassi Brar } 94348ba02b2SJassi Brar 94448ba02b2SJassi Brar static int max3420_ep_enable(struct usb_ep *_ep, 94548ba02b2SJassi Brar const struct usb_endpoint_descriptor *desc) 94648ba02b2SJassi Brar { 94748ba02b2SJassi Brar struct max3420_ep *ep = to_max3420_ep(_ep); 94848ba02b2SJassi Brar struct max3420_udc *udc = ep->udc; 94948ba02b2SJassi Brar 95048ba02b2SJassi Brar __max3420_ep_enable(ep, desc); 95148ba02b2SJassi Brar 95248ba02b2SJassi Brar wake_up_process(udc->thread_task); 95348ba02b2SJassi Brar 95448ba02b2SJassi Brar return 0; 95548ba02b2SJassi Brar } 95648ba02b2SJassi Brar 95748ba02b2SJassi Brar static void max3420_nuke(struct max3420_ep *ep, int status) 95848ba02b2SJassi Brar { 95948ba02b2SJassi Brar struct max3420_req *req, *r; 96048ba02b2SJassi Brar unsigned long flags; 96148ba02b2SJassi Brar 96248ba02b2SJassi Brar spin_lock_irqsave(&ep->lock, flags); 96348ba02b2SJassi Brar 96448ba02b2SJassi Brar list_for_each_entry_safe(req, r, &ep->queue, queue) { 96548ba02b2SJassi Brar list_del_init(&req->queue); 96648ba02b2SJassi Brar 96748ba02b2SJassi Brar spin_unlock_irqrestore(&ep->lock, flags); 96848ba02b2SJassi Brar max3420_req_done(req, status); 96948ba02b2SJassi Brar spin_lock_irqsave(&ep->lock, flags); 97048ba02b2SJassi Brar } 97148ba02b2SJassi Brar 97248ba02b2SJassi Brar spin_unlock_irqrestore(&ep->lock, flags); 97348ba02b2SJassi Brar } 97448ba02b2SJassi Brar 97548ba02b2SJassi Brar static void __max3420_ep_disable(struct max3420_ep *ep) 97648ba02b2SJassi Brar { 97748ba02b2SJassi Brar struct max3420_udc *udc = ep->udc; 97848ba02b2SJassi Brar unsigned long flags; 97948ba02b2SJassi Brar 98048ba02b2SJassi Brar spin_lock_irqsave(&ep->lock, flags); 98148ba02b2SJassi Brar 98248ba02b2SJassi Brar ep->ep_usb.desc = NULL; 98348ba02b2SJassi Brar 98448ba02b2SJassi Brar ep->todo &= ~ENABLE_EP; 98548ba02b2SJassi Brar ep->todo |= DISABLE; 98648ba02b2SJassi Brar 98748ba02b2SJassi Brar spin_unlock_irqrestore(&ep->lock, flags); 98848ba02b2SJassi Brar 98948ba02b2SJassi Brar dev_dbg(udc->dev, "Disabled %s\n", ep->name); 99048ba02b2SJassi Brar } 99148ba02b2SJassi Brar 99248ba02b2SJassi Brar static int max3420_ep_disable(struct usb_ep *_ep) 99348ba02b2SJassi Brar { 99448ba02b2SJassi Brar struct max3420_ep *ep = to_max3420_ep(_ep); 99548ba02b2SJassi Brar struct max3420_udc *udc = ep->udc; 99648ba02b2SJassi Brar 99748ba02b2SJassi Brar max3420_nuke(ep, -ESHUTDOWN); 99848ba02b2SJassi Brar 99948ba02b2SJassi Brar __max3420_ep_disable(ep); 100048ba02b2SJassi Brar 100148ba02b2SJassi Brar wake_up_process(udc->thread_task); 100248ba02b2SJassi Brar 100348ba02b2SJassi Brar return 0; 100448ba02b2SJassi Brar } 100548ba02b2SJassi Brar 100648ba02b2SJassi Brar static struct usb_request *max3420_alloc_request(struct usb_ep *_ep, 100748ba02b2SJassi Brar gfp_t gfp_flags) 100848ba02b2SJassi Brar { 100948ba02b2SJassi Brar struct max3420_ep *ep = to_max3420_ep(_ep); 101048ba02b2SJassi Brar struct max3420_req *req; 101148ba02b2SJassi Brar 101248ba02b2SJassi Brar req = kzalloc(sizeof(*req), gfp_flags); 101348ba02b2SJassi Brar if (!req) 101448ba02b2SJassi Brar return NULL; 101548ba02b2SJassi Brar 101648ba02b2SJassi Brar req->ep = ep; 101748ba02b2SJassi Brar 101848ba02b2SJassi Brar return &req->usb_req; 101948ba02b2SJassi Brar } 102048ba02b2SJassi Brar 102148ba02b2SJassi Brar static void max3420_free_request(struct usb_ep *_ep, struct usb_request *_req) 102248ba02b2SJassi Brar { 102348ba02b2SJassi Brar kfree(to_max3420_req(_req)); 102448ba02b2SJassi Brar } 102548ba02b2SJassi Brar 102648ba02b2SJassi Brar static int max3420_ep_queue(struct usb_ep *_ep, struct usb_request *_req, 102748ba02b2SJassi Brar gfp_t ignored) 102848ba02b2SJassi Brar { 102948ba02b2SJassi Brar struct max3420_req *req = to_max3420_req(_req); 103048ba02b2SJassi Brar struct max3420_ep *ep = to_max3420_ep(_ep); 103148ba02b2SJassi Brar struct max3420_udc *udc = ep->udc; 103248ba02b2SJassi Brar unsigned long flags; 103348ba02b2SJassi Brar 103448ba02b2SJassi Brar _req->status = -EINPROGRESS; 103548ba02b2SJassi Brar _req->actual = 0; 103648ba02b2SJassi Brar 103748ba02b2SJassi Brar spin_lock_irqsave(&ep->lock, flags); 103848ba02b2SJassi Brar list_add_tail(&req->queue, &ep->queue); 103948ba02b2SJassi Brar spin_unlock_irqrestore(&ep->lock, flags); 104048ba02b2SJassi Brar 104148ba02b2SJassi Brar wake_up_process(udc->thread_task); 104248ba02b2SJassi Brar return 0; 104348ba02b2SJassi Brar } 104448ba02b2SJassi Brar 104548ba02b2SJassi Brar static int max3420_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) 104648ba02b2SJassi Brar { 104748ba02b2SJassi Brar struct max3420_req *t, *req = to_max3420_req(_req); 104848ba02b2SJassi Brar struct max3420_ep *ep = to_max3420_ep(_ep); 104948ba02b2SJassi Brar unsigned long flags; 105048ba02b2SJassi Brar 105148ba02b2SJassi Brar spin_lock_irqsave(&ep->lock, flags); 105248ba02b2SJassi Brar 105348ba02b2SJassi Brar /* Pluck the descriptor from queue */ 105448ba02b2SJassi Brar list_for_each_entry(t, &ep->queue, queue) 105548ba02b2SJassi Brar if (t == req) { 105648ba02b2SJassi Brar list_del_init(&req->queue); 105748ba02b2SJassi Brar break; 105848ba02b2SJassi Brar } 105948ba02b2SJassi Brar 106048ba02b2SJassi Brar spin_unlock_irqrestore(&ep->lock, flags); 106148ba02b2SJassi Brar 106248ba02b2SJassi Brar if (t == req) 106348ba02b2SJassi Brar max3420_req_done(req, -ECONNRESET); 106448ba02b2SJassi Brar 106548ba02b2SJassi Brar return 0; 106648ba02b2SJassi Brar } 106748ba02b2SJassi Brar 106848ba02b2SJassi Brar static const struct usb_ep_ops max3420_ep_ops = { 106948ba02b2SJassi Brar .enable = max3420_ep_enable, 107048ba02b2SJassi Brar .disable = max3420_ep_disable, 107148ba02b2SJassi Brar .alloc_request = max3420_alloc_request, 107248ba02b2SJassi Brar .free_request = max3420_free_request, 107348ba02b2SJassi Brar .queue = max3420_ep_queue, 107448ba02b2SJassi Brar .dequeue = max3420_ep_dequeue, 107548ba02b2SJassi Brar .set_halt = max3420_ep_set_halt, 107648ba02b2SJassi Brar }; 107748ba02b2SJassi Brar 107848ba02b2SJassi Brar static int max3420_wakeup(struct usb_gadget *gadget) 107948ba02b2SJassi Brar { 108048ba02b2SJassi Brar struct max3420_udc *udc = to_udc(gadget); 108148ba02b2SJassi Brar unsigned long flags; 108248ba02b2SJassi Brar int ret = -EINVAL; 108348ba02b2SJassi Brar 108448ba02b2SJassi Brar spin_lock_irqsave(&udc->lock, flags); 108548ba02b2SJassi Brar 108648ba02b2SJassi Brar /* Only if wakeup allowed by host */ 108748ba02b2SJassi Brar if (udc->remote_wkp) { 108848ba02b2SJassi Brar udc->todo |= REMOTE_WAKEUP; 108948ba02b2SJassi Brar ret = 0; 109048ba02b2SJassi Brar } 109148ba02b2SJassi Brar 109248ba02b2SJassi Brar spin_unlock_irqrestore(&udc->lock, flags); 109348ba02b2SJassi Brar 109437aadc68SPeter Zijlstra if (udc->thread_task) 109548ba02b2SJassi Brar wake_up_process(udc->thread_task); 109648ba02b2SJassi Brar return ret; 109748ba02b2SJassi Brar } 109848ba02b2SJassi Brar 109948ba02b2SJassi Brar static int max3420_udc_start(struct usb_gadget *gadget, 110048ba02b2SJassi Brar struct usb_gadget_driver *driver) 110148ba02b2SJassi Brar { 110248ba02b2SJassi Brar struct max3420_udc *udc = to_udc(gadget); 110348ba02b2SJassi Brar unsigned long flags; 110448ba02b2SJassi Brar 110548ba02b2SJassi Brar spin_lock_irqsave(&udc->lock, flags); 110648ba02b2SJassi Brar /* hook up the driver */ 110748ba02b2SJassi Brar driver->driver.bus = NULL; 110848ba02b2SJassi Brar udc->driver = driver; 110948ba02b2SJassi Brar udc->gadget.speed = USB_SPEED_FULL; 111048ba02b2SJassi Brar 111148ba02b2SJassi Brar udc->gadget.is_selfpowered = udc->is_selfpowered; 111248ba02b2SJassi Brar udc->remote_wkp = 0; 111348ba02b2SJassi Brar udc->softconnect = true; 111448ba02b2SJassi Brar udc->todo |= UDC_START; 111548ba02b2SJassi Brar spin_unlock_irqrestore(&udc->lock, flags); 111648ba02b2SJassi Brar 111737aadc68SPeter Zijlstra if (udc->thread_task) 111848ba02b2SJassi Brar wake_up_process(udc->thread_task); 111948ba02b2SJassi Brar 112048ba02b2SJassi Brar return 0; 112148ba02b2SJassi Brar } 112248ba02b2SJassi Brar 112348ba02b2SJassi Brar static int max3420_udc_stop(struct usb_gadget *gadget) 112448ba02b2SJassi Brar { 112548ba02b2SJassi Brar struct max3420_udc *udc = to_udc(gadget); 112648ba02b2SJassi Brar unsigned long flags; 112748ba02b2SJassi Brar 112848ba02b2SJassi Brar spin_lock_irqsave(&udc->lock, flags); 112948ba02b2SJassi Brar udc->is_selfpowered = udc->gadget.is_selfpowered; 113048ba02b2SJassi Brar udc->gadget.speed = USB_SPEED_UNKNOWN; 113148ba02b2SJassi Brar udc->driver = NULL; 113248ba02b2SJassi Brar udc->softconnect = false; 113348ba02b2SJassi Brar udc->todo |= UDC_START; 113448ba02b2SJassi Brar spin_unlock_irqrestore(&udc->lock, flags); 113548ba02b2SJassi Brar 113637aadc68SPeter Zijlstra if (udc->thread_task) 113748ba02b2SJassi Brar wake_up_process(udc->thread_task); 113848ba02b2SJassi Brar 113948ba02b2SJassi Brar return 0; 114048ba02b2SJassi Brar } 114148ba02b2SJassi Brar 114248ba02b2SJassi Brar static const struct usb_gadget_ops max3420_udc_ops = { 114348ba02b2SJassi Brar .udc_start = max3420_udc_start, 114448ba02b2SJassi Brar .udc_stop = max3420_udc_stop, 114548ba02b2SJassi Brar .wakeup = max3420_wakeup, 114648ba02b2SJassi Brar }; 114748ba02b2SJassi Brar 114848ba02b2SJassi Brar static void max3420_eps_init(struct max3420_udc *udc) 114948ba02b2SJassi Brar { 115048ba02b2SJassi Brar int idx; 115148ba02b2SJassi Brar 115248ba02b2SJassi Brar INIT_LIST_HEAD(&udc->gadget.ep_list); 115348ba02b2SJassi Brar 115448ba02b2SJassi Brar for (idx = 0; idx < MAX3420_MAX_EPS; idx++) { 115548ba02b2SJassi Brar struct max3420_ep *ep = &udc->ep[idx]; 115648ba02b2SJassi Brar 115748ba02b2SJassi Brar spin_lock_init(&ep->lock); 115848ba02b2SJassi Brar INIT_LIST_HEAD(&ep->queue); 115948ba02b2SJassi Brar 116048ba02b2SJassi Brar ep->udc = udc; 116148ba02b2SJassi Brar ep->id = idx; 116248ba02b2SJassi Brar ep->halted = 0; 116348ba02b2SJassi Brar ep->maxpacket = 0; 116448ba02b2SJassi Brar ep->ep_usb.name = ep->name; 116548ba02b2SJassi Brar ep->ep_usb.ops = &max3420_ep_ops; 116648ba02b2SJassi Brar usb_ep_set_maxpacket_limit(&ep->ep_usb, MAX3420_EP_MAX_PACKET); 116748ba02b2SJassi Brar 116848ba02b2SJassi Brar if (idx == 0) { /* For EP0 */ 116948ba02b2SJassi Brar ep->ep_usb.desc = &ep0_desc; 117048ba02b2SJassi Brar ep->ep_usb.maxpacket = usb_endpoint_maxp(&ep0_desc); 117148ba02b2SJassi Brar ep->ep_usb.caps.type_control = true; 117248ba02b2SJassi Brar ep->ep_usb.caps.dir_in = true; 117348ba02b2SJassi Brar ep->ep_usb.caps.dir_out = true; 117448ba02b2SJassi Brar snprintf(ep->name, MAX3420_EPNAME_SIZE, "ep0"); 117548ba02b2SJassi Brar continue; 117648ba02b2SJassi Brar } 117748ba02b2SJassi Brar 117848ba02b2SJassi Brar if (idx == 1) { /* EP1 is OUT */ 117948ba02b2SJassi Brar ep->ep_usb.caps.dir_in = false; 118048ba02b2SJassi Brar ep->ep_usb.caps.dir_out = true; 118148ba02b2SJassi Brar snprintf(ep->name, MAX3420_EPNAME_SIZE, "ep1-bulk-out"); 118248ba02b2SJassi Brar } else { /* EP2 & EP3 are IN */ 118348ba02b2SJassi Brar ep->ep_usb.caps.dir_in = true; 118448ba02b2SJassi Brar ep->ep_usb.caps.dir_out = false; 118548ba02b2SJassi Brar snprintf(ep->name, MAX3420_EPNAME_SIZE, 118648ba02b2SJassi Brar "ep%d-bulk-in", idx); 118748ba02b2SJassi Brar } 118848ba02b2SJassi Brar ep->ep_usb.caps.type_iso = false; 118948ba02b2SJassi Brar ep->ep_usb.caps.type_int = false; 119048ba02b2SJassi Brar ep->ep_usb.caps.type_bulk = true; 119148ba02b2SJassi Brar 119248ba02b2SJassi Brar list_add_tail(&ep->ep_usb.ep_list, 119348ba02b2SJassi Brar &udc->gadget.ep_list); 119448ba02b2SJassi Brar } 119548ba02b2SJassi Brar } 119648ba02b2SJassi Brar 119748ba02b2SJassi Brar static int max3420_probe(struct spi_device *spi) 119848ba02b2SJassi Brar { 119948ba02b2SJassi Brar struct max3420_udc *udc; 120048ba02b2SJassi Brar int err, irq; 120148ba02b2SJassi Brar u8 reg[8]; 120248ba02b2SJassi Brar 120348ba02b2SJassi Brar if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) { 120448ba02b2SJassi Brar dev_err(&spi->dev, "UDC needs full duplex to work\n"); 120548ba02b2SJassi Brar return -EINVAL; 120648ba02b2SJassi Brar } 120748ba02b2SJassi Brar 120848ba02b2SJassi Brar spi->mode = SPI_MODE_3; 120948ba02b2SJassi Brar spi->bits_per_word = 8; 121048ba02b2SJassi Brar 121148ba02b2SJassi Brar err = spi_setup(spi); 121248ba02b2SJassi Brar if (err) { 121348ba02b2SJassi Brar dev_err(&spi->dev, "Unable to setup SPI bus\n"); 121448ba02b2SJassi Brar return -EFAULT; 121548ba02b2SJassi Brar } 121648ba02b2SJassi Brar 121748ba02b2SJassi Brar udc = devm_kzalloc(&spi->dev, sizeof(*udc), GFP_KERNEL); 121848ba02b2SJassi Brar if (!udc) 121948ba02b2SJassi Brar return -ENOMEM; 122048ba02b2SJassi Brar 122148ba02b2SJassi Brar udc->spi = spi; 122248ba02b2SJassi Brar 122348ba02b2SJassi Brar udc->remote_wkp = 0; 122448ba02b2SJassi Brar 122548ba02b2SJassi Brar /* Setup gadget structure */ 122648ba02b2SJassi Brar udc->gadget.ops = &max3420_udc_ops; 122748ba02b2SJassi Brar udc->gadget.max_speed = USB_SPEED_FULL; 122848ba02b2SJassi Brar udc->gadget.speed = USB_SPEED_UNKNOWN; 122948ba02b2SJassi Brar udc->gadget.ep0 = &udc->ep[0].ep_usb; 123048ba02b2SJassi Brar udc->gadget.name = driver_name; 123148ba02b2SJassi Brar 123248ba02b2SJassi Brar spin_lock_init(&udc->lock); 123348ba02b2SJassi Brar mutex_init(&udc->spi_bus_mutex); 123448ba02b2SJassi Brar 123548ba02b2SJassi Brar udc->ep0req.ep = &udc->ep[0]; 123648ba02b2SJassi Brar udc->ep0req.usb_req.buf = udc->ep0buf; 123748ba02b2SJassi Brar INIT_LIST_HEAD(&udc->ep0req.queue); 123848ba02b2SJassi Brar 123948ba02b2SJassi Brar /* setup Endpoints */ 124048ba02b2SJassi Brar max3420_eps_init(udc); 124148ba02b2SJassi Brar 124248ba02b2SJassi Brar /* configure SPI */ 124348ba02b2SJassi Brar spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8); 124448ba02b2SJassi Brar spi_wr8(udc, MAX3420_REG_PINCTL, FDUPSPI); 124548ba02b2SJassi Brar 124648ba02b2SJassi Brar err = usb_add_gadget_udc(&spi->dev, &udc->gadget); 124748ba02b2SJassi Brar if (err) 124848ba02b2SJassi Brar return err; 124948ba02b2SJassi Brar 125048ba02b2SJassi Brar udc->dev = &udc->gadget.dev; 125148ba02b2SJassi Brar 125248ba02b2SJassi Brar spi_set_drvdata(spi, udc); 125348ba02b2SJassi Brar 125448ba02b2SJassi Brar irq = of_irq_get_byname(spi->dev.of_node, "udc"); 125548ba02b2SJassi Brar err = devm_request_irq(&spi->dev, irq, max3420_irq_handler, 0, 125648ba02b2SJassi Brar "max3420", udc); 125748ba02b2SJassi Brar if (err < 0) 1258fa4a8dcfSZhang Qilong goto del_gadget; 125948ba02b2SJassi Brar 126048ba02b2SJassi Brar udc->thread_task = kthread_create(max3420_thread, udc, 126148ba02b2SJassi Brar "max3420-thread"); 1262fa4a8dcfSZhang Qilong if (IS_ERR(udc->thread_task)) { 1263fa4a8dcfSZhang Qilong err = PTR_ERR(udc->thread_task); 1264fa4a8dcfSZhang Qilong goto del_gadget; 1265fa4a8dcfSZhang Qilong } 126648ba02b2SJassi Brar 126748ba02b2SJassi Brar irq = of_irq_get_byname(spi->dev.of_node, "vbus"); 126848ba02b2SJassi Brar if (irq <= 0) { /* no vbus irq implies self-powered design */ 126948ba02b2SJassi Brar udc->is_selfpowered = 1; 127048ba02b2SJassi Brar udc->vbus_active = true; 127148ba02b2SJassi Brar udc->todo |= UDC_START; 127248ba02b2SJassi Brar usb_udc_vbus_handler(&udc->gadget, udc->vbus_active); 127348ba02b2SJassi Brar usb_gadget_set_state(&udc->gadget, USB_STATE_POWERED); 127448ba02b2SJassi Brar max3420_start(udc); 127548ba02b2SJassi Brar } else { 127648ba02b2SJassi Brar udc->is_selfpowered = 0; 127748ba02b2SJassi Brar /* Detect current vbus status */ 127848ba02b2SJassi Brar spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8); 127948ba02b2SJassi Brar if (reg[7] != 0xff) 128048ba02b2SJassi Brar udc->vbus_active = true; 128148ba02b2SJassi Brar 128248ba02b2SJassi Brar err = devm_request_irq(&spi->dev, irq, 128348ba02b2SJassi Brar max3420_vbus_handler, 0, "vbus", udc); 128448ba02b2SJassi Brar if (err < 0) 1285fa4a8dcfSZhang Qilong goto del_gadget; 128648ba02b2SJassi Brar } 128748ba02b2SJassi Brar 128848ba02b2SJassi Brar return 0; 1289fa4a8dcfSZhang Qilong 1290fa4a8dcfSZhang Qilong del_gadget: 1291fa4a8dcfSZhang Qilong usb_del_gadget_udc(&udc->gadget); 1292fa4a8dcfSZhang Qilong return err; 129348ba02b2SJassi Brar } 129448ba02b2SJassi Brar 1295*a0386bbaSUwe Kleine-König static void max3420_remove(struct spi_device *spi) 129648ba02b2SJassi Brar { 129748ba02b2SJassi Brar struct max3420_udc *udc = spi_get_drvdata(spi); 129848ba02b2SJassi Brar unsigned long flags; 129948ba02b2SJassi Brar 130048ba02b2SJassi Brar usb_del_gadget_udc(&udc->gadget); 130148ba02b2SJassi Brar 130248ba02b2SJassi Brar spin_lock_irqsave(&udc->lock, flags); 130348ba02b2SJassi Brar 130448ba02b2SJassi Brar kthread_stop(udc->thread_task); 130548ba02b2SJassi Brar 130648ba02b2SJassi Brar spin_unlock_irqrestore(&udc->lock, flags); 130748ba02b2SJassi Brar } 130848ba02b2SJassi Brar 130948ba02b2SJassi Brar static const struct of_device_id max3420_udc_of_match[] = { 131048ba02b2SJassi Brar { .compatible = "maxim,max3420-udc"}, 131148ba02b2SJassi Brar { .compatible = "maxim,max3421-udc"}, 131248ba02b2SJassi Brar {}, 131348ba02b2SJassi Brar }; 131448ba02b2SJassi Brar MODULE_DEVICE_TABLE(of, max3420_udc_of_match); 131548ba02b2SJassi Brar 131648ba02b2SJassi Brar static struct spi_driver max3420_driver = { 131748ba02b2SJassi Brar .driver = { 131848ba02b2SJassi Brar .name = "max3420-udc", 131948ba02b2SJassi Brar .of_match_table = of_match_ptr(max3420_udc_of_match), 132048ba02b2SJassi Brar }, 132148ba02b2SJassi Brar .probe = max3420_probe, 132248ba02b2SJassi Brar .remove = max3420_remove, 132348ba02b2SJassi Brar }; 132448ba02b2SJassi Brar 132548ba02b2SJassi Brar module_spi_driver(max3420_driver); 132648ba02b2SJassi Brar 132748ba02b2SJassi Brar MODULE_DESCRIPTION(DRIVER_DESC); 132848ba02b2SJassi Brar MODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>"); 132948ba02b2SJassi Brar MODULE_LICENSE("GPL"); 1330