162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Intel PXA25x and IXP4xx on-chip full speed USB device controllers 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) 662306a36Sopenharmony_ci * Copyright (C) 2003 Robert Schwebel, Pengutronix 762306a36Sopenharmony_ci * Copyright (C) 2003 Benedikt Spranger, Pengutronix 862306a36Sopenharmony_ci * Copyright (C) 2003 David Brownell 962306a36Sopenharmony_ci * Copyright (C) 2003 Joshua Wise 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* #define VERBOSE_DEBUG */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/device.h> 1562306a36Sopenharmony_ci#include <linux/gpio.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/ioport.h> 1962306a36Sopenharmony_ci#include <linux/types.h> 2062306a36Sopenharmony_ci#include <linux/errno.h> 2162306a36Sopenharmony_ci#include <linux/err.h> 2262306a36Sopenharmony_ci#include <linux/delay.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <linux/timer.h> 2562306a36Sopenharmony_ci#include <linux/list.h> 2662306a36Sopenharmony_ci#include <linux/interrupt.h> 2762306a36Sopenharmony_ci#include <linux/mm.h> 2862306a36Sopenharmony_ci#include <linux/platform_data/pxa2xx_udc.h> 2962306a36Sopenharmony_ci#include <linux/platform_device.h> 3062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 3162306a36Sopenharmony_ci#include <linux/irq.h> 3262306a36Sopenharmony_ci#include <linux/clk.h> 3362306a36Sopenharmony_ci#include <linux/seq_file.h> 3462306a36Sopenharmony_ci#include <linux/debugfs.h> 3562306a36Sopenharmony_ci#include <linux/io.h> 3662306a36Sopenharmony_ci#include <linux/prefetch.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include <asm/byteorder.h> 3962306a36Sopenharmony_ci#include <asm/dma.h> 4062306a36Sopenharmony_ci#include <asm/mach-types.h> 4162306a36Sopenharmony_ci#include <asm/unaligned.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include <linux/usb/ch9.h> 4462306a36Sopenharmony_ci#include <linux/usb/gadget.h> 4562306a36Sopenharmony_ci#include <linux/usb/otg.h> 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define UDCCR 0x0000 /* UDC Control Register */ 4862306a36Sopenharmony_ci#define UDC_RES1 0x0004 /* UDC Undocumented - Reserved1 */ 4962306a36Sopenharmony_ci#define UDC_RES2 0x0008 /* UDC Undocumented - Reserved2 */ 5062306a36Sopenharmony_ci#define UDC_RES3 0x000C /* UDC Undocumented - Reserved3 */ 5162306a36Sopenharmony_ci#define UDCCS0 0x0010 /* UDC Endpoint 0 Control/Status Register */ 5262306a36Sopenharmony_ci#define UDCCS1 0x0014 /* UDC Endpoint 1 (IN) Control/Status Register */ 5362306a36Sopenharmony_ci#define UDCCS2 0x0018 /* UDC Endpoint 2 (OUT) Control/Status Register */ 5462306a36Sopenharmony_ci#define UDCCS3 0x001C /* UDC Endpoint 3 (IN) Control/Status Register */ 5562306a36Sopenharmony_ci#define UDCCS4 0x0020 /* UDC Endpoint 4 (OUT) Control/Status Register */ 5662306a36Sopenharmony_ci#define UDCCS5 0x0024 /* UDC Endpoint 5 (Interrupt) Control/Status Register */ 5762306a36Sopenharmony_ci#define UDCCS6 0x0028 /* UDC Endpoint 6 (IN) Control/Status Register */ 5862306a36Sopenharmony_ci#define UDCCS7 0x002C /* UDC Endpoint 7 (OUT) Control/Status Register */ 5962306a36Sopenharmony_ci#define UDCCS8 0x0030 /* UDC Endpoint 8 (IN) Control/Status Register */ 6062306a36Sopenharmony_ci#define UDCCS9 0x0034 /* UDC Endpoint 9 (OUT) Control/Status Register */ 6162306a36Sopenharmony_ci#define UDCCS10 0x0038 /* UDC Endpoint 10 (Interrupt) Control/Status Register */ 6262306a36Sopenharmony_ci#define UDCCS11 0x003C /* UDC Endpoint 11 (IN) Control/Status Register */ 6362306a36Sopenharmony_ci#define UDCCS12 0x0040 /* UDC Endpoint 12 (OUT) Control/Status Register */ 6462306a36Sopenharmony_ci#define UDCCS13 0x0044 /* UDC Endpoint 13 (IN) Control/Status Register */ 6562306a36Sopenharmony_ci#define UDCCS14 0x0048 /* UDC Endpoint 14 (OUT) Control/Status Register */ 6662306a36Sopenharmony_ci#define UDCCS15 0x004C /* UDC Endpoint 15 (Interrupt) Control/Status Register */ 6762306a36Sopenharmony_ci#define UFNRH 0x0060 /* UDC Frame Number Register High */ 6862306a36Sopenharmony_ci#define UFNRL 0x0064 /* UDC Frame Number Register Low */ 6962306a36Sopenharmony_ci#define UBCR2 0x0068 /* UDC Byte Count Reg 2 */ 7062306a36Sopenharmony_ci#define UBCR4 0x006c /* UDC Byte Count Reg 4 */ 7162306a36Sopenharmony_ci#define UBCR7 0x0070 /* UDC Byte Count Reg 7 */ 7262306a36Sopenharmony_ci#define UBCR9 0x0074 /* UDC Byte Count Reg 9 */ 7362306a36Sopenharmony_ci#define UBCR12 0x0078 /* UDC Byte Count Reg 12 */ 7462306a36Sopenharmony_ci#define UBCR14 0x007c /* UDC Byte Count Reg 14 */ 7562306a36Sopenharmony_ci#define UDDR0 0x0080 /* UDC Endpoint 0 Data Register */ 7662306a36Sopenharmony_ci#define UDDR1 0x0100 /* UDC Endpoint 1 Data Register */ 7762306a36Sopenharmony_ci#define UDDR2 0x0180 /* UDC Endpoint 2 Data Register */ 7862306a36Sopenharmony_ci#define UDDR3 0x0200 /* UDC Endpoint 3 Data Register */ 7962306a36Sopenharmony_ci#define UDDR4 0x0400 /* UDC Endpoint 4 Data Register */ 8062306a36Sopenharmony_ci#define UDDR5 0x00A0 /* UDC Endpoint 5 Data Register */ 8162306a36Sopenharmony_ci#define UDDR6 0x0600 /* UDC Endpoint 6 Data Register */ 8262306a36Sopenharmony_ci#define UDDR7 0x0680 /* UDC Endpoint 7 Data Register */ 8362306a36Sopenharmony_ci#define UDDR8 0x0700 /* UDC Endpoint 8 Data Register */ 8462306a36Sopenharmony_ci#define UDDR9 0x0900 /* UDC Endpoint 9 Data Register */ 8562306a36Sopenharmony_ci#define UDDR10 0x00C0 /* UDC Endpoint 10 Data Register */ 8662306a36Sopenharmony_ci#define UDDR11 0x0B00 /* UDC Endpoint 11 Data Register */ 8762306a36Sopenharmony_ci#define UDDR12 0x0B80 /* UDC Endpoint 12 Data Register */ 8862306a36Sopenharmony_ci#define UDDR13 0x0C00 /* UDC Endpoint 13 Data Register */ 8962306a36Sopenharmony_ci#define UDDR14 0x0E00 /* UDC Endpoint 14 Data Register */ 9062306a36Sopenharmony_ci#define UDDR15 0x00E0 /* UDC Endpoint 15 Data Register */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define UICR0 0x0050 /* UDC Interrupt Control Register 0 */ 9362306a36Sopenharmony_ci#define UICR1 0x0054 /* UDC Interrupt Control Register 1 */ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#define USIR0 0x0058 /* UDC Status Interrupt Register 0 */ 9662306a36Sopenharmony_ci#define USIR1 0x005C /* UDC Status Interrupt Register 1 */ 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#define UDCCR_UDE (1 << 0) /* UDC enable */ 9962306a36Sopenharmony_ci#define UDCCR_UDA (1 << 1) /* UDC active */ 10062306a36Sopenharmony_ci#define UDCCR_RSM (1 << 2) /* Device resume */ 10162306a36Sopenharmony_ci#define UDCCR_RESIR (1 << 3) /* Resume interrupt request */ 10262306a36Sopenharmony_ci#define UDCCR_SUSIR (1 << 4) /* Suspend interrupt request */ 10362306a36Sopenharmony_ci#define UDCCR_SRM (1 << 5) /* Suspend/resume interrupt mask */ 10462306a36Sopenharmony_ci#define UDCCR_RSTIR (1 << 6) /* Reset interrupt request */ 10562306a36Sopenharmony_ci#define UDCCR_REM (1 << 7) /* Reset interrupt mask */ 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#define UDCCS0_OPR (1 << 0) /* OUT packet ready */ 10862306a36Sopenharmony_ci#define UDCCS0_IPR (1 << 1) /* IN packet ready */ 10962306a36Sopenharmony_ci#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */ 11062306a36Sopenharmony_ci#define UDCCS0_DRWF (1 << 3) /* Device remote wakeup feature */ 11162306a36Sopenharmony_ci#define UDCCS0_SST (1 << 4) /* Sent stall */ 11262306a36Sopenharmony_ci#define UDCCS0_FST (1 << 5) /* Force stall */ 11362306a36Sopenharmony_ci#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */ 11462306a36Sopenharmony_ci#define UDCCS0_SA (1 << 7) /* Setup active */ 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci#define UDCCS_BI_TFS (1 << 0) /* Transmit FIFO service */ 11762306a36Sopenharmony_ci#define UDCCS_BI_TPC (1 << 1) /* Transmit packet complete */ 11862306a36Sopenharmony_ci#define UDCCS_BI_FTF (1 << 2) /* Flush Tx FIFO */ 11962306a36Sopenharmony_ci#define UDCCS_BI_TUR (1 << 3) /* Transmit FIFO underrun */ 12062306a36Sopenharmony_ci#define UDCCS_BI_SST (1 << 4) /* Sent stall */ 12162306a36Sopenharmony_ci#define UDCCS_BI_FST (1 << 5) /* Force stall */ 12262306a36Sopenharmony_ci#define UDCCS_BI_TSP (1 << 7) /* Transmit short packet */ 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci#define UDCCS_BO_RFS (1 << 0) /* Receive FIFO service */ 12562306a36Sopenharmony_ci#define UDCCS_BO_RPC (1 << 1) /* Receive packet complete */ 12662306a36Sopenharmony_ci#define UDCCS_BO_DME (1 << 3) /* DMA enable */ 12762306a36Sopenharmony_ci#define UDCCS_BO_SST (1 << 4) /* Sent stall */ 12862306a36Sopenharmony_ci#define UDCCS_BO_FST (1 << 5) /* Force stall */ 12962306a36Sopenharmony_ci#define UDCCS_BO_RNE (1 << 6) /* Receive FIFO not empty */ 13062306a36Sopenharmony_ci#define UDCCS_BO_RSP (1 << 7) /* Receive short packet */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#define UDCCS_II_TFS (1 << 0) /* Transmit FIFO service */ 13362306a36Sopenharmony_ci#define UDCCS_II_TPC (1 << 1) /* Transmit packet complete */ 13462306a36Sopenharmony_ci#define UDCCS_II_FTF (1 << 2) /* Flush Tx FIFO */ 13562306a36Sopenharmony_ci#define UDCCS_II_TUR (1 << 3) /* Transmit FIFO underrun */ 13662306a36Sopenharmony_ci#define UDCCS_II_TSP (1 << 7) /* Transmit short packet */ 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci#define UDCCS_IO_RFS (1 << 0) /* Receive FIFO service */ 13962306a36Sopenharmony_ci#define UDCCS_IO_RPC (1 << 1) /* Receive packet complete */ 14062306a36Sopenharmony_ci#ifdef CONFIG_ARCH_IXP4XX /* FIXME: is this right?, datasheed says '2' */ 14162306a36Sopenharmony_ci#define UDCCS_IO_ROF (1 << 3) /* Receive overflow */ 14262306a36Sopenharmony_ci#endif 14362306a36Sopenharmony_ci#ifdef CONFIG_ARCH_PXA 14462306a36Sopenharmony_ci#define UDCCS_IO_ROF (1 << 2) /* Receive overflow */ 14562306a36Sopenharmony_ci#endif 14662306a36Sopenharmony_ci#define UDCCS_IO_DME (1 << 3) /* DMA enable */ 14762306a36Sopenharmony_ci#define UDCCS_IO_RNE (1 << 6) /* Receive FIFO not empty */ 14862306a36Sopenharmony_ci#define UDCCS_IO_RSP (1 << 7) /* Receive short packet */ 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci#define UDCCS_INT_TFS (1 << 0) /* Transmit FIFO service */ 15162306a36Sopenharmony_ci#define UDCCS_INT_TPC (1 << 1) /* Transmit packet complete */ 15262306a36Sopenharmony_ci#define UDCCS_INT_FTF (1 << 2) /* Flush Tx FIFO */ 15362306a36Sopenharmony_ci#define UDCCS_INT_TUR (1 << 3) /* Transmit FIFO underrun */ 15462306a36Sopenharmony_ci#define UDCCS_INT_SST (1 << 4) /* Sent stall */ 15562306a36Sopenharmony_ci#define UDCCS_INT_FST (1 << 5) /* Force stall */ 15662306a36Sopenharmony_ci#define UDCCS_INT_TSP (1 << 7) /* Transmit short packet */ 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#define UICR0_IM0 (1 << 0) /* Interrupt mask ep 0 */ 15962306a36Sopenharmony_ci#define UICR0_IM1 (1 << 1) /* Interrupt mask ep 1 */ 16062306a36Sopenharmony_ci#define UICR0_IM2 (1 << 2) /* Interrupt mask ep 2 */ 16162306a36Sopenharmony_ci#define UICR0_IM3 (1 << 3) /* Interrupt mask ep 3 */ 16262306a36Sopenharmony_ci#define UICR0_IM4 (1 << 4) /* Interrupt mask ep 4 */ 16362306a36Sopenharmony_ci#define UICR0_IM5 (1 << 5) /* Interrupt mask ep 5 */ 16462306a36Sopenharmony_ci#define UICR0_IM6 (1 << 6) /* Interrupt mask ep 6 */ 16562306a36Sopenharmony_ci#define UICR0_IM7 (1 << 7) /* Interrupt mask ep 7 */ 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci#define UICR1_IM8 (1 << 0) /* Interrupt mask ep 8 */ 16862306a36Sopenharmony_ci#define UICR1_IM9 (1 << 1) /* Interrupt mask ep 9 */ 16962306a36Sopenharmony_ci#define UICR1_IM10 (1 << 2) /* Interrupt mask ep 10 */ 17062306a36Sopenharmony_ci#define UICR1_IM11 (1 << 3) /* Interrupt mask ep 11 */ 17162306a36Sopenharmony_ci#define UICR1_IM12 (1 << 4) /* Interrupt mask ep 12 */ 17262306a36Sopenharmony_ci#define UICR1_IM13 (1 << 5) /* Interrupt mask ep 13 */ 17362306a36Sopenharmony_ci#define UICR1_IM14 (1 << 6) /* Interrupt mask ep 14 */ 17462306a36Sopenharmony_ci#define UICR1_IM15 (1 << 7) /* Interrupt mask ep 15 */ 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci#define USIR0_IR0 (1 << 0) /* Interrupt request ep 0 */ 17762306a36Sopenharmony_ci#define USIR0_IR1 (1 << 1) /* Interrupt request ep 1 */ 17862306a36Sopenharmony_ci#define USIR0_IR2 (1 << 2) /* Interrupt request ep 2 */ 17962306a36Sopenharmony_ci#define USIR0_IR3 (1 << 3) /* Interrupt request ep 3 */ 18062306a36Sopenharmony_ci#define USIR0_IR4 (1 << 4) /* Interrupt request ep 4 */ 18162306a36Sopenharmony_ci#define USIR0_IR5 (1 << 5) /* Interrupt request ep 5 */ 18262306a36Sopenharmony_ci#define USIR0_IR6 (1 << 6) /* Interrupt request ep 6 */ 18362306a36Sopenharmony_ci#define USIR0_IR7 (1 << 7) /* Interrupt request ep 7 */ 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci#define USIR1_IR8 (1 << 0) /* Interrupt request ep 8 */ 18662306a36Sopenharmony_ci#define USIR1_IR9 (1 << 1) /* Interrupt request ep 9 */ 18762306a36Sopenharmony_ci#define USIR1_IR10 (1 << 2) /* Interrupt request ep 10 */ 18862306a36Sopenharmony_ci#define USIR1_IR11 (1 << 3) /* Interrupt request ep 11 */ 18962306a36Sopenharmony_ci#define USIR1_IR12 (1 << 4) /* Interrupt request ep 12 */ 19062306a36Sopenharmony_ci#define USIR1_IR13 (1 << 5) /* Interrupt request ep 13 */ 19162306a36Sopenharmony_ci#define USIR1_IR14 (1 << 6) /* Interrupt request ep 14 */ 19262306a36Sopenharmony_ci#define USIR1_IR15 (1 << 7) /* Interrupt request ep 15 */ 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci/* 19562306a36Sopenharmony_ci * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x 19662306a36Sopenharmony_ci * series processors. The UDC for the IXP 4xx series is very similar. 19762306a36Sopenharmony_ci * There are fifteen endpoints, in addition to ep0. 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * Such controller drivers work with a gadget driver. The gadget driver 20062306a36Sopenharmony_ci * returns descriptors, implements configuration and data protocols used 20162306a36Sopenharmony_ci * by the host to interact with this device, and allocates endpoints to 20262306a36Sopenharmony_ci * the different protocol interfaces. The controller driver virtualizes 20362306a36Sopenharmony_ci * usb hardware so that the gadget drivers will be more portable. 20462306a36Sopenharmony_ci * 20562306a36Sopenharmony_ci * This UDC hardware wants to implement a bit too much USB protocol, so 20662306a36Sopenharmony_ci * it constrains the sorts of USB configuration change events that work. 20762306a36Sopenharmony_ci * The errata for these chips are misleading; some "fixed" bugs from 20862306a36Sopenharmony_ci * pxa250 a0/a1 b0/b1/b2 sure act like they're still there. 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * Note that the UDC hardware supports DMA (except on IXP) but that's 21162306a36Sopenharmony_ci * not used here. IN-DMA (to host) is simple enough, when the data is 21262306a36Sopenharmony_ci * suitably aligned (16 bytes) ... the network stack doesn't do that, 21362306a36Sopenharmony_ci * other software can. OUT-DMA is buggy in most chip versions, as well 21462306a36Sopenharmony_ci * as poorly designed (data toggle not automatic). So this driver won't 21562306a36Sopenharmony_ci * bother using DMA. (Mostly-working IN-DMA support was available in 21662306a36Sopenharmony_ci * kernels before 2.6.23, but was never enabled or well tested.) 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci#define DRIVER_VERSION "30-June-2007" 22062306a36Sopenharmony_ci#define DRIVER_DESC "PXA 25x USB Device Controller driver" 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic const char driver_name [] = "pxa25x_udc"; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic const char ep0name [] = "ep0"; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci#ifdef CONFIG_ARCH_IXP4XX 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/* cpu-specific register addresses are compiled in to this code */ 23162306a36Sopenharmony_ci#ifdef CONFIG_ARCH_PXA 23262306a36Sopenharmony_ci#error "Can't configure both IXP and PXA" 23362306a36Sopenharmony_ci#endif 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* IXP doesn't yet support <linux/clk.h> */ 23662306a36Sopenharmony_ci#define clk_get(dev,name) NULL 23762306a36Sopenharmony_ci#define clk_enable(clk) do { } while (0) 23862306a36Sopenharmony_ci#define clk_disable(clk) do { } while (0) 23962306a36Sopenharmony_ci#define clk_put(clk) do { } while (0) 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci#endif 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci#include "pxa25x_udc.h" 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci#ifdef CONFIG_USB_PXA25X_SMALL 24762306a36Sopenharmony_ci#define SIZE_STR " (small)" 24862306a36Sopenharmony_ci#else 24962306a36Sopenharmony_ci#define SIZE_STR "" 25062306a36Sopenharmony_ci#endif 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci/* --------------------------------------------------------------------------- 25362306a36Sopenharmony_ci * endpoint related parts of the api to the usb controller hardware, 25462306a36Sopenharmony_ci * used by gadget driver; and the inner talker-to-hardware core. 25562306a36Sopenharmony_ci * --------------------------------------------------------------------------- 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic void pxa25x_ep_fifo_flush (struct usb_ep *ep); 25962306a36Sopenharmony_cistatic void nuke (struct pxa25x_ep *, int status); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/* one GPIO should control a D+ pullup, so host sees this device (or not) */ 26262306a36Sopenharmony_cistatic void pullup_off(void) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct pxa2xx_udc_mach_info *mach = the_controller->mach; 26562306a36Sopenharmony_ci int off_level = mach->gpio_pullup_inverted; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (gpio_is_valid(mach->gpio_pullup)) 26862306a36Sopenharmony_ci gpio_set_value(mach->gpio_pullup, off_level); 26962306a36Sopenharmony_ci else if (mach->udc_command) 27062306a36Sopenharmony_ci mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic void pullup_on(void) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct pxa2xx_udc_mach_info *mach = the_controller->mach; 27662306a36Sopenharmony_ci int on_level = !mach->gpio_pullup_inverted; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (gpio_is_valid(mach->gpio_pullup)) 27962306a36Sopenharmony_ci gpio_set_value(mach->gpio_pullup, on_level); 28062306a36Sopenharmony_ci else if (mach->udc_command) 28162306a36Sopenharmony_ci mach->udc_command(PXA2XX_UDC_CMD_CONNECT); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci#if defined(CONFIG_CPU_BIG_ENDIAN) 28562306a36Sopenharmony_ci/* 28662306a36Sopenharmony_ci * IXP4xx has its buses wired up in a way that relies on never doing any 28762306a36Sopenharmony_ci * byte swaps, independent of whether it runs in big-endian or little-endian 28862306a36Sopenharmony_ci * mode, as explained by Krzysztof Hałasa. 28962306a36Sopenharmony_ci * 29062306a36Sopenharmony_ci * We only support pxa25x in little-endian mode, but it is very likely 29162306a36Sopenharmony_ci * that it works the same way. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_cistatic inline void udc_set_reg(struct pxa25x_udc *dev, u32 reg, u32 val) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci iowrite32be(val, dev->regs + reg); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic inline u32 udc_get_reg(struct pxa25x_udc *dev, u32 reg) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci return ioread32be(dev->regs + reg); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci#else 30362306a36Sopenharmony_cistatic inline void udc_set_reg(struct pxa25x_udc *dev, u32 reg, u32 val) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci writel(val, dev->regs + reg); 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic inline u32 udc_get_reg(struct pxa25x_udc *dev, u32 reg) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci return readl(dev->regs + reg); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci#endif 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic void pio_irq_enable(struct pxa25x_ep *ep) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci u32 bEndpointAddress = ep->bEndpointAddress & 0xf; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (bEndpointAddress < 8) 31962306a36Sopenharmony_ci udc_set_reg(ep->dev, UICR0, udc_get_reg(ep->dev, UICR0) & 32062306a36Sopenharmony_ci ~(1 << bEndpointAddress)); 32162306a36Sopenharmony_ci else { 32262306a36Sopenharmony_ci bEndpointAddress -= 8; 32362306a36Sopenharmony_ci udc_set_reg(ep->dev, UICR1, udc_get_reg(ep->dev, UICR1) & 32462306a36Sopenharmony_ci ~(1 << bEndpointAddress)); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic void pio_irq_disable(struct pxa25x_ep *ep) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci u32 bEndpointAddress = ep->bEndpointAddress & 0xf; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (bEndpointAddress < 8) 33362306a36Sopenharmony_ci udc_set_reg(ep->dev, UICR0, udc_get_reg(ep->dev, UICR0) | 33462306a36Sopenharmony_ci (1 << bEndpointAddress)); 33562306a36Sopenharmony_ci else { 33662306a36Sopenharmony_ci bEndpointAddress -= 8; 33762306a36Sopenharmony_ci udc_set_reg(ep->dev, UICR1, udc_get_reg(ep->dev, UICR1) | 33862306a36Sopenharmony_ci (1 << bEndpointAddress)); 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci/* The UDCCR reg contains mask and interrupt status bits, 34362306a36Sopenharmony_ci * so using '|=' isn't safe as it may ack an interrupt. 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_ci#define UDCCR_MASK_BITS (UDCCR_REM | UDCCR_SRM | UDCCR_UDE) 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic inline void udc_set_mask_UDCCR(struct pxa25x_udc *dev, int mask) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci u32 udccr = udc_get_reg(dev, UDCCR); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci udc_set_reg(dev, (udccr & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS), UDCCR); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic inline void udc_clear_mask_UDCCR(struct pxa25x_udc *dev, int mask) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci u32 udccr = udc_get_reg(dev, UDCCR); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci udc_set_reg(dev, (udccr & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS), UDCCR); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic inline void udc_ack_int_UDCCR(struct pxa25x_udc *dev, int mask) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci /* udccr contains the bits we dont want to change */ 36462306a36Sopenharmony_ci u32 udccr = udc_get_reg(dev, UDCCR) & UDCCR_MASK_BITS; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci udc_set_reg(dev, udccr | (mask & ~UDCCR_MASK_BITS), UDCCR); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic inline u32 udc_ep_get_UDCCS(struct pxa25x_ep *ep) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci return udc_get_reg(ep->dev, ep->regoff_udccs); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic inline void udc_ep_set_UDCCS(struct pxa25x_ep *ep, u32 data) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci udc_set_reg(ep->dev, data, ep->regoff_udccs); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic inline u32 udc_ep0_get_UDCCS(struct pxa25x_udc *dev) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci return udc_get_reg(dev, UDCCS0); 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic inline void udc_ep0_set_UDCCS(struct pxa25x_udc *dev, u32 data) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci udc_set_reg(dev, data, UDCCS0); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic inline u32 udc_ep_get_UDDR(struct pxa25x_ep *ep) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci return udc_get_reg(ep->dev, ep->regoff_uddr); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic inline void udc_ep_set_UDDR(struct pxa25x_ep *ep, u32 data) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci udc_set_reg(ep->dev, data, ep->regoff_uddr); 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic inline u32 udc_ep_get_UBCR(struct pxa25x_ep *ep) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci return udc_get_reg(ep->dev, ep->regoff_ubcr); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci/* 40562306a36Sopenharmony_ci * endpoint enable/disable 40662306a36Sopenharmony_ci * 40762306a36Sopenharmony_ci * we need to verify the descriptors used to enable endpoints. since pxa25x 40862306a36Sopenharmony_ci * endpoint configurations are fixed, and are pretty much always enabled, 40962306a36Sopenharmony_ci * there's not a lot to manage here. 41062306a36Sopenharmony_ci * 41162306a36Sopenharmony_ci * because pxa25x can't selectively initialize bulk (or interrupt) endpoints, 41262306a36Sopenharmony_ci * (resetting endpoint halt and toggle), SET_INTERFACE is unusable except 41362306a36Sopenharmony_ci * for a single interface (with only the default altsetting) and for gadget 41462306a36Sopenharmony_ci * drivers that don't halt endpoints (not reset by set_interface). that also 41562306a36Sopenharmony_ci * means that if you use ISO, you must violate the USB spec rule that all 41662306a36Sopenharmony_ci * iso endpoints must be in non-default altsettings. 41762306a36Sopenharmony_ci */ 41862306a36Sopenharmony_cistatic int pxa25x_ep_enable (struct usb_ep *_ep, 41962306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct pxa25x_ep *ep; 42262306a36Sopenharmony_ci struct pxa25x_udc *dev; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci ep = container_of (_ep, struct pxa25x_ep, ep); 42562306a36Sopenharmony_ci if (!_ep || !desc || _ep->name == ep0name 42662306a36Sopenharmony_ci || desc->bDescriptorType != USB_DT_ENDPOINT 42762306a36Sopenharmony_ci || ep->bEndpointAddress != desc->bEndpointAddress 42862306a36Sopenharmony_ci || ep->fifo_size < usb_endpoint_maxp (desc)) { 42962306a36Sopenharmony_ci DMSG("%s, bad ep or descriptor\n", __func__); 43062306a36Sopenharmony_ci return -EINVAL; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* xfer types must match, except that interrupt ~= bulk */ 43462306a36Sopenharmony_ci if (ep->bmAttributes != desc->bmAttributes 43562306a36Sopenharmony_ci && ep->bmAttributes != USB_ENDPOINT_XFER_BULK 43662306a36Sopenharmony_ci && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { 43762306a36Sopenharmony_ci DMSG("%s, %s type mismatch\n", __func__, _ep->name); 43862306a36Sopenharmony_ci return -EINVAL; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* hardware _could_ do smaller, but driver doesn't */ 44262306a36Sopenharmony_ci if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK 44362306a36Sopenharmony_ci && usb_endpoint_maxp (desc) 44462306a36Sopenharmony_ci != BULK_FIFO_SIZE) 44562306a36Sopenharmony_ci || !desc->wMaxPacketSize) { 44662306a36Sopenharmony_ci DMSG("%s, bad %s maxpacket\n", __func__, _ep->name); 44762306a36Sopenharmony_ci return -ERANGE; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci dev = ep->dev; 45162306a36Sopenharmony_ci if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { 45262306a36Sopenharmony_ci DMSG("%s, bogus device state\n", __func__); 45362306a36Sopenharmony_ci return -ESHUTDOWN; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci ep->ep.desc = desc; 45762306a36Sopenharmony_ci ep->stopped = 0; 45862306a36Sopenharmony_ci ep->pio_irqs = 0; 45962306a36Sopenharmony_ci ep->ep.maxpacket = usb_endpoint_maxp (desc); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* flush fifo (mostly for OUT buffers) */ 46262306a36Sopenharmony_ci pxa25x_ep_fifo_flush (_ep); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* ... reset halt state too, if we could ... */ 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci DBG(DBG_VERBOSE, "enabled %s\n", _ep->name); 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int pxa25x_ep_disable (struct usb_ep *_ep) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci struct pxa25x_ep *ep; 47362306a36Sopenharmony_ci unsigned long flags; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci ep = container_of (_ep, struct pxa25x_ep, ep); 47662306a36Sopenharmony_ci if (!_ep || !ep->ep.desc) { 47762306a36Sopenharmony_ci DMSG("%s, %s not enabled\n", __func__, 47862306a36Sopenharmony_ci _ep ? ep->ep.name : NULL); 47962306a36Sopenharmony_ci return -EINVAL; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci local_irq_save(flags); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci nuke (ep, -ESHUTDOWN); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* flush fifo (mostly for IN buffers) */ 48662306a36Sopenharmony_ci pxa25x_ep_fifo_flush (_ep); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci ep->ep.desc = NULL; 48962306a36Sopenharmony_ci ep->stopped = 1; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci local_irq_restore(flags); 49262306a36Sopenharmony_ci DBG(DBG_VERBOSE, "%s disabled\n", _ep->name); 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci/* for the pxa25x, these can just wrap kmalloc/kfree. gadget drivers 49962306a36Sopenharmony_ci * must still pass correctly initialized endpoints, since other controller 50062306a36Sopenharmony_ci * drivers may care about how it's currently set up (dma issues etc). 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci/* 50462306a36Sopenharmony_ci * pxa25x_ep_alloc_request - allocate a request data structure 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_cistatic struct usb_request * 50762306a36Sopenharmony_cipxa25x_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci struct pxa25x_request *req; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci req = kzalloc(sizeof(*req), gfp_flags); 51262306a36Sopenharmony_ci if (!req) 51362306a36Sopenharmony_ci return NULL; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci INIT_LIST_HEAD (&req->queue); 51662306a36Sopenharmony_ci return &req->req; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci/* 52162306a36Sopenharmony_ci * pxa25x_ep_free_request - deallocate a request data structure 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_cistatic void 52462306a36Sopenharmony_cipxa25x_ep_free_request (struct usb_ep *_ep, struct usb_request *_req) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct pxa25x_request *req; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci req = container_of (_req, struct pxa25x_request, req); 52962306a36Sopenharmony_ci WARN_ON(!list_empty (&req->queue)); 53062306a36Sopenharmony_ci kfree(req); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci/* 53662306a36Sopenharmony_ci * done - retire a request; caller blocked irqs 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_cistatic void done(struct pxa25x_ep *ep, struct pxa25x_request *req, int status) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci unsigned stopped = ep->stopped; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci list_del_init(&req->queue); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (likely (req->req.status == -EINPROGRESS)) 54562306a36Sopenharmony_ci req->req.status = status; 54662306a36Sopenharmony_ci else 54762306a36Sopenharmony_ci status = req->req.status; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (status && status != -ESHUTDOWN) 55062306a36Sopenharmony_ci DBG(DBG_VERBOSE, "complete %s req %p stat %d len %u/%u\n", 55162306a36Sopenharmony_ci ep->ep.name, &req->req, status, 55262306a36Sopenharmony_ci req->req.actual, req->req.length); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* don't modify queue heads during completion callback */ 55562306a36Sopenharmony_ci ep->stopped = 1; 55662306a36Sopenharmony_ci usb_gadget_giveback_request(&ep->ep, &req->req); 55762306a36Sopenharmony_ci ep->stopped = stopped; 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic inline void ep0_idle (struct pxa25x_udc *dev) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci dev->ep0state = EP0_IDLE; 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic int 56762306a36Sopenharmony_ciwrite_packet(struct pxa25x_ep *ep, struct pxa25x_request *req, unsigned max) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci u8 *buf; 57062306a36Sopenharmony_ci unsigned length, count; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci buf = req->req.buf + req->req.actual; 57362306a36Sopenharmony_ci prefetch(buf); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* how big will this packet be? */ 57662306a36Sopenharmony_ci length = min(req->req.length - req->req.actual, max); 57762306a36Sopenharmony_ci req->req.actual += length; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci count = length; 58062306a36Sopenharmony_ci while (likely(count--)) 58162306a36Sopenharmony_ci udc_ep_set_UDDR(ep, *buf++); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci return length; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci/* 58762306a36Sopenharmony_ci * write to an IN endpoint fifo, as many packets as possible. 58862306a36Sopenharmony_ci * irqs will use this to write the rest later. 58962306a36Sopenharmony_ci * caller guarantees at least one packet buffer is ready (or a zlp). 59062306a36Sopenharmony_ci */ 59162306a36Sopenharmony_cistatic int 59262306a36Sopenharmony_ciwrite_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci unsigned max; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci max = usb_endpoint_maxp(ep->ep.desc); 59762306a36Sopenharmony_ci do { 59862306a36Sopenharmony_ci unsigned count; 59962306a36Sopenharmony_ci int is_last, is_short; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci count = write_packet(ep, req, max); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* last packet is usually short (or a zlp) */ 60462306a36Sopenharmony_ci if (unlikely (count != max)) 60562306a36Sopenharmony_ci is_last = is_short = 1; 60662306a36Sopenharmony_ci else { 60762306a36Sopenharmony_ci if (likely(req->req.length != req->req.actual) 60862306a36Sopenharmony_ci || req->req.zero) 60962306a36Sopenharmony_ci is_last = 0; 61062306a36Sopenharmony_ci else 61162306a36Sopenharmony_ci is_last = 1; 61262306a36Sopenharmony_ci /* interrupt/iso maxpacket may not fill the fifo */ 61362306a36Sopenharmony_ci is_short = unlikely (max < ep->fifo_size); 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci DBG(DBG_VERY_NOISY, "wrote %s %d bytes%s%s %d left %p\n", 61762306a36Sopenharmony_ci ep->ep.name, count, 61862306a36Sopenharmony_ci is_last ? "/L" : "", is_short ? "/S" : "", 61962306a36Sopenharmony_ci req->req.length - req->req.actual, req); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci /* let loose that packet. maybe try writing another one, 62262306a36Sopenharmony_ci * double buffering might work. TSP, TPC, and TFS 62362306a36Sopenharmony_ci * bit values are the same for all normal IN endpoints. 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ci udc_ep_set_UDCCS(ep, UDCCS_BI_TPC); 62662306a36Sopenharmony_ci if (is_short) 62762306a36Sopenharmony_ci udc_ep_set_UDCCS(ep, UDCCS_BI_TSP); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* requests complete when all IN data is in the FIFO */ 63062306a36Sopenharmony_ci if (is_last) { 63162306a36Sopenharmony_ci done (ep, req, 0); 63262306a36Sopenharmony_ci if (list_empty(&ep->queue)) 63362306a36Sopenharmony_ci pio_irq_disable(ep); 63462306a36Sopenharmony_ci return 1; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci // TODO experiment: how robust can fifo mode tweaking be? 63862306a36Sopenharmony_ci // double buffering is off in the default fifo mode, which 63962306a36Sopenharmony_ci // prevents TFS from being set here. 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci } while (udc_ep_get_UDCCS(ep) & UDCCS_BI_TFS); 64262306a36Sopenharmony_ci return 0; 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci/* caller asserts req->pending (ep0 irq status nyet cleared); starts 64662306a36Sopenharmony_ci * ep0 data stage. these chips want very simple state transitions. 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_cistatic inline 64962306a36Sopenharmony_civoid ep0start(struct pxa25x_udc *dev, u32 flags, const char *tag) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci udc_ep0_set_UDCCS(dev, flags|UDCCS0_SA|UDCCS0_OPR); 65262306a36Sopenharmony_ci udc_set_reg(dev, USIR0, USIR0_IR0); 65362306a36Sopenharmony_ci dev->req_pending = 0; 65462306a36Sopenharmony_ci DBG(DBG_VERY_NOISY, "%s %s, %02x/%02x\n", 65562306a36Sopenharmony_ci __func__, tag, udc_ep0_get_UDCCS(dev), flags); 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic int 65962306a36Sopenharmony_ciwrite_ep0_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct pxa25x_udc *dev = ep->dev; 66262306a36Sopenharmony_ci unsigned count; 66362306a36Sopenharmony_ci int is_short; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci count = write_packet(&dev->ep[0], req, EP0_FIFO_SIZE); 66662306a36Sopenharmony_ci ep->dev->stats.write.bytes += count; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* last packet "must be" short (or a zlp) */ 66962306a36Sopenharmony_ci is_short = (count != EP0_FIFO_SIZE); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci DBG(DBG_VERY_NOISY, "ep0in %d bytes %d left %p\n", count, 67262306a36Sopenharmony_ci req->req.length - req->req.actual, req); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (unlikely (is_short)) { 67562306a36Sopenharmony_ci if (ep->dev->req_pending) 67662306a36Sopenharmony_ci ep0start(ep->dev, UDCCS0_IPR, "short IN"); 67762306a36Sopenharmony_ci else 67862306a36Sopenharmony_ci udc_ep0_set_UDCCS(dev, UDCCS0_IPR); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci count = req->req.length; 68162306a36Sopenharmony_ci done (ep, req, 0); 68262306a36Sopenharmony_ci ep0_idle(ep->dev); 68362306a36Sopenharmony_ci#ifndef CONFIG_ARCH_IXP4XX 68462306a36Sopenharmony_ci#if 1 68562306a36Sopenharmony_ci /* This seems to get rid of lost status irqs in some cases: 68662306a36Sopenharmony_ci * host responds quickly, or next request involves config 68762306a36Sopenharmony_ci * change automagic, or should have been hidden, or ... 68862306a36Sopenharmony_ci * 68962306a36Sopenharmony_ci * FIXME get rid of all udelays possible... 69062306a36Sopenharmony_ci */ 69162306a36Sopenharmony_ci if (count >= EP0_FIFO_SIZE) { 69262306a36Sopenharmony_ci count = 100; 69362306a36Sopenharmony_ci do { 69462306a36Sopenharmony_ci if ((udc_ep0_get_UDCCS(dev) & UDCCS0_OPR) != 0) { 69562306a36Sopenharmony_ci /* clear OPR, generate ack */ 69662306a36Sopenharmony_ci udc_ep0_set_UDCCS(dev, UDCCS0_OPR); 69762306a36Sopenharmony_ci break; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci count--; 70062306a36Sopenharmony_ci udelay(1); 70162306a36Sopenharmony_ci } while (count); 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci#endif 70462306a36Sopenharmony_ci#endif 70562306a36Sopenharmony_ci } else if (ep->dev->req_pending) 70662306a36Sopenharmony_ci ep0start(ep->dev, 0, "IN"); 70762306a36Sopenharmony_ci return is_short; 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci/* 71262306a36Sopenharmony_ci * read_fifo - unload packet(s) from the fifo we use for usb OUT 71362306a36Sopenharmony_ci * transfers and put them into the request. caller should have made 71462306a36Sopenharmony_ci * sure there's at least one packet ready. 71562306a36Sopenharmony_ci * 71662306a36Sopenharmony_ci * returns true if the request completed because of short packet or the 71762306a36Sopenharmony_ci * request buffer having filled (and maybe overran till end-of-packet). 71862306a36Sopenharmony_ci */ 71962306a36Sopenharmony_cistatic int 72062306a36Sopenharmony_ciread_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci for (;;) { 72362306a36Sopenharmony_ci u32 udccs; 72462306a36Sopenharmony_ci u8 *buf; 72562306a36Sopenharmony_ci unsigned bufferspace, count, is_short; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* make sure there's a packet in the FIFO. 72862306a36Sopenharmony_ci * UDCCS_{BO,IO}_RPC are all the same bit value. 72962306a36Sopenharmony_ci * UDCCS_{BO,IO}_RNE are all the same bit value. 73062306a36Sopenharmony_ci */ 73162306a36Sopenharmony_ci udccs = udc_ep_get_UDCCS(ep); 73262306a36Sopenharmony_ci if (unlikely ((udccs & UDCCS_BO_RPC) == 0)) 73362306a36Sopenharmony_ci break; 73462306a36Sopenharmony_ci buf = req->req.buf + req->req.actual; 73562306a36Sopenharmony_ci prefetchw(buf); 73662306a36Sopenharmony_ci bufferspace = req->req.length - req->req.actual; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci /* read all bytes from this packet */ 73962306a36Sopenharmony_ci if (likely (udccs & UDCCS_BO_RNE)) { 74062306a36Sopenharmony_ci count = 1 + (0x0ff & udc_ep_get_UBCR(ep)); 74162306a36Sopenharmony_ci req->req.actual += min (count, bufferspace); 74262306a36Sopenharmony_ci } else /* zlp */ 74362306a36Sopenharmony_ci count = 0; 74462306a36Sopenharmony_ci is_short = (count < ep->ep.maxpacket); 74562306a36Sopenharmony_ci DBG(DBG_VERY_NOISY, "read %s %02x, %d bytes%s req %p %d/%d\n", 74662306a36Sopenharmony_ci ep->ep.name, udccs, count, 74762306a36Sopenharmony_ci is_short ? "/S" : "", 74862306a36Sopenharmony_ci req, req->req.actual, req->req.length); 74962306a36Sopenharmony_ci while (likely (count-- != 0)) { 75062306a36Sopenharmony_ci u8 byte = (u8) udc_ep_get_UDDR(ep); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (unlikely (bufferspace == 0)) { 75362306a36Sopenharmony_ci /* this happens when the driver's buffer 75462306a36Sopenharmony_ci * is smaller than what the host sent. 75562306a36Sopenharmony_ci * discard the extra data. 75662306a36Sopenharmony_ci */ 75762306a36Sopenharmony_ci if (req->req.status != -EOVERFLOW) 75862306a36Sopenharmony_ci DMSG("%s overflow %d\n", 75962306a36Sopenharmony_ci ep->ep.name, count); 76062306a36Sopenharmony_ci req->req.status = -EOVERFLOW; 76162306a36Sopenharmony_ci } else { 76262306a36Sopenharmony_ci *buf++ = byte; 76362306a36Sopenharmony_ci bufferspace--; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci udc_ep_set_UDCCS(ep, UDCCS_BO_RPC); 76762306a36Sopenharmony_ci /* RPC/RSP/RNE could now reflect the other packet buffer */ 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* iso is one request per packet */ 77062306a36Sopenharmony_ci if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { 77162306a36Sopenharmony_ci if (udccs & UDCCS_IO_ROF) 77262306a36Sopenharmony_ci req->req.status = -EHOSTUNREACH; 77362306a36Sopenharmony_ci /* more like "is_done" */ 77462306a36Sopenharmony_ci is_short = 1; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* completion */ 77862306a36Sopenharmony_ci if (is_short || req->req.actual == req->req.length) { 77962306a36Sopenharmony_ci done (ep, req, 0); 78062306a36Sopenharmony_ci if (list_empty(&ep->queue)) 78162306a36Sopenharmony_ci pio_irq_disable(ep); 78262306a36Sopenharmony_ci return 1; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* finished that packet. the next one may be waiting... */ 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci return 0; 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci/* 79162306a36Sopenharmony_ci * special ep0 version of the above. no UBCR0 or double buffering; status 79262306a36Sopenharmony_ci * handshaking is magic. most device protocols don't need control-OUT. 79362306a36Sopenharmony_ci * CDC vendor commands (and RNDIS), mass storage CB/CBI, and some other 79462306a36Sopenharmony_ci * protocols do use them. 79562306a36Sopenharmony_ci */ 79662306a36Sopenharmony_cistatic int 79762306a36Sopenharmony_ciread_ep0_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci u8 *buf, byte; 80062306a36Sopenharmony_ci unsigned bufferspace; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci buf = req->req.buf + req->req.actual; 80362306a36Sopenharmony_ci bufferspace = req->req.length - req->req.actual; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci while (udc_ep_get_UDCCS(ep) & UDCCS0_RNE) { 80662306a36Sopenharmony_ci byte = (u8) UDDR0; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (unlikely (bufferspace == 0)) { 80962306a36Sopenharmony_ci /* this happens when the driver's buffer 81062306a36Sopenharmony_ci * is smaller than what the host sent. 81162306a36Sopenharmony_ci * discard the extra data. 81262306a36Sopenharmony_ci */ 81362306a36Sopenharmony_ci if (req->req.status != -EOVERFLOW) 81462306a36Sopenharmony_ci DMSG("%s overflow\n", ep->ep.name); 81562306a36Sopenharmony_ci req->req.status = -EOVERFLOW; 81662306a36Sopenharmony_ci } else { 81762306a36Sopenharmony_ci *buf++ = byte; 81862306a36Sopenharmony_ci req->req.actual++; 81962306a36Sopenharmony_ci bufferspace--; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci udc_ep_set_UDCCS(ep, UDCCS0_OPR | UDCCS0_IPR); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci /* completion */ 82662306a36Sopenharmony_ci if (req->req.actual >= req->req.length) 82762306a36Sopenharmony_ci return 1; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci /* finished that packet. the next one may be waiting... */ 83062306a36Sopenharmony_ci return 0; 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_cistatic int 83662306a36Sopenharmony_cipxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci struct pxa25x_request *req; 83962306a36Sopenharmony_ci struct pxa25x_ep *ep; 84062306a36Sopenharmony_ci struct pxa25x_udc *dev; 84162306a36Sopenharmony_ci unsigned long flags; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci req = container_of(_req, struct pxa25x_request, req); 84462306a36Sopenharmony_ci if (unlikely (!_req || !_req->complete || !_req->buf 84562306a36Sopenharmony_ci || !list_empty(&req->queue))) { 84662306a36Sopenharmony_ci DMSG("%s, bad params\n", __func__); 84762306a36Sopenharmony_ci return -EINVAL; 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci ep = container_of(_ep, struct pxa25x_ep, ep); 85162306a36Sopenharmony_ci if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) { 85262306a36Sopenharmony_ci DMSG("%s, bad ep\n", __func__); 85362306a36Sopenharmony_ci return -EINVAL; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci dev = ep->dev; 85762306a36Sopenharmony_ci if (unlikely (!dev->driver 85862306a36Sopenharmony_ci || dev->gadget.speed == USB_SPEED_UNKNOWN)) { 85962306a36Sopenharmony_ci DMSG("%s, bogus device state\n", __func__); 86062306a36Sopenharmony_ci return -ESHUTDOWN; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* iso is always one packet per request, that's the only way 86462306a36Sopenharmony_ci * we can report per-packet status. that also helps with dma. 86562306a36Sopenharmony_ci */ 86662306a36Sopenharmony_ci if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC 86762306a36Sopenharmony_ci && req->req.length > usb_endpoint_maxp(ep->ep.desc))) 86862306a36Sopenharmony_ci return -EMSGSIZE; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n", 87162306a36Sopenharmony_ci _ep->name, _req, _req->length, _req->buf); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci local_irq_save(flags); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci _req->status = -EINPROGRESS; 87662306a36Sopenharmony_ci _req->actual = 0; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci /* kickstart this i/o queue? */ 87962306a36Sopenharmony_ci if (list_empty(&ep->queue) && !ep->stopped) { 88062306a36Sopenharmony_ci if (ep->ep.desc == NULL/* ep0 */) { 88162306a36Sopenharmony_ci unsigned length = _req->length; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci switch (dev->ep0state) { 88462306a36Sopenharmony_ci case EP0_IN_DATA_PHASE: 88562306a36Sopenharmony_ci dev->stats.write.ops++; 88662306a36Sopenharmony_ci if (write_ep0_fifo(ep, req)) 88762306a36Sopenharmony_ci req = NULL; 88862306a36Sopenharmony_ci break; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci case EP0_OUT_DATA_PHASE: 89162306a36Sopenharmony_ci dev->stats.read.ops++; 89262306a36Sopenharmony_ci /* messy ... */ 89362306a36Sopenharmony_ci if (dev->req_config) { 89462306a36Sopenharmony_ci DBG(DBG_VERBOSE, "ep0 config ack%s\n", 89562306a36Sopenharmony_ci dev->has_cfr ? "" : " raced"); 89662306a36Sopenharmony_ci if (dev->has_cfr) 89762306a36Sopenharmony_ci udc_set_reg(dev, UDCCFR, UDCCFR_AREN | 89862306a36Sopenharmony_ci UDCCFR_ACM | UDCCFR_MB1); 89962306a36Sopenharmony_ci done(ep, req, 0); 90062306a36Sopenharmony_ci dev->ep0state = EP0_END_XFER; 90162306a36Sopenharmony_ci local_irq_restore (flags); 90262306a36Sopenharmony_ci return 0; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci if (dev->req_pending) 90562306a36Sopenharmony_ci ep0start(dev, UDCCS0_IPR, "OUT"); 90662306a36Sopenharmony_ci if (length == 0 || ((udc_ep0_get_UDCCS(dev) & UDCCS0_RNE) != 0 90762306a36Sopenharmony_ci && read_ep0_fifo(ep, req))) { 90862306a36Sopenharmony_ci ep0_idle(dev); 90962306a36Sopenharmony_ci done(ep, req, 0); 91062306a36Sopenharmony_ci req = NULL; 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci break; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci default: 91562306a36Sopenharmony_ci DMSG("ep0 i/o, odd state %d\n", dev->ep0state); 91662306a36Sopenharmony_ci local_irq_restore (flags); 91762306a36Sopenharmony_ci return -EL2HLT; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci /* can the FIFO can satisfy the request immediately? */ 92062306a36Sopenharmony_ci } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) { 92162306a36Sopenharmony_ci if ((udc_ep_get_UDCCS(ep) & UDCCS_BI_TFS) != 0 92262306a36Sopenharmony_ci && write_fifo(ep, req)) 92362306a36Sopenharmony_ci req = NULL; 92462306a36Sopenharmony_ci } else if ((udc_ep_get_UDCCS(ep) & UDCCS_BO_RFS) != 0 92562306a36Sopenharmony_ci && read_fifo(ep, req)) { 92662306a36Sopenharmony_ci req = NULL; 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (likely(req && ep->ep.desc)) 93062306a36Sopenharmony_ci pio_irq_enable(ep); 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* pio or dma irq handler advances the queue. */ 93462306a36Sopenharmony_ci if (likely(req != NULL)) 93562306a36Sopenharmony_ci list_add_tail(&req->queue, &ep->queue); 93662306a36Sopenharmony_ci local_irq_restore(flags); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci return 0; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci/* 94362306a36Sopenharmony_ci * nuke - dequeue ALL requests 94462306a36Sopenharmony_ci */ 94562306a36Sopenharmony_cistatic void nuke(struct pxa25x_ep *ep, int status) 94662306a36Sopenharmony_ci{ 94762306a36Sopenharmony_ci struct pxa25x_request *req; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci /* called with irqs blocked */ 95062306a36Sopenharmony_ci while (!list_empty(&ep->queue)) { 95162306a36Sopenharmony_ci req = list_entry(ep->queue.next, 95262306a36Sopenharmony_ci struct pxa25x_request, 95362306a36Sopenharmony_ci queue); 95462306a36Sopenharmony_ci done(ep, req, status); 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci if (ep->ep.desc) 95762306a36Sopenharmony_ci pio_irq_disable(ep); 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci/* dequeue JUST ONE request */ 96262306a36Sopenharmony_cistatic int pxa25x_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) 96362306a36Sopenharmony_ci{ 96462306a36Sopenharmony_ci struct pxa25x_ep *ep; 96562306a36Sopenharmony_ci struct pxa25x_request *req = NULL; 96662306a36Sopenharmony_ci struct pxa25x_request *iter; 96762306a36Sopenharmony_ci unsigned long flags; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci ep = container_of(_ep, struct pxa25x_ep, ep); 97062306a36Sopenharmony_ci if (!_ep || ep->ep.name == ep0name) 97162306a36Sopenharmony_ci return -EINVAL; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci local_irq_save(flags); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci /* make sure it's actually queued on this endpoint */ 97662306a36Sopenharmony_ci list_for_each_entry(iter, &ep->queue, queue) { 97762306a36Sopenharmony_ci if (&iter->req != _req) 97862306a36Sopenharmony_ci continue; 97962306a36Sopenharmony_ci req = iter; 98062306a36Sopenharmony_ci break; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci if (!req) { 98362306a36Sopenharmony_ci local_irq_restore(flags); 98462306a36Sopenharmony_ci return -EINVAL; 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci done(ep, req, -ECONNRESET); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci local_irq_restore(flags); 99062306a36Sopenharmony_ci return 0; 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_cistatic int pxa25x_ep_set_halt(struct usb_ep *_ep, int value) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci struct pxa25x_ep *ep; 99862306a36Sopenharmony_ci unsigned long flags; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci ep = container_of(_ep, struct pxa25x_ep, ep); 100162306a36Sopenharmony_ci if (unlikely (!_ep 100262306a36Sopenharmony_ci || (!ep->ep.desc && ep->ep.name != ep0name)) 100362306a36Sopenharmony_ci || ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { 100462306a36Sopenharmony_ci DMSG("%s, bad ep\n", __func__); 100562306a36Sopenharmony_ci return -EINVAL; 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci if (value == 0) { 100862306a36Sopenharmony_ci /* this path (reset toggle+halt) is needed to implement 100962306a36Sopenharmony_ci * SET_INTERFACE on normal hardware. but it can't be 101062306a36Sopenharmony_ci * done from software on the PXA UDC, and the hardware 101162306a36Sopenharmony_ci * forgets to do it as part of SET_INTERFACE automagic. 101262306a36Sopenharmony_ci */ 101362306a36Sopenharmony_ci DMSG("only host can clear %s halt\n", _ep->name); 101462306a36Sopenharmony_ci return -EROFS; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci local_irq_save(flags); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci if ((ep->bEndpointAddress & USB_DIR_IN) != 0 102062306a36Sopenharmony_ci && ((udc_ep_get_UDCCS(ep) & UDCCS_BI_TFS) == 0 102162306a36Sopenharmony_ci || !list_empty(&ep->queue))) { 102262306a36Sopenharmony_ci local_irq_restore(flags); 102362306a36Sopenharmony_ci return -EAGAIN; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci /* FST bit is the same for control, bulk in, bulk out, interrupt in */ 102762306a36Sopenharmony_ci udc_ep_set_UDCCS(ep, UDCCS_BI_FST|UDCCS_BI_FTF); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci /* ep0 needs special care */ 103062306a36Sopenharmony_ci if (!ep->ep.desc) { 103162306a36Sopenharmony_ci start_watchdog(ep->dev); 103262306a36Sopenharmony_ci ep->dev->req_pending = 0; 103362306a36Sopenharmony_ci ep->dev->ep0state = EP0_STALL; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci /* and bulk/intr endpoints like dropping stalls too */ 103662306a36Sopenharmony_ci } else { 103762306a36Sopenharmony_ci unsigned i; 103862306a36Sopenharmony_ci for (i = 0; i < 1000; i += 20) { 103962306a36Sopenharmony_ci if (udc_ep_get_UDCCS(ep) & UDCCS_BI_SST) 104062306a36Sopenharmony_ci break; 104162306a36Sopenharmony_ci udelay(20); 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci local_irq_restore(flags); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci DBG(DBG_VERBOSE, "%s halt\n", _ep->name); 104762306a36Sopenharmony_ci return 0; 104862306a36Sopenharmony_ci} 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_cistatic int pxa25x_ep_fifo_status(struct usb_ep *_ep) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci struct pxa25x_ep *ep; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci ep = container_of(_ep, struct pxa25x_ep, ep); 105562306a36Sopenharmony_ci if (!_ep) { 105662306a36Sopenharmony_ci DMSG("%s, bad ep\n", __func__); 105762306a36Sopenharmony_ci return -ENODEV; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci /* pxa can't report unclaimed bytes from IN fifos */ 106062306a36Sopenharmony_ci if ((ep->bEndpointAddress & USB_DIR_IN) != 0) 106162306a36Sopenharmony_ci return -EOPNOTSUPP; 106262306a36Sopenharmony_ci if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN 106362306a36Sopenharmony_ci || (udc_ep_get_UDCCS(ep) & UDCCS_BO_RFS) == 0) 106462306a36Sopenharmony_ci return 0; 106562306a36Sopenharmony_ci else 106662306a36Sopenharmony_ci return (udc_ep_get_UBCR(ep) & 0xfff) + 1; 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_cistatic void pxa25x_ep_fifo_flush(struct usb_ep *_ep) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci struct pxa25x_ep *ep; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci ep = container_of(_ep, struct pxa25x_ep, ep); 107462306a36Sopenharmony_ci if (!_ep || ep->ep.name == ep0name || !list_empty(&ep->queue)) { 107562306a36Sopenharmony_ci DMSG("%s, bad ep\n", __func__); 107662306a36Sopenharmony_ci return; 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci /* toggle and halt bits stay unchanged */ 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci /* for OUT, just read and discard the FIFO contents. */ 108262306a36Sopenharmony_ci if ((ep->bEndpointAddress & USB_DIR_IN) == 0) { 108362306a36Sopenharmony_ci while (((udc_ep_get_UDCCS(ep)) & UDCCS_BO_RNE) != 0) 108462306a36Sopenharmony_ci (void)udc_ep_get_UDDR(ep); 108562306a36Sopenharmony_ci return; 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci /* most IN status is the same, but ISO can't stall */ 108962306a36Sopenharmony_ci udc_ep_set_UDCCS(ep, UDCCS_BI_TPC|UDCCS_BI_FTF|UDCCS_BI_TUR 109062306a36Sopenharmony_ci | (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC 109162306a36Sopenharmony_ci ? 0 : UDCCS_BI_SST)); 109262306a36Sopenharmony_ci} 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_cistatic const struct usb_ep_ops pxa25x_ep_ops = { 109662306a36Sopenharmony_ci .enable = pxa25x_ep_enable, 109762306a36Sopenharmony_ci .disable = pxa25x_ep_disable, 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci .alloc_request = pxa25x_ep_alloc_request, 110062306a36Sopenharmony_ci .free_request = pxa25x_ep_free_request, 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci .queue = pxa25x_ep_queue, 110362306a36Sopenharmony_ci .dequeue = pxa25x_ep_dequeue, 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci .set_halt = pxa25x_ep_set_halt, 110662306a36Sopenharmony_ci .fifo_status = pxa25x_ep_fifo_status, 110762306a36Sopenharmony_ci .fifo_flush = pxa25x_ep_fifo_flush, 110862306a36Sopenharmony_ci}; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci/* --------------------------------------------------------------------------- 111262306a36Sopenharmony_ci * device-scoped parts of the api to the usb controller hardware 111362306a36Sopenharmony_ci * --------------------------------------------------------------------------- 111462306a36Sopenharmony_ci */ 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_cistatic int pxa25x_udc_get_frame(struct usb_gadget *_gadget) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci struct pxa25x_udc *dev; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci dev = container_of(_gadget, struct pxa25x_udc, gadget); 112162306a36Sopenharmony_ci return ((udc_get_reg(dev, UFNRH) & 0x07) << 8) | 112262306a36Sopenharmony_ci (udc_get_reg(dev, UFNRL) & 0xff); 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cistatic int pxa25x_udc_wakeup(struct usb_gadget *_gadget) 112662306a36Sopenharmony_ci{ 112762306a36Sopenharmony_ci struct pxa25x_udc *udc; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci udc = container_of(_gadget, struct pxa25x_udc, gadget); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci /* host may not have enabled remote wakeup */ 113262306a36Sopenharmony_ci if ((udc_ep0_get_UDCCS(udc) & UDCCS0_DRWF) == 0) 113362306a36Sopenharmony_ci return -EHOSTUNREACH; 113462306a36Sopenharmony_ci udc_set_mask_UDCCR(udc, UDCCR_RSM); 113562306a36Sopenharmony_ci return 0; 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic void stop_activity(struct pxa25x_udc *, struct usb_gadget_driver *); 113962306a36Sopenharmony_cistatic void udc_enable (struct pxa25x_udc *); 114062306a36Sopenharmony_cistatic void udc_disable(struct pxa25x_udc *); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci/* We disable the UDC -- and its 48 MHz clock -- whenever it's not 114362306a36Sopenharmony_ci * in active use. 114462306a36Sopenharmony_ci */ 114562306a36Sopenharmony_cistatic int pullup(struct pxa25x_udc *udc) 114662306a36Sopenharmony_ci{ 114762306a36Sopenharmony_ci int is_active = udc->vbus && udc->pullup && !udc->suspended; 114862306a36Sopenharmony_ci DMSG("%s\n", is_active ? "active" : "inactive"); 114962306a36Sopenharmony_ci if (is_active) { 115062306a36Sopenharmony_ci if (!udc->active) { 115162306a36Sopenharmony_ci udc->active = 1; 115262306a36Sopenharmony_ci /* Enable clock for USB device */ 115362306a36Sopenharmony_ci clk_enable(udc->clk); 115462306a36Sopenharmony_ci udc_enable(udc); 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci } else { 115762306a36Sopenharmony_ci if (udc->active) { 115862306a36Sopenharmony_ci if (udc->gadget.speed != USB_SPEED_UNKNOWN) { 115962306a36Sopenharmony_ci DMSG("disconnect %s\n", udc->driver 116062306a36Sopenharmony_ci ? udc->driver->driver.name 116162306a36Sopenharmony_ci : "(no driver)"); 116262306a36Sopenharmony_ci stop_activity(udc, udc->driver); 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci udc_disable(udc); 116562306a36Sopenharmony_ci /* Disable clock for USB device */ 116662306a36Sopenharmony_ci clk_disable(udc->clk); 116762306a36Sopenharmony_ci udc->active = 0; 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci return 0; 117262306a36Sopenharmony_ci} 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci/* VBUS reporting logically comes from a transceiver */ 117562306a36Sopenharmony_cistatic int pxa25x_udc_vbus_session(struct usb_gadget *_gadget, int is_active) 117662306a36Sopenharmony_ci{ 117762306a36Sopenharmony_ci struct pxa25x_udc *udc; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci udc = container_of(_gadget, struct pxa25x_udc, gadget); 118062306a36Sopenharmony_ci udc->vbus = is_active; 118162306a36Sopenharmony_ci DMSG("vbus %s\n", is_active ? "supplied" : "inactive"); 118262306a36Sopenharmony_ci pullup(udc); 118362306a36Sopenharmony_ci return 0; 118462306a36Sopenharmony_ci} 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci/* drivers may have software control over D+ pullup */ 118762306a36Sopenharmony_cistatic int pxa25x_udc_pullup(struct usb_gadget *_gadget, int is_active) 118862306a36Sopenharmony_ci{ 118962306a36Sopenharmony_ci struct pxa25x_udc *udc; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci udc = container_of(_gadget, struct pxa25x_udc, gadget); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci /* not all boards support pullup control */ 119462306a36Sopenharmony_ci if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command) 119562306a36Sopenharmony_ci return -EOPNOTSUPP; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci udc->pullup = (is_active != 0); 119862306a36Sopenharmony_ci pullup(udc); 119962306a36Sopenharmony_ci return 0; 120062306a36Sopenharmony_ci} 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci/* boards may consume current from VBUS, up to 100-500mA based on config. 120362306a36Sopenharmony_ci * the 500uA suspend ceiling means that exclusively vbus-powered PXA designs 120462306a36Sopenharmony_ci * violate USB specs. 120562306a36Sopenharmony_ci */ 120662306a36Sopenharmony_cistatic int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) 120762306a36Sopenharmony_ci{ 120862306a36Sopenharmony_ci struct pxa25x_udc *udc; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci udc = container_of(_gadget, struct pxa25x_udc, gadget); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(udc->transceiver)) 121362306a36Sopenharmony_ci return usb_phy_set_power(udc->transceiver, mA); 121462306a36Sopenharmony_ci return -EOPNOTSUPP; 121562306a36Sopenharmony_ci} 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_cistatic int pxa25x_udc_start(struct usb_gadget *g, 121862306a36Sopenharmony_ci struct usb_gadget_driver *driver); 121962306a36Sopenharmony_cistatic int pxa25x_udc_stop(struct usb_gadget *g); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_cistatic const struct usb_gadget_ops pxa25x_udc_ops = { 122262306a36Sopenharmony_ci .get_frame = pxa25x_udc_get_frame, 122362306a36Sopenharmony_ci .wakeup = pxa25x_udc_wakeup, 122462306a36Sopenharmony_ci .vbus_session = pxa25x_udc_vbus_session, 122562306a36Sopenharmony_ci .pullup = pxa25x_udc_pullup, 122662306a36Sopenharmony_ci .vbus_draw = pxa25x_udc_vbus_draw, 122762306a36Sopenharmony_ci .udc_start = pxa25x_udc_start, 122862306a36Sopenharmony_ci .udc_stop = pxa25x_udc_stop, 122962306a36Sopenharmony_ci}; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci#ifdef CONFIG_USB_GADGET_DEBUG_FS 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic int udc_debug_show(struct seq_file *m, void *_d) 123662306a36Sopenharmony_ci{ 123762306a36Sopenharmony_ci struct pxa25x_udc *dev = m->private; 123862306a36Sopenharmony_ci unsigned long flags; 123962306a36Sopenharmony_ci int i; 124062306a36Sopenharmony_ci u32 tmp; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci local_irq_save(flags); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci /* basic device status */ 124562306a36Sopenharmony_ci seq_printf(m, DRIVER_DESC "\n" 124662306a36Sopenharmony_ci "%s version: %s\nGadget driver: %s\nHost %s\n\n", 124762306a36Sopenharmony_ci driver_name, DRIVER_VERSION SIZE_STR "(pio)", 124862306a36Sopenharmony_ci dev->driver ? dev->driver->driver.name : "(none)", 124962306a36Sopenharmony_ci dev->gadget.speed == USB_SPEED_FULL ? "full speed" : "disconnected"); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci /* registers for device and ep0 */ 125262306a36Sopenharmony_ci seq_printf(m, 125362306a36Sopenharmony_ci "uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n", 125462306a36Sopenharmony_ci udc_get_reg(dev, UICR1), udc_get_reg(dev, UICR0), 125562306a36Sopenharmony_ci udc_get_reg(dev, USIR1), udc_get_reg(dev, USIR0), 125662306a36Sopenharmony_ci udc_get_reg(dev, UFNRH), udc_get_reg(dev, UFNRL)); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci tmp = udc_get_reg(dev, UDCCR); 125962306a36Sopenharmony_ci seq_printf(m, 126062306a36Sopenharmony_ci "udccr %02X =%s%s%s%s%s%s%s%s\n", tmp, 126162306a36Sopenharmony_ci (tmp & UDCCR_REM) ? " rem" : "", 126262306a36Sopenharmony_ci (tmp & UDCCR_RSTIR) ? " rstir" : "", 126362306a36Sopenharmony_ci (tmp & UDCCR_SRM) ? " srm" : "", 126462306a36Sopenharmony_ci (tmp & UDCCR_SUSIR) ? " susir" : "", 126562306a36Sopenharmony_ci (tmp & UDCCR_RESIR) ? " resir" : "", 126662306a36Sopenharmony_ci (tmp & UDCCR_RSM) ? " rsm" : "", 126762306a36Sopenharmony_ci (tmp & UDCCR_UDA) ? " uda" : "", 126862306a36Sopenharmony_ci (tmp & UDCCR_UDE) ? " ude" : ""); 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci tmp = udc_ep0_get_UDCCS(dev); 127162306a36Sopenharmony_ci seq_printf(m, 127262306a36Sopenharmony_ci "udccs0 %02X =%s%s%s%s%s%s%s%s\n", tmp, 127362306a36Sopenharmony_ci (tmp & UDCCS0_SA) ? " sa" : "", 127462306a36Sopenharmony_ci (tmp & UDCCS0_RNE) ? " rne" : "", 127562306a36Sopenharmony_ci (tmp & UDCCS0_FST) ? " fst" : "", 127662306a36Sopenharmony_ci (tmp & UDCCS0_SST) ? " sst" : "", 127762306a36Sopenharmony_ci (tmp & UDCCS0_DRWF) ? " dwrf" : "", 127862306a36Sopenharmony_ci (tmp & UDCCS0_FTF) ? " ftf" : "", 127962306a36Sopenharmony_ci (tmp & UDCCS0_IPR) ? " ipr" : "", 128062306a36Sopenharmony_ci (tmp & UDCCS0_OPR) ? " opr" : ""); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci if (dev->has_cfr) { 128362306a36Sopenharmony_ci tmp = udc_get_reg(dev, UDCCFR); 128462306a36Sopenharmony_ci seq_printf(m, 128562306a36Sopenharmony_ci "udccfr %02X =%s%s\n", tmp, 128662306a36Sopenharmony_ci (tmp & UDCCFR_AREN) ? " aren" : "", 128762306a36Sopenharmony_ci (tmp & UDCCFR_ACM) ? " acm" : ""); 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci if (dev->gadget.speed != USB_SPEED_FULL || !dev->driver) 129162306a36Sopenharmony_ci goto done; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci seq_printf(m, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", 129462306a36Sopenharmony_ci dev->stats.write.bytes, dev->stats.write.ops, 129562306a36Sopenharmony_ci dev->stats.read.bytes, dev->stats.read.ops, 129662306a36Sopenharmony_ci dev->stats.irqs); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci /* dump endpoint queues */ 129962306a36Sopenharmony_ci for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { 130062306a36Sopenharmony_ci struct pxa25x_ep *ep = &dev->ep [i]; 130162306a36Sopenharmony_ci struct pxa25x_request *req; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if (i != 0) { 130462306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci desc = ep->ep.desc; 130762306a36Sopenharmony_ci if (!desc) 130862306a36Sopenharmony_ci continue; 130962306a36Sopenharmony_ci tmp = udc_ep_get_UDCCS(&dev->ep[i]); 131062306a36Sopenharmony_ci seq_printf(m, 131162306a36Sopenharmony_ci "%s max %d %s udccs %02x irqs %lu\n", 131262306a36Sopenharmony_ci ep->ep.name, usb_endpoint_maxp(desc), 131362306a36Sopenharmony_ci "pio", tmp, ep->pio_irqs); 131462306a36Sopenharmony_ci /* TODO translate all five groups of udccs bits! */ 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci } else /* ep0 should only have one transfer queued */ 131762306a36Sopenharmony_ci seq_printf(m, "ep0 max 16 pio irqs %lu\n", 131862306a36Sopenharmony_ci ep->pio_irqs); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci if (list_empty(&ep->queue)) { 132162306a36Sopenharmony_ci seq_printf(m, "\t(nothing queued)\n"); 132262306a36Sopenharmony_ci continue; 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci list_for_each_entry(req, &ep->queue, queue) { 132562306a36Sopenharmony_ci seq_printf(m, 132662306a36Sopenharmony_ci "\treq %p len %d/%d buf %p\n", 132762306a36Sopenharmony_ci &req->req, req->req.actual, 132862306a36Sopenharmony_ci req->req.length, req->req.buf); 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_cidone: 133362306a36Sopenharmony_ci local_irq_restore(flags); 133462306a36Sopenharmony_ci return 0; 133562306a36Sopenharmony_ci} 133662306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(udc_debug); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci#define create_debug_files(dev) \ 133962306a36Sopenharmony_ci do { \ 134062306a36Sopenharmony_ci debugfs_create_file(dev->gadget.name, \ 134162306a36Sopenharmony_ci S_IRUGO, NULL, dev, &udc_debug_fops); \ 134262306a36Sopenharmony_ci } while (0) 134362306a36Sopenharmony_ci#define remove_debug_files(dev) debugfs_lookup_and_remove(dev->gadget.name, NULL) 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci#else /* !CONFIG_USB_GADGET_DEBUG_FILES */ 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci#define create_debug_files(dev) do {} while (0) 134862306a36Sopenharmony_ci#define remove_debug_files(dev) do {} while (0) 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci/* 135562306a36Sopenharmony_ci * udc_disable - disable USB device controller 135662306a36Sopenharmony_ci */ 135762306a36Sopenharmony_cistatic void udc_disable(struct pxa25x_udc *dev) 135862306a36Sopenharmony_ci{ 135962306a36Sopenharmony_ci /* block all irqs */ 136062306a36Sopenharmony_ci udc_set_mask_UDCCR(dev, UDCCR_SRM|UDCCR_REM); 136162306a36Sopenharmony_ci udc_set_reg(dev, UICR0, 0xff); 136262306a36Sopenharmony_ci udc_set_reg(dev, UICR1, 0xff); 136362306a36Sopenharmony_ci udc_set_reg(dev, UFNRH, UFNRH_SIM); 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci /* if hardware supports it, disconnect from usb */ 136662306a36Sopenharmony_ci pullup_off(); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci udc_clear_mask_UDCCR(dev, UDCCR_UDE); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci ep0_idle (dev); 137162306a36Sopenharmony_ci dev->gadget.speed = USB_SPEED_UNKNOWN; 137262306a36Sopenharmony_ci} 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci/* 137662306a36Sopenharmony_ci * udc_reinit - initialize software state 137762306a36Sopenharmony_ci */ 137862306a36Sopenharmony_cistatic void udc_reinit(struct pxa25x_udc *dev) 137962306a36Sopenharmony_ci{ 138062306a36Sopenharmony_ci u32 i; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci /* device/ep0 records init */ 138362306a36Sopenharmony_ci INIT_LIST_HEAD (&dev->gadget.ep_list); 138462306a36Sopenharmony_ci INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); 138562306a36Sopenharmony_ci dev->ep0state = EP0_IDLE; 138662306a36Sopenharmony_ci dev->gadget.quirk_altset_not_supp = 1; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci /* basic endpoint records init */ 138962306a36Sopenharmony_ci for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { 139062306a36Sopenharmony_ci struct pxa25x_ep *ep = &dev->ep[i]; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci if (i != 0) 139362306a36Sopenharmony_ci list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci ep->ep.desc = NULL; 139662306a36Sopenharmony_ci ep->stopped = 0; 139762306a36Sopenharmony_ci INIT_LIST_HEAD (&ep->queue); 139862306a36Sopenharmony_ci ep->pio_irqs = 0; 139962306a36Sopenharmony_ci usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket); 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci /* the rest was statically initialized, and is read-only */ 140362306a36Sopenharmony_ci} 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci/* until it's enabled, this UDC should be completely invisible 140662306a36Sopenharmony_ci * to any USB host. 140762306a36Sopenharmony_ci */ 140862306a36Sopenharmony_cistatic void udc_enable (struct pxa25x_udc *dev) 140962306a36Sopenharmony_ci{ 141062306a36Sopenharmony_ci udc_clear_mask_UDCCR(dev, UDCCR_UDE); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci /* try to clear these bits before we enable the udc */ 141362306a36Sopenharmony_ci udc_ack_int_UDCCR(dev, UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci ep0_idle(dev); 141662306a36Sopenharmony_ci dev->gadget.speed = USB_SPEED_UNKNOWN; 141762306a36Sopenharmony_ci dev->stats.irqs = 0; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci /* 142062306a36Sopenharmony_ci * sequence taken from chapter 12.5.10, PXA250 AppProcDevManual: 142162306a36Sopenharmony_ci * - enable UDC 142262306a36Sopenharmony_ci * - if RESET is already in progress, ack interrupt 142362306a36Sopenharmony_ci * - unmask reset interrupt 142462306a36Sopenharmony_ci */ 142562306a36Sopenharmony_ci udc_set_mask_UDCCR(dev, UDCCR_UDE); 142662306a36Sopenharmony_ci if (!(udc_get_reg(dev, UDCCR) & UDCCR_UDA)) 142762306a36Sopenharmony_ci udc_ack_int_UDCCR(dev, UDCCR_RSTIR); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci if (dev->has_cfr /* UDC_RES2 is defined */) { 143062306a36Sopenharmony_ci /* pxa255 (a0+) can avoid a set_config race that could 143162306a36Sopenharmony_ci * prevent gadget drivers from configuring correctly 143262306a36Sopenharmony_ci */ 143362306a36Sopenharmony_ci udc_set_reg(dev, UDCCFR, UDCCFR_ACM | UDCCFR_MB1); 143462306a36Sopenharmony_ci } else { 143562306a36Sopenharmony_ci /* "USB test mode" for pxa250 errata 40-42 (stepping a0, a1) 143662306a36Sopenharmony_ci * which could result in missing packets and interrupts. 143762306a36Sopenharmony_ci * supposedly one bit per endpoint, controlling whether it 143862306a36Sopenharmony_ci * double buffers or not; ACM/AREN bits fit into the holes. 143962306a36Sopenharmony_ci * zero bits (like USIR0_IRx) disable double buffering. 144062306a36Sopenharmony_ci */ 144162306a36Sopenharmony_ci udc_set_reg(dev, UDC_RES1, 0x00); 144262306a36Sopenharmony_ci udc_set_reg(dev, UDC_RES2, 0x00); 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci /* enable suspend/resume and reset irqs */ 144662306a36Sopenharmony_ci udc_clear_mask_UDCCR(dev, UDCCR_SRM | UDCCR_REM); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci /* enable ep0 irqs */ 144962306a36Sopenharmony_ci udc_set_reg(dev, UICR0, udc_get_reg(dev, UICR0) & ~UICR0_IM0); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci /* if hardware supports it, pullup D+ and wait for reset */ 145262306a36Sopenharmony_ci pullup_on(); 145362306a36Sopenharmony_ci} 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci/* when a driver is successfully registered, it will receive 145762306a36Sopenharmony_ci * control requests including set_configuration(), which enables 145862306a36Sopenharmony_ci * non-control requests. then usb traffic follows until a 145962306a36Sopenharmony_ci * disconnect is reported. then a host may connect again, or 146062306a36Sopenharmony_ci * the driver might get unbound. 146162306a36Sopenharmony_ci */ 146262306a36Sopenharmony_cistatic int pxa25x_udc_start(struct usb_gadget *g, 146362306a36Sopenharmony_ci struct usb_gadget_driver *driver) 146462306a36Sopenharmony_ci{ 146562306a36Sopenharmony_ci struct pxa25x_udc *dev = to_pxa25x(g); 146662306a36Sopenharmony_ci int retval; 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci /* first hook up the driver ... */ 146962306a36Sopenharmony_ci dev->driver = driver; 147062306a36Sopenharmony_ci dev->pullup = 1; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci /* ... then enable host detection and ep0; and we're ready 147362306a36Sopenharmony_ci * for set_configuration as well as eventual disconnect. 147462306a36Sopenharmony_ci */ 147562306a36Sopenharmony_ci /* connect to bus through transceiver */ 147662306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(dev->transceiver)) { 147762306a36Sopenharmony_ci retval = otg_set_peripheral(dev->transceiver->otg, 147862306a36Sopenharmony_ci &dev->gadget); 147962306a36Sopenharmony_ci if (retval) 148062306a36Sopenharmony_ci goto bind_fail; 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci dump_state(dev); 148462306a36Sopenharmony_ci return 0; 148562306a36Sopenharmony_cibind_fail: 148662306a36Sopenharmony_ci return retval; 148762306a36Sopenharmony_ci} 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_cistatic void 149062306a36Sopenharmony_cireset_gadget(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) 149162306a36Sopenharmony_ci{ 149262306a36Sopenharmony_ci int i; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci /* don't disconnect drivers more than once */ 149562306a36Sopenharmony_ci if (dev->gadget.speed == USB_SPEED_UNKNOWN) 149662306a36Sopenharmony_ci driver = NULL; 149762306a36Sopenharmony_ci dev->gadget.speed = USB_SPEED_UNKNOWN; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci /* prevent new request submissions, kill any outstanding requests */ 150062306a36Sopenharmony_ci for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { 150162306a36Sopenharmony_ci struct pxa25x_ep *ep = &dev->ep[i]; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci ep->stopped = 1; 150462306a36Sopenharmony_ci nuke(ep, -ESHUTDOWN); 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci del_timer_sync(&dev->timer); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci /* report reset; the driver is already quiesced */ 150962306a36Sopenharmony_ci if (driver) 151062306a36Sopenharmony_ci usb_gadget_udc_reset(&dev->gadget, driver); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci /* re-init driver-visible data structures */ 151362306a36Sopenharmony_ci udc_reinit(dev); 151462306a36Sopenharmony_ci} 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_cistatic void 151762306a36Sopenharmony_cistop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) 151862306a36Sopenharmony_ci{ 151962306a36Sopenharmony_ci int i; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci /* don't disconnect drivers more than once */ 152262306a36Sopenharmony_ci if (dev->gadget.speed == USB_SPEED_UNKNOWN) 152362306a36Sopenharmony_ci driver = NULL; 152462306a36Sopenharmony_ci dev->gadget.speed = USB_SPEED_UNKNOWN; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci /* prevent new request submissions, kill any outstanding requests */ 152762306a36Sopenharmony_ci for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { 152862306a36Sopenharmony_ci struct pxa25x_ep *ep = &dev->ep[i]; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci ep->stopped = 1; 153162306a36Sopenharmony_ci nuke(ep, -ESHUTDOWN); 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci del_timer_sync(&dev->timer); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci /* report disconnect; the driver is already quiesced */ 153662306a36Sopenharmony_ci if (driver) 153762306a36Sopenharmony_ci driver->disconnect(&dev->gadget); 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci /* re-init driver-visible data structures */ 154062306a36Sopenharmony_ci udc_reinit(dev); 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_cistatic int pxa25x_udc_stop(struct usb_gadget*g) 154462306a36Sopenharmony_ci{ 154562306a36Sopenharmony_ci struct pxa25x_udc *dev = to_pxa25x(g); 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci local_irq_disable(); 154862306a36Sopenharmony_ci dev->pullup = 0; 154962306a36Sopenharmony_ci stop_activity(dev, NULL); 155062306a36Sopenharmony_ci local_irq_enable(); 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(dev->transceiver)) 155362306a36Sopenharmony_ci (void) otg_set_peripheral(dev->transceiver->otg, NULL); 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci dev->driver = NULL; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci dump_state(dev); 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci return 0; 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_cistatic inline void clear_ep_state (struct pxa25x_udc *dev) 156562306a36Sopenharmony_ci{ 156662306a36Sopenharmony_ci unsigned i; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci /* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint 156962306a36Sopenharmony_ci * fifos, and pending transactions mustn't be continued in any case. 157062306a36Sopenharmony_ci */ 157162306a36Sopenharmony_ci for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) 157262306a36Sopenharmony_ci nuke(&dev->ep[i], -ECONNABORTED); 157362306a36Sopenharmony_ci} 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_cistatic void udc_watchdog(struct timer_list *t) 157662306a36Sopenharmony_ci{ 157762306a36Sopenharmony_ci struct pxa25x_udc *dev = from_timer(dev, t, timer); 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci local_irq_disable(); 158062306a36Sopenharmony_ci if (dev->ep0state == EP0_STALL 158162306a36Sopenharmony_ci && (udc_ep0_get_UDCCS(dev) & UDCCS0_FST) == 0 158262306a36Sopenharmony_ci && (udc_ep0_get_UDCCS(dev) & UDCCS0_SST) == 0) { 158362306a36Sopenharmony_ci udc_ep0_set_UDCCS(dev, UDCCS0_FST|UDCCS0_FTF); 158462306a36Sopenharmony_ci DBG(DBG_VERBOSE, "ep0 re-stall\n"); 158562306a36Sopenharmony_ci start_watchdog(dev); 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci local_irq_enable(); 158862306a36Sopenharmony_ci} 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_cistatic void handle_ep0 (struct pxa25x_udc *dev) 159162306a36Sopenharmony_ci{ 159262306a36Sopenharmony_ci u32 udccs0 = udc_ep0_get_UDCCS(dev); 159362306a36Sopenharmony_ci struct pxa25x_ep *ep = &dev->ep [0]; 159462306a36Sopenharmony_ci struct pxa25x_request *req; 159562306a36Sopenharmony_ci union { 159662306a36Sopenharmony_ci struct usb_ctrlrequest r; 159762306a36Sopenharmony_ci u8 raw [8]; 159862306a36Sopenharmony_ci u32 word [2]; 159962306a36Sopenharmony_ci } u; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci if (list_empty(&ep->queue)) 160262306a36Sopenharmony_ci req = NULL; 160362306a36Sopenharmony_ci else 160462306a36Sopenharmony_ci req = list_entry(ep->queue.next, struct pxa25x_request, queue); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci /* clear stall status */ 160762306a36Sopenharmony_ci if (udccs0 & UDCCS0_SST) { 160862306a36Sopenharmony_ci nuke(ep, -EPIPE); 160962306a36Sopenharmony_ci udc_ep0_set_UDCCS(dev, UDCCS0_SST); 161062306a36Sopenharmony_ci del_timer(&dev->timer); 161162306a36Sopenharmony_ci ep0_idle(dev); 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci /* previous request unfinished? non-error iff back-to-back ... */ 161562306a36Sopenharmony_ci if ((udccs0 & UDCCS0_SA) != 0 && dev->ep0state != EP0_IDLE) { 161662306a36Sopenharmony_ci nuke(ep, 0); 161762306a36Sopenharmony_ci del_timer(&dev->timer); 161862306a36Sopenharmony_ci ep0_idle(dev); 161962306a36Sopenharmony_ci } 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci switch (dev->ep0state) { 162262306a36Sopenharmony_ci case EP0_IDLE: 162362306a36Sopenharmony_ci /* late-breaking status? */ 162462306a36Sopenharmony_ci udccs0 = udc_ep0_get_UDCCS(dev); 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci /* start control request? */ 162762306a36Sopenharmony_ci if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE)) 162862306a36Sopenharmony_ci == (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE))) { 162962306a36Sopenharmony_ci int i; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci nuke (ep, -EPROTO); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci /* read SETUP packet */ 163462306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 163562306a36Sopenharmony_ci if (unlikely(!(udc_ep0_get_UDCCS(dev) & UDCCS0_RNE))) { 163662306a36Sopenharmony_cibad_setup: 163762306a36Sopenharmony_ci DMSG("SETUP %d!\n", i); 163862306a36Sopenharmony_ci goto stall; 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci u.raw [i] = (u8) UDDR0; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci if (unlikely((udc_ep0_get_UDCCS(dev) & UDCCS0_RNE) != 0)) 164362306a36Sopenharmony_ci goto bad_setup; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_cigot_setup: 164662306a36Sopenharmony_ci DBG(DBG_VERBOSE, "SETUP %02x.%02x v%04x i%04x l%04x\n", 164762306a36Sopenharmony_ci u.r.bRequestType, u.r.bRequest, 164862306a36Sopenharmony_ci le16_to_cpu(u.r.wValue), 164962306a36Sopenharmony_ci le16_to_cpu(u.r.wIndex), 165062306a36Sopenharmony_ci le16_to_cpu(u.r.wLength)); 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci /* cope with automagic for some standard requests. */ 165362306a36Sopenharmony_ci dev->req_std = (u.r.bRequestType & USB_TYPE_MASK) 165462306a36Sopenharmony_ci == USB_TYPE_STANDARD; 165562306a36Sopenharmony_ci dev->req_config = 0; 165662306a36Sopenharmony_ci dev->req_pending = 1; 165762306a36Sopenharmony_ci switch (u.r.bRequest) { 165862306a36Sopenharmony_ci /* hardware restricts gadget drivers here! */ 165962306a36Sopenharmony_ci case USB_REQ_SET_CONFIGURATION: 166062306a36Sopenharmony_ci if (u.r.bRequestType == USB_RECIP_DEVICE) { 166162306a36Sopenharmony_ci /* reflect hardware's automagic 166262306a36Sopenharmony_ci * up to the gadget driver. 166362306a36Sopenharmony_ci */ 166462306a36Sopenharmony_ciconfig_change: 166562306a36Sopenharmony_ci dev->req_config = 1; 166662306a36Sopenharmony_ci clear_ep_state(dev); 166762306a36Sopenharmony_ci /* if !has_cfr, there's no synch 166862306a36Sopenharmony_ci * else use AREN (later) not SA|OPR 166962306a36Sopenharmony_ci * USIR0_IR0 acts edge sensitive 167062306a36Sopenharmony_ci */ 167162306a36Sopenharmony_ci } 167262306a36Sopenharmony_ci break; 167362306a36Sopenharmony_ci /* ... and here, even more ... */ 167462306a36Sopenharmony_ci case USB_REQ_SET_INTERFACE: 167562306a36Sopenharmony_ci if (u.r.bRequestType == USB_RECIP_INTERFACE) { 167662306a36Sopenharmony_ci /* udc hardware is broken by design: 167762306a36Sopenharmony_ci * - altsetting may only be zero; 167862306a36Sopenharmony_ci * - hw resets all interfaces' eps; 167962306a36Sopenharmony_ci * - ep reset doesn't include halt(?). 168062306a36Sopenharmony_ci */ 168162306a36Sopenharmony_ci DMSG("broken set_interface (%d/%d)\n", 168262306a36Sopenharmony_ci le16_to_cpu(u.r.wIndex), 168362306a36Sopenharmony_ci le16_to_cpu(u.r.wValue)); 168462306a36Sopenharmony_ci goto config_change; 168562306a36Sopenharmony_ci } 168662306a36Sopenharmony_ci break; 168762306a36Sopenharmony_ci /* hardware was supposed to hide this */ 168862306a36Sopenharmony_ci case USB_REQ_SET_ADDRESS: 168962306a36Sopenharmony_ci if (u.r.bRequestType == USB_RECIP_DEVICE) { 169062306a36Sopenharmony_ci ep0start(dev, 0, "address"); 169162306a36Sopenharmony_ci return; 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci break; 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci if (u.r.bRequestType & USB_DIR_IN) 169762306a36Sopenharmony_ci dev->ep0state = EP0_IN_DATA_PHASE; 169862306a36Sopenharmony_ci else 169962306a36Sopenharmony_ci dev->ep0state = EP0_OUT_DATA_PHASE; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci i = dev->driver->setup(&dev->gadget, &u.r); 170262306a36Sopenharmony_ci if (i < 0) { 170362306a36Sopenharmony_ci /* hardware automagic preventing STALL... */ 170462306a36Sopenharmony_ci if (dev->req_config) { 170562306a36Sopenharmony_ci /* hardware sometimes neglects to tell 170662306a36Sopenharmony_ci * tell us about config change events, 170762306a36Sopenharmony_ci * so later ones may fail... 170862306a36Sopenharmony_ci */ 170962306a36Sopenharmony_ci WARNING("config change %02x fail %d?\n", 171062306a36Sopenharmony_ci u.r.bRequest, i); 171162306a36Sopenharmony_ci return; 171262306a36Sopenharmony_ci /* TODO experiment: if has_cfr, 171362306a36Sopenharmony_ci * hardware didn't ACK; maybe we 171462306a36Sopenharmony_ci * could actually STALL! 171562306a36Sopenharmony_ci */ 171662306a36Sopenharmony_ci } 171762306a36Sopenharmony_ci DBG(DBG_VERBOSE, "protocol STALL, " 171862306a36Sopenharmony_ci "%02x err %d\n", udc_ep0_get_UDCCS(dev), i); 171962306a36Sopenharmony_cistall: 172062306a36Sopenharmony_ci /* the watchdog timer helps deal with cases 172162306a36Sopenharmony_ci * where udc seems to clear FST wrongly, and 172262306a36Sopenharmony_ci * then NAKs instead of STALLing. 172362306a36Sopenharmony_ci */ 172462306a36Sopenharmony_ci ep0start(dev, UDCCS0_FST|UDCCS0_FTF, "stall"); 172562306a36Sopenharmony_ci start_watchdog(dev); 172662306a36Sopenharmony_ci dev->ep0state = EP0_STALL; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci /* deferred i/o == no response yet */ 172962306a36Sopenharmony_ci } else if (dev->req_pending) { 173062306a36Sopenharmony_ci if (likely(dev->ep0state == EP0_IN_DATA_PHASE 173162306a36Sopenharmony_ci || dev->req_std || u.r.wLength)) 173262306a36Sopenharmony_ci ep0start(dev, 0, "defer"); 173362306a36Sopenharmony_ci else 173462306a36Sopenharmony_ci ep0start(dev, UDCCS0_IPR, "defer/IPR"); 173562306a36Sopenharmony_ci } 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci /* expect at least one data or status stage irq */ 173862306a36Sopenharmony_ci return; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci } else if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA)) 174162306a36Sopenharmony_ci == (UDCCS0_OPR|UDCCS0_SA))) { 174262306a36Sopenharmony_ci unsigned i; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci /* pxa210/250 erratum 131 for B0/B1 says RNE lies. 174562306a36Sopenharmony_ci * still observed on a pxa255 a0. 174662306a36Sopenharmony_ci */ 174762306a36Sopenharmony_ci DBG(DBG_VERBOSE, "e131\n"); 174862306a36Sopenharmony_ci nuke(ep, -EPROTO); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci /* read SETUP data, but don't trust it too much */ 175162306a36Sopenharmony_ci for (i = 0; i < 8; i++) 175262306a36Sopenharmony_ci u.raw [i] = (u8) UDDR0; 175362306a36Sopenharmony_ci if ((u.r.bRequestType & USB_RECIP_MASK) 175462306a36Sopenharmony_ci > USB_RECIP_OTHER) 175562306a36Sopenharmony_ci goto stall; 175662306a36Sopenharmony_ci if (u.word [0] == 0 && u.word [1] == 0) 175762306a36Sopenharmony_ci goto stall; 175862306a36Sopenharmony_ci goto got_setup; 175962306a36Sopenharmony_ci } else { 176062306a36Sopenharmony_ci /* some random early IRQ: 176162306a36Sopenharmony_ci * - we acked FST 176262306a36Sopenharmony_ci * - IPR cleared 176362306a36Sopenharmony_ci * - OPR got set, without SA (likely status stage) 176462306a36Sopenharmony_ci */ 176562306a36Sopenharmony_ci udc_ep0_set_UDCCS(dev, udccs0 & (UDCCS0_SA|UDCCS0_OPR)); 176662306a36Sopenharmony_ci } 176762306a36Sopenharmony_ci break; 176862306a36Sopenharmony_ci case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ 176962306a36Sopenharmony_ci if (udccs0 & UDCCS0_OPR) { 177062306a36Sopenharmony_ci udc_ep0_set_UDCCS(dev, UDCCS0_OPR|UDCCS0_FTF); 177162306a36Sopenharmony_ci DBG(DBG_VERBOSE, "ep0in premature status\n"); 177262306a36Sopenharmony_ci if (req) 177362306a36Sopenharmony_ci done(ep, req, 0); 177462306a36Sopenharmony_ci ep0_idle(dev); 177562306a36Sopenharmony_ci } else /* irq was IPR clearing */ { 177662306a36Sopenharmony_ci if (req) { 177762306a36Sopenharmony_ci /* this IN packet might finish the request */ 177862306a36Sopenharmony_ci (void) write_ep0_fifo(ep, req); 177962306a36Sopenharmony_ci } /* else IN token before response was written */ 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci break; 178262306a36Sopenharmony_ci case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ 178362306a36Sopenharmony_ci if (udccs0 & UDCCS0_OPR) { 178462306a36Sopenharmony_ci if (req) { 178562306a36Sopenharmony_ci /* this OUT packet might finish the request */ 178662306a36Sopenharmony_ci if (read_ep0_fifo(ep, req)) 178762306a36Sopenharmony_ci done(ep, req, 0); 178862306a36Sopenharmony_ci /* else more OUT packets expected */ 178962306a36Sopenharmony_ci } /* else OUT token before read was issued */ 179062306a36Sopenharmony_ci } else /* irq was IPR clearing */ { 179162306a36Sopenharmony_ci DBG(DBG_VERBOSE, "ep0out premature status\n"); 179262306a36Sopenharmony_ci if (req) 179362306a36Sopenharmony_ci done(ep, req, 0); 179462306a36Sopenharmony_ci ep0_idle(dev); 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci break; 179762306a36Sopenharmony_ci case EP0_END_XFER: 179862306a36Sopenharmony_ci if (req) 179962306a36Sopenharmony_ci done(ep, req, 0); 180062306a36Sopenharmony_ci /* ack control-IN status (maybe in-zlp was skipped) 180162306a36Sopenharmony_ci * also appears after some config change events. 180262306a36Sopenharmony_ci */ 180362306a36Sopenharmony_ci if (udccs0 & UDCCS0_OPR) 180462306a36Sopenharmony_ci udc_ep0_set_UDCCS(dev, UDCCS0_OPR); 180562306a36Sopenharmony_ci ep0_idle(dev); 180662306a36Sopenharmony_ci break; 180762306a36Sopenharmony_ci case EP0_STALL: 180862306a36Sopenharmony_ci udc_ep0_set_UDCCS(dev, UDCCS0_FST); 180962306a36Sopenharmony_ci break; 181062306a36Sopenharmony_ci } 181162306a36Sopenharmony_ci udc_set_reg(dev, USIR0, USIR0_IR0); 181262306a36Sopenharmony_ci} 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_cistatic void handle_ep(struct pxa25x_ep *ep) 181562306a36Sopenharmony_ci{ 181662306a36Sopenharmony_ci struct pxa25x_request *req; 181762306a36Sopenharmony_ci int is_in = ep->bEndpointAddress & USB_DIR_IN; 181862306a36Sopenharmony_ci int completed; 181962306a36Sopenharmony_ci u32 udccs, tmp; 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci do { 182262306a36Sopenharmony_ci completed = 0; 182362306a36Sopenharmony_ci if (likely (!list_empty(&ep->queue))) 182462306a36Sopenharmony_ci req = list_entry(ep->queue.next, 182562306a36Sopenharmony_ci struct pxa25x_request, queue); 182662306a36Sopenharmony_ci else 182762306a36Sopenharmony_ci req = NULL; 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci // TODO check FST handling 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci udccs = udc_ep_get_UDCCS(ep); 183262306a36Sopenharmony_ci if (unlikely(is_in)) { /* irq from TPC, SST, or (ISO) TUR */ 183362306a36Sopenharmony_ci tmp = UDCCS_BI_TUR; 183462306a36Sopenharmony_ci if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK)) 183562306a36Sopenharmony_ci tmp |= UDCCS_BI_SST; 183662306a36Sopenharmony_ci tmp &= udccs; 183762306a36Sopenharmony_ci if (likely (tmp)) 183862306a36Sopenharmony_ci udc_ep_set_UDCCS(ep, tmp); 183962306a36Sopenharmony_ci if (req && likely ((udccs & UDCCS_BI_TFS) != 0)) 184062306a36Sopenharmony_ci completed = write_fifo(ep, req); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci } else { /* irq from RPC (or for ISO, ROF) */ 184362306a36Sopenharmony_ci if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK)) 184462306a36Sopenharmony_ci tmp = UDCCS_BO_SST | UDCCS_BO_DME; 184562306a36Sopenharmony_ci else 184662306a36Sopenharmony_ci tmp = UDCCS_IO_ROF | UDCCS_IO_DME; 184762306a36Sopenharmony_ci tmp &= udccs; 184862306a36Sopenharmony_ci if (likely(tmp)) 184962306a36Sopenharmony_ci udc_ep_set_UDCCS(ep, tmp); 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci /* fifos can hold packets, ready for reading... */ 185262306a36Sopenharmony_ci if (likely(req)) { 185362306a36Sopenharmony_ci completed = read_fifo(ep, req); 185462306a36Sopenharmony_ci } else 185562306a36Sopenharmony_ci pio_irq_disable(ep); 185662306a36Sopenharmony_ci } 185762306a36Sopenharmony_ci ep->pio_irqs++; 185862306a36Sopenharmony_ci } while (completed); 185962306a36Sopenharmony_ci} 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci/* 186262306a36Sopenharmony_ci * pxa25x_udc_irq - interrupt handler 186362306a36Sopenharmony_ci * 186462306a36Sopenharmony_ci * avoid delays in ep0 processing. the control handshaking isn't always 186562306a36Sopenharmony_ci * under software control (pxa250c0 and the pxa255 are better), and delays 186662306a36Sopenharmony_ci * could cause usb protocol errors. 186762306a36Sopenharmony_ci */ 186862306a36Sopenharmony_cistatic irqreturn_t 186962306a36Sopenharmony_cipxa25x_udc_irq(int irq, void *_dev) 187062306a36Sopenharmony_ci{ 187162306a36Sopenharmony_ci struct pxa25x_udc *dev = _dev; 187262306a36Sopenharmony_ci int handled; 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci dev->stats.irqs++; 187562306a36Sopenharmony_ci do { 187662306a36Sopenharmony_ci u32 udccr = udc_get_reg(dev, UDCCR); 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci handled = 0; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci /* SUSpend Interrupt Request */ 188162306a36Sopenharmony_ci if (unlikely(udccr & UDCCR_SUSIR)) { 188262306a36Sopenharmony_ci udc_ack_int_UDCCR(dev, UDCCR_SUSIR); 188362306a36Sopenharmony_ci handled = 1; 188462306a36Sopenharmony_ci DBG(DBG_VERBOSE, "USB suspend\n"); 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci if (dev->gadget.speed != USB_SPEED_UNKNOWN 188762306a36Sopenharmony_ci && dev->driver 188862306a36Sopenharmony_ci && dev->driver->suspend) 188962306a36Sopenharmony_ci dev->driver->suspend(&dev->gadget); 189062306a36Sopenharmony_ci ep0_idle (dev); 189162306a36Sopenharmony_ci } 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci /* RESume Interrupt Request */ 189462306a36Sopenharmony_ci if (unlikely(udccr & UDCCR_RESIR)) { 189562306a36Sopenharmony_ci udc_ack_int_UDCCR(dev, UDCCR_RESIR); 189662306a36Sopenharmony_ci handled = 1; 189762306a36Sopenharmony_ci DBG(DBG_VERBOSE, "USB resume\n"); 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci if (dev->gadget.speed != USB_SPEED_UNKNOWN 190062306a36Sopenharmony_ci && dev->driver 190162306a36Sopenharmony_ci && dev->driver->resume) 190262306a36Sopenharmony_ci dev->driver->resume(&dev->gadget); 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci /* ReSeT Interrupt Request - USB reset */ 190662306a36Sopenharmony_ci if (unlikely(udccr & UDCCR_RSTIR)) { 190762306a36Sopenharmony_ci udc_ack_int_UDCCR(dev, UDCCR_RSTIR); 190862306a36Sopenharmony_ci handled = 1; 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci if ((udc_get_reg(dev, UDCCR) & UDCCR_UDA) == 0) { 191162306a36Sopenharmony_ci DBG(DBG_VERBOSE, "USB reset start\n"); 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci /* reset driver and endpoints, 191462306a36Sopenharmony_ci * in case that's not yet done 191562306a36Sopenharmony_ci */ 191662306a36Sopenharmony_ci reset_gadget(dev, dev->driver); 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci } else { 191962306a36Sopenharmony_ci DBG(DBG_VERBOSE, "USB reset end\n"); 192062306a36Sopenharmony_ci dev->gadget.speed = USB_SPEED_FULL; 192162306a36Sopenharmony_ci memset(&dev->stats, 0, sizeof dev->stats); 192262306a36Sopenharmony_ci /* driver and endpoints are still reset */ 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci } else { 192662306a36Sopenharmony_ci u32 usir0 = udc_get_reg(dev, USIR0) & 192762306a36Sopenharmony_ci ~udc_get_reg(dev, UICR0); 192862306a36Sopenharmony_ci u32 usir1 = udc_get_reg(dev, USIR1) & 192962306a36Sopenharmony_ci ~udc_get_reg(dev, UICR1); 193062306a36Sopenharmony_ci int i; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci if (unlikely (!usir0 && !usir1)) 193362306a36Sopenharmony_ci continue; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci DBG(DBG_VERY_NOISY, "irq %02x.%02x\n", usir1, usir0); 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci /* control traffic */ 193862306a36Sopenharmony_ci if (usir0 & USIR0_IR0) { 193962306a36Sopenharmony_ci dev->ep[0].pio_irqs++; 194062306a36Sopenharmony_ci handle_ep0(dev); 194162306a36Sopenharmony_ci handled = 1; 194262306a36Sopenharmony_ci } 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci /* endpoint data transfers */ 194562306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 194662306a36Sopenharmony_ci u32 tmp = 1 << i; 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci if (i && (usir0 & tmp)) { 194962306a36Sopenharmony_ci handle_ep(&dev->ep[i]); 195062306a36Sopenharmony_ci udc_set_reg(dev, USIR0, 195162306a36Sopenharmony_ci udc_get_reg(dev, USIR0) | tmp); 195262306a36Sopenharmony_ci handled = 1; 195362306a36Sopenharmony_ci } 195462306a36Sopenharmony_ci#ifndef CONFIG_USB_PXA25X_SMALL 195562306a36Sopenharmony_ci if (usir1 & tmp) { 195662306a36Sopenharmony_ci handle_ep(&dev->ep[i+8]); 195762306a36Sopenharmony_ci udc_set_reg(dev, USIR1, 195862306a36Sopenharmony_ci udc_get_reg(dev, USIR1) | tmp); 195962306a36Sopenharmony_ci handled = 1; 196062306a36Sopenharmony_ci } 196162306a36Sopenharmony_ci#endif 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci } 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci /* we could also ask for 1 msec SOF (SIR) interrupts */ 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci } while (handled); 196862306a36Sopenharmony_ci return IRQ_HANDLED; 196962306a36Sopenharmony_ci} 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_cistatic void nop_release (struct device *dev) 197462306a36Sopenharmony_ci{ 197562306a36Sopenharmony_ci DMSG("%s %s\n", __func__, dev_name(dev)); 197662306a36Sopenharmony_ci} 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci/* this uses load-time allocation and initialization (instead of 197962306a36Sopenharmony_ci * doing it at run-time) to save code, eliminate fault paths, and 198062306a36Sopenharmony_ci * be more obviously correct. 198162306a36Sopenharmony_ci */ 198262306a36Sopenharmony_cistatic struct pxa25x_udc memory = { 198362306a36Sopenharmony_ci .gadget = { 198462306a36Sopenharmony_ci .ops = &pxa25x_udc_ops, 198562306a36Sopenharmony_ci .ep0 = &memory.ep[0].ep, 198662306a36Sopenharmony_ci .name = driver_name, 198762306a36Sopenharmony_ci .dev = { 198862306a36Sopenharmony_ci .init_name = "gadget", 198962306a36Sopenharmony_ci .release = nop_release, 199062306a36Sopenharmony_ci }, 199162306a36Sopenharmony_ci }, 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci /* control endpoint */ 199462306a36Sopenharmony_ci .ep[0] = { 199562306a36Sopenharmony_ci .ep = { 199662306a36Sopenharmony_ci .name = ep0name, 199762306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 199862306a36Sopenharmony_ci .maxpacket = EP0_FIFO_SIZE, 199962306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, 200062306a36Sopenharmony_ci USB_EP_CAPS_DIR_ALL), 200162306a36Sopenharmony_ci }, 200262306a36Sopenharmony_ci .dev = &memory, 200362306a36Sopenharmony_ci .regoff_udccs = UDCCS0, 200462306a36Sopenharmony_ci .regoff_uddr = UDDR0, 200562306a36Sopenharmony_ci }, 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci /* first group of endpoints */ 200862306a36Sopenharmony_ci .ep[1] = { 200962306a36Sopenharmony_ci .ep = { 201062306a36Sopenharmony_ci .name = "ep1in-bulk", 201162306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 201262306a36Sopenharmony_ci .maxpacket = BULK_FIFO_SIZE, 201362306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 201462306a36Sopenharmony_ci USB_EP_CAPS_DIR_IN), 201562306a36Sopenharmony_ci }, 201662306a36Sopenharmony_ci .dev = &memory, 201762306a36Sopenharmony_ci .fifo_size = BULK_FIFO_SIZE, 201862306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN | 1, 201962306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_BULK, 202062306a36Sopenharmony_ci .regoff_udccs = UDCCS1, 202162306a36Sopenharmony_ci .regoff_uddr = UDDR1, 202262306a36Sopenharmony_ci }, 202362306a36Sopenharmony_ci .ep[2] = { 202462306a36Sopenharmony_ci .ep = { 202562306a36Sopenharmony_ci .name = "ep2out-bulk", 202662306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 202762306a36Sopenharmony_ci .maxpacket = BULK_FIFO_SIZE, 202862306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 202962306a36Sopenharmony_ci USB_EP_CAPS_DIR_OUT), 203062306a36Sopenharmony_ci }, 203162306a36Sopenharmony_ci .dev = &memory, 203262306a36Sopenharmony_ci .fifo_size = BULK_FIFO_SIZE, 203362306a36Sopenharmony_ci .bEndpointAddress = 2, 203462306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_BULK, 203562306a36Sopenharmony_ci .regoff_udccs = UDCCS2, 203662306a36Sopenharmony_ci .regoff_ubcr = UBCR2, 203762306a36Sopenharmony_ci .regoff_uddr = UDDR2, 203862306a36Sopenharmony_ci }, 203962306a36Sopenharmony_ci#ifndef CONFIG_USB_PXA25X_SMALL 204062306a36Sopenharmony_ci .ep[3] = { 204162306a36Sopenharmony_ci .ep = { 204262306a36Sopenharmony_ci .name = "ep3in-iso", 204362306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 204462306a36Sopenharmony_ci .maxpacket = ISO_FIFO_SIZE, 204562306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 204662306a36Sopenharmony_ci USB_EP_CAPS_DIR_IN), 204762306a36Sopenharmony_ci }, 204862306a36Sopenharmony_ci .dev = &memory, 204962306a36Sopenharmony_ci .fifo_size = ISO_FIFO_SIZE, 205062306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN | 3, 205162306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_ISOC, 205262306a36Sopenharmony_ci .regoff_udccs = UDCCS3, 205362306a36Sopenharmony_ci .regoff_uddr = UDDR3, 205462306a36Sopenharmony_ci }, 205562306a36Sopenharmony_ci .ep[4] = { 205662306a36Sopenharmony_ci .ep = { 205762306a36Sopenharmony_ci .name = "ep4out-iso", 205862306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 205962306a36Sopenharmony_ci .maxpacket = ISO_FIFO_SIZE, 206062306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 206162306a36Sopenharmony_ci USB_EP_CAPS_DIR_OUT), 206262306a36Sopenharmony_ci }, 206362306a36Sopenharmony_ci .dev = &memory, 206462306a36Sopenharmony_ci .fifo_size = ISO_FIFO_SIZE, 206562306a36Sopenharmony_ci .bEndpointAddress = 4, 206662306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_ISOC, 206762306a36Sopenharmony_ci .regoff_udccs = UDCCS4, 206862306a36Sopenharmony_ci .regoff_ubcr = UBCR4, 206962306a36Sopenharmony_ci .regoff_uddr = UDDR4, 207062306a36Sopenharmony_ci }, 207162306a36Sopenharmony_ci .ep[5] = { 207262306a36Sopenharmony_ci .ep = { 207362306a36Sopenharmony_ci .name = "ep5in-int", 207462306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 207562306a36Sopenharmony_ci .maxpacket = INT_FIFO_SIZE, 207662306a36Sopenharmony_ci .caps = USB_EP_CAPS(0, 0), 207762306a36Sopenharmony_ci }, 207862306a36Sopenharmony_ci .dev = &memory, 207962306a36Sopenharmony_ci .fifo_size = INT_FIFO_SIZE, 208062306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN | 5, 208162306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_INT, 208262306a36Sopenharmony_ci .regoff_udccs = UDCCS5, 208362306a36Sopenharmony_ci .regoff_uddr = UDDR5, 208462306a36Sopenharmony_ci }, 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci /* second group of endpoints */ 208762306a36Sopenharmony_ci .ep[6] = { 208862306a36Sopenharmony_ci .ep = { 208962306a36Sopenharmony_ci .name = "ep6in-bulk", 209062306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 209162306a36Sopenharmony_ci .maxpacket = BULK_FIFO_SIZE, 209262306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 209362306a36Sopenharmony_ci USB_EP_CAPS_DIR_IN), 209462306a36Sopenharmony_ci }, 209562306a36Sopenharmony_ci .dev = &memory, 209662306a36Sopenharmony_ci .fifo_size = BULK_FIFO_SIZE, 209762306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN | 6, 209862306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_BULK, 209962306a36Sopenharmony_ci .regoff_udccs = UDCCS6, 210062306a36Sopenharmony_ci .regoff_uddr = UDDR6, 210162306a36Sopenharmony_ci }, 210262306a36Sopenharmony_ci .ep[7] = { 210362306a36Sopenharmony_ci .ep = { 210462306a36Sopenharmony_ci .name = "ep7out-bulk", 210562306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 210662306a36Sopenharmony_ci .maxpacket = BULK_FIFO_SIZE, 210762306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 210862306a36Sopenharmony_ci USB_EP_CAPS_DIR_OUT), 210962306a36Sopenharmony_ci }, 211062306a36Sopenharmony_ci .dev = &memory, 211162306a36Sopenharmony_ci .fifo_size = BULK_FIFO_SIZE, 211262306a36Sopenharmony_ci .bEndpointAddress = 7, 211362306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_BULK, 211462306a36Sopenharmony_ci .regoff_udccs = UDCCS7, 211562306a36Sopenharmony_ci .regoff_ubcr = UBCR7, 211662306a36Sopenharmony_ci .regoff_uddr = UDDR7, 211762306a36Sopenharmony_ci }, 211862306a36Sopenharmony_ci .ep[8] = { 211962306a36Sopenharmony_ci .ep = { 212062306a36Sopenharmony_ci .name = "ep8in-iso", 212162306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 212262306a36Sopenharmony_ci .maxpacket = ISO_FIFO_SIZE, 212362306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 212462306a36Sopenharmony_ci USB_EP_CAPS_DIR_IN), 212562306a36Sopenharmony_ci }, 212662306a36Sopenharmony_ci .dev = &memory, 212762306a36Sopenharmony_ci .fifo_size = ISO_FIFO_SIZE, 212862306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN | 8, 212962306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_ISOC, 213062306a36Sopenharmony_ci .regoff_udccs = UDCCS8, 213162306a36Sopenharmony_ci .regoff_uddr = UDDR8, 213262306a36Sopenharmony_ci }, 213362306a36Sopenharmony_ci .ep[9] = { 213462306a36Sopenharmony_ci .ep = { 213562306a36Sopenharmony_ci .name = "ep9out-iso", 213662306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 213762306a36Sopenharmony_ci .maxpacket = ISO_FIFO_SIZE, 213862306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 213962306a36Sopenharmony_ci USB_EP_CAPS_DIR_OUT), 214062306a36Sopenharmony_ci }, 214162306a36Sopenharmony_ci .dev = &memory, 214262306a36Sopenharmony_ci .fifo_size = ISO_FIFO_SIZE, 214362306a36Sopenharmony_ci .bEndpointAddress = 9, 214462306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_ISOC, 214562306a36Sopenharmony_ci .regoff_udccs = UDCCS9, 214662306a36Sopenharmony_ci .regoff_ubcr = UBCR9, 214762306a36Sopenharmony_ci .regoff_uddr = UDDR9, 214862306a36Sopenharmony_ci }, 214962306a36Sopenharmony_ci .ep[10] = { 215062306a36Sopenharmony_ci .ep = { 215162306a36Sopenharmony_ci .name = "ep10in-int", 215262306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 215362306a36Sopenharmony_ci .maxpacket = INT_FIFO_SIZE, 215462306a36Sopenharmony_ci .caps = USB_EP_CAPS(0, 0), 215562306a36Sopenharmony_ci }, 215662306a36Sopenharmony_ci .dev = &memory, 215762306a36Sopenharmony_ci .fifo_size = INT_FIFO_SIZE, 215862306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN | 10, 215962306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_INT, 216062306a36Sopenharmony_ci .regoff_udccs = UDCCS10, 216162306a36Sopenharmony_ci .regoff_uddr = UDDR10, 216262306a36Sopenharmony_ci }, 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci /* third group of endpoints */ 216562306a36Sopenharmony_ci .ep[11] = { 216662306a36Sopenharmony_ci .ep = { 216762306a36Sopenharmony_ci .name = "ep11in-bulk", 216862306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 216962306a36Sopenharmony_ci .maxpacket = BULK_FIFO_SIZE, 217062306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 217162306a36Sopenharmony_ci USB_EP_CAPS_DIR_IN), 217262306a36Sopenharmony_ci }, 217362306a36Sopenharmony_ci .dev = &memory, 217462306a36Sopenharmony_ci .fifo_size = BULK_FIFO_SIZE, 217562306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN | 11, 217662306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_BULK, 217762306a36Sopenharmony_ci .regoff_udccs = UDCCS11, 217862306a36Sopenharmony_ci .regoff_uddr = UDDR11, 217962306a36Sopenharmony_ci }, 218062306a36Sopenharmony_ci .ep[12] = { 218162306a36Sopenharmony_ci .ep = { 218262306a36Sopenharmony_ci .name = "ep12out-bulk", 218362306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 218462306a36Sopenharmony_ci .maxpacket = BULK_FIFO_SIZE, 218562306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, 218662306a36Sopenharmony_ci USB_EP_CAPS_DIR_OUT), 218762306a36Sopenharmony_ci }, 218862306a36Sopenharmony_ci .dev = &memory, 218962306a36Sopenharmony_ci .fifo_size = BULK_FIFO_SIZE, 219062306a36Sopenharmony_ci .bEndpointAddress = 12, 219162306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_BULK, 219262306a36Sopenharmony_ci .regoff_udccs = UDCCS12, 219362306a36Sopenharmony_ci .regoff_ubcr = UBCR12, 219462306a36Sopenharmony_ci .regoff_uddr = UDDR12, 219562306a36Sopenharmony_ci }, 219662306a36Sopenharmony_ci .ep[13] = { 219762306a36Sopenharmony_ci .ep = { 219862306a36Sopenharmony_ci .name = "ep13in-iso", 219962306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 220062306a36Sopenharmony_ci .maxpacket = ISO_FIFO_SIZE, 220162306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 220262306a36Sopenharmony_ci USB_EP_CAPS_DIR_IN), 220362306a36Sopenharmony_ci }, 220462306a36Sopenharmony_ci .dev = &memory, 220562306a36Sopenharmony_ci .fifo_size = ISO_FIFO_SIZE, 220662306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN | 13, 220762306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_ISOC, 220862306a36Sopenharmony_ci .regoff_udccs = UDCCS13, 220962306a36Sopenharmony_ci .regoff_uddr = UDDR13, 221062306a36Sopenharmony_ci }, 221162306a36Sopenharmony_ci .ep[14] = { 221262306a36Sopenharmony_ci .ep = { 221362306a36Sopenharmony_ci .name = "ep14out-iso", 221462306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 221562306a36Sopenharmony_ci .maxpacket = ISO_FIFO_SIZE, 221662306a36Sopenharmony_ci .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, 221762306a36Sopenharmony_ci USB_EP_CAPS_DIR_OUT), 221862306a36Sopenharmony_ci }, 221962306a36Sopenharmony_ci .dev = &memory, 222062306a36Sopenharmony_ci .fifo_size = ISO_FIFO_SIZE, 222162306a36Sopenharmony_ci .bEndpointAddress = 14, 222262306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_ISOC, 222362306a36Sopenharmony_ci .regoff_udccs = UDCCS14, 222462306a36Sopenharmony_ci .regoff_ubcr = UBCR14, 222562306a36Sopenharmony_ci .regoff_uddr = UDDR14, 222662306a36Sopenharmony_ci }, 222762306a36Sopenharmony_ci .ep[15] = { 222862306a36Sopenharmony_ci .ep = { 222962306a36Sopenharmony_ci .name = "ep15in-int", 223062306a36Sopenharmony_ci .ops = &pxa25x_ep_ops, 223162306a36Sopenharmony_ci .maxpacket = INT_FIFO_SIZE, 223262306a36Sopenharmony_ci .caps = USB_EP_CAPS(0, 0), 223362306a36Sopenharmony_ci }, 223462306a36Sopenharmony_ci .dev = &memory, 223562306a36Sopenharmony_ci .fifo_size = INT_FIFO_SIZE, 223662306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN | 15, 223762306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_INT, 223862306a36Sopenharmony_ci .regoff_udccs = UDCCS15, 223962306a36Sopenharmony_ci .regoff_uddr = UDDR15, 224062306a36Sopenharmony_ci }, 224162306a36Sopenharmony_ci#endif /* !CONFIG_USB_PXA25X_SMALL */ 224262306a36Sopenharmony_ci}; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci#define CP15R0_VENDOR_MASK 0xffffe000 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci#if defined(CONFIG_ARCH_PXA) 224762306a36Sopenharmony_ci#define CP15R0_XSCALE_VALUE 0x69052000 /* intel/arm/xscale */ 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci#elif defined(CONFIG_ARCH_IXP4XX) 225062306a36Sopenharmony_ci#define CP15R0_XSCALE_VALUE 0x69054000 /* intel/arm/ixp4xx */ 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci#endif 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci#define CP15R0_PROD_MASK 0x000003f0 225562306a36Sopenharmony_ci#define PXA25x 0x00000100 /* and PXA26x */ 225662306a36Sopenharmony_ci#define PXA210 0x00000120 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci#define CP15R0_REV_MASK 0x0000000f 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci#define CP15R0_PRODREV_MASK (CP15R0_PROD_MASK | CP15R0_REV_MASK) 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci#define PXA255_A0 0x00000106 /* or PXA260_B1 */ 226362306a36Sopenharmony_ci#define PXA250_C0 0x00000105 /* or PXA26x_B0 */ 226462306a36Sopenharmony_ci#define PXA250_B2 0x00000104 226562306a36Sopenharmony_ci#define PXA250_B1 0x00000103 /* or PXA260_A0 */ 226662306a36Sopenharmony_ci#define PXA250_B0 0x00000102 226762306a36Sopenharmony_ci#define PXA250_A1 0x00000101 226862306a36Sopenharmony_ci#define PXA250_A0 0x00000100 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci#define PXA210_C0 0x00000125 227162306a36Sopenharmony_ci#define PXA210_B2 0x00000124 227262306a36Sopenharmony_ci#define PXA210_B1 0x00000123 227362306a36Sopenharmony_ci#define PXA210_B0 0x00000122 227462306a36Sopenharmony_ci#define IXP425_A0 0x000001c1 227562306a36Sopenharmony_ci#define IXP425_B0 0x000001f1 227662306a36Sopenharmony_ci#define IXP465_AD 0x00000200 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci/* 227962306a36Sopenharmony_ci * probe - binds to the platform device 228062306a36Sopenharmony_ci */ 228162306a36Sopenharmony_cistatic int pxa25x_udc_probe(struct platform_device *pdev) 228262306a36Sopenharmony_ci{ 228362306a36Sopenharmony_ci struct pxa25x_udc *dev = &memory; 228462306a36Sopenharmony_ci int retval, irq; 228562306a36Sopenharmony_ci u32 chiprev; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci pr_info("%s: version %s\n", driver_name, DRIVER_VERSION); 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci /* insist on Intel/ARM/XScale */ 229062306a36Sopenharmony_ci asm("mrc p15, 0, %0, c0, c0" : "=r" (chiprev)); 229162306a36Sopenharmony_ci if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) { 229262306a36Sopenharmony_ci pr_err("%s: not XScale!\n", driver_name); 229362306a36Sopenharmony_ci return -ENODEV; 229462306a36Sopenharmony_ci } 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci /* trigger chiprev-specific logic */ 229762306a36Sopenharmony_ci switch (chiprev & CP15R0_PRODREV_MASK) { 229862306a36Sopenharmony_ci#if defined(CONFIG_ARCH_PXA) 229962306a36Sopenharmony_ci case PXA255_A0: 230062306a36Sopenharmony_ci dev->has_cfr = 1; 230162306a36Sopenharmony_ci break; 230262306a36Sopenharmony_ci case PXA250_A0: 230362306a36Sopenharmony_ci case PXA250_A1: 230462306a36Sopenharmony_ci /* A0/A1 "not released"; ep 13, 15 unusable */ 230562306a36Sopenharmony_ci fallthrough; 230662306a36Sopenharmony_ci case PXA250_B2: case PXA210_B2: 230762306a36Sopenharmony_ci case PXA250_B1: case PXA210_B1: 230862306a36Sopenharmony_ci case PXA250_B0: case PXA210_B0: 230962306a36Sopenharmony_ci /* OUT-DMA is broken ... */ 231062306a36Sopenharmony_ci fallthrough; 231162306a36Sopenharmony_ci case PXA250_C0: case PXA210_C0: 231262306a36Sopenharmony_ci break; 231362306a36Sopenharmony_ci#elif defined(CONFIG_ARCH_IXP4XX) 231462306a36Sopenharmony_ci case IXP425_A0: 231562306a36Sopenharmony_ci case IXP425_B0: 231662306a36Sopenharmony_ci case IXP465_AD: 231762306a36Sopenharmony_ci dev->has_cfr = 1; 231862306a36Sopenharmony_ci break; 231962306a36Sopenharmony_ci#endif 232062306a36Sopenharmony_ci default: 232162306a36Sopenharmony_ci pr_err("%s: unrecognized processor: %08x\n", 232262306a36Sopenharmony_ci driver_name, chiprev); 232362306a36Sopenharmony_ci /* iop3xx, ixp4xx, ... */ 232462306a36Sopenharmony_ci return -ENODEV; 232562306a36Sopenharmony_ci } 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 232862306a36Sopenharmony_ci if (irq < 0) 232962306a36Sopenharmony_ci return irq; 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci dev->regs = devm_platform_ioremap_resource(pdev, 0); 233262306a36Sopenharmony_ci if (IS_ERR(dev->regs)) 233362306a36Sopenharmony_ci return PTR_ERR(dev->regs); 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci dev->clk = devm_clk_get(&pdev->dev, NULL); 233662306a36Sopenharmony_ci if (IS_ERR(dev->clk)) 233762306a36Sopenharmony_ci return PTR_ERR(dev->clk); 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci pr_debug("%s: IRQ %d%s%s\n", driver_name, irq, 234062306a36Sopenharmony_ci dev->has_cfr ? "" : " (!cfr)", 234162306a36Sopenharmony_ci SIZE_STR "(pio)" 234262306a36Sopenharmony_ci ); 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci /* other non-static parts of init */ 234562306a36Sopenharmony_ci dev->dev = &pdev->dev; 234662306a36Sopenharmony_ci dev->mach = dev_get_platdata(&pdev->dev); 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci dev->transceiver = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_ci if (gpio_is_valid(dev->mach->gpio_pullup)) { 235162306a36Sopenharmony_ci retval = devm_gpio_request(&pdev->dev, dev->mach->gpio_pullup, 235262306a36Sopenharmony_ci "pca25x_udc GPIO PULLUP"); 235362306a36Sopenharmony_ci if (retval) { 235462306a36Sopenharmony_ci dev_dbg(&pdev->dev, 235562306a36Sopenharmony_ci "can't get pullup gpio %d, err: %d\n", 235662306a36Sopenharmony_ci dev->mach->gpio_pullup, retval); 235762306a36Sopenharmony_ci goto err; 235862306a36Sopenharmony_ci } 235962306a36Sopenharmony_ci gpio_direction_output(dev->mach->gpio_pullup, 0); 236062306a36Sopenharmony_ci } 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci timer_setup(&dev->timer, udc_watchdog, 0); 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci the_controller = dev; 236562306a36Sopenharmony_ci platform_set_drvdata(pdev, dev); 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci udc_disable(dev); 236862306a36Sopenharmony_ci udc_reinit(dev); 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci dev->vbus = 0; 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci /* irq setup after old hardware state is cleaned up */ 237362306a36Sopenharmony_ci retval = devm_request_irq(&pdev->dev, irq, pxa25x_udc_irq, 0, 237462306a36Sopenharmony_ci driver_name, dev); 237562306a36Sopenharmony_ci if (retval != 0) { 237662306a36Sopenharmony_ci pr_err("%s: can't get irq %d, err %d\n", 237762306a36Sopenharmony_ci driver_name, irq, retval); 237862306a36Sopenharmony_ci goto err; 237962306a36Sopenharmony_ci } 238062306a36Sopenharmony_ci dev->got_irq = 1; 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci create_debug_files(dev); 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); 238562306a36Sopenharmony_ci if (!retval) 238662306a36Sopenharmony_ci return retval; 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci remove_debug_files(dev); 238962306a36Sopenharmony_ci err: 239062306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(dev->transceiver)) 239162306a36Sopenharmony_ci dev->transceiver = NULL; 239262306a36Sopenharmony_ci return retval; 239362306a36Sopenharmony_ci} 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_cistatic void pxa25x_udc_shutdown(struct platform_device *_dev) 239662306a36Sopenharmony_ci{ 239762306a36Sopenharmony_ci pullup_off(); 239862306a36Sopenharmony_ci} 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_cistatic int pxa25x_udc_remove(struct platform_device *pdev) 240162306a36Sopenharmony_ci{ 240262306a36Sopenharmony_ci struct pxa25x_udc *dev = platform_get_drvdata(pdev); 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci if (dev->driver) 240562306a36Sopenharmony_ci return -EBUSY; 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci usb_del_gadget_udc(&dev->gadget); 240862306a36Sopenharmony_ci dev->pullup = 0; 240962306a36Sopenharmony_ci pullup(dev); 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci remove_debug_files(dev); 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(dev->transceiver)) 241462306a36Sopenharmony_ci dev->transceiver = NULL; 241562306a36Sopenharmony_ci 241662306a36Sopenharmony_ci the_controller = NULL; 241762306a36Sopenharmony_ci return 0; 241862306a36Sopenharmony_ci} 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci#ifdef CONFIG_PM 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci/* USB suspend (controlled by the host) and system suspend (controlled 242562306a36Sopenharmony_ci * by the PXA) don't necessarily work well together. If USB is active, 242662306a36Sopenharmony_ci * the 48 MHz clock is required; so the system can't enter 33 MHz idle 242762306a36Sopenharmony_ci * mode, or any deeper PM saving state. 242862306a36Sopenharmony_ci * 242962306a36Sopenharmony_ci * For now, we punt and forcibly disconnect from the USB host when PXA 243062306a36Sopenharmony_ci * enters any suspend state. While we're disconnected, we always disable 243162306a36Sopenharmony_ci * the 48MHz USB clock ... allowing PXA sleep and/or 33 MHz idle states. 243262306a36Sopenharmony_ci * Boards without software pullup control shouldn't use those states. 243362306a36Sopenharmony_ci * VBUS IRQs should probably be ignored so that the PXA device just acts 243462306a36Sopenharmony_ci * "dead" to USB hosts until system resume. 243562306a36Sopenharmony_ci */ 243662306a36Sopenharmony_cistatic int pxa25x_udc_suspend(struct platform_device *dev, pm_message_t state) 243762306a36Sopenharmony_ci{ 243862306a36Sopenharmony_ci struct pxa25x_udc *udc = platform_get_drvdata(dev); 243962306a36Sopenharmony_ci unsigned long flags; 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command) 244262306a36Sopenharmony_ci WARNING("USB host won't detect disconnect!\n"); 244362306a36Sopenharmony_ci udc->suspended = 1; 244462306a36Sopenharmony_ci 244562306a36Sopenharmony_ci local_irq_save(flags); 244662306a36Sopenharmony_ci pullup(udc); 244762306a36Sopenharmony_ci local_irq_restore(flags); 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_ci return 0; 245062306a36Sopenharmony_ci} 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_cistatic int pxa25x_udc_resume(struct platform_device *dev) 245362306a36Sopenharmony_ci{ 245462306a36Sopenharmony_ci struct pxa25x_udc *udc = platform_get_drvdata(dev); 245562306a36Sopenharmony_ci unsigned long flags; 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci udc->suspended = 0; 245862306a36Sopenharmony_ci local_irq_save(flags); 245962306a36Sopenharmony_ci pullup(udc); 246062306a36Sopenharmony_ci local_irq_restore(flags); 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci return 0; 246362306a36Sopenharmony_ci} 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci#else 246662306a36Sopenharmony_ci#define pxa25x_udc_suspend NULL 246762306a36Sopenharmony_ci#define pxa25x_udc_resume NULL 246862306a36Sopenharmony_ci#endif 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci/*-------------------------------------------------------------------------*/ 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_cistatic struct platform_driver udc_driver = { 247362306a36Sopenharmony_ci .shutdown = pxa25x_udc_shutdown, 247462306a36Sopenharmony_ci .probe = pxa25x_udc_probe, 247562306a36Sopenharmony_ci .remove = pxa25x_udc_remove, 247662306a36Sopenharmony_ci .suspend = pxa25x_udc_suspend, 247762306a36Sopenharmony_ci .resume = pxa25x_udc_resume, 247862306a36Sopenharmony_ci .driver = { 247962306a36Sopenharmony_ci .name = "pxa25x-udc", 248062306a36Sopenharmony_ci }, 248162306a36Sopenharmony_ci}; 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_cimodule_platform_driver(udc_driver); 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 248662306a36Sopenharmony_ciMODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell"); 248762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 248862306a36Sopenharmony_ciMODULE_ALIAS("platform:pxa25x-udc"); 2489