229 lines
		
	
	
	
		
			5.8 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			229 lines
		
	
	
	
		
			5.8 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Intel Langwell USB Device Controller driver
							 | 
						||
| 
								 | 
							
								 * Copyright (C) 2008-2009, Intel Corporation.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This program is free software; you can redistribute it and/or modify it
							 | 
						||
| 
								 | 
							
								 * under the terms and conditions of the GNU General Public License,
							 | 
						||
| 
								 | 
							
								 * version 2, as published by the Free Software Foundation.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This program is distributed in the hope it will be useful, but WITHOUT
							 | 
						||
| 
								 | 
							
								 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
							 | 
						||
| 
								 | 
							
								 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
							 | 
						||
| 
								 | 
							
								 * more details.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * You should have received a copy of the GNU General Public License along with
							 | 
						||
| 
								 | 
							
								 * this program; if not, write to the Free Software Foundation, Inc.,
							 | 
						||
| 
								 | 
							
								 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <linux/usb/langwell_udc.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined(CONFIG_USB_LANGWELL_OTG)
							 | 
						||
| 
								 | 
							
								#include <linux/usb/langwell_otg.h>
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*-------------------------------------------------------------------------*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* driver data structures and utilities */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * dTD: Device Endpoint Transfer Descriptor
							 | 
						||
| 
								 | 
							
								 * describe to the device controller the location and quantity of
							 | 
						||
| 
								 | 
							
								 * data to be send/received for given transfer
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								struct langwell_dtd {
							 | 
						||
| 
								 | 
							
									u32	dtd_next;
							 | 
						||
| 
								 | 
							
								/* bits 31:5, next transfer element pointer */
							 | 
						||
| 
								 | 
							
								#define	DTD_NEXT(d)	(((d)>>5)&0x7ffffff)
							 | 
						||
| 
								 | 
							
								#define	DTD_NEXT_MASK	(0x7ffffff << 5)
							 | 
						||
| 
								 | 
							
								/* terminate */
							 | 
						||
| 
								 | 
							
								#define	DTD_TERM	BIT(0)
							 | 
						||
| 
								 | 
							
									/* bits 7:0, execution back states */
							 | 
						||
| 
								 | 
							
									u32	dtd_status:8;
							 | 
						||
| 
								 | 
							
								#define	DTD_STATUS(d)	(((d)>>0)&0xff)
							 | 
						||
| 
								 | 
							
								#define	DTD_STS_ACTIVE	BIT(7)	/* active */
							 | 
						||
| 
								 | 
							
								#define	DTD_STS_HALTED	BIT(6)	/* halted */
							 | 
						||
| 
								 | 
							
								#define	DTD_STS_DBE	BIT(5)	/* data buffer error */
							 | 
						||
| 
								 | 
							
								#define	DTD_STS_TRE	BIT(3)	/* transaction error  */
							 | 
						||
| 
								 | 
							
									/* bits 9:8 */
							 | 
						||
| 
								 | 
							
									u32	dtd_res0:2;
							 | 
						||
| 
								 | 
							
									/* bits 11:10, multipier override */
							 | 
						||
| 
								 | 
							
									u32	dtd_multo:2;
							 | 
						||
| 
								 | 
							
								#define	DTD_MULTO	(BIT(11) | BIT(10))
							 | 
						||
| 
								 | 
							
									/* bits 14:12 */
							 | 
						||
| 
								 | 
							
									u32	dtd_res1:3;
							 | 
						||
| 
								 | 
							
									/* bit 15, interrupt on complete */
							 | 
						||
| 
								 | 
							
									u32	dtd_ioc:1;
							 | 
						||
| 
								 | 
							
								#define	DTD_IOC		BIT(15)
							 | 
						||
| 
								 | 
							
									/* bits 30:16, total bytes */
							 | 
						||
| 
								 | 
							
									u32	dtd_total:15;
							 | 
						||
| 
								 | 
							
								#define	DTD_TOTAL(d)	(((d)>>16)&0x7fff)
							 | 
						||
| 
								 | 
							
								#define	DTD_MAX_TRANSFER_LENGTH	0x4000
							 | 
						||
| 
								 | 
							
									/* bit 31 */
							 | 
						||
| 
								 | 
							
									u32	dtd_res2:1;
							 | 
						||
| 
								 | 
							
									/* dTD buffer pointer page 0 to 4 */
							 | 
						||
| 
								 | 
							
									u32	dtd_buf[5];
							 | 
						||
| 
								 | 
							
								#define	DTD_OFFSET_MASK	0xfff
							 | 
						||
| 
								 | 
							
								/* bits 31:12, buffer pointer */
							 | 
						||
| 
								 | 
							
								#define	DTD_BUFFER(d)	(((d)>>12)&0x3ff)
							 | 
						||
| 
								 | 
							
								/* bits 11:0, current offset */
							 | 
						||
| 
								 | 
							
								#define	DTD_C_OFFSET(d)	(((d)>>0)&0xfff)
							 | 
						||
| 
								 | 
							
								/* bits 10:0, frame number */
							 | 
						||
| 
								 | 
							
								#define	DTD_FRAME(d)	(((d)>>0)&0x7ff)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* driver-private parts */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* dtd dma address */
							 | 
						||
| 
								 | 
							
									dma_addr_t		dtd_dma;
							 | 
						||
| 
								 | 
							
									/* next dtd virtual address */
							 | 
						||
| 
								 | 
							
									struct langwell_dtd	*next_dtd_virt;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * dQH: Device Endpoint Queue Head
							 | 
						||
| 
								 | 
							
								 * describe where all transfers are managed
							 | 
						||
| 
								 | 
							
								 * 48-byte data structure, aligned on 64-byte boundary
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * These are associated with dTD structure
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								struct langwell_dqh {
							 | 
						||
| 
								 | 
							
									/* endpoint capabilities and characteristics */
							 | 
						||
| 
								 | 
							
									u32	dqh_res0:15;	/* bits 14:0 */
							 | 
						||
| 
								 | 
							
									u32	dqh_ios:1;	/* bit 15, interrupt on setup */
							 | 
						||
| 
								 | 
							
								#define	DQH_IOS		BIT(15)
							 | 
						||
| 
								 | 
							
									u32	dqh_mpl:11;	/* bits 26:16, maximum packet length */
							 | 
						||
| 
								 | 
							
								#define	DQH_MPL		(0x7ff << 16)
							 | 
						||
| 
								 | 
							
									u32	dqh_res1:2;	/* bits 28:27 */
							 | 
						||
| 
								 | 
							
									u32	dqh_zlt:1;	/* bit 29, zero length termination */
							 | 
						||
| 
								 | 
							
								#define	DQH_ZLT		BIT(29)
							 | 
						||
| 
								 | 
							
									u32	dqh_mult:2;	/* bits 31:30 */
							 | 
						||
| 
								 | 
							
								#define	DQH_MULT	(BIT(30) | BIT(31))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* current dTD pointer */
							 | 
						||
| 
								 | 
							
									u32	dqh_current;	/* locate the transfer in progress */
							 | 
						||
| 
								 | 
							
								#define DQH_C_DTD(e)	\
							 | 
						||
| 
								 | 
							
									(((e)>>5)&0x7ffffff)	/* bits 31:5, current dTD pointer */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* transfer overlay, hardware parts of a struct langwell_dtd */
							 | 
						||
| 
								 | 
							
									u32	dtd_next;
							 | 
						||
| 
								 | 
							
									u32	dtd_status:8;	/* bits 7:0, execution back states */
							 | 
						||
| 
								 | 
							
									u32	dtd_res0:2;	/* bits 9:8 */
							 | 
						||
| 
								 | 
							
									u32	dtd_multo:2;	/* bits 11:10, multipier override */
							 | 
						||
| 
								 | 
							
									u32	dtd_res1:3;	/* bits 14:12 */
							 | 
						||
| 
								 | 
							
									u32	dtd_ioc:1;	/* bit 15, interrupt on complete */
							 | 
						||
| 
								 | 
							
									u32	dtd_total:15;	/* bits 30:16, total bytes */
							 | 
						||
| 
								 | 
							
									u32	dtd_res2:1;	/* bit 31 */
							 | 
						||
| 
								 | 
							
									u32	dtd_buf[5];	/* dTD buffer pointer page 0 to 4 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									u32	dqh_res2;
							 | 
						||
| 
								 | 
							
									struct usb_ctrlrequest	dqh_setup;	/* setup packet buffer */
							 | 
						||
| 
								 | 
							
								} __attribute__ ((aligned(64)));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* endpoint data structure */
							 | 
						||
| 
								 | 
							
								struct langwell_ep {
							 | 
						||
| 
								 | 
							
									struct usb_ep		ep;
							 | 
						||
| 
								 | 
							
									dma_addr_t		dma;
							 | 
						||
| 
								 | 
							
									struct langwell_udc	*dev;
							 | 
						||
| 
								 | 
							
									unsigned long		irqs;
							 | 
						||
| 
								 | 
							
									struct list_head	queue;
							 | 
						||
| 
								 | 
							
									struct langwell_dqh	*dqh;
							 | 
						||
| 
								 | 
							
									const struct usb_endpoint_descriptor	*desc;
							 | 
						||
| 
								 | 
							
									char			name[14];
							 | 
						||
| 
								 | 
							
									unsigned		stopped:1,
							 | 
						||
| 
								 | 
							
												ep_type:2,
							 | 
						||
| 
								 | 
							
												ep_num:8;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* request data structure */
							 | 
						||
| 
								 | 
							
								struct langwell_request {
							 | 
						||
| 
								 | 
							
									struct usb_request	req;
							 | 
						||
| 
								 | 
							
									struct langwell_dtd	*dtd, *head, *tail;
							 | 
						||
| 
								 | 
							
									struct langwell_ep	*ep;
							 | 
						||
| 
								 | 
							
									dma_addr_t		dtd_dma;
							 | 
						||
| 
								 | 
							
									struct list_head	queue;
							 | 
						||
| 
								 | 
							
									unsigned		dtd_count;
							 | 
						||
| 
								 | 
							
									unsigned		mapped:1;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* ep0 transfer state */
							 | 
						||
| 
								 | 
							
								enum ep0_state {
							 | 
						||
| 
								 | 
							
									WAIT_FOR_SETUP,
							 | 
						||
| 
								 | 
							
									DATA_STATE_XMIT,
							 | 
						||
| 
								 | 
							
									DATA_STATE_NEED_ZLP,
							 | 
						||
| 
								 | 
							
									WAIT_FOR_OUT_STATUS,
							 | 
						||
| 
								 | 
							
									DATA_STATE_RECV,
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* device suspend state */
							 | 
						||
| 
								 | 
							
								enum lpm_state {
							 | 
						||
| 
								 | 
							
									LPM_L0,	/* on */
							 | 
						||
| 
								 | 
							
									LPM_L1,	/* LPM L1 sleep */
							 | 
						||
| 
								 | 
							
									LPM_L2,	/* suspend */
							 | 
						||
| 
								 | 
							
									LPM_L3,	/* off */
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* device data structure */
							 | 
						||
| 
								 | 
							
								struct langwell_udc {
							 | 
						||
| 
								 | 
							
									/* each pci device provides one gadget, several endpoints */
							 | 
						||
| 
								 | 
							
									struct usb_gadget	gadget;
							 | 
						||
| 
								 | 
							
									spinlock_t		lock;	/* device lock */
							 | 
						||
| 
								 | 
							
									struct langwell_ep	*ep;
							 | 
						||
| 
								 | 
							
									struct usb_gadget_driver	*driver;
							 | 
						||
| 
								 | 
							
									struct otg_transceiver	*transceiver;
							 | 
						||
| 
								 | 
							
									u8			dev_addr;
							 | 
						||
| 
								 | 
							
									u32			usb_state;
							 | 
						||
| 
								 | 
							
									u32			resume_state;
							 | 
						||
| 
								 | 
							
									u32			bus_reset;
							 | 
						||
| 
								 | 
							
									enum lpm_state		lpm_state;
							 | 
						||
| 
								 | 
							
									enum ep0_state		ep0_state;
							 | 
						||
| 
								 | 
							
									u32			ep0_dir;
							 | 
						||
| 
								 | 
							
									u16			dciversion;
							 | 
						||
| 
								 | 
							
									unsigned		ep_max;
							 | 
						||
| 
								 | 
							
									unsigned		devcap:1,
							 | 
						||
| 
								 | 
							
												enabled:1,
							 | 
						||
| 
								 | 
							
												region:1,
							 | 
						||
| 
								 | 
							
												got_irq:1,
							 | 
						||
| 
								 | 
							
												powered:1,
							 | 
						||
| 
								 | 
							
												remote_wakeup:1,
							 | 
						||
| 
								 | 
							
												rate:1,
							 | 
						||
| 
								 | 
							
												is_reset:1,
							 | 
						||
| 
								 | 
							
												softconnected:1,
							 | 
						||
| 
								 | 
							
												vbus_active:1,
							 | 
						||
| 
								 | 
							
												suspended:1,
							 | 
						||
| 
								 | 
							
												stopped:1,
							 | 
						||
| 
								 | 
							
												lpm:1;	/* LPM capability */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* pci state used to access those endpoints */
							 | 
						||
| 
								 | 
							
									struct pci_dev		*pdev;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* Langwell otg transceiver */
							 | 
						||
| 
								 | 
							
									struct langwell_otg	*lotg;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* control registers */
							 | 
						||
| 
								 | 
							
									struct langwell_cap_regs	__iomem	*cap_regs;
							 | 
						||
| 
								 | 
							
									struct langwell_op_regs		__iomem	*op_regs;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									struct usb_ctrlrequest	local_setup_buff;
							 | 
						||
| 
								 | 
							
									struct langwell_dqh	*ep_dqh;
							 | 
						||
| 
								 | 
							
									size_t			ep_dqh_size;
							 | 
						||
| 
								 | 
							
									dma_addr_t		ep_dqh_dma;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* ep0 status request */
							 | 
						||
| 
								 | 
							
									struct langwell_request	*status_req;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* dma pool */
							 | 
						||
| 
								 | 
							
									struct dma_pool		*dtd_pool;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* make sure release() is done */
							 | 
						||
| 
								 | 
							
									struct completion	*done;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 |