blob: cb0c75e49df1481b80ada28bd3d47259b76d4b61 [file] [log] [blame]
/*
* Copyright (c) 2013 Qualcomm Atheros, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Atheros USB Device Controller Driver
*/
#include <linux/autoconf.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/dmapool.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
#define ATH_USB_DEBUG 1
#define TRIP_WIRE
#include "ath_udc.h"
/*
* debug level zones can be enabled individually for different level of
* debugging. Debug messages can delay the init sequence if the prints are
* redirected to serial console, and result in device detection failure.
* Enable them only if required.
*/
#ifdef ATH_USB_DEBUG
static int ath_usb_debug_level = (
//ATH_USB_DEBUG_FUNCTION |
//ATH_USB_DEBUG_INTERRUPT |
//ATH_USB_DEBUG_ENDPOINT |
//ATH_USB_DEBUG_PORTSTATUS |
//ATH_USB_DEBUG_DEVICE |
//ATH_USB_DEBUG_MEMORY |
//ATH_USB_DEBUG_QUEUEHEAD |
//ATH_USB_DEBUG_DTD |
0x0);
static const char *ep_direction[] = { "OUT", "IN" };
#endif
#define DRIVER_DESC "Atheros UDC Driver"
/*
* There are a maximum of 32 endpoints (16 IN and 16 OUT). But currently only
* 12 (6 IN and 6 OUT) endpoints are enabled.
*/
#define ATH_USB_MAX_EP (6)
#define ATH_USB_MAX_EP_IN_SYSTEM (32)
#define ATH_USB_MAX_DTD (64)
#define ATH_USB_REMOTE_WKUP (0x02)
#define USB_RECV (0)
#define USB_SEND (1)
#define ATH_USB_CTRL_EP (1 << 0)
#define DMA_ADDR_INVALID ((dma_addr_t)~0)
/*
* The platform device in ATH_USB still reflects the old ar7100 name. So we
* maintain two names here - one for the platform driver and other for local
* reference
*/
#if defined(CONFIG_MACH_AR7240) || defined(CONFIG_MACH_HORNET)
static const char driver_name [] = "ar7240-ehci";
#else
static const char driver_name[] = "ath-ehci";
#endif
static const char device_name[] = "ath_udc";
static struct ath_usb_udc *ap_gadget;
unsigned long int_count, case1, case2;
unsigned long actual_data_count;
unsigned long complete_count;
unsigned long queue_count;
unsigned long wipe_count;
unsigned long alloc_init_dtd_count;
unsigned long start_trans_count;
unsigned long isr_count;
unsigned long retire_dtd_count;
struct ath_usb_ep {
struct usb_ep ep;
char name[15];
const struct usb_endpoint_descriptor *ep_desc;
struct list_head queue;
struct list_head skipped_queue;
__u8 bEndpointAddress;
__u8 bmAttributes;
__u16 maxpacket;
struct ep_qhead *ep_qh;
struct ath_usb_udc *udc;
};
struct ath_usb_req {
struct usb_request req;
struct list_head queue;
struct ep_dtd *ep_dtd;
unsigned mapped:1;
};
struct ath_usb_udc {
struct usb_gadget gadget;
struct usb_gadget_driver *ga_driver;
struct device *dev;
struct ath_usb __iomem *op_base;
struct ath_usb_ep ep[32];
struct ath_usb_otg *ath_usb_otg;
struct ep_qhead *ep_queue_head;
struct dma_pool *dtd_pool;
struct list_head dtd_list[ATH_USB_MAX_EP_IN_SYSTEM];
struct ep_dtd *dtd_heads[ATH_USB_MAX_EP * 2];
struct ep_dtd *dtd_tails[ATH_USB_MAX_EP * 2];
struct usb_request *ctrl_req[ATH_MAX_CTRL_REQ];
void *ctrl_buf[ATH_MAX_CTRL_REQ];
void __iomem *reg_base;
spinlock_t lock;
__u16 usbState;
__u16 usbDevState;
__u8 usbCurrConfig;
__u8 devAddr;
__u8 ep0setup;
dma_addr_t qh_dma;
};
static void ath_usb_start_udc(struct ath_usb_udc *udc);
static void ath_usb_stop_udc(struct ath_usb_udc *udc);
static void ath_usb_stop_activity(struct ath_usb_udc *udc);
static void ath_usb_init_device(struct ath_usb_udc *udc);
static int ath_usb_setup(struct ath_usb_udc *udc);
static int ath_usb_udc_mem_init(struct ath_usb_udc *udc);
static void ath_usb_udc_mem_free(struct ath_usb_udc *udc);
static void ath_usb_udc_ep_wipe(struct ath_usb_ep *ep, int status);
static void ath_usb_free_dtd(struct ath_usb_udc *udc, struct ep_dtd *ep_dtd, __u32 index);
static void ath_usb_complete_transfer(struct ath_usb_ep *ep, struct ath_usb_req *req,
__u8 epdir, int status);
static void ath_usb_send_data(struct ath_usb_udc *udc, __u8 epno, __u8 * buff,
__u32 size);
static void ath_usb_stall_endpoint(struct ath_usb_udc *udc, __u8 epno,
__u8 epdir);
static void ath_usb_unstall_endpoint(struct ath_usb_udc *udc, __u8 epno,
__u8 epdir);
//#define ATH_USB_UDC_DEBUG 1
#ifdef ATH_USB_UDC_DEBUG
/*
* Print Queue Head information. EP0 information is not printed right now
* as it interferes in Device attach/detection
*/
static void ath_usb_print_qh(struct ep_qhead *ep_qh, __u16 epno, __u16 epdir,
char *str)
{
if ((epno >= ATH_USB_MAX_EP) && (epno < 1)) {
return;
}
ath_usb_debug_qh("%s Endpoint %d-%s Queue %p\n\tmaxPacketLen %x\n\t"
"curr_dtd %x\n\tnext_dtd %x\n\tstatus %x\n\tBuff0 %x\n",
str, epno, ep_direction[epdir], ep_qh,
le32_to_cpu(ep_qh->maxPacketLen),
le32_to_cpu(ep_qh->curr_dtd),
le32_to_cpu(ep_qh->next_dtd),
le32_to_cpu(ep_qh->size_ioc_int_status),
le32_to_cpu(ep_qh->buff[0]));
}
/*
* Print Device Transfer Descriptor information. EP0 information is not
* printed right now as it interferes in Device attach/detection.
*/
static void ath_usb_print_dtd(struct ep_dtd *ep_dtd, __u16 epno, __u16 epdir,
char *str)
{
if ((epno >= ATH_USB_MAX_EP) && (epno < 1)) {
return;
}
ath_usb_debug_dtd("%s Endpoint %d-%s Descriptor %p\n\tnextTr %x\n\t"
"status %x\n\tBuff0 %x\n\tBuff1 %x\n",
str, epno, ep_direction[epdir], ep_dtd,
le32_to_cpu(ep_dtd->next_dtd),
le32_to_cpu(ep_dtd->size_ioc_status),
le32_to_cpu(ep_dtd->buff[0]),
le32_to_cpu(ep_dtd->buff[1]));
}
#else
#define ath_usb_print_qh(ep_qh, epno, epdir, str) \
do { (void)(epno); } while (0)
#define ath_usb_print_dtd(ep_dtd, epno, epdir, str) \
do { (void)(epno); } while (0)
#endif
void ath_usb_dbg_buf(struct usb_request *req)
{
int i;
unsigned char *tmp_buf = (unsigned char *)req->buf;
for (i = 0; i < req->length; i++) {
printk(" %02x ", *(tmp_buf++));
if ((i % 64) == 0) {
printk("\n");
}
}
}
void ath_usb_fill_buf(struct usb_request *req)
{
int i, j = 0;
unsigned char *tmp_buf = (unsigned char *)req->buf;
for (i = 0; i < req->length; i++) {
*tmp_buf++ = j++;
if ((j % 256) == 0) { j = 0; }
}
}
/* Allocate an USB Request - used by gadget drivers */
static struct usb_request *ath_usb_alloc_request(struct usb_ep *ep,
gfp_t gfp_flags)
{
struct ath_usb_req *req;
ath_usb_debug_fn("__enter %s\n", __func__);
req = (struct ath_usb_req *)kmalloc(sizeof(struct ath_usb_req), GFP_ATOMIC);
if (req) {
memset(req, 0, sizeof(struct ath_usb_req));
req->req.dma = DMA_ADDR_INVALID;
req->ep_dtd = NULL;
INIT_LIST_HEAD(&req->queue);
} else {
return NULL;
}
return &req->req;
}
/* Free an USB Request - used by gadget drivers */
static void ath_usb_free_request(struct usb_ep *ep, struct usb_request *_req)
{
struct ath_usb_req *req;
ath_usb_debug_fn("__enter %s\n", __func__);
if (_req) {
req = container_of(_req, struct ath_usb_req, req);
kfree(req);
}
}
/* Allocate data buffer for use by USB request - used by gadget drivers */
static void *ath_usb_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
dma_addr_t * dma, gfp_t gfp_flags)
{
struct ath_usb_ep *ep = container_of(_ep, struct ath_usb_ep, ep);
ath_usb_debug_fn("__enter %s\n", __func__);
/*
* Small memory allocation wastes memory :
* dma_coherent go for one page
*/
return dma_alloc_coherent(ep->udc->gadget.dev.parent,
bytes, dma, gfp_flags);
}
/* Free data buffer - used by gadget drivers */
static void ath_usb_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma,
unsigned bytes)
{
struct ath_usb_ep *ep = container_of(_ep, struct ath_usb_ep, ep);
ath_usb_debug_fn("__enter %s\n", __func__);
dma_free_coherent(ep->udc->dev, bytes, buf, dma);
}
/*
* Enable an endpoint.
* The endpoint is configured using the ep descriptor properties. The selected
* endpoint already has endpoint types configured properly. This function
* primarily enables the endpoint in hardware and sets the max packet size.
*/
static int ath_usb_ep_enable(struct usb_ep *_ep,
const struct usb_endpoint_descriptor *desc)
{
struct ath_usb_ep *ep = container_of(_ep, struct ath_usb_ep, ep);
__u8 epno, epdir, qh_offset;
__u32 bits = 0;
__u16 maxpacket;
__u32 qh_maxpacket;
__u32 bit_pos;
unsigned long flags;
struct ath_usb_udc *udc;
struct ep_qhead *ep_QHead;
ath_usb_debug_fn("__enter %s\n", __func__);
/* Sanity check between the endpoint and descriptor properties */
if (!_ep || !desc || (desc->bDescriptorType != USB_DT_ENDPOINT)
|| (ep->bEndpointAddress != desc->bEndpointAddress)) {
ath_usb_warn("%s, bad ep or descriptor \n", __func__);
return -EINVAL;
}
ath_usb_debug_ep("ep_enable name:%s, maxpacket:%d, ep_addr:%x\n",
_ep->name, _ep->maxpacket, ep->bEndpointAddress);
ath_usb_debug_ep("descriptor lenth:%x, type:%x, ep_addr:%x, maxpacket:%x\n",
desc->bLength, desc->bDescriptorType, desc->bEndpointAddress,
desc->wMaxPacketSize);
/* Get endpoint number and direction */
epno = ep->bEndpointAddress & 0x0f;
epdir = (ep->bEndpointAddress & USB_DIR_IN) ? USB_SEND : USB_RECV;
bit_pos = (1 << (16 * epdir + epno));
qh_offset = (2 * epno) + epdir;
udc = ep->udc;
if (ep != &udc->ep[qh_offset]) {
ath_usb_warn("%s, bad ep or descriptor \n", __func__);
return -EINVAL;
};
/* Get endpoint Queue Head based on EP number and direction */
ep_QHead = (udc->ep_queue_head + qh_offset);
spin_lock_irqsave(&udc->lock, flags);
/* Set max packet length for the endpoint in EP queue head */
ep->ep_desc = desc;
maxpacket = le16_to_cpu(desc->wMaxPacketSize);
qh_maxpacket = le32_to_cpu(ep_QHead->maxPacketLen);
qh_maxpacket = (qh_maxpacket & 0xF800FFFF) | (maxpacket << 16);
ep_QHead->maxPacketLen = cpu_to_le32(qh_maxpacket);
_ep->maxpacket = ep->maxpacket = maxpacket;
#if 0
if (epno > 0) {
//printk("ep->mps %d ep_Qhead %d \n", ep->maxpacket, ep_QHead->maxPacketLen);
printk("ep_QHead %x \n", ep_QHead);
}
#endif
/* Enable endpoint in Hardware */
bits = epdir ? (ATH_USB_EPCTRL_TX_ENABLE) : (ATH_USB_EPCTRL_RX_ENABLE);
writel((readl(&udc->op_base->ep_ctrlx[epno]) | bits),
&udc->op_base->ep_ctrlx[epno]);
#if 1
/* Flush the endpoint and make sure that the endpoint status is zero */
writel(bit_pos, &udc->op_base->ep_flush);
/* Wait till flush completes */
while (readl(&udc->op_base->ep_flush) & bit_pos) ;
while (readl(&udc->op_base->ep_status) & bit_pos) {
writel(bit_pos, &udc->op_base->ep_flush);
while (readl(&udc->op_base->ep_flush) & bit_pos) ;
}
#endif
ath_usb_debug_ep("ep_enable ==> ep%d-%s queue:%d, name:%s, maxlen:%x, "
"ctrl:%x\n", epno, ep_direction[epdir], qh_offset,
ep->name, qh_maxpacket, readl(&udc->op_base->ep_ctrlx[epno]));
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
}
/*
* Disable an endpoint
* If there are any pending requests on the endpoint, shut them and inform the
* gadget driver about it. Disable the endpoint in the hardware.
*/
static int ath_usb_ep_disable(struct usb_ep *_ep)
{
struct ath_usb_udc *udc;
struct ath_usb_ep *ep;
unsigned long flags;
__u8 epno, epdir;
__u32 bits;
ep = container_of(_ep, struct ath_usb_ep, ep);
if (!_ep || !ep->ep_desc) {
return -EINVAL;
}
spin_lock_irqsave(&ap_gadget->lock, flags);
/* Cancel all current and pending requests for this endpoint */
ep->ep_desc = NULL;
ath_usb_udc_ep_wipe(ep, -ESHUTDOWN);
ep->ep.maxpacket = ep->maxpacket;
/* Get endpoint number and direction */
epno = ep->bEndpointAddress & 0x0f;
epdir = (ep->bEndpointAddress & USB_DIR_IN) ? USB_SEND : USB_RECV;
/* Disable the endpoint in hardware */
bits = epdir ? (ATH_USB_EPCTRL_TX_ENABLE) : (ATH_USB_EPCTRL_RX_ENABLE);
udc = ep->udc;
writel((readl(&udc->op_base->ep_ctrlx[epno]) & ~bits),
&udc->op_base->ep_ctrlx[epno]);
spin_unlock_irqrestore(&ap_gadget->lock, flags);
return 0;
}
/* for a selected endpoint cancel all pending requests and inform the upper
* layer about cancellation */
static void ath_usb_udc_ep_wipe(struct ath_usb_ep *ep, int status)
{
struct ath_usb_req *req;
struct ath_usb_udc *udc;
struct ep_dtd *ep_dtd;
udc = ep->udc;
while (!list_empty(&ep->queue)) {
__u8 epdir = (ep->bEndpointAddress & USB_DIR_IN) ? USB_SEND : USB_RECV;
__u8 epno = ep->bEndpointAddress & 0x0f;
if ((ep_dtd = udc->dtd_heads[(epno * 2) + epdir]) != NULL) {
udc->dtd_heads[(epno * 2) + epdir] = NULL;
}
if ((ep_dtd = udc->dtd_tails[(epno * 2) + epdir]) != NULL) {
udc->dtd_tails[(epno * 2) + epdir] = NULL;
}
req = list_entry(ep->queue.next, struct ath_usb_req, queue);
ath_usb_free_dtd(udc, req->ep_dtd, ((epno * 2) + epdir));
list_del_init(&req->queue);
ath_usb_complete_transfer(ep, req, epdir, status);
}
while(!list_empty(&ep->skipped_queue)) {
__u8 epdir = (ep->bEndpointAddress & USB_DIR_IN) ? USB_SEND : USB_RECV;
req = list_entry(ep->skipped_queue.next, struct ath_usb_req, queue);
list_del_init(&req->queue);
ath_usb_complete_transfer(ep, req, epdir, status);
}
}
static struct ep_dtd *
ath_usb_alloc_init_dtd(struct ath_usb_udc *udc, struct ath_usb_ep *ep, struct ath_usb_req *req, __u32 catalyst)
{
struct list_head *temp;
struct ep_dtd *ep_dtd = NULL;
alloc_init_dtd_count++;
/* Get a free device transfer descriptor from the pre-allocated dtd list */
if(!list_empty(&udc->dtd_list[catalyst])) {
temp = udc->dtd_list[catalyst].next;
ep_dtd = list_entry(temp, struct ep_dtd, tr_list);
list_del(temp);
memset(ep_dtd, 0, 28); /* only Hardware access fields */
//printk("****** DTD allocation success***** %u\n", catalyst);
} else {
dma_addr_t dma;
ep_dtd = dma_pool_alloc(udc->dtd_pool, GFP_ATOMIC, &dma);
if (ep_dtd == NULL) {
return NULL;
}
ath_usb_debug_mem("DTD Alloc %p, %x\n", ep_dtd, dma);
//printk("DTD Alloc %p, %x\n", ep_dtd, dma);
ep_dtd->dtd_dma = dma;
ep_dtd->next = NULL;
list_add_tail(&ep_dtd->tr_list, &udc->dtd_list[catalyst]);
ep_dtd->size_ioc_status &= cpu_to_le32(~ATH_USB_TD_RESERVED_FIELDS);
}
/* Initialize dtd */
ep_dtd->next_dtd = __constant_cpu_to_le32(ATH_USB_TD_NEXT_TERMINATE);
ep_dtd->size_ioc_status = cpu_to_le32 (
((req->req.length)<< ATH_USB_TD_LENGTH_BIT_POS) | ATH_USB_TD_IOC |
(ATH_USB_TD_STATUS_ACTIVE));
/* Set Reserved Field to 0 */
ep_dtd->size_ioc_status &= cpu_to_le32(~ATH_USB_TD_RESERVED_FIELDS);
/* We can transfer a maximum of 20K using a single dtd. Fill in the dtd
* transfer buffers accordingly */
if (req->req.length) {
ep_dtd->buff[0] = cpu_to_le32((__u32)(req->req.dma));
ep_dtd->buff[1] = cpu_to_le32(((__u32)(req->req.dma)) + 4096);
ep_dtd->buff[2] = cpu_to_le32(((__u32)(req->req.dma)) + (4096 * 2));
ep_dtd->buff[3] = cpu_to_le32(((__u32)(req->req.dma)) + (4096 * 3));
ep_dtd->buff[4] = cpu_to_le32(((__u32)(req->req.dma)) + (4096 * 4));
} else {
ep_dtd->buff[0] = 0;
ep_dtd->buff[1] = ep_dtd->buff[2] = ep_dtd->buff[3] =
ep_dtd->buff[4] = cpu_to_le32(4096);
}
req->ep_dtd = ep_dtd;
return ep_dtd;
}
static int ath_usb_ep_prime(struct ath_usb_udc *udc, struct ep_dtd *ep_dtd,
struct ep_dtd *prev_dtd, __u32 bit_pos, __u32 catalyst, __u8 empty)
{
struct ep_qhead *ep_QHead;
__u8 transFlag;
__u32 temp_pos;
ep_QHead =udc->ep_queue_head + catalyst;
if(empty) {
ep_QHead->next_dtd = cpu_to_le32(ep_dtd->dtd_dma);
ep_QHead->size_ioc_int_status = __constant_cpu_to_le32(0);
writel(bit_pos, &udc->op_base->ep_prime);
return 0;
} else {
// printk("epno = %u, epdir = %u, dtd_temp= %x\n", epno, epdir, dtd_temp);
prev_dtd->next_dtd = cpu_to_le32(ep_dtd->dtd_dma);
if(readl(&udc->op_base->ep_prime) & bit_pos)
return 0;
/* Use hardware tripwire semaphore mechanism before priming the endpoint */
#ifdef TRIP_WIRE
transFlag = 0;
while(!transFlag) {
writel(readl(&udc->op_base->usbcmd) |ATH_USB_CMD_ATDTW_TRIPWIRE_SET,
&udc->op_base->usbcmd);
temp_pos = readl(&udc->op_base->ep_status) & bit_pos;
if(readl(&udc->op_base->usbcmd) & ATH_USB_CMD_ATDTW_TRIPWIRE_SET) {
transFlag = 1;
}
}
writel(readl(&udc->op_base->usbcmd) & ATH_USB_CMD_ATDTW_TRIPWIRE_CLEAR,
&udc->op_base->usbcmd);
#endif
}
if(!temp_pos) {
/* Initialize queue head and prime the endpoint */
ep_QHead->next_dtd = cpu_to_le32(ep_dtd->dtd_dma);
ep_QHead->size_ioc_int_status = __constant_cpu_to_le32(0);
/* Prime the EndPoint */
writel(bit_pos, &udc->op_base->ep_prime);
}
return 0;
}
/*
* Start an IN or OUT transaction based on usb request and endpoint.
*/
static int ath_usb_start_trans(struct ath_usb_udc *udc, struct ath_usb_ep *ep,
struct ath_usb_req *req, int flag)
{
struct ep_qhead *ep_QHead;
struct ep_dtd *ep_dtd = NULL, *dtd_temp = NULL;
//unsigned long flags;
__u32 catalyst, bit_pos =0;
__u8 epno, epdir;
__u8 empty;
start_trans_count++;
ath_usb_debug_fn("__enter %s\n", __func__);
/* Get endpoint number and direction */
epno = ep->bEndpointAddress & 0x0f;
epdir = (ep->bEndpointAddress & USB_DIR_IN) ? USB_SEND : USB_RECV;
catalyst = ((2 * epno) + epdir);
bit_pos = (1 << ((16 * epdir) + epno));
/* Get endpoint queue head based on EP number and direction */
ep_QHead =udc->ep_queue_head + catalyst;
if(catalyst < 0) {
printk("Warning... wrong dtd head position \n");
}
/* Get a free device transfer descriptor from the pre-allocated dtd list */
//spin_lock_irqsave(&udc->lock, flags);
if(flag == 1) {
ep_dtd = ath_usb_alloc_init_dtd(udc, ep, req, catalyst);
if(!ep_dtd) {
ath_usb_warn("__err - dtd List Empty %s\n", __func__);
return -ENOMEM;
}
//printk("epno = %u, epdir = %u, ep_dtd = %x\n", epno, epdir, ep_dtd);
/*
* If the endpoint is already primed we have nothing to do here; just
* return; TODO - attach the current dtd to the dtd list in the queue
* head if the endpoint is already primed.
*/
} else {
if(!list_empty(&ep->skipped_queue)) {
req = container_of(ep->skipped_queue.next, struct ath_usb_req, queue);
list_del_init(&req->queue);
}
ep_dtd = req->ep_dtd;
//printk("epno = %u, epdir = %u, ep_dtd = %x\n", epno, epdir, ep_dtd);
}
empty = list_empty(&ep->queue);
if(empty) {
//printk("epno = %u, epdir = %u ep_dtd = %x tail= %x, head = %x, catalist = %u flag = %d\n", epno, epdir, ep_dtd, udc->dtd_tails[catalyst], udc->dtd_heads[catalyst], catalyst, flag);
udc->dtd_heads[catalyst] = ep_dtd;
udc->dtd_tails[catalyst] = ep_dtd;
} else {
if(udc->dtd_tails[catalyst]) {
dtd_temp = udc->dtd_tails[catalyst];
} else {
dtd_temp = udc->dtd_heads[catalyst];
}
if(dtd_temp) {
dtd_temp->next = ep_dtd;
} else {
return 0;
}
udc->dtd_tails[catalyst] = ep_dtd;
//printk("Changing dtd_tails of epno = %u, epdir = %u tail= %x, head = %x, catalist = %u\n", epno, epdir, udc->dtd_tails[catalyst], udc->dtd_heads[catalyst], catalyst);
}
#if 0
if((readl(&udc->op_base->ep_complete) & bit_pos) &&
(!(readl(&udc->op_base->ep_prime) & bit_pos)) &&
(readl(&udc->op_base->ep_status) & bit_pos)) {
//printk("epno = %u, epdir = %u, ep_dtd = %x dtd_temp = %x\n", epno, epdir, ep_dtd, dtd_temp);
list_add_tail(&req->queue, &ep->skipped_queue);
} else {
#endif
ath_usb_ep_prime(udc, ep_dtd, dtd_temp, bit_pos, catalyst, empty);
#if 0
}
#endif
//spin_unlock_irqrestore(&udc->lock, flags);
return 0;
}
/*
* Endpoint queue.
* Queue a request to the endpoint and transer it immediately if possible
*/
static int ath_usb_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
gfp_t gfp_flags)
{
struct ath_usb_req *req;
struct ath_usb_ep *ep;
struct ath_usb_udc *udc;
unsigned long flags;
//__u8 empty;
ath_usb_debug_fn("__enter %s\n", __func__);
ath_usb_debug_ep("_ep->name :%s, _ep->maxpacket :%d\n", _ep->name,
_ep->maxpacket);
/* Sanity checks */
req = container_of(_req, struct ath_usb_req, req);
if (!_req || !req->req.buf || !list_empty(&req->queue)) {
ath_usb_error("%s, _ep->name :%s, Invalid Params %p %p, %d\n", __func__, _ep->name,
req->req.buf, _req, list_empty(&req->queue));
return -EINVAL;
}
ep = container_of(_ep, struct ath_usb_ep, ep);
if (!_ep || (!ep->ep_desc && (ep->bEndpointAddress & 0x0F))) {
ath_usb_error("%s, Invalid Endpoint %p %x\n", __func__,
ep->ep_desc, ep->bEndpointAddress);
return -EINVAL;
}
udc = ep->udc;
if (!udc->ga_driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
ath_usb_error("%s, Driver Error \n", __func__);
return -ESHUTDOWN;
}
/* If the usb request contains data transfer, then synchronize the buffer
* for DMA Transfer */
if (_req->length) {
/* DMA for All Trans */
if (_req->dma == DMA_ADDR_INVALID) {
_req->dma = dma_map_single(ep->udc->gadget.dev.parent,
_req->buf, _req->length,
(ep->bEndpointAddress & USB_DIR_IN) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->mapped = 1;
} else {
dma_sync_single_for_device(ep->udc->gadget.dev.parent,
_req->dma, _req->length,
(ep->bEndpointAddress & USB_DIR_IN) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->mapped = 0;
}
} else {
_req->dma = DMA_ADDR_INVALID;
}
_req->status = -EINPROGRESS;
_req->actual = 0;
#if 0
empty = list_empty(&ep->queue);
if(empty) {
#if 0
if((ep->bEndpointAddress & 0x0f) > 0)
printk("S ");
#endif
ath_usb_start_trans(udc, ep, req);
} else {
printk("List not empty\n\n");
}
#endif
spin_lock_irqsave (&ap_gadget->lock, flags);
ath_usb_start_trans(udc, ep, req, 1);
/*
* Add the request to Endpoint queue. If there are no transfers happening
* right now, start the current transfer
*/
list_add_tail(&req->queue, &ep->queue);
spin_unlock_irqrestore (&ap_gadget->lock, flags);
return 0;
}
static int ath_usb_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{
struct ath_usb_ep *ep = container_of(_ep, struct ath_usb_ep, ep);
struct ath_usb_req *req;
unsigned long flags;
__u8 epdir;
if (!_ep || !_req) {
return -EINVAL;
}
ath_usb_debug_fn("__enter %s\n", __func__);
ath_usb_debug_ep("_ep->name :%s, _ep->maxpacket :%d\n",
_ep->name, _ep->maxpacket);
spin_lock_irqsave(&ap_gadget->lock, flags);
/* make sure it's actually queued on this endpoint */
list_for_each_entry(req, &ep->queue, queue) {
if (&req->req == _req)
break;
}
if (&req->req != _req) {
spin_unlock_irqrestore(&ap_gadget->lock, flags);
return -EINVAL;
}
epdir = (ep->bEndpointAddress & USB_DIR_IN) ? USB_SEND : USB_RECV;
if (ep->queue.next == &req->queue) {
list_del_init(&req->queue);
ath_usb_complete_transfer(ep, req, epdir, -ECONNRESET);
}
spin_unlock_irqrestore(&ap_gadget->lock, flags);
return 0;
}
static void ath_usb_complete_transfer(struct ath_usb_ep *ep, struct ath_usb_req *req,
__u8 epdir, int status)
{
ath_usb_debug_fn("__enter %s\n", __func__);
complete_count++;
//list_del_init(&req->queue);
//if(((ep->bEndpointAddress & 0x0f) == 1) || ((ep->bEndpointAddress & 0x0f) == 2))
//printk("%s ep_no :%d dir = %u status = %d ep_dtd = %x entry = %d\n", __func__, (ep->bEndpointAddress & 0x0f), epdir, status, req->ep_dtd, list_empty(&ep->queue));
#if 0
if ((ep->bEndpointAddress & 0x0f))
printk("ep_no :%d \n", (ep->bEndpointAddress & 0x0f));
#endif
if (req->req.status == -EINPROGRESS) {
req->req.status = status;
} else {
status = req->req.status;
}
if (req->req.length) {
if (req->mapped) {
dma_unmap_single(ep->udc->gadget.dev.parent,
req->req.dma, req->req.length,
(ep->bEndpointAddress & USB_DIR_IN)
? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->req.dma = DMA_ADDR_INVALID;
req->mapped = 0;
} else {
dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
req->req.dma, req->req.length,
(ep->bEndpointAddress & USB_DIR_IN)
? DMA_TO_DEVICE : DMA_FROM_DEVICE);
}
}
if(status != 0) {
spin_unlock(&ep->udc->lock);
if (req->req.complete) {
req->req.complete(&ep->ep, &req->req);
}
spin_lock(&ep->udc->lock);
}
}
static int ath_usb_udc_get_frame(struct usb_gadget *_gadget)
{
ath_usb_debug_fn("__enter %s\n", __func__);
return 0;
}
static int ath_usb_udc_wakeup(struct usb_gadget *_gadget)
{
#ifdef CONFIG_USB_ATH_OTG
struct ath_usb_udc *udc = ap_gadget;
#endif
ath_usb_debug_fn("__enter %s\n", __func__);
#ifdef CONFIG_USB_ATH_OTG
if (readl(&udc->op_base->portscx[0]) & ATH_USB_PORTSCX_PORT_SUSPEND) {
/*TODO: Do Remote Wake up */
} else {
#if 0
if (udc->transceiver) {
otg_start_srp(udc->transceiver);
}
#endif
}
#endif
return 0;
}
static int ath_usb_udc_pullup(struct usb_gadget *_gadget, int is_active)
{
struct ath_usb_udc *udc = ap_gadget;
ath_usb_debug_fn("__enter %s\n", __func__);
if (is_active) {
ath_usb_start_udc(udc);
} else {
ath_usb_stop_udc(udc);
ath_usb_stop_activity(udc);
}
return 0;
}
static int ath_usb_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
{
struct ath_usb_udc *udc = ap_gadget;
ath_usb_debug_fn("__enter %s\n", __func__);
if (is_active) {
ath_usb_start_udc(udc);
} else {
printk("VBUS Reset\n");
ath_usb_stop_udc(udc);
ath_usb_stop_activity(udc);
}
return 0;
}
static int ath_usb_ep_set_halt(struct usb_ep *_ep, int value)
{
ath_usb_debug_fn("__enter %s\n", __func__);
return 0;
}
static const struct usb_gadget_ops ath_usb_udc_ops = {
.get_frame = ath_usb_udc_get_frame,
.wakeup = ath_usb_udc_wakeup,
.vbus_session = ath_usb_udc_vbus_session,
.pullup = ath_usb_udc_pullup,
};
static struct usb_ep_ops ath_usb_ep_ops = {
.enable = ath_usb_ep_enable,
.disable = ath_usb_ep_disable,
.alloc_request = ath_usb_alloc_request,
.free_request = ath_usb_free_request,
//.alloc_buffer = ath_usb_alloc_buffer,
//.free_buffer = ath_usb_free_buffer,
.queue = ath_usb_ep_queue,
.dequeue = ath_usb_ep_dequeue,
.set_halt = ath_usb_ep_set_halt,
};
/* Used by EP0 status phase */
static void ath_usb_send_data(struct ath_usb_udc *udc, __u8 epno, __u8 * buff,
__u32 size)
{
struct usb_request *_req;
struct ath_usb_req *req;
unsigned long flags;
ath_usb_debug_fn("__enter %s\n", __func__);
_req = udc->ctrl_req[ATH_SND_CTRL_REQ];
_req->zero = 0;
if (size) {
memcpy(_req->buf, buff, size);
}
_req->length = size;
req = container_of(_req, struct ath_usb_req, req);
INIT_LIST_HEAD(&req->queue);
if (ath_usb_ep_queue(&udc->ep[1].ep, _req, GFP_ATOMIC) < 0) {
ath_usb_error("send setup phase failed\n");
spin_lock_irqsave(&udc->lock, flags);
ath_usb_udc_ep_wipe(&udc->ep[1], -ESHUTDOWN);
spin_unlock_irqrestore(&udc->lock, flags);
}
}
/* Used by EP0 status phase */
static void usb_recv_data(struct ath_usb_udc *udc, __u8 epno, __u8 * buff,
__u32 size)
{
struct usb_request *_req;
struct ath_usb_req *req;
unsigned long flags;
ath_usb_debug_fn("__enter %s\n", __func__);
_req = udc->ctrl_req[ATH_RCV_CTRL_REQ];
_req->zero = 0;
_req->length = size;
req = container_of(_req, struct ath_usb_req, req);
INIT_LIST_HEAD(&req->queue);
if (ath_usb_ep_queue(&udc->ep[0].ep, _req, GFP_ATOMIC) < 0) {
ath_usb_error("recv setup phase failed\n");
spin_lock_irqsave(&udc->lock, flags);
ath_usb_udc_ep_wipe(&udc->ep[0], -ESHUTDOWN);
spin_unlock_irqrestore(&udc->lock, flags);
}
}
void read_setup_data(struct ath_usb_udc *udc, __u8 * dest, int noBytes)
{
struct ep_qhead *qHead;
int cal, read_safe;
ath_usb_debug_fn("__enter %s\n", __func__);
qHead = udc->ep_queue_head;
/* if semaphore mechanism is used the following code is compiled in */
read_safe = 0;
while (!read_safe) {
/* CI 8.4.3.1.2 step 2 */
writel((readl(&udc->op_base->usbcmd) | ATH_USB_CMD_SETUP_TRIPWIRE_SET),
&udc->op_base->usbcmd);
/* CI 8.4.3.1.2 step 3 */
for (cal = 0; cal < noBytes; cal++) {
*(dest + cal) = qHead->setup_buff[cal];
}
/* CI 8.4.3.1.2 step 4 */
if (readl(&udc->op_base->usbcmd) & ATH_USB_CMD_SETUP_TRIPWIRE_SET) {
read_safe = 1; /* we can proceed exiting out of loop */
}
}
/* CI 8.4.3.1.2 step 5 */
writel((readl(&udc->op_base->usbcmd) & ATH_USB_CMD_SETUP_TRIPWIRE_CLEAR),
&udc->op_base->usbcmd);
}
static void ath_usb_stall_endpoint(struct ath_usb_udc *udc, __u8 epno,
__u8 epdir)
{
struct ep_qhead *qHead;
qHead = udc->ep_queue_head + (2 * epno) + epdir;
ath_usb_debug_fn("__enter %s\n", __func__);
if (epno > 0)
printk("__enter %s\n", __func__);
if (le32_to_cpu(qHead->maxPacketLen) & ATH_USB_EP_QUEUE_HEAD_IOS) {
writel(readl(&udc->op_base->ep_ctrlx[epno]) |
(ATH_USB_EPCTRL_TX_EP_STALL | ATH_USB_EPCTRL_RX_EP_STALL),
&udc->op_base->ep_ctrlx[epno]);
} else {
writel(readl(&udc->op_base->ep_ctrlx[epno]) |
(epdir ? ATH_USB_EPCTRL_TX_EP_STALL : ATH_USB_EPCTRL_RX_EP_STALL),
&udc->op_base->ep_ctrlx[epno]);
}
}
static void ath_usb_unstall_endpoint(struct ath_usb_udc *udc, __u8 epno,
__u8 epdir)
{
/* Enable the endpoint for Rx or Tx and set the endpoint type */
writel(readl(&udc->op_base->ep_ctrlx[epno]) &
(epdir ? ~ATH_USB_EPCTRL_TX_EP_STALL : ~ATH_USB_EPCTRL_RX_EP_STALL),
&udc->op_base->ep_ctrlx[epno]);
}
static int getStatus(struct ath_usb_udc *udc, struct usb_ctrlrequest *ctrl)
{
__u16 status;
__u16 intStatus;
__u8 ep;
ath_usb_debug_fn("__enter %s\n", __func__);
switch (ctrl->bRequestType) {
case (USB_DIR_IN | USB_RECIP_DEVICE):
status = udc->usbDevState;
ath_usb_send_data(udc, 0, (__u8 *) & status, sizeof(status));
break;
case (USB_DIR_IN | USB_RECIP_INTERFACE):
intStatus = (__u16)(ctrl->wIndex & 0x00ff);
ath_usb_send_data(udc, 0, (__u8 *) & intStatus, sizeof(intStatus));
break;
case (USB_DIR_IN | USB_RECIP_ENDPOINT):
ep = le16_to_cpu(ctrl->wIndex) & 0x8f;
/* ep&0x0f ->ep_num;ep&0x80->ep_dir */
intStatus = readl(&udc->op_base->ep_ctrlx[ep & 0x0f]);
status = cpu_to_le16(intStatus);
ath_usb_send_data(udc, 0, (__u8 *) & status, sizeof(status));
break;
default:
return 1;
#if 0
ath_usb_stall_endpoint(udc, 0, 0);
#endif
}
return 0;
}
static void setFeature(struct ath_usb_udc *udc, struct usb_ctrlrequest *ctrl)
{
__u16 status;
__u8 intStatus, ep;
ath_usb_debug_fn("__enter %s\n", __func__);
switch (ctrl->bRequestType) {
case USB_RECIP_DEVICE:
switch (le16_to_cpu(ctrl->wValue)) {
case USB_DEVICE_REMOTE_WAKEUP:
/* Set Remote Wakeup */
status = udc->usbDevState;
status |= ATH_USB_REMOTE_WKUP;
udc->usbDevState = status;
break;
case USB_DEVICE_B_HNP_ENABLE:
udc->gadget.b_hnp_enable = 1;
break;
case USB_DEVICE_A_HNP_SUPPORT:
udc->gadget.a_hnp_support = 1;
break;
case USB_DEVICE_A_ALT_HNP_SUPPORT:
udc->gadget.a_alt_hnp_support = 1;
break;
}
break;
case USB_RECIP_ENDPOINT:
if (le16_to_cpu(ctrl->wValue) != 0) {
ath_usb_stall_endpoint(udc, 0, 0);
}
ep = le16_to_cpu(ctrl->wIndex) & 0x8F;
/* Get Endpoint Status */
intStatus = readl(&udc->op_base->ep_ctrlx[ep & 0x0f]);
status = intStatus & ((ep & 0x80) ? 1 : 0);
/* Set Endpoint Status ; set stall */
writel(readl(&udc->op_base->ep_ctrlx[ep & 0x0f]) |
(ATH_USB_EPCTRL_TX_EP_STALL | ATH_USB_EPCTRL_RX_EP_STALL),
&udc->op_base->ep_ctrlx[ep & 0x0f]);
break;
default:
printk("Stall Endpoints\n");
ath_usb_stall_endpoint(udc, 0, 0);
}
ath_usb_send_data(udc, 0, 0, 0);
}
static void clrFeature(struct ath_usb_udc *udc, struct usb_ctrlrequest *ctrl)
{
__u16 status;
__u8 intStatus, ep;
ath_usb_debug_fn("__enter %s\n", __func__);
if ((udc->usbState != USB_STATE_CONFIGURED) &&
(udc->usbState != USB_STATE_ADDRESS)) {
ath_usb_stall_endpoint(udc, 0, 0);
return;
}
switch (ctrl->bRequestType) {
case USB_RECIP_DEVICE:
if (le16_to_cpu(ctrl->wValue) == 1) {
/* clear remove wakeup */
status = udc->usbDevState;
status &= ~USB_DEVICE_REMOTE_WAKEUP;
udc->usbDevState = status;
} else {
ath_usb_stall_endpoint(udc, 0, 0);
return;
}
break;
case USB_RECIP_ENDPOINT:
if (le16_to_cpu(ctrl->wValue) != 0) {
ath_usb_stall_endpoint(udc, 0, 0);
}
ep = le16_to_cpu(ctrl->wIndex) & 0x8F;
/* Get Endpoint Status */
intStatus = readl(&udc->op_base->ep_ctrlx[ep & 0x0f]);
status = intStatus & ((ep & 0x80) ? 1 : 0);
/* Set Endpoint Status ; unstall */
writel(readl(&udc->op_base->ep_ctrlx[ep & 0x0f]) &
~(ATH_USB_EPCTRL_TX_EP_STALL | ATH_USB_EPCTRL_RX_EP_STALL),
&udc->op_base->ep_ctrlx[ep & 0x0f]);
break;
default:
ath_usb_stall_endpoint(udc, 0, 0);
}
ath_usb_send_data(udc, 0, 0, 0);
}
static void setConfiguration(struct ath_usb_udc *udc,
struct usb_ctrlrequest *ctrl)
{
__u16 usbStatus, wValue;
ath_usb_debug_fn("__enter %s\n", __func__);
wValue = le16_to_cpu(ctrl->wValue);
if (le16_to_cpu(ctrl->wLength) != 0) {
ath_usb_stall_endpoint(udc, 0, 0);
goto end;
}
if ((wValue & 0x00ff) == 0) {
usbStatus = udc->usbState;
if ((usbStatus == USB_STATE_CONFIGURED) ||
(usbStatus == USB_STATE_ADDRESS)) {
/* Clear current config values */
udc->usbCurrConfig = 0;
udc->usbState = USB_STATE_ADDRESS;
} else {
ath_usb_stall_endpoint(udc, 0, 0);
}
goto end;
}
/* Read the current Conf Value */
usbStatus = udc->usbCurrConfig;
if (usbStatus != (wValue & 0x00ff)) {
udc->usbCurrConfig = (wValue & 0x00ff);
udc->usbState = USB_STATE_CONFIGURED;
goto end;
}
udc->usbState = USB_STATE_CONFIGURED;
end:
return;
}
/* Hardware assisted SET_ADDRESS */
static void setAddress(struct ath_usb_udc *udc, __u16 addr)
{
ath_usb_debug_fn("__enter %s Address %d \n", __func__, addr);
udc->devAddr = addr;
writel((((__u32) udc->devAddr) << ATH_USB_ADDRESS_BIT_SHIFT |
(0x01 << (ATH_USB_DEVADDR_USBADRA))), &udc->op_base->devaddr);
udc->usbState = USB_STATE_ADDRESS;
}
static void handle_ep0_setup(struct ath_usb_udc *udc)
{
struct usb_ctrlrequest ctrl;
int status = 0;
ath_usb_debug_fn("__enter %s\n", __func__);
/* Clear the bit in ep_setup_stat 8.4.3.1.2 step 1 */
writel(ATH_USB_CTRL_EP, &udc->op_base->ep_setup_stat);
read_setup_data(udc, (__u8 *) & ctrl, 8);
while (readl(&udc->op_base->ep_setup_stat) & ATH_USB_CTRL_EP) {
//udelay(1);
}
if (ctrl.bRequestType & USB_DIR_IN) {
/* setup phase */
udc->ep0setup = 1;
} else {
udc->ep0setup = 0;
}
switch (ctrl.bRequest) {
case USB_REQ_GET_STATUS:
//printk ("Get Status \n");
if (getStatus(udc, &ctrl)) {
goto cliOper;
}
break;
case USB_REQ_SET_FEATURE:
//printk ("Set Feature\n");
setFeature(udc, &ctrl);
break;
case USB_REQ_CLEAR_FEATURE:
//printk ("Clear Feature\n");
clrFeature(udc, &ctrl);
break;
case USB_REQ_SET_CONFIGURATION:
//printk ("Set Configuration \n");
setConfiguration(udc, &ctrl);
goto cliOper;
case USB_REQ_SET_ADDRESS:
//printk ("Set Address \n");
setAddress(udc, le16_to_cpu(ctrl.wValue));
ath_usb_send_data(udc, 0, 0, 0);
break;
default:
/*Hope Rest all Requests are Handled by CLIENT */
cliOper:
ath_usb_debug_dev("SETUP %02x.%02x v%04x i%04x l%04x\n",
ctrl.bRequestType, ctrl.bRequest,
le16_to_cpu(ctrl.wValue), le16_to_cpu(ctrl.wIndex),
le16_to_cpu(ctrl.wLength));
status = udc->ga_driver->setup(&udc->gadget, &ctrl);
}
if (status < 0) {
ath_usb_error("request = %x, type = %x error %d, stalling endpoint\n", ctrl.bRequest, le16_to_cpu(ctrl.wIndex), status);
ath_usb_stall_endpoint(udc, 0, 0);
}
}
static void ath_usb_free_dtd(struct ath_usb_udc *udc, struct ep_dtd *ep_dtd, __u32 index)
{
list_add_tail(&ep_dtd->tr_list, &udc->dtd_list[index]);
}
static struct ath_usb_req *
ath_usb_retire_dtd(struct ath_usb_udc *udc, struct ep_dtd *ep_dtd, __u8 epno, __u8 epdir)
{
__u32 bit_pos, tmp;
//unsigned long flags;
struct ath_usb_ep *ep;
struct ath_usb_req *req;
struct ep_qhead *ep_QHead;
//struct ep_dtd *temp;
bit_pos = (1 << (16 * epdir + epno));
tmp = (2 * epno + epdir);
ep = &udc->ep[tmp];
ep_QHead =udc->ep_queue_head + tmp;
retire_dtd_count++;
if (ep_dtd) {
__u32 size_ioc_status;
if (epno > 0) {
if (le32_to_cpu(ep_dtd->size_ioc_status) & ATH_USB_TD_STATUS_ACTIVE) {
//printk("%s:epno = %d, epdir = %d ep_dtd = %x next = %x QueueH_Curr =%x next = %x Active\n", __func__, epno, epdir, ep_dtd, ep_dtd->next_dtd, ep_QHead->curr_dtd, ep_QHead->next_dtd);
return NULL;
#if 0
/*Repriming */
temp = (struct ep_dtd *)ep_dtd->next_dtd;
ep_QHead->next_dtd = cpu_to_le32(temp->dtd_dma);
ep_QHead->size_ioc_int_status = __constant_cpu_to_le32(0);
writel(bit_pos, &udc->op_base->ep_prime);
#endif
}
}
ath_usb_print_dtd(ep_dtd, epno, epdir, "nit");
size_ioc_status = le32_to_cpu(ep_dtd->size_ioc_status);
#if 0
if(size_ioc_status)
printk("size_ioc_status %x epno %d\n", size_ioc_status, epno);
#endif
ep_dtd->size_ioc_status = __constant_cpu_to_le32(0);
ath_usb_free_dtd(udc, ep_dtd, tmp);
if (!list_empty(&ep->queue)) {
req = container_of(ep->queue.next, struct ath_usb_req, queue);
req->req.actual = req->req.length -
((size_ioc_status >> ATH_USB_TD_LENGTH_BIT_POS) & 0x7FFF);
actual_data_count += req->req.actual;
list_del_init(&req->queue);
#if 1
if(list_empty(&ep->queue)) {
udc->dtd_heads[tmp] = NULL;
} else {
udc->dtd_heads[tmp] = (struct ep_dtd *)(udc->dtd_heads[tmp]->next);
//printk("dtd_heads = %x, dtd_tails = %x, ep_dtd = %x\n", udc->dtd_heads[tmp], udc->dtd_tails[tmp], ep_dtd);
}
#endif
ath_usb_complete_transfer(ep, req, epdir, 0);
}
} else {
printk("Null ep_dtd Err \n");
}
if (udc->ep0setup) {
udc->ep0setup = 0;
if (epno == 0) {
usb_recv_data(udc, 0, 0, 0);
}
}
return req;
}
/* Endpoint Transfer Complete interrupt handling */
static void ath_usb_process_USB_Intr(struct ath_usb_udc *udc)
{
struct ep_qhead *ep_QHead;
struct ep_dtd *ep_dtd;
__u8 epno = 0, epdir = 0;
__u32 setup_stat = 0, bit_pos = 0, tmp, err;
__u8 epDetect;
int i, count, prev_count = 0;
int_count++;
/* EP0 Setup transfer complete */
setup_stat = readl(&udc->op_base->ep_setup_stat);
if (setup_stat & ATH_USB_CTRL_EP) {
handle_ep0_setup(udc);
}
bit_pos = readl(&udc->op_base->ep_complete);
/* Clear the bit in Registers */
writel(bit_pos, &udc->op_base->ep_complete);
if (bit_pos) {
for (i = 0; i < ATH_USB_MAX_EP; i++) {
/* Based on the bit position get EP number and direction */
epDetect = 0;
epno = i;
if (bit_pos & (1 << i)) {
epdir = 0;
epDetect = 1;
}
if (bit_pos & (1 << (i + 16))) {
if(!epDetect) {
epdir = 1;
}
epDetect++;
}
for(;epDetect > 0; epDetect--) {
count = 0;
ep_dtd = NULL;
if(epDetect) {
unsigned long flags;
struct ath_usb_req *req;
struct ath_usb_ep *ep;
/* Based on EP number and direction Get Queue head and dtd */
tmp = ((2 * epno) + epdir);
ep = &udc->ep[tmp];
ep_QHead = udc->ep_queue_head + tmp;
/*Searching for all the inactive DTDs*/
do {
spin_lock_irqsave(&udc->lock, flags);
if (!ep_dtd) {
ep_dtd = udc->dtd_heads[tmp];
if (ep_dtd) {
if(le32_to_cpu(ep_dtd->size_ioc_status) & ATH_USB_TD_STATUS_ACTIVE) {
//printk("Hitting here ep_dtd = %x\n", ep_dtd);
spin_unlock_irqrestore(&udc->lock, flags);
break;
}
} else {
//printk("dtd Null tmp = %d, epno = %u, epdir = %u count = %u\n", tmp, epno, epdir);
spin_unlock_irqrestore(&udc->lock, flags);
break;
}
}
if (ep_dtd) {
if ((err = (le32_to_cpu(ep_dtd->size_ioc_status) &
ATH_USB_TD_ERROR_MASK))) {
if (err & ATH_USB_TD_STATUS_HALTED) {
printk("Descp Halted \n");
ep_QHead->size_ioc_int_status &= cpu_to_le32(~err);
}
if (err & 0x20 || err & 0x08) {
printk("Data Trans Err %x \n", err);
}
}
}
count++;
/* Retire dtd & start next transfer */
req = ath_usb_retire_dtd(udc, ep_dtd, epno, epdir);
ep_dtd = udc->dtd_heads[tmp];
spin_unlock_irqrestore(&udc->lock, flags);
if (req) {
if (req->req.complete) {
req->req.complete(&ep->ep, &req->req);
}
} /* else {
printk("bit_pos = %x epno = %u epdir = %u epDetect = %u tmp = %u count = %d prev_count = %d\n", bit_pos, epno, epdir, epDetect, tmp, count, prev_count);
} */
if (!ep_dtd) /*If no discriptor in the queue*/
break;
} while (!(le32_to_cpu(ep_dtd->size_ioc_status) & ATH_USB_TD_STATUS_ACTIVE));
}
epdir = 1;
prev_count = count;
}
}
}
return;
}
static void ath_usb_handle_reset(struct ath_usb_udc *udc)
{
int i;
ath_usb_debug_fn("__enter %s\n", __func__);
ath_usb_debug_ps("Port Status %x \n", readl(&udc->op_base->portscx[0]));
ath_usb_stop_activity(udc);
if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
udc->gadget.speed = USB_SPEED_UNKNOWN;
}
/* The address bits are past bit 25-31. Set the address */
setAddress(udc, 0);
/* Clear all the setup token semaphores */
writel(readl(&udc->op_base->ep_setup_stat), &udc->op_base->ep_setup_stat);
/* Clear all the endpoint complete status bits */
writel(readl(&udc->op_base->ep_complete), &udc->op_base->ep_complete);
while (readl(&udc->op_base->ep_prime) & 0xFFFFFFFF) {
/* Wait until all ENDPTPRIME bits cleared */
}
/* Write 1s to the Flush register */
writel(0xffffffff, &udc->op_base->ep_flush);
/* Unstall all endpoints */
for (i = 0; i < (ATH_USB_MAX_EP * 2); i++) {
ath_usb_unstall_endpoint(udc, i, 0);
ath_usb_unstall_endpoint(udc, i, 1);
}
ath_usb_debug_ps("Port Status %x \n", readl(&udc->op_base->portscx[0]));
if (readl(&udc->op_base->portscx[0]) & ATH_USB_PORTSCX_PORT_RESET) {
udc->usbState = USB_STATE_POWERED;
} else {
ath_usb_init_device(udc);
ath_usb_setup(udc);
}
}
static void ath_usb_process_port_change(struct ath_usb_udc *udc)
{
unsigned int rddata;
ath_usb_debug_fn("__enter %s\n", __func__);
if (!(readl(&udc->op_base->portscx[0]) & ATH_USB_PORTSCX_PORT_RESET)) {
/* Get the speed */
if (readl(&udc->op_base->portscx[0]) & ATH_USB_PORTSCX_PORT_HIGH_SPEED) {
udc->gadget.speed = USB_SPEED_HIGH;
} else {
udc->gadget.speed = USB_SPEED_FULL;
}
}
if (readl(&udc->op_base->portscx[0]) & ATH_USB_PORTSCX_PORT_SUSPEND) {
if ((udc->gadget.speed != USB_SPEED_UNKNOWN) &&
(udc->ga_driver->suspend)) {
#if 0
/* Issue PHY Low Power Suspend - Stops the phy clock */
writel((readl(&udc->op_base->portscx[0]) | (1 << 23)),
&udc->op_base->portscx[0]);
#endif
spin_unlock(&udc->lock);
udc->ga_driver->suspend(&udc->gadget);
spin_lock(&udc->lock);
if(is_wasp()) {
ap_usb_led_off();
// ath_reg_rmw_set(ATH_GPIO_OUT, (1<<11));
}
}
}
if (!(readl(&udc->op_base->portscx[0]) & ATH_USB_PORTSCX_PORT_SUSPEND)) {
if ((udc->gadget.speed != USB_SPEED_UNKNOWN) &&
(udc->ga_driver->resume)) {
/* Resume - starts the phy clock(not necessary when host issues resume) */
#if 1
writel((readl(&udc->op_base->portscx[0]) & ~(1 << 23)),
&udc->op_base->portscx[0]);
#endif
spin_unlock(&udc->lock);
udc->ga_driver->resume(&udc->gadget);
spin_lock(&udc->lock);
if(is_wasp()) {
ap_usb_led_on();
#if 0
rddata = ath_reg_rd(ATH_GPIO_OUT_FUNCTION2); //87- for USB suspend
rddata = rddata & 0x00ffffff;
rddata = rddata | ATH_GPIO_OUT_FUNCTION2_ENABLE_GPIO_11(0x0);
ath_reg_wr(ATH_GPIO_OUT_FUNCTION2, rddata);
ath_reg_rmw_clear(ATH_GPIO_OE, (1<<11));
ath_reg_rmw_clear(ATH_GPIO_OUT, (1<<11));
#endif
}
}
}
}
#define ATH_USB_SUSPEND_ENTRY_COUNT 0xff /*TODO: Value needs to be checked*/
#define ATH_USB_SUSPEND_EXIT_COUNT 2000 /*TODO: Value needs to be checked*/
#define ATH_USB_GPIO_USB_SUSP_POLARITY (1u << 2)
#define ATH_USB_CHIP_RESET_ON_RESUME (1u << 1)
#define ATH_USB_MASTER_SUSPEND_ENABLE (1u)
#define ATH_SELF_REFRESH (ATH_DDR_CTL_BASE+0x110)
#define EN_SELF_REFRESH (1 << 31)
#define EN_AUTO_SF_EXIT (1 << 30)
#define CUT_CLK (1 << 28)
#define ATH_SRAM_DEV_PTR ((struct ath_usb **)(ATH_SRAM_BASE+0x1000))
#define TEMP_INT ((unsigned int *)(ATH_SRAM_BASE+0x1020))
#define TEMP_INT1 ((unsigned int *)(ATH_SRAM_BASE+0x1040))
#undef MASTER_SUSPEND
#define ATH_ENABLE_DDR_SELFREFRESH
void ath_usb_suspend(void)
{
#ifndef ATH_ENABLE_DDR_SELFREFRESH
ath_usb_reg_wr(&(*ATH_SRAM_DEV_PTR)->portscx[0], (ath_usb_reg_rd(&(*ATH_SRAM_DEV_PTR)->portscx[0]) | (1u<<23))); //enable PHY clock
/*TODO: Put all PLLs in Bypass mode and then power down all of them*/
ath_usb_reg_wr(ATH_USB_SUSPEND_RESUME_CNTR, ((ATH_USB_SUSPEND_ENTRY_COUNT << 24) \
| ATH_USB_SUSPEND_EXIT_COUNT));
ath_usb_reg_wr(ATH_USB_DEV_SUSPEND_CTRL, (ath_usb_reg_rd(ATH_USB_DEV_SUSPEND_CTRL) \
| ATH_USB_CHIP_RESET_ON_RESUME));
/*TODO: Programs the Switcher to be in Discontinuous Mode*/
ath_usb_reg_wr(ATH_USB_DEV_SUSPEND_CTRL, (ath_usb_reg_rd(ATH_USB_DEV_SUSPEND_CTRL) \
| ATH_USB_MASTER_SUSPEND_ENABLE));
ath_usb_reg_wr(ATH_USB_CONFIG, (ath_usb_reg_rd(ATH_USB_CONFIG) & ~(1u<<4)));//for USB configuration in device mode
ath_usb_reg_wr(ATH_STICKY_REG, (ath_usb_reg_rd(ATH_STICKY_REG) | (1u<<31))); //Set the sticky register
while(1);
#else
ath_usb_reg_wr(&(*ATH_SRAM_DEV_PTR)->portscx[0], (ath_usb_reg_rd(&(*ATH_SRAM_DEV_PTR)->portscx[0]) | (1u<<23)));
ath_usb_reg_wr(ATH_SELF_REFRESH, (ath_usb_reg_rd(ATH_SELF_REFRESH) | (EN_SELF_REFRESH | EN_AUTO_SF_EXIT)));
while((ath_usb_reg_rd(ATH_SELF_REFRESH) & (1<<29))); // Wait for self refresh entry done
ath_usb_reg_rmw_set(ATH_DDR_CLK_CTRL, (1<<2));
ath_usb_reg_rmw_set(ATH_DDR_CLK_CTRL, (1<<4));
ath_usb_reg_rmw_set(ATH_DDR_CLK_CTRL, (1<<3));
ath_usb_reg_wr(ATH_DDR_PLL_CONFIG, (ath_usb_reg_rd(ATH_DDR_PLL_CONFIG) | (1u<<30))); //DDR PLL control register: Bit 30(Power down)
ath_usb_reg_wr(ATH_PLL_CONFIG, (ath_usb_reg_rd(ATH_PLL_CONFIG) | (1u<<30))); //CPU PLL control register: Bit 30(Power down)
ath_usb_reg_wr(ATH_USB_CONFIG, (ath_usb_reg_rd(ATH_USB_CONFIG) & ~(1u<<4)));
ath_usb_reg_wr(ATH_USB_DEV_SUSPEND_CTRL, (ath_usb_reg_rd(ATH_USB_DEV_SUSPEND_CTRL) \
| (ATH_USB_MASTER_SUSPEND_ENABLE)));
while(!((ath_usb_reg_rd(&(*ATH_SRAM_DEV_PTR)->usbsts) & ATH_USB_EHCI_STS_PORT_CHANGE) &&
(!(ath_usb_reg_rd(&(*ATH_SRAM_DEV_PTR)->portscx[0]) & ATH_USB_PORTSCX_PORT_SUSPEND))));
/* Resume Sequence */
ath_usb_reg_wr(ATH_USB_DEV_SUSPEND_CTRL, (ath_usb_reg_rd(ATH_USB_DEV_SUSPEND_CTRL) \
& ~(ATH_USB_MASTER_SUSPEND_ENABLE)));
ath_usb_reg_wr(ATH_USB_CONFIG, (ath_usb_reg_rd(ATH_USB_CONFIG) | (1u<<4)));
ath_usb_reg_wr(ATH_PLL_CONFIG, (ath_usb_reg_rd(ATH_PLL_CONFIG) & ~(1u<<30))); //CPU PLL control register: Bit 30(Power up)
ath_usb_reg_wr(ATH_DDR_PLL_CONFIG, (ath_usb_reg_rd(ATH_DDR_PLL_CONFIG) & ~(1u<<30))); //DDR PLL control register: Bit 30(Power up)
ath_usb_reg_wr(ATH_DDR_CLK_CTRL, 0x01308000); //PLL Bypass register :Bit 2,3,4 (CPU, DDR)
#endif
}
void ath_usb_switch_to_sram(void)
{
printk("Going to Suspend mode\n\n");
void (*foo)(void) = 0xbd000000;
memcpy(0xbd000000, ath_usb_suspend, 600);
foo();
printk("Going to Resume\n\n");
}
/*
* UDC Driver Interrupt handler. This is called directly by the UDC or
* indirectly by OTG driver
*/
static int suspend_flag;
irqreturn_t ath_usb_udc_isr(int irq, void *_udc)
{
struct ath_usb_udc *udc = (struct ath_usb_udc *)_udc;
__u32 status = 0, setupstat = 0;
isr_count++;
if(!udc){
printk("udc null condition \n");
return IRQ_NONE;
}
if (!udc->op_base) {
printk("udc_isr null values %p, %p\n", udc, (udc) ? udc->op_base : NULL);
return IRQ_NONE;
}
/*
* Avoid delays during device attach times by handling all interrupts
* at once
*/
for (;;) {
status = readl(&udc->op_base->usbsts);
setupstat = readl(&udc->op_base->ep_setup_stat);
if (!(status & readl(&udc->op_base->usbintr))) {
/* Nothing to do - exit */
break;
}
/* Clear all interrupts */
// writel(status, &udc->op_base->usbsts);
/* USB Port Reset Event */
if (status & ATH_USB_EHCI_STS_RESET) {
ath_usb_debug_int("Port Reset Interrupt\n");
ath_usb_handle_reset(udc);
}
/* USB Port Change Event */
if (status & ATH_USB_EHCI_STS_PORT_CHANGE) {
ath_usb_debug_int("Port Change Interrupt\n");
ath_usb_process_port_change(udc);
}
if (status & ATH_USB_EHCI_STS_ERR) {
ath_usb_error("Error Interrupt\n");
printk("Error Interrupt\n");
/* Not Handled */
}
if (status & ATH_USB_EHCI_STS_SOF) {
/* Not Handled - Nothing to do */
}
/* Endpoint Transfer Complete Events */
if (status & ATH_USB_EHCI_STS_INT) {
ath_usb_debug_int("USB Interrupt\n");
ath_usb_process_USB_Intr(udc);
}
/* USB Port Suspend Event */
if (status & ATH_USB_EHCI_STS_SUSPEND) {
#ifdef MASTER_SUSPEND
__u32 otgsc = readl(&udc->op_base->otgsc);
ath_usb_debug_int("USB Suspend\n");
if (udc->ga_driver->suspend) {
/* USB Device suspend event - inform gadget driver */
writel((1 << 20), &udc->op_base->otgsc);
udc->ga_driver->suspend(&udc->gadget);
}
*ATH_SRAM_DEV_PTR = &udc->op_base->usbcmd; //sram location pointer initialization
if (suspend_flag) {
ath_usb_switch_to_sram();
}
suspend_flag = 1;
printk("Suspend event ignored...\n");
#else
writel((1 << 20), &udc->op_base->otgsc);
#endif
}
/* Clear all interrupts */
writel(status, &udc->op_base->usbsts);
}
return IRQ_HANDLED;
}
/* Endpoint Initialization */
static int ath_usb_endpoint_setup(char *ep_name, __u8 ep_addr, __u8 ep_type,
__u16 maxPack, struct ath_usb_udc *udc)
{
struct ath_usb_ep *ep;
struct usb_ep *_ep;
struct ep_qhead *ep_QHead;
__u8 epno, epdir, qh_offset;
__u32 bits = 0;
__u32 xferFlags = 0;
ath_usb_debug_fn("__enter %s\n", __func__);
/* Get endpoint number and direction */
epno = ep_addr & 0x0f;
epdir = (ep_addr & USB_DIR_IN) ? USB_SEND : USB_RECV;
qh_offset = (2 * epno) + epdir;
/* Select the Queue Head based on EP number and direction */
ep = &udc->ep[qh_offset];
ep_QHead = (udc->ep_queue_head + qh_offset);
ep->ep_qh = ep_QHead;
strlcpy(ep->name, ep_name, sizeof ep->name);
ep->udc = udc;
ep->bEndpointAddress = ep_addr;
ep->bmAttributes = ep_type;
INIT_LIST_HEAD(&ep->queue);
INIT_LIST_HEAD(&ep->skipped_queue);
/* Initialize EndPoint queue head params based on EP type */
switch (ep_type) {
case USB_ENDPOINT_XFER_ISOC:
xferFlags = (1 << ATH_USB_EP_QUEUE_HEAD_MULT_POS);
break;
case USB_ENDPOINT_XFER_CONTROL:
xferFlags = ATH_USB_EP_QUEUE_HEAD_IOS;
break;
default:
xferFlags = ATH_USB_EP_QUEUE_HEAD_ZERO_LEN_TER_SEL;
break;
}
/*
* We select a default max packet length now. This is later modified as
* required when the endpoint is enabled by gadget drivers
*/
ep_QHead->maxPacketLen = cpu_to_le32((maxPack << 16) | xferFlags);
ath_usb_debug_ep("ep_setup ==> ep%d-%s queue:%d, name:%s, maxlen:%d, "
"ctrl:%x\n", epno, ep_direction[epdir], qh_offset,
ep->name, maxPack, readl(&udc->op_base->ep_ctrlx[epno]));
_ep = &ep->ep;
_ep->name = ep->name; /* ep- (name, type, direction) */
_ep->ops = &ath_usb_ep_ops;
_ep->maxpacket = ep->maxpacket = maxPack;
/*
* Only configure the endpoint properties in the control register, but do
* not enable them. The endpoints are enabled by gadget drivers
*/
bits = (((epdir) ? (ATH_USB_EPCTRL_TX_DATA_TOGGLE_RST) :
(ATH_USB_EPCTRL_RX_DATA_TOGGLE_RST)) |
(ep_type << (epdir ? (ATH_USB_EPCTRL_TX_EP_TYPE_SHIFT) :
(ATH_USB_EPCTRL_RX_EP_TYPE_SHIFT))));
writel((readl(&udc->op_base->ep_ctrlx[epno]) | bits),
&udc->op_base->ep_ctrlx[epno]);
ath_usb_debug_ep("ep_setup ==> ep%d-%s queue:%d, name:%s, maxlen:%d, "
"ctrl:%x, %x\n", epno, ep_direction[epdir], qh_offset,
ep->name, maxPack, readl(&udc->op_base->ep_ctrlx[epno]), bits);
/* EP0 not added to the gadget endpoint list */
if (epno > 0) {
list_add_tail(&_ep->ep_list, &udc->gadget.ep_list);
}
return 0;
}
static int ath_usb_setup(struct ath_usb_udc *udc)
{
ath_usb_debug_fn("__enter %s \n", __func__);
/*Init EndPoint 0 Properties */
ath_usb_debug_ep("Init Endpoint 0 \n");
writel((ATH_USB_EPCTRL_TX_DATA_TOGGLE_RST | ATH_USB_EPCTRL_RX_DATA_TOGGLE_RST),
&udc->op_base->ep_ctrlx[0]);
writel((readl(&udc->op_base->ep_ctrlx[0]) &
~(ATH_USB_EPCTRL_TX_EP_STALL | ATH_USB_EPCTRL_RX_EP_STALL)),
&udc->op_base->ep_ctrlx[0]);
/* Clear all ENDPTPRIME Status */
writel(0, &udc->op_base->ep_prime);
/*
* We have a total of 5 IN/OUT endpoints, split them for different transfer
* Control IN/OUT - 1
* Bulk INOUT - 2
* ISO IN/OUT - 1
* INT IN/OUT - 1
*/
/* Init EndPoint 0 */
ath_usb_endpoint_setup("ep0out", 0, USB_ENDPOINT_XFER_CONTROL, 64, udc);
ath_usb_endpoint_setup("ep0in", 0 | USB_DIR_IN,
USB_ENDPOINT_XFER_CONTROL, 64, udc);
/* Init Bulk EndPoints, Set Required Block maxBlockSize later */
ath_usb_endpoint_setup("ep1out-bulk", 1, USB_ENDPOINT_XFER_BULK, 0x400, udc);
ath_usb_endpoint_setup("ep1in-bulk", 1 | USB_DIR_IN,
USB_ENDPOINT_XFER_BULK, 0x400, udc);
ath_usb_endpoint_setup("ep2out-bulk", 2, USB_ENDPOINT_XFER_BULK, 0x400, udc);
ath_usb_endpoint_setup("ep2in-bulk", 2 | USB_DIR_IN,
USB_ENDPOINT_XFER_BULK, 0x400, udc);
ath_usb_endpoint_setup("ep3out-iso", 3, USB_ENDPOINT_XFER_ISOC, 0x400, udc);
ath_usb_endpoint_setup("ep3in-iso", 3 | USB_DIR_IN,
USB_ENDPOINT_XFER_ISOC, 0x400, udc);
ath_usb_endpoint_setup("ep4out-int", 4, USB_ENDPOINT_XFER_INT, 0x400, udc);
ath_usb_endpoint_setup("ep4in-int", 4 | USB_DIR_IN,
USB_ENDPOINT_XFER_INT, 0x400, udc);
return 0;
}
static void ath_usb_udc_release(struct device *dev)
{
ath_usb_debug_fn("__enter %s\n", __func__);
#if 0
kfree(ap_gadget);
ap_gadget = NULL;
#endif
}
static void ath_usb_init_device(struct ath_usb_udc *udc)
{
ath_usb_debug_fn("__enter %s \n", __func__);
/*
* Device controller Initialization
*/
ath_usb_debug_dev("STOP UDC\n");
writel(~ATH_USB_CMD_RUN_STOP, &udc->op_base->usbcmd);
udelay(100);
ath_usb_debug_dev("RESET UDC\n");
writel(ATH_USB_CMD_CTRL_RESET, &udc->op_base->usbcmd);
udelay(100);
ath_usb_debug_dev("Waiting for Reset to complete \n");
while (readl(&udc->op_base->usbcmd) & ATH_USB_CMD_CTRL_RESET) ;
ath_usb_debug_dev("Setting Device Mode \n");
/* Set Device Mode */
writel((ATH_USB_SET_DEV_MODE | ATH_USB_MODE_SLOM), &udc->op_base->usbmode);
writel(0, &udc->op_base->ep_setup_stat);
/* Initialize EndPointList Addr */
writel(udc->qh_dma, &udc->op_base->ep_list_addr);
#if 0 // TODO OTG
if (readl(&udc->op_base->hcs_params) &
ATH_USB_HCS_PARAMS_PORT_POWER_CONTROL_FLAG) {
__u32 port_control;
port_control = readl(&udc->op_base.portscx[0]);
port_control &= (~EHCI_PORTSCX_W1C_BITS | ~EHCI_PORTSCX_PORT_POWER);
writel(port_control, &udc->op_base.portscx[0]);
}
#endif
#if 0
/* Force to Full Speed - shekar(Nov 29) */
ath_usb_reg_rmw_set(&udc->op_base->portscx[0], (1 << 24));
printk("Port Status %x\n", readl(&udc->op_base->portscx[0]));
#endif
if(is_wasp()) {
ath_reg_wr(&udc->op_base->tx_filltuning,
(ath_reg_rd(&udc->op_base->tx_filltuning) | (0x2 <<16)));
ath_reg_wr(&udc->op_base->burst_size, \
(ath_reg_rd(&udc->op_base->burst_size) | (0x20 <<8) | (0x20)));
ath_reg_wr(0xb80000c4, 0x72224222);
ath_reg_wr(0xb80000c8, 0x22224222);
}
ath_usb_debug_fn("__exit %s \n", __func__);
}
static void ath_usb_udc_mem_free(struct ath_usb_udc *udc)
{
struct ep_dtd *ep_dtd;
int count;
//int ret = 0;
ath_usb_debug_fn("ath_usb_udc_mem_free \n");
printk("ath_usb_udc_mem_free \n");
writel(0, &udc->op_base->ep_list_addr);
if (udc->dtd_pool) {
for(count = 0; count < ATH_USB_MAX_EP_IN_SYSTEM; count++) {
while (!list_empty(&udc->dtd_list[count])) {
struct list_head *temp;
temp = udc->dtd_list[count].next;
ep_dtd = list_entry(temp, struct ep_dtd, tr_list);
dma_pool_free(udc->dtd_pool, ep_dtd, ep_dtd->dtd_dma);
list_del(temp);
}
}
dma_pool_destroy(udc->dtd_pool);
udc->dtd_pool = NULL;
}
if (udc->ep_queue_head) {
dma_free_coherent(udc->dev,
(sizeof(struct ep_qhead) * ATH_USB_MAX_EP * 2),
udc->ep_queue_head, udc->qh_dma);
udc->ep_queue_head = NULL;
}
for( count = 0; count < ATH_MAX_CTRL_REQ; count++ ) {
if (udc->ctrl_req[count]) {
ath_usb_free_request(NULL, udc->ctrl_req[count]);
udc->ctrl_req[count] = NULL;
}
if (udc->ctrl_buf[count]) {
kfree(udc->ctrl_buf[count]);
udc->ctrl_buf[count] = NULL;
}
}
}
static int ath_usb_udc_mem_init(struct ath_usb_udc *udc)
{
int count, i;
struct ep_dtd *ep_dtd;
/* Allocate pool for device transfer descriptors(DTD) -DTDs are DMA-able */
udc->dtd_pool = dma_pool_create(
"udc_dtd",
udc->dev,
sizeof(struct ep_dtd),
(ATH_USB_MAX_EP_IN_SYSTEM * ATH_USB_MAX_DTD) /* byte alignment (for hw parts) */ ,
4096 * ATH_USB_MAX_DTD /* can't cross 4K */);
if (!udc->dtd_pool) {
ath_usb_error("ath_usb_udc: dtd dma_pool_create failure\n");
return -ENOMEM;
}
/* Allocate Queue Heads for transfer -QHs are DMA-able */
udc->ep_queue_head = dma_alloc_coherent(
udc->dev,
(sizeof(struct ep_qhead) * ATH_USB_MAX_EP * 2),
&udc->qh_dma, 0);
if (!udc->ep_queue_head) {
ath_usb_udc_mem_free(udc);
return -ENOMEM;
}
ath_usb_debug_mem("queue head %p %x Allocated\n", udc->ep_queue_head,
udc->qh_dma);
printk("queue head %p %x Allocated\n", udc->ep_queue_head,
udc->qh_dma);
/* Pre-allocate a transfer request and buffer for EP0 operations */
for( count = 0; count < ATH_MAX_CTRL_REQ; count++ ) {
udc->ctrl_req[count] = ath_usb_alloc_request(NULL, GFP_ATOMIC);
udc->ctrl_buf[count] = kmalloc(64, GFP_ATOMIC);
if (!udc->ctrl_req[count] || !udc->ctrl_buf[count]) {
ath_usb_udc_mem_free(udc);
return -ENOMEM;
}
udc->ctrl_req[count]->buf = udc->ctrl_buf[count];
}
/* Pre-allocate DTDs */
for (count = 0; count < ATH_USB_MAX_EP_IN_SYSTEM; count++) {
for (i = 0; i < ATH_USB_MAX_DTD; i++) {
dma_addr_t dma;
ep_dtd = dma_pool_alloc(udc->dtd_pool, GFP_ATOMIC, &dma);
if (ep_dtd == NULL) {
ath_usb_udc_mem_free(udc);
return -ENOMEM;
}
ath_usb_debug_mem("DTD Alloc %p, %x\n", ep_dtd, dma);
ep_dtd->dtd_dma = dma;
list_add_tail(&ep_dtd->tr_list, &udc->dtd_list[count]);
ep_dtd->size_ioc_status &= cpu_to_le32(~ATH_USB_TD_RESERVED_FIELDS);
ep_dtd->next_dtd = __constant_cpu_to_le32(ATH_USB_TD_NEXT_TERMINATE);
}
}
return 0;
}
/* Provides a graceful exit for the gadget/udc driver */
static void ath_usb_stop_activity(struct ath_usb_udc *udc)
{
struct ath_usb_ep *ep = NULL;
unsigned long flags;
spin_lock_irqsave(&udc->lock, flags);
udc->gadget.speed = USB_SPEED_UNKNOWN;
/* Cancel any EP0 IN/OUT transfers */
ath_usb_udc_ep_wipe(&udc->ep[0], -ESHUTDOWN);
ath_usb_udc_ep_wipe(&udc->ep[1], -ESHUTDOWN);
/* Cancel all other EP IN/OUT transfers used by gadget driver */
list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
ath_usb_udc_ep_wipe(ep, -ESHUTDOWN);
}
spin_unlock_irqrestore(&udc->lock, flags);
/* Disconnect event to Gadget driver */
if (udc->ga_driver->disconnect) {
udc->ga_driver->disconnect(&udc->gadget);
}
}
/* Start ATH_USB device controller hardware */
static void ath_usb_start_udc(struct ath_usb_udc *udc)
{
ath_usb_debug_dev("Starting Device Controller ...\n");
ath_usb_init_device(udc);
ath_usb_setup(udc);
/* Enable Interrupts */
writel((ATH_USB_INTR_INT_EN | ATH_USB_INTR_ERR_INT_EN |
ATH_USB_INTR_PORT_CHANGE_DETECT_EN | ATH_USB_INTR_RESET_EN |
/*ATH_USB_INTR_SOF_UFRAME_EN | */ ATH_USB_INTR_DEVICE_SUSPEND),
&udc->op_base->usbintr);
/* Start Device Controller */
writel(ATH_USB_CMD_RUN_STOP, &udc->op_base->usbcmd);
if (!is_ar933x())
ath_reg_rmw_set(ATH_GPIO_FUNCTIONS, ATH_GPIO_FUNCTION_USB_LED);
udelay(100);
}
/* Stop ATH_USB device controller hardware */
static void ath_usb_stop_udc(struct ath_usb_udc *udc)
{
ath_usb_debug_dev("Stoping Device Controller ...\n");
/* Disable Interrupts */
writel(0, &udc->op_base->usbintr);
/* Stop Device Controller */
writel(~ATH_USB_CMD_RUN_STOP, &udc->op_base->usbcmd);
if (!is_ar933x())
ath_reg_rmw_clear(ATH_GPIO_FUNCTIONS, ATH_GPIO_FUNCTION_USB_LED);
suspend_flag = 0;
udelay(100);
}
/*
* Gadget driver registration
* The device controller driver starts the actual operation only after a
* gadget driver is registered. This is where we enable the UDC interrupts
*/
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
{
struct ath_usb_udc *udc = ap_gadget;
int ret;
ath_usb_debug_fn("__enter %s\n", __func__);
/* Sanity checks */
if (!udc) {
ath_usb_error("no udc %p\n", udc);
return -ENODEV;
}
if (!driver || driver->speed != USB_SPEED_HIGH || !driver->bind
/*|| !driver->unbind */ || !driver->setup) {
ath_usb_error("gadget driver does not match udc\n");
return -EINVAL;
}
/* hook up the driver */
driver->driver.bus = NULL;
udc->ga_driver = driver;
udc->gadget.dev.driver = &driver->driver;
/* Bind the gadget driver */
ret = driver->bind(&udc->gadget);
if (ret) {
ath_usb_error("unable to bind driver %s --> %d\n",
driver->driver.name, ret);
udc->ga_driver = NULL;
udc->gadget.dev.driver = NULL;
return ret;
}
#ifdef CONFIG_USB_ATH_OTG
udc->ath_usb_otg->udc = udc;
udc->ath_usb_otg->udc_isr = ath_usb_udc_isr;
/* Enable peripheral mode in OTG */
if (otg_set_peripheral(&udc->ath_usb_otg->otg, &udc->gadget)) {
if (driver->unbind) {
driver->unbind(&udc->gadget);
}
udc->gadget.dev.driver = NULL;
udc->ga_driver = NULL;
return -EINVAL;
}
#else
/* Everything is fine - start the device controller */
ath_usb_start_udc(udc);
#endif
ath_usb_debug_fn("__exit %s\n", __func__);
return 0;
}
EXPORT_SYMBOL(usb_gadget_register_driver);
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
{
struct ath_usb_udc *udc = ap_gadget;
if (!udc) {
return -ENODEV;
}
if (!driver || driver != udc->ga_driver) {
return -EINVAL;
}
ath_usb_stop_udc(udc);
ath_usb_stop_activity(udc);
#ifdef CONFIG_USB_ATH_OTG
/* Disable peripheral mode in OTG */
printk("set peripheral null\n");
otg_set_peripheral(&udc->ath_usb_otg->otg, NULL);
udc->ath_usb_otg->udc = NULL;
udc->ath_usb_otg->udc_isr = NULL;
#endif
if (driver->unbind) {
driver->unbind(&udc->gadget);
}
udc->gadget.dev.driver = NULL;
udc->ga_driver = NULL;
return 0;
}
EXPORT_SYMBOL(usb_gadget_unregister_driver);
static int ath_usb_udc_init(struct ath_usb_udc *udc, struct device *dev)
{
struct ep_qhead *ep_queue_head;
int temp;
udc->dev = dev;
spin_lock_init(&udc->lock);
for(temp = 0; temp < ATH_USB_MAX_EP_IN_SYSTEM; temp++)
INIT_LIST_HEAD(&udc->dtd_list[temp]);
if (ath_usb_udc_mem_init(udc) != 0) {
return -ENOMEM;
}
/* Initialize all device Q Head */
ep_queue_head = udc->ep_queue_head;
ath_usb_debug_dev("QHead Size %x : eTD Size %x \n",
sizeof(struct ep_qhead), sizeof(struct ep_dtd));
ath_usb_debug_dev("Initialize Dev Trans Descp \n");
for (temp = 0; temp < (ATH_USB_MAX_EP * 2); temp++) {
(ep_queue_head + temp)->maxPacketLen = cpu_to_le32(0x400);
(ep_queue_head + temp)->next_dtd =
cpu_to_le32(ATH_USB_EP_QUEUE_HEAD_NEXT_TERMINATE);
}
udc->gadget.ops = &ath_usb_udc_ops;
udc->gadget.ep0 = &udc->ep[1].ep;
INIT_LIST_HEAD(&udc->gadget.ep_list);
udc->gadget.speed = USB_SPEED_UNKNOWN;
udc->gadget.name = device_name;
device_initialize(&udc->gadget.dev);
//strcpy(udc->gadget.dev.bus_id, "gadget");
udc->gadget.dev.release = ath_usb_udc_release;
udc->gadget.dev.parent = dev;
ap_gadget = udc;
ath_usb_debug_dev("UDC %p\n", ap_gadget);
/* Setup all endpoints */
ath_usb_setup(udc);
udc->gadget.dev.init_name = device_name;
device_add(&udc->gadget.dev);
return 0;
}
#ifndef CONFIG_USB_ATH_OTG
static int ath_usb_udc_probe(struct platform_device *pdev)
{
struct ath_usb_udc *udc;
void __iomem *reg_base;
int retval;
ath_usb_debug_fn("__enter %s \n", __func__);
udc = (struct ath_usb_udc *)kmalloc(sizeof(struct ath_usb_udc), GFP_ATOMIC);
if (udc == NULL) {
ath_usb_error("Unable to allocate udc device\n");
return -ENOMEM;
}
memset(udc, 0, sizeof(struct ath_usb_udc));
/* Allocate and map resources */
if (!request_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1,
driver_name)) {
ath_usb_error("ath_usb_udc: controller already in use\n");
retval = -EBUSY;
goto err1;
}
reg_base = ioremap(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1);
if (!reg_base) {
ath_usb_error("ath_usb_udc: error mapping memory\n");
retval = -EFAULT;
goto err2;
}
udc->reg_base = reg_base;
reg_base += 0x140;
udc->op_base = reg_base;
/* Device Initialization - start */
ath_usb_debug_dev("Device Initialization\n");
#if 0
/*Setting to 8-bit 6th March */
ath_usb_reg_rmw_clear(ATH_USB_RESET, ATH_USB_RESET_USB_HOST);
ath_usb_reg_rmw_set(ATH_USB_RESET, ATH_USB_RESET_USB_PHY); //PHY RESET
#endif
if (is_qca955x() || is_wasp() || is_ar7242() || is_ar7241() || is_ar933x()) {
ath_usb_reg_rmw_set(ATH_USB_RESET, ATH_USB_RESET_USBSUS_OVRIDE);
mdelay(10);
ath_usb_reg_wr(ATH_USB_RESET,
((ath_usb_reg_rd(ATH_USB_RESET) &
~(ATH_USB_RESET_USB_HOST)) |
ATH_USB_RESET_USBSUS_OVRIDE));
mdelay(10);
ath_usb_reg_wr(ATH_USB_RESET,
((ath_usb_reg_rd(ATH_USB_RESET) &
~(ATH_USB_RESET_USB_PHY)) |
ATH_USB_RESET_USBSUS_OVRIDE));
mdelay(10);
} else {
ath_usb_reg_rmw_clear(ATH_USB_RESET, ATH_USB_RESET_USB_PHY); //PHY CLEAR RESET
ath_usb_debug_dev("ATH_USB_RESET %x \n", ath_usb_reg_rd(ATH_USB_RESET));
mdelay(10);
ath_usb_reg_rmw_clear(ATH_USB_RESET, ATH_USB_RESET_USB_HOST); // 6th March
mdelay(10);
}
/* Setting 16-bit mode */
ath_usb_reg_rmw_set(&udc->op_base->portscx[0], (1 << 28));
ath_usb_debug_dev("PORT_STATUS[0] %x\n", readl(&udc->op_base->portscx[0]));
mdelay(10);
/* Clear Host Mode */
if (is_qca955x() || is_wasp() || is_ar7242() || is_ar7241() || is_ar933x()) {
ath_usb_reg_rmw_clear(ATH_USB_CONFIG, (1 << 8));
} else {
ath_usb_reg_rmw_clear(ATH_USB_CONFIG, (1 << 2));
}
ath_usb_debug_dev("Usb Config Reg %x\n", ath_usb_reg_rd(ATH_USB_CONFIG));
mdelay(10);
/*Debug Info */
ath_usb_debug_dev("Platform Device Info:\n");
ath_usb_debug_dev("pdev->resource[0].start %x\n", pdev->resource[0].start);
ath_usb_debug_dev("pdev->resource[1].start %u\n", pdev->resource[1].start);
ath_usb_debug_dev("reg_base :%p udc->op_base :%p\n", reg_base, udc->op_base);
/* Interrupt Request */
if ((retval = request_irq(pdev->resource[1].start, ath_usb_udc_isr,
IRQF_SHARED, driver_name, udc)) != 0) {
ath_usb_error("request interrupt %x failed\n", pdev->resource[1].start);
retval = -EBUSY;
goto err3;
}
ath_usb_debug_dev("PORT_STATUS[0] %x\n", readl(&udc->op_base->portscx[0]));
if (ath_usb_udc_init(udc, &pdev->dev) == 0) {
return 0;
}
free_irq(pdev->resource[1].start, udc);
err3:
iounmap(reg_base);
err2:
release_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1);
err1:
ap_gadget = NULL;
kfree(udc);
return retval;
}
static int ath_usb_udc_remove(struct platform_device *pdev)
{
struct ath_usb_udc *udc = ap_gadget;
ath_usb_udc_mem_free(udc);
free_irq(pdev->resource[1].start, udc);
iounmap(udc->reg_base);
release_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1);
device_unregister(&udc->gadget.dev);
ap_gadget = NULL;
kfree(udc);
return 0;
}
static struct platform_driver ath_usb_udc_drv = {
.probe = ath_usb_udc_probe,
.remove = ath_usb_udc_remove,
.driver = {
.name = (char *)driver_name,
.owner = THIS_MODULE,
},
};
#else
static int ath_usb_udc_probe(void)
{
struct ath_usb_otg *ath_usb_otg;
struct ath_usb_udc *udc;
ath_usb_debug_fn("__enter %s \n", __func__);
if ((ath_usb_otg = ath_usb_get_otg()) == NULL) {
return -ENODEV;
}
udc = (struct ath_usb_udc *)kmalloc(sizeof(struct ath_usb_udc), GFP_ATOMIC);
if (udc == NULL) {
ath_usb_error("Unable to allocate udc device\n");
return -ENOMEM;
}
memset(udc, 0, sizeof(struct ath_usb_udc));
udc->ath_usb_otg = ath_usb_otg;
udc->gadget.is_otg = 1;
udc->op_base = ath_usb_otg->usb_reg;
if (ath_usb_udc_init(udc, ath_usb_otg->dev) < 0) {
kfree(udc);
return -ENODEV;
}
return 0;
}
static int ath_usb_udc_remove(void)
{
struct ath_usb_udc *udc = ap_gadget;
if (udc) {
ath_usb_udc_mem_free(udc);
udc->ath_usb_otg = NULL;
device_unregister(&udc->gadget.dev);
kfree(udc);
}
ap_gadget = NULL;
return 0;
}
#endif
static int ath_usb_udc_read_procmem(char *buf, char **start, off_t offset,
int count, int *eof, void *data)
{
return sprintf(buf,
"Total interrupt count = %li\n"
"Total complete count = %li\n"
"Total actual data count = %li\n"
"DTD alloc count = %li\n"
"Start transfer count = %li\n"
"Endpoint queue count = %li\n"
"Retire dtd count = %li\n"
"Case1 = %li Case2 = %li\n",
int_count, complete_count, actual_data_count,
alloc_init_dtd_count, start_trans_count,
queue_count, retire_dtd_count,
case1, case2);
}
static int __init ath_usb_init(void)
{
ath_usb_debug_fn("__enter %s\n", __func__);
create_proc_read_entry("udc", 0, NULL,
ath_usb_udc_read_procmem, NULL);
#ifdef CONFIG_MACH_HORNET
printk("%s: id: %lx\n", __func__,
(unsigned long) ar7240_reg_rd(AR7240_REV_ID));
#else
printk("%s: id: %lx\n", __func__,
(unsigned long) ath_reg_rd(ATH_REV_ID));
#endif
#ifdef CONFIG_USB_ATH_OTG
return (ath_usb_udc_probe());
#else
return platform_driver_register(&ath_usb_udc_drv);
#endif
}
static void __exit ath_usb_exit(void)
{
ath_usb_debug_fn("__enter %s\n", __func__);
#ifdef CONFIG_USB_ATH_OTG
ath_usb_udc_remove();
#else
platform_driver_unregister(&ath_usb_udc_drv);
#endif
remove_proc_entry("udc", NULL);
}
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
arch_initcall(ath_usb_init);
module_exit(ath_usb_exit);