| /* |
| * 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. |
| */ |
| |
| #include <linux/usb/langwell_udc.h> |
| #include <linux/usb/langwell_otg.h> |
| |
| /*-------------------------------------------------------------------------*/ |
| |
| /* 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 */ |
| has_sram:1, /* SRAM caching */ |
| got_sram:1; |
| |
| /* 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; |
| |
| /* for private SRAM caching */ |
| unsigned int sram_addr; |
| unsigned int sram_size; |
| |
| /* device status data for get_status request */ |
| u16 dev_status; |
| }; |
| |
| #define gadget_to_langwell(g) container_of((g), struct langwell_udc, gadget) |
| |