/*
* FOTG210 UDC Driver supports Bulk transfer so far
*
* Copyright (C) 2013 Faraday Technology Corporation
*
* Author : Yuan-Hsin Chen <yhchen@faraday-tech.com>
*
* 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; version 2 of the License.
*/
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include "fotg210.h"
#define DRIVER_DESC "FOTG210 USB Device Controller Driver"
#define DRIVER_VERSION "30-April-2013"
static const char udc_name[] = "fotg210_udc";
static const char * const fotg210_ep_name[] = {
"ep0", "ep1", "ep2", "ep3", "ep4"};
static void fotg210_disable_fifo_int(struct fotg210_ep *ep)
{
u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR1);
if (ep->dir_in)
value |= DMISGR1_MF_IN_INT(ep->epnum - 1);
else
value |= DMISGR1_MF_OUTSPK_INT(ep->epnum - 1);
iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR1);
}
static void fotg210_enable_fifo_int(struct fotg210_ep *ep)
{
u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR1);
if (ep->dir_in)
value &= ~DMISGR1_MF_IN_INT(ep->epnum - 1);
else
value &= ~DMISGR1_MF_OUTSPK_INT(ep->epnum - 1);
iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR1);
}
static void fotg210_set_cxdone(struct fotg210_udc *fotg210)
{
u32 value = ioread32(fotg210->reg + FOTG210_DCFESR);
value |= DCFESR_CX_DONE;
iowrite32(value, fotg210->reg + FOTG210_DCFESR);
}
static void fotg210_done(struct fotg210_ep *ep, struct fotg210_request *req,
int status)
{
list_del_init(&req->queue);
/* don't modify queue heads during completion callback */
if (ep->fotg210->gadget.speed == USB_SPEED_UNKNOWN)
req->req.status = -ESHUTDOWN;
else
req->req.status = status;
spin_unlock(&ep->fotg210->lock);
req->req.complete(&ep->ep, &req->req);
spin_lock(&ep->fotg210->lock);
if (ep->epnum) {
if (list_empty(&ep->queue))
fotg210_disable_fifo_int(ep);
} else {
fotg210_set_cxdone(ep->fotg210);
}
}
static void fotg210_fifo_ep_mapping(struct fotg210_ep *ep, u32 epnum,
u32 dir_in)
{
struct fotg210_udc *fotg210 = ep->fotg210;
u32 val;
/* Driver should map an ep to a fifo and then map the fifo
* to the ep. What a brain-damaged design!
*/
/* map a fifo to an ep */
val = ioread32(fotg210->reg + FOTG210_EPMAP);
val &= ~EPMAP_FIFONOMSK(epnum,