2020-01-21 21:04:16 -06:00
// SPDX-License-Identifier: GPL-2.0+
/*
* MAX3420 Device Controller driver for USB .
*
* Author : Jaswinder Singh Brar < jaswinder . singh @ linaro . org >
* ( C ) Copyright 2019 - 2020 Linaro Ltd
*
* Based on :
* o MAX3420E datasheet
2020-07-10 21:09:19 +02:00
* https : //datasheets.maximintegrated.com/en/ds/MAX3420E.pdf
2020-01-21 21:04:16 -06:00
* o MAX342 { 0 , 1 } E Programming Guides
* https : //pdfserv.maximintegrated.com/en/an/AN3598.pdf
* https : //pdfserv.maximintegrated.com/en/an/AN3785.pdf
*/
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/module.h>
# include <linux/bitfield.h>
# include <linux/of_address.h>
# include <linux/of_device.h>
# include <linux/of_platform.h>
# include <linux/of_irq.h>
# include <linux/prefetch.h>
# include <linux/usb/ch9.h>
# include <linux/usb/gadget.h>
# include <linux/spi/spi.h>
# include <linux/gpio/consumer.h>
# define MAX3420_MAX_EPS 4
# define MAX3420_EP_MAX_PACKET 64 /* Same for all Endpoints */
# define MAX3420_EPNAME_SIZE 16 /* Buffer size for endpoint name */
# define MAX3420_ACKSTAT BIT(0)
# define MAX3420_SPI_DIR_RD 0 /* read register from MAX3420 */
# define MAX3420_SPI_DIR_WR 1 /* write register to MAX3420 */
/* SPI commands: */
# define MAX3420_SPI_DIR_SHIFT 1
# define MAX3420_SPI_REG_SHIFT 3
# define MAX3420_REG_EP0FIFO 0
# define MAX3420_REG_EP1FIFO 1
# define MAX3420_REG_EP2FIFO 2
# define MAX3420_REG_EP3FIFO 3
# define MAX3420_REG_SUDFIFO 4
# define MAX3420_REG_EP0BC 5
# define MAX3420_REG_EP1BC 6
# define MAX3420_REG_EP2BC 7
# define MAX3420_REG_EP3BC 8
# define MAX3420_REG_EPSTALLS 9
# define ACKSTAT BIT(6)
# define STLSTAT BIT(5)
# define STLEP3IN BIT(4)
# define STLEP2IN BIT(3)
# define STLEP1OUT BIT(2)
# define STLEP0OUT BIT(1)
# define STLEP0IN BIT(0)
# define MAX3420_REG_CLRTOGS 10
# define EP3DISAB BIT(7)
# define EP2DISAB BIT(6)
# define EP1DISAB BIT(5)
# define CTGEP3IN BIT(4)
# define CTGEP2IN BIT(3)
# define CTGEP1OUT BIT(2)
# define MAX3420_REG_EPIRQ 11
# define MAX3420_REG_EPIEN 12
# define SUDAVIRQ BIT(5)
# define IN3BAVIRQ BIT(4)
# define IN2BAVIRQ BIT(3)
# define OUT1DAVIRQ BIT(2)
# define OUT0DAVIRQ BIT(1)
# define IN0BAVIRQ BIT(0)
# define MAX3420_REG_USBIRQ 13
# define MAX3420_REG_USBIEN 14
# define OSCOKIRQ BIT(0)
# define RWUDNIRQ BIT(1)
# define BUSACTIRQ BIT(2)
# define URESIRQ BIT(3)
# define SUSPIRQ BIT(4)
# define NOVBUSIRQ BIT(5)
# define VBUSIRQ BIT(6)
# define URESDNIRQ BIT(7)
# define MAX3420_REG_USBCTL 15
# define HOSCSTEN BIT(7)
# define VBGATE BIT(6)
# define CHIPRES BIT(5)
# define PWRDOWN BIT(4)
# define CONNECT BIT(3)
# define SIGRWU BIT(2)
# define MAX3420_REG_CPUCTL 16
# define IE BIT(0)
# define MAX3420_REG_PINCTL 17
# define EP3INAK BIT(7)
# define EP2INAK BIT(6)
# define EP0INAK BIT(5)
# define FDUPSPI BIT(4)
# define INTLEVEL BIT(3)
# define POSINT BIT(2)
# define GPXB BIT(1)
# define GPXA BIT(0)
# define MAX3420_REG_REVISION 18
# define MAX3420_REG_FNADDR 19
# define FNADDR_MASK 0x7f
# define MAX3420_REG_IOPINS 20
# define MAX3420_REG_IOPINS2 21
# define MAX3420_REG_GPINIRQ 22
# define MAX3420_REG_GPINIEN 23
# define MAX3420_REG_GPINPOL 24
# define MAX3420_REG_HIRQ 25
# define MAX3420_REG_HIEN 26
# define MAX3420_REG_MODE 27
# define MAX3420_REG_PERADDR 28
# define MAX3420_REG_HCTL 29
# define MAX3420_REG_HXFR 30
# define MAX3420_REG_HRSL 31
# define ENABLE_IRQ BIT(0)
# define IOPIN_UPDATE BIT(1)
# define REMOTE_WAKEUP BIT(2)
# define CONNECT_HOST GENMASK(4, 3)
# define HCONNECT (1 << 3)
# define HDISCONNECT (3 << 3)
# define UDC_START GENMASK(6, 5)
# define START (1 << 5)
# define STOP (3 << 5)
# define ENABLE_EP GENMASK(8, 7)
# define ENABLE (1 << 7)
# define DISABLE (3 << 7)
# define STALL_EP GENMASK(10, 9)
# define STALL (1 << 9)
# define UNSTALL (3 << 9)
# define MAX3420_CMD(c) FIELD_PREP(GENMASK(7, 3), c)
# define MAX3420_SPI_CMD_RD(c) (MAX3420_CMD(c) | (0 << 1))
# define MAX3420_SPI_CMD_WR(c) (MAX3420_CMD(c) | (1 << 1))
struct max3420_req {
struct usb_request usb_req ;
struct list_head queue ;
struct max3420_ep * ep ;
} ;
struct max3420_ep {
struct usb_ep ep_usb ;
struct max3420_udc * udc ;
struct list_head queue ;
char name [ MAX3420_EPNAME_SIZE ] ;
unsigned int maxpacket ;
spinlock_t lock ;
int halted ;
u32 todo ;
int id ;
} ;
struct max3420_udc {
struct usb_gadget gadget ;
struct max3420_ep ep [ MAX3420_MAX_EPS ] ;
struct usb_gadget_driver * driver ;
struct task_struct * thread_task ;
int remote_wkp , is_selfpowered ;
bool vbus_active , softconnect ;
struct usb_ctrlrequest setup ;
struct mutex spi_bus_mutex ;
struct max3420_req ep0req ;
struct spi_device * spi ;
struct device * dev ;
spinlock_t lock ;
bool suspended ;
u8 ep0buf [ 64 ] ;
u32 todo ;
} ;
# define to_max3420_req(r) container_of((r), struct max3420_req, usb_req)
# define to_max3420_ep(e) container_of((e), struct max3420_ep, ep_usb)
# define to_udc(g) container_of((g), struct max3420_udc, gadget)
# define DRIVER_DESC "MAX3420 USB Device-Mode Driver"
static const char driver_name [ ] = " max3420-udc " ;
/* Control endpoint configuration.*/
static const struct usb_endpoint_descriptor ep0_desc = {
. bEndpointAddress = USB_DIR_OUT ,
. bmAttributes = USB_ENDPOINT_XFER_CONTROL ,
. wMaxPacketSize = cpu_to_le16 ( MAX3420_EP_MAX_PACKET ) ,
} ;
static void spi_ack_ctrl ( struct max3420_udc * udc )
{
struct spi_device * spi = udc - > spi ;
struct spi_transfer transfer ;
struct spi_message msg ;
u8 txdata [ 1 ] ;
memset ( & transfer , 0 , sizeof ( transfer ) ) ;
spi_message_init ( & msg ) ;
txdata [ 0 ] = MAX3420_ACKSTAT ;
transfer . tx_buf = txdata ;
transfer . len = 1 ;
spi_message_add_tail ( & transfer , & msg ) ;
spi_sync ( spi , & msg ) ;
}
static u8 spi_rd8_ack ( struct max3420_udc * udc , u8 reg , int actstat )
{
struct spi_device * spi = udc - > spi ;
struct spi_transfer transfer ;
struct spi_message msg ;
u8 txdata [ 2 ] , rxdata [ 2 ] ;
memset ( & transfer , 0 , sizeof ( transfer ) ) ;
spi_message_init ( & msg ) ;
txdata [ 0 ] = MAX3420_SPI_CMD_RD ( reg ) | ( actstat ? MAX3420_ACKSTAT : 0 ) ;
transfer . tx_buf = txdata ;
transfer . rx_buf = rxdata ;
transfer . len = 2 ;
spi_message_add_tail ( & transfer , & msg ) ;
spi_sync ( spi , & msg ) ;
return rxdata [ 1 ] ;
}
static u8 spi_rd8 ( struct max3420_udc * udc , u8 reg )
{
return spi_rd8_ack ( udc , reg , 0 ) ;
}
static void spi_wr8_ack ( struct max3420_udc * udc , u8 reg , u8 val , int actstat )
{
struct spi_device * spi = udc - > spi ;
struct spi_transfer transfer ;
struct spi_message msg ;
u8 txdata [ 2 ] ;
memset ( & transfer , 0 , sizeof ( transfer ) ) ;
spi_message_init ( & msg ) ;
txdata [ 0 ] = MAX3420_SPI_CMD_WR ( reg ) | ( actstat ? MAX3420_ACKSTAT : 0 ) ;
txdata [ 1 ] = val ;
transfer . tx_buf = txdata ;
transfer . len = 2 ;
spi_message_add_tail ( & transfer , & msg ) ;
spi_sync ( spi , & msg ) ;
}
static void spi_wr8 ( struct max3420_udc * udc , u8 reg , u8 val )
{
spi_wr8_ack ( udc , reg , val , 0 ) ;
}
static void spi_rd_buf ( struct max3420_udc * udc , u8 reg , void * buf , u8 len )
{
struct spi_device * spi = udc - > spi ;
struct spi_transfer transfer ;
struct spi_message msg ;
u8 local_buf [ MAX3420_EP_MAX_PACKET + 1 ] = { } ;
memset ( & transfer , 0 , sizeof ( transfer ) ) ;
spi_message_init ( & msg ) ;
local_buf [ 0 ] = MAX3420_SPI_CMD_RD ( reg ) ;
transfer . tx_buf = & local_buf [ 0 ] ;
transfer . rx_buf = & local_buf [ 0 ] ;
transfer . len = len + 1 ;
spi_message_add_tail ( & transfer , & msg ) ;
spi_sync ( spi , & msg ) ;
memcpy ( buf , & local_buf [ 1 ] , len ) ;
}
static void spi_wr_buf ( struct max3420_udc * udc , u8 reg , void * buf , u8 len )
{
struct spi_device * spi = udc - > spi ;
struct spi_transfer transfer ;
struct spi_message msg ;
u8 local_buf [ MAX3420_EP_MAX_PACKET + 1 ] = { } ;
memset ( & transfer , 0 , sizeof ( transfer ) ) ;
spi_message_init ( & msg ) ;
local_buf [ 0 ] = MAX3420_SPI_CMD_WR ( reg ) ;
memcpy ( & local_buf [ 1 ] , buf , len ) ;
transfer . tx_buf = local_buf ;
transfer . len = len + 1 ;
spi_message_add_tail ( & transfer , & msg ) ;
spi_sync ( spi , & msg ) ;
}
static int spi_max3420_enable ( struct max3420_ep * ep )
{
struct max3420_udc * udc = ep - > udc ;
unsigned long flags ;
u8 epdis , epien ;
int todo ;
spin_lock_irqsave ( & ep - > lock , flags ) ;
todo = ep - > todo & ENABLE_EP ;
ep - > todo & = ~ ENABLE_EP ;
spin_unlock_irqrestore ( & ep - > lock , flags ) ;
if ( ! todo | | ep - > id = = 0 )
return false ;
epien = spi_rd8 ( udc , MAX3420_REG_EPIEN ) ;
epdis = spi_rd8 ( udc , MAX3420_REG_CLRTOGS ) ;
if ( todo = = ENABLE ) {
epdis & = ~ BIT ( ep - > id + 4 ) ;
epien | = BIT ( ep - > id + 1 ) ;
} else {
epdis | = BIT ( ep - > id + 4 ) ;
epien & = ~ BIT ( ep - > id + 1 ) ;
}
spi_wr8 ( udc , MAX3420_REG_CLRTOGS , epdis ) ;
spi_wr8 ( udc , MAX3420_REG_EPIEN , epien ) ;
return true ;
}
static int spi_max3420_stall ( struct max3420_ep * ep )
{
struct max3420_udc * udc = ep - > udc ;
unsigned long flags ;
u8 epstalls ;
int todo ;
spin_lock_irqsave ( & ep - > lock , flags ) ;
todo = ep - > todo & STALL_EP ;
ep - > todo & = ~ STALL_EP ;
spin_unlock_irqrestore ( & ep - > lock , flags ) ;
if ( ! todo | | ep - > id = = 0 )
return false ;
epstalls = spi_rd8 ( udc , MAX3420_REG_EPSTALLS ) ;
if ( todo = = STALL ) {
ep - > halted = 1 ;
epstalls | = BIT ( ep - > id + 1 ) ;
} else {
u8 clrtogs ;
ep - > halted = 0 ;
epstalls & = ~ BIT ( ep - > id + 1 ) ;
clrtogs = spi_rd8 ( udc , MAX3420_REG_CLRTOGS ) ;
clrtogs | = BIT ( ep - > id + 1 ) ;
spi_wr8 ( udc , MAX3420_REG_CLRTOGS , clrtogs ) ;
}
spi_wr8 ( udc , MAX3420_REG_EPSTALLS , epstalls | ACKSTAT ) ;
return true ;
}
static int spi_max3420_rwkup ( struct max3420_udc * udc )
{
unsigned long flags ;
int wake_remote ;
u8 usbctl ;
spin_lock_irqsave ( & udc - > lock , flags ) ;
wake_remote = udc - > todo & REMOTE_WAKEUP ;
udc - > todo & = ~ REMOTE_WAKEUP ;
spin_unlock_irqrestore ( & udc - > lock , flags ) ;
if ( ! wake_remote | | ! udc - > suspended )
return false ;
/* Set Remote-WkUp Signal*/
usbctl = spi_rd8 ( udc , MAX3420_REG_USBCTL ) ;
usbctl | = SIGRWU ;
spi_wr8 ( udc , MAX3420_REG_USBCTL , usbctl ) ;
msleep_interruptible ( 5 ) ;
/* Clear Remote-WkUp Signal*/
usbctl = spi_rd8 ( udc , MAX3420_REG_USBCTL ) ;
usbctl & = ~ SIGRWU ;
spi_wr8 ( udc , MAX3420_REG_USBCTL , usbctl ) ;
udc - > suspended = false ;
return true ;
}
static void max3420_nuke ( struct max3420_ep * ep , int status ) ;
static void __max3420_stop ( struct max3420_udc * udc )
{
u8 val ;
int i ;
/* clear all pending requests */
for ( i = 1 ; i < MAX3420_MAX_EPS ; i + + )
max3420_nuke ( & udc - > ep [ i ] , - ECONNRESET ) ;
/* Disable IRQ to CPU */
spi_wr8 ( udc , MAX3420_REG_CPUCTL , 0 ) ;
val = spi_rd8 ( udc , MAX3420_REG_USBCTL ) ;
val | = PWRDOWN ;
if ( udc - > is_selfpowered )
val & = ~ HOSCSTEN ;
else
val | = HOSCSTEN ;
spi_wr8 ( udc , MAX3420_REG_USBCTL , val ) ;
}
static void __max3420_start ( struct max3420_udc * udc )
{
u8 val ;
/* Need this delay if bus-powered,
* but even for self - powered it helps stability
*/
msleep_interruptible ( 250 ) ;
/* configure SPI */
spi_wr8 ( udc , MAX3420_REG_PINCTL , FDUPSPI ) ;
/* Chip Reset */
spi_wr8 ( udc , MAX3420_REG_USBCTL , CHIPRES ) ;
msleep_interruptible ( 5 ) ;
spi_wr8 ( udc , MAX3420_REG_USBCTL , 0 ) ;
/* Poll for OSC to stabilize */
while ( 1 ) {
val = spi_rd8 ( udc , MAX3420_REG_USBIRQ ) ;
if ( val & OSCOKIRQ )
break ;
cond_resched ( ) ;
}
/* Enable PULL-UP only when Vbus detected */
val = spi_rd8 ( udc , MAX3420_REG_USBCTL ) ;
val | = VBGATE | CONNECT ;
spi_wr8 ( udc , MAX3420_REG_USBCTL , val ) ;
val = URESDNIRQ | URESIRQ ;
if ( udc - > is_selfpowered )
val | = NOVBUSIRQ ;
spi_wr8 ( udc , MAX3420_REG_USBIEN , val ) ;
/* Enable only EP0 interrupts */
val = IN0BAVIRQ | OUT0DAVIRQ | SUDAVIRQ ;
spi_wr8 ( udc , MAX3420_REG_EPIEN , val ) ;
/* Enable IRQ to CPU */
spi_wr8 ( udc , MAX3420_REG_CPUCTL , IE ) ;
}
static int max3420_start ( struct max3420_udc * udc )
{
unsigned long flags ;
int todo ;
spin_lock_irqsave ( & udc - > lock , flags ) ;
todo = udc - > todo & UDC_START ;
udc - > todo & = ~ UDC_START ;
spin_unlock_irqrestore ( & udc - > lock , flags ) ;
if ( ! todo )
return false ;
if ( udc - > vbus_active & & udc - > softconnect )
__max3420_start ( udc ) ;
else
__max3420_stop ( udc ) ;
return true ;
}
static irqreturn_t max3420_vbus_handler ( int irq , void * dev_id )
{
struct max3420_udc * udc = dev_id ;
unsigned long flags ;
spin_lock_irqsave ( & udc - > lock , flags ) ;
/* its a vbus change interrupt */
udc - > vbus_active = ! udc - > vbus_active ;
udc - > todo | = UDC_START ;
usb_udc_vbus_handler ( & udc - > gadget , udc - > vbus_active ) ;
usb_gadget_set_state ( & udc - > gadget , udc - > vbus_active
? USB_STATE_POWERED : USB_STATE_NOTATTACHED ) ;
spin_unlock_irqrestore ( & udc - > lock , flags ) ;
2021-06-11 10:28:11 +02:00
if ( udc - > thread_task )
2020-01-21 21:04:16 -06:00
wake_up_process ( udc - > thread_task ) ;
return IRQ_HANDLED ;
}
static irqreturn_t max3420_irq_handler ( int irq , void * dev_id )
{
struct max3420_udc * udc = dev_id ;
struct spi_device * spi = udc - > spi ;
unsigned long flags ;
spin_lock_irqsave ( & udc - > lock , flags ) ;
if ( ( udc - > todo & ENABLE_IRQ ) = = 0 ) {
disable_irq_nosync ( spi - > irq ) ;
udc - > todo | = ENABLE_IRQ ;
}
spin_unlock_irqrestore ( & udc - > lock , flags ) ;
2021-06-11 10:28:11 +02:00
if ( udc - > thread_task )
2020-01-21 21:04:16 -06:00
wake_up_process ( udc - > thread_task ) ;
return IRQ_HANDLED ;
}
static void max3420_getstatus ( struct max3420_udc * udc )
{
struct max3420_ep * ep ;
u16 status = 0 ;
switch ( udc - > setup . bRequestType & USB_RECIP_MASK ) {
case USB_RECIP_DEVICE :
/* Get device status */
status = udc - > gadget . is_selfpowered < < USB_DEVICE_SELF_POWERED ;
status | = ( udc - > remote_wkp < < USB_DEVICE_REMOTE_WAKEUP ) ;
break ;
case USB_RECIP_INTERFACE :
if ( udc - > driver - > setup ( & udc - > gadget , & udc - > setup ) < 0 )
goto stall ;
break ;
case USB_RECIP_ENDPOINT :
ep = & udc - > ep [ udc - > setup . wIndex & USB_ENDPOINT_NUMBER_MASK ] ;
if ( udc - > setup . wIndex & USB_DIR_IN ) {
if ( ! ep - > ep_usb . caps . dir_in )
goto stall ;
} else {
if ( ! ep - > ep_usb . caps . dir_out )
goto stall ;
}
if ( ep - > halted )
status = 1 < < USB_ENDPOINT_HALT ;
break ;
default :
goto stall ;
}
status = cpu_to_le16 ( status ) ;
spi_wr_buf ( udc , MAX3420_REG_EP0FIFO , & status , 2 ) ;
spi_wr8_ack ( udc , MAX3420_REG_EP0BC , 2 , 1 ) ;
return ;
stall :
dev_err ( udc - > dev , " Can't respond to getstatus request \n " ) ;
spi_wr8 ( udc , MAX3420_REG_EPSTALLS , STLEP0IN | STLEP0OUT | STLSTAT ) ;
}
static void max3420_set_clear_feature ( struct max3420_udc * udc )
{
struct max3420_ep * ep ;
int set = udc - > setup . bRequest = = USB_REQ_SET_FEATURE ;
unsigned long flags ;
int id ;
switch ( udc - > setup . bRequestType ) {
case USB_RECIP_DEVICE :
if ( udc - > setup . wValue ! = USB_DEVICE_REMOTE_WAKEUP )
break ;
if ( udc - > setup . bRequest = = USB_REQ_SET_FEATURE )
udc - > remote_wkp = 1 ;
else
udc - > remote_wkp = 0 ;
return spi_ack_ctrl ( udc ) ;
case USB_RECIP_ENDPOINT :
if ( udc - > setup . wValue ! = USB_ENDPOINT_HALT )
break ;
id = udc - > setup . wIndex & USB_ENDPOINT_NUMBER_MASK ;
ep = & udc - > ep [ id ] ;
spin_lock_irqsave ( & ep - > lock , flags ) ;
ep - > todo & = ~ STALL_EP ;
if ( set )
ep - > todo | = STALL ;
else
ep - > todo | = UNSTALL ;
spin_unlock_irqrestore ( & ep - > lock , flags ) ;
spi_max3420_stall ( ep ) ;
return ;
default :
break ;
}
dev_err ( udc - > dev , " Can't respond to SET/CLEAR FEATURE \n " ) ;
spi_wr8 ( udc , MAX3420_REG_EPSTALLS , STLEP0IN | STLEP0OUT | STLSTAT ) ;
}
static void max3420_handle_setup ( struct max3420_udc * udc )
{
struct usb_ctrlrequest setup ;
spi_rd_buf ( udc , MAX3420_REG_SUDFIFO , ( void * ) & setup , 8 ) ;
udc - > setup = setup ;
udc - > setup . wValue = cpu_to_le16 ( setup . wValue ) ;
udc - > setup . wIndex = cpu_to_le16 ( setup . wIndex ) ;
udc - > setup . wLength = cpu_to_le16 ( setup . wLength ) ;
switch ( udc - > setup . bRequest ) {
case USB_REQ_GET_STATUS :
/* Data+Status phase form udc */
if ( ( udc - > setup . bRequestType &
( USB_DIR_IN | USB_TYPE_MASK ) ) ! =
( USB_DIR_IN | USB_TYPE_STANDARD ) ) {
break ;
}
return max3420_getstatus ( udc ) ;
case USB_REQ_SET_ADDRESS :
/* Status phase from udc */
if ( udc - > setup . bRequestType ! = ( USB_DIR_OUT |
USB_TYPE_STANDARD | USB_RECIP_DEVICE ) ) {
break ;
}
2020-07-06 14:33:32 +01:00
spi_rd8_ack ( udc , MAX3420_REG_FNADDR , 1 ) ;
2020-01-21 21:04:16 -06:00
dev_dbg ( udc - > dev , " Assigned Address=%d \n " , udc - > setup . wValue ) ;
return ;
case USB_REQ_CLEAR_FEATURE :
case USB_REQ_SET_FEATURE :
/* Requests with no data phase, status phase from udc */
if ( ( udc - > setup . bRequestType & USB_TYPE_MASK )
! = USB_TYPE_STANDARD )
break ;
return max3420_set_clear_feature ( udc ) ;
default :
break ;
}
if ( udc - > driver - > setup ( & udc - > gadget , & setup ) < 0 ) {
/* Stall EP0 */
spi_wr8 ( udc , MAX3420_REG_EPSTALLS ,
STLEP0IN | STLEP0OUT | STLSTAT ) ;
}
}
static void max3420_req_done ( struct max3420_req * req , int status )
{
struct max3420_ep * ep = req - > ep ;
struct max3420_udc * udc = ep - > udc ;
if ( req - > usb_req . status = = - EINPROGRESS )
req - > usb_req . status = status ;
else
status = req - > usb_req . status ;
if ( status & & status ! = - ESHUTDOWN )
dev_err ( udc - > dev , " %s done %p, status %d \n " ,
ep - > ep_usb . name , req , status ) ;
if ( req - > usb_req . complete )
req - > usb_req . complete ( & ep - > ep_usb , & req - > usb_req ) ;
}
static int max3420_do_data ( struct max3420_udc * udc , int ep_id , int in )
{
struct max3420_ep * ep = & udc - > ep [ ep_id ] ;
struct max3420_req * req ;
int done , length , psz ;
void * buf ;
if ( list_empty ( & ep - > queue ) )
return false ;
req = list_first_entry ( & ep - > queue , struct max3420_req , queue ) ;
buf = req - > usb_req . buf + req - > usb_req . actual ;
psz = ep - > ep_usb . maxpacket ;
length = req - > usb_req . length - req - > usb_req . actual ;
length = min ( length , psz ) ;
if ( length = = 0 ) {
done = 1 ;
goto xfer_done ;
}
done = 0 ;
if ( in ) {
prefetch ( buf ) ;
spi_wr_buf ( udc , MAX3420_REG_EP0FIFO + ep_id , buf , length ) ;
spi_wr8 ( udc , MAX3420_REG_EP0BC + ep_id , length ) ;
if ( length < psz )
done = 1 ;
} else {
psz = spi_rd8 ( udc , MAX3420_REG_EP0BC + ep_id ) ;
length = min ( length , psz ) ;
prefetchw ( buf ) ;
spi_rd_buf ( udc , MAX3420_REG_EP0FIFO + ep_id , buf , length ) ;
if ( length < ep - > ep_usb . maxpacket )
done = 1 ;
}
req - > usb_req . actual + = length ;
if ( req - > usb_req . actual = = req - > usb_req . length )
done = 1 ;
xfer_done :
if ( done ) {
unsigned long flags ;
spin_lock_irqsave ( & ep - > lock , flags ) ;
list_del_init ( & req - > queue ) ;
spin_unlock_irqrestore ( & ep - > lock , flags ) ;
if ( ep_id = = 0 )
spi_ack_ctrl ( udc ) ;
max3420_req_done ( req , 0 ) ;
}
return true ;
}
static int max3420_handle_irqs ( struct max3420_udc * udc )
{
u8 epien , epirq , usbirq , usbien , reg [ 4 ] ;
bool ret = false ;
spi_rd_buf ( udc , MAX3420_REG_EPIRQ , reg , 4 ) ;
epirq = reg [ 0 ] ;
epien = reg [ 1 ] ;
usbirq = reg [ 2 ] ;
usbien = reg [ 3 ] ;
usbirq & = usbien ;
epirq & = epien ;
if ( epirq & SUDAVIRQ ) {
spi_wr8 ( udc , MAX3420_REG_EPIRQ , SUDAVIRQ ) ;
max3420_handle_setup ( udc ) ;
return true ;
}
if ( usbirq & VBUSIRQ ) {
spi_wr8 ( udc , MAX3420_REG_USBIRQ , VBUSIRQ ) ;
dev_dbg ( udc - > dev , " Cable plugged in \n " ) ;
return true ;
}
if ( usbirq & NOVBUSIRQ ) {
spi_wr8 ( udc , MAX3420_REG_USBIRQ , NOVBUSIRQ ) ;
dev_dbg ( udc - > dev , " Cable pulled out \n " ) ;
return true ;
}
if ( usbirq & URESIRQ ) {
spi_wr8 ( udc , MAX3420_REG_USBIRQ , URESIRQ ) ;
dev_dbg ( udc - > dev , " USB Reset - Start \n " ) ;
return true ;
}
if ( usbirq & URESDNIRQ ) {
spi_wr8 ( udc , MAX3420_REG_USBIRQ , URESDNIRQ ) ;
dev_dbg ( udc - > dev , " USB Reset - END \n " ) ;
spi_wr8 ( udc , MAX3420_REG_USBIEN , URESDNIRQ | URESIRQ ) ;
spi_wr8 ( udc , MAX3420_REG_EPIEN , SUDAVIRQ | IN0BAVIRQ
| OUT0DAVIRQ ) ;
return true ;
}
if ( usbirq & SUSPIRQ ) {
spi_wr8 ( udc , MAX3420_REG_USBIRQ , SUSPIRQ ) ;
dev_dbg ( udc - > dev , " USB Suspend - Enter \n " ) ;
udc - > suspended = true ;
return true ;
}
if ( usbirq & BUSACTIRQ ) {
spi_wr8 ( udc , MAX3420_REG_USBIRQ , BUSACTIRQ ) ;
dev_dbg ( udc - > dev , " USB Suspend - Exit \n " ) ;
udc - > suspended = false ;
return true ;
}
if ( usbirq & RWUDNIRQ ) {
spi_wr8 ( udc , MAX3420_REG_USBIRQ , RWUDNIRQ ) ;
dev_dbg ( udc - > dev , " Asked Host to wakeup \n " ) ;
return true ;
}
if ( usbirq & OSCOKIRQ ) {
spi_wr8 ( udc , MAX3420_REG_USBIRQ , OSCOKIRQ ) ;
dev_dbg ( udc - > dev , " Osc stabilized, start work \n " ) ;
return true ;
}
if ( epirq & OUT0DAVIRQ & & max3420_do_data ( udc , 0 , 0 ) ) {
spi_wr8_ack ( udc , MAX3420_REG_EPIRQ , OUT0DAVIRQ , 1 ) ;
ret = true ;
}
if ( epirq & IN0BAVIRQ & & max3420_do_data ( udc , 0 , 1 ) )
ret = true ;
if ( epirq & OUT1DAVIRQ & & max3420_do_data ( udc , 1 , 0 ) ) {
spi_wr8_ack ( udc , MAX3420_REG_EPIRQ , OUT1DAVIRQ , 1 ) ;
ret = true ;
}
if ( epirq & IN2BAVIRQ & & max3420_do_data ( udc , 2 , 1 ) )
ret = true ;
if ( epirq & IN3BAVIRQ & & max3420_do_data ( udc , 3 , 1 ) )
ret = true ;
return ret ;
}
static int max3420_thread ( void * dev_id )
{
struct max3420_udc * udc = dev_id ;
struct spi_device * spi = udc - > spi ;
int i , loop_again = 1 ;
unsigned long flags ;
while ( ! kthread_should_stop ( ) ) {
if ( ! loop_again ) {
ktime_t kt = ns_to_ktime ( 1000 * 1000 * 250 ) ; /* 250ms */
set_current_state ( TASK_INTERRUPTIBLE ) ;
spin_lock_irqsave ( & udc - > lock , flags ) ;
if ( udc - > todo & ENABLE_IRQ ) {
enable_irq ( spi - > irq ) ;
udc - > todo & = ~ ENABLE_IRQ ;
}
spin_unlock_irqrestore ( & udc - > lock , flags ) ;
schedule_hrtimeout ( & kt , HRTIMER_MODE_REL ) ;
}
loop_again = 0 ;
mutex_lock ( & udc - > spi_bus_mutex ) ;
/* If bus-vbus_active and disconnected */
if ( ! udc - > vbus_active | | ! udc - > softconnect )
goto loop ;
if ( max3420_start ( udc ) ) {
loop_again = 1 ;
goto loop ;
}
if ( max3420_handle_irqs ( udc ) ) {
loop_again = 1 ;
goto loop ;
}
if ( spi_max3420_rwkup ( udc ) ) {
loop_again = 1 ;
goto loop ;
}
max3420_do_data ( udc , 0 , 1 ) ; /* get done with the EP0 ZLP */
for ( i = 1 ; i < MAX3420_MAX_EPS ; i + + ) {
struct max3420_ep * ep = & udc - > ep [ i ] ;
if ( spi_max3420_enable ( ep ) )
loop_again = 1 ;
if ( spi_max3420_stall ( ep ) )
loop_again = 1 ;
}
loop :
mutex_unlock ( & udc - > spi_bus_mutex ) ;
}
set_current_state ( TASK_RUNNING ) ;
2020-04-11 08:56:21 +02:00
dev_info ( udc - > dev , " SPI thread exiting \n " ) ;
2020-01-21 21:04:16 -06:00
return 0 ;
}
static int max3420_ep_set_halt ( struct usb_ep * _ep , int stall )
{
struct max3420_ep * ep = to_max3420_ep ( _ep ) ;
struct max3420_udc * udc = ep - > udc ;
unsigned long flags ;
spin_lock_irqsave ( & ep - > lock , flags ) ;
ep - > todo & = ~ STALL_EP ;
if ( stall )
ep - > todo | = STALL ;
else
ep - > todo | = UNSTALL ;
spin_unlock_irqrestore ( & ep - > lock , flags ) ;
wake_up_process ( udc - > thread_task ) ;
dev_dbg ( udc - > dev , " %sStall %s \n " , stall ? " " : " Un " , ep - > name ) ;
return 0 ;
}
static int __max3420_ep_enable ( struct max3420_ep * ep ,
const struct usb_endpoint_descriptor * desc )
{
unsigned int maxp = usb_endpoint_maxp ( desc ) ;
unsigned long flags ;
spin_lock_irqsave ( & ep - > lock , flags ) ;
ep - > ep_usb . desc = desc ;
ep - > ep_usb . maxpacket = maxp ;
ep - > todo & = ~ ENABLE_EP ;
ep - > todo | = ENABLE ;
spin_unlock_irqrestore ( & ep - > lock , flags ) ;
return 0 ;
}
static int max3420_ep_enable ( struct usb_ep * _ep ,
const struct usb_endpoint_descriptor * desc )
{
struct max3420_ep * ep = to_max3420_ep ( _ep ) ;
struct max3420_udc * udc = ep - > udc ;
__max3420_ep_enable ( ep , desc ) ;
wake_up_process ( udc - > thread_task ) ;
return 0 ;
}
static void max3420_nuke ( struct max3420_ep * ep , int status )
{
struct max3420_req * req , * r ;
unsigned long flags ;
spin_lock_irqsave ( & ep - > lock , flags ) ;
list_for_each_entry_safe ( req , r , & ep - > queue , queue ) {
list_del_init ( & req - > queue ) ;
spin_unlock_irqrestore ( & ep - > lock , flags ) ;
max3420_req_done ( req , status ) ;
spin_lock_irqsave ( & ep - > lock , flags ) ;
}
spin_unlock_irqrestore ( & ep - > lock , flags ) ;
}
static void __max3420_ep_disable ( struct max3420_ep * ep )
{
struct max3420_udc * udc = ep - > udc ;
unsigned long flags ;
spin_lock_irqsave ( & ep - > lock , flags ) ;
ep - > ep_usb . desc = NULL ;
ep - > todo & = ~ ENABLE_EP ;
ep - > todo | = DISABLE ;
spin_unlock_irqrestore ( & ep - > lock , flags ) ;
dev_dbg ( udc - > dev , " Disabled %s \n " , ep - > name ) ;
}
static int max3420_ep_disable ( struct usb_ep * _ep )
{
struct max3420_ep * ep = to_max3420_ep ( _ep ) ;
struct max3420_udc * udc = ep - > udc ;
max3420_nuke ( ep , - ESHUTDOWN ) ;
__max3420_ep_disable ( ep ) ;
wake_up_process ( udc - > thread_task ) ;
return 0 ;
}
static struct usb_request * max3420_alloc_request ( struct usb_ep * _ep ,
gfp_t gfp_flags )
{
struct max3420_ep * ep = to_max3420_ep ( _ep ) ;
struct max3420_req * req ;
req = kzalloc ( sizeof ( * req ) , gfp_flags ) ;
if ( ! req )
return NULL ;
req - > ep = ep ;
return & req - > usb_req ;
}
static void max3420_free_request ( struct usb_ep * _ep , struct usb_request * _req )
{
kfree ( to_max3420_req ( _req ) ) ;
}
static int max3420_ep_queue ( struct usb_ep * _ep , struct usb_request * _req ,
gfp_t ignored )
{
struct max3420_req * req = to_max3420_req ( _req ) ;
struct max3420_ep * ep = to_max3420_ep ( _ep ) ;
struct max3420_udc * udc = ep - > udc ;
unsigned long flags ;
_req - > status = - EINPROGRESS ;
_req - > actual = 0 ;
spin_lock_irqsave ( & ep - > lock , flags ) ;
list_add_tail ( & req - > queue , & ep - > queue ) ;
spin_unlock_irqrestore ( & ep - > lock , flags ) ;
wake_up_process ( udc - > thread_task ) ;
return 0 ;
}
static int max3420_ep_dequeue ( struct usb_ep * _ep , struct usb_request * _req )
{
2022-03-08 18:18:11 +01:00
struct max3420_req * t = NULL ;
struct max3420_req * req = to_max3420_req ( _req ) ;
struct max3420_req * iter ;
2020-01-21 21:04:16 -06:00
struct max3420_ep * ep = to_max3420_ep ( _ep ) ;
unsigned long flags ;
spin_lock_irqsave ( & ep - > lock , flags ) ;
/* Pluck the descriptor from queue */
2022-03-08 18:18:11 +01:00
list_for_each_entry ( iter , & ep - > queue , queue ) {
if ( iter ! = req )
continue ;
list_del_init ( & req - > queue ) ;
t = iter ;
break ;
}
2020-01-21 21:04:16 -06:00
spin_unlock_irqrestore ( & ep - > lock , flags ) ;
2022-03-08 18:18:11 +01:00
if ( t )
2020-01-21 21:04:16 -06:00
max3420_req_done ( req , - ECONNRESET ) ;
return 0 ;
}
static const struct usb_ep_ops max3420_ep_ops = {
. enable = max3420_ep_enable ,
. disable = max3420_ep_disable ,
. alloc_request = max3420_alloc_request ,
. free_request = max3420_free_request ,
. queue = max3420_ep_queue ,
. dequeue = max3420_ep_dequeue ,
. set_halt = max3420_ep_set_halt ,
} ;
static int max3420_wakeup ( struct usb_gadget * gadget )
{
struct max3420_udc * udc = to_udc ( gadget ) ;
unsigned long flags ;
int ret = - EINVAL ;
spin_lock_irqsave ( & udc - > lock , flags ) ;
/* Only if wakeup allowed by host */
if ( udc - > remote_wkp ) {
udc - > todo | = REMOTE_WAKEUP ;
ret = 0 ;
}
spin_unlock_irqrestore ( & udc - > lock , flags ) ;
2021-06-11 10:28:11 +02:00
if ( udc - > thread_task )
2020-01-21 21:04:16 -06:00
wake_up_process ( udc - > thread_task ) ;
return ret ;
}
static int max3420_udc_start ( struct usb_gadget * gadget ,
struct usb_gadget_driver * driver )
{
struct max3420_udc * udc = to_udc ( gadget ) ;
unsigned long flags ;
spin_lock_irqsave ( & udc - > lock , flags ) ;
/* hook up the driver */
driver - > driver . bus = NULL ;
udc - > driver = driver ;
udc - > gadget . speed = USB_SPEED_FULL ;
udc - > gadget . is_selfpowered = udc - > is_selfpowered ;
udc - > remote_wkp = 0 ;
udc - > softconnect = true ;
udc - > todo | = UDC_START ;
spin_unlock_irqrestore ( & udc - > lock , flags ) ;
2021-06-11 10:28:11 +02:00
if ( udc - > thread_task )
2020-01-21 21:04:16 -06:00
wake_up_process ( udc - > thread_task ) ;
return 0 ;
}
static int max3420_udc_stop ( struct usb_gadget * gadget )
{
struct max3420_udc * udc = to_udc ( gadget ) ;
unsigned long flags ;
spin_lock_irqsave ( & udc - > lock , flags ) ;
udc - > is_selfpowered = udc - > gadget . is_selfpowered ;
udc - > gadget . speed = USB_SPEED_UNKNOWN ;
udc - > driver = NULL ;
udc - > softconnect = false ;
udc - > todo | = UDC_START ;
spin_unlock_irqrestore ( & udc - > lock , flags ) ;
2021-06-11 10:28:11 +02:00
if ( udc - > thread_task )
2020-01-21 21:04:16 -06:00
wake_up_process ( udc - > thread_task ) ;
return 0 ;
}
static const struct usb_gadget_ops max3420_udc_ops = {
. udc_start = max3420_udc_start ,
. udc_stop = max3420_udc_stop ,
. wakeup = max3420_wakeup ,
} ;
static void max3420_eps_init ( struct max3420_udc * udc )
{
int idx ;
INIT_LIST_HEAD ( & udc - > gadget . ep_list ) ;
for ( idx = 0 ; idx < MAX3420_MAX_EPS ; idx + + ) {
struct max3420_ep * ep = & udc - > ep [ idx ] ;
spin_lock_init ( & ep - > lock ) ;
INIT_LIST_HEAD ( & ep - > queue ) ;
ep - > udc = udc ;
ep - > id = idx ;
ep - > halted = 0 ;
ep - > maxpacket = 0 ;
ep - > ep_usb . name = ep - > name ;
ep - > ep_usb . ops = & max3420_ep_ops ;
usb_ep_set_maxpacket_limit ( & ep - > ep_usb , MAX3420_EP_MAX_PACKET ) ;
if ( idx = = 0 ) { /* For EP0 */
ep - > ep_usb . desc = & ep0_desc ;
ep - > ep_usb . maxpacket = usb_endpoint_maxp ( & ep0_desc ) ;
ep - > ep_usb . caps . type_control = true ;
ep - > ep_usb . caps . dir_in = true ;
ep - > ep_usb . caps . dir_out = true ;
snprintf ( ep - > name , MAX3420_EPNAME_SIZE , " ep0 " ) ;
continue ;
}
if ( idx = = 1 ) { /* EP1 is OUT */
ep - > ep_usb . caps . dir_in = false ;
ep - > ep_usb . caps . dir_out = true ;
snprintf ( ep - > name , MAX3420_EPNAME_SIZE , " ep1-bulk-out " ) ;
} else { /* EP2 & EP3 are IN */
ep - > ep_usb . caps . dir_in = true ;
ep - > ep_usb . caps . dir_out = false ;
snprintf ( ep - > name , MAX3420_EPNAME_SIZE ,
" ep%d-bulk-in " , idx ) ;
}
ep - > ep_usb . caps . type_iso = false ;
ep - > ep_usb . caps . type_int = false ;
ep - > ep_usb . caps . type_bulk = true ;
list_add_tail ( & ep - > ep_usb . ep_list ,
& udc - > gadget . ep_list ) ;
}
}
static int max3420_probe ( struct spi_device * spi )
{
struct max3420_udc * udc ;
int err , irq ;
u8 reg [ 8 ] ;
if ( spi - > master - > flags & SPI_MASTER_HALF_DUPLEX ) {
dev_err ( & spi - > dev , " UDC needs full duplex to work \n " ) ;
return - EINVAL ;
}
spi - > mode = SPI_MODE_3 ;
spi - > bits_per_word = 8 ;
err = spi_setup ( spi ) ;
if ( err ) {
dev_err ( & spi - > dev , " Unable to setup SPI bus \n " ) ;
return - EFAULT ;
}
udc = devm_kzalloc ( & spi - > dev , sizeof ( * udc ) , GFP_KERNEL ) ;
if ( ! udc )
return - ENOMEM ;
udc - > spi = spi ;
udc - > remote_wkp = 0 ;
/* Setup gadget structure */
udc - > gadget . ops = & max3420_udc_ops ;
udc - > gadget . max_speed = USB_SPEED_FULL ;
udc - > gadget . speed = USB_SPEED_UNKNOWN ;
udc - > gadget . ep0 = & udc - > ep [ 0 ] . ep_usb ;
udc - > gadget . name = driver_name ;
spin_lock_init ( & udc - > lock ) ;
mutex_init ( & udc - > spi_bus_mutex ) ;
udc - > ep0req . ep = & udc - > ep [ 0 ] ;
udc - > ep0req . usb_req . buf = udc - > ep0buf ;
INIT_LIST_HEAD ( & udc - > ep0req . queue ) ;
/* setup Endpoints */
max3420_eps_init ( udc ) ;
/* configure SPI */
spi_rd_buf ( udc , MAX3420_REG_EPIRQ , reg , 8 ) ;
spi_wr8 ( udc , MAX3420_REG_PINCTL , FDUPSPI ) ;
err = usb_add_gadget_udc ( & spi - > dev , & udc - > gadget ) ;
if ( err )
return err ;
udc - > dev = & udc - > gadget . dev ;
spi_set_drvdata ( spi , udc ) ;
irq = of_irq_get_byname ( spi - > dev . of_node , " udc " ) ;
err = devm_request_irq ( & spi - > dev , irq , max3420_irq_handler , 0 ,
" max3420 " , udc ) ;
if ( err < 0 )
2021-07-27 15:31:42 +08:00
goto del_gadget ;
2020-01-21 21:04:16 -06:00
udc - > thread_task = kthread_create ( max3420_thread , udc ,
" max3420-thread " ) ;
2021-07-27 15:31:42 +08:00
if ( IS_ERR ( udc - > thread_task ) ) {
err = PTR_ERR ( udc - > thread_task ) ;
goto del_gadget ;
}
2020-01-21 21:04:16 -06:00
irq = of_irq_get_byname ( spi - > dev . of_node , " vbus " ) ;
if ( irq < = 0 ) { /* no vbus irq implies self-powered design */
udc - > is_selfpowered = 1 ;
udc - > vbus_active = true ;
udc - > todo | = UDC_START ;
usb_udc_vbus_handler ( & udc - > gadget , udc - > vbus_active ) ;
usb_gadget_set_state ( & udc - > gadget , USB_STATE_POWERED ) ;
max3420_start ( udc ) ;
} else {
udc - > is_selfpowered = 0 ;
/* Detect current vbus status */
spi_rd_buf ( udc , MAX3420_REG_EPIRQ , reg , 8 ) ;
if ( reg [ 7 ] ! = 0xff )
udc - > vbus_active = true ;
err = devm_request_irq ( & spi - > dev , irq ,
max3420_vbus_handler , 0 , " vbus " , udc ) ;
if ( err < 0 )
2021-07-27 15:31:42 +08:00
goto del_gadget ;
2020-01-21 21:04:16 -06:00
}
return 0 ;
2021-07-27 15:31:42 +08:00
del_gadget :
usb_del_gadget_udc ( & udc - > gadget ) ;
return err ;
2020-01-21 21:04:16 -06:00
}
2022-01-23 18:52:01 +01:00
static void max3420_remove ( struct spi_device * spi )
2020-01-21 21:04:16 -06:00
{
struct max3420_udc * udc = spi_get_drvdata ( spi ) ;
unsigned long flags ;
usb_del_gadget_udc ( & udc - > gadget ) ;
spin_lock_irqsave ( & udc - > lock , flags ) ;
kthread_stop ( udc - > thread_task ) ;
spin_unlock_irqrestore ( & udc - > lock , flags ) ;
}
static const struct of_device_id max3420_udc_of_match [ ] = {
{ . compatible = " maxim,max3420-udc " } ,
{ . compatible = " maxim,max3421-udc " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , max3420_udc_of_match ) ;
static struct spi_driver max3420_driver = {
. driver = {
. name = " max3420-udc " ,
. of_match_table = of_match_ptr ( max3420_udc_of_match ) ,
} ,
. probe = max3420_probe ,
. remove = max3420_remove ,
} ;
module_spi_driver ( max3420_driver ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_AUTHOR ( " Jassi Brar <jaswinder.singh@linaro.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;