// SPDX-License-Identifier: GPL-2.0
/*
* FOTG210 UDC Driver supports Bulk transfer so far
*
* Copyright (C) 2013 Faraday Technology Corporation
*
* Author : Yuan-Hsin Chen <yhchen@faraday-tech.com>
*/
#include <linux/delay.h>
#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 <linux/usb/otg.h>
#include <linux/usb/phy.h>
#include "fotg210.h"
#include "fotg210-udc.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_ack_int(struct fotg210_udc *fotg210, u32 offset, u32 mask)
{
u32 value = ioread32(fotg210->reg + offset);
value &= ~mask;
iowrite32(value, fotg210->reg + offset);
}
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);
usb_gadget_giveback_request(&ep->ep, &req->req);
spin_lock(&ep->fotg210->lock);
if (ep->epnum) {
if (list_empty(&ep->queue))
fotg210_disable_fifo_int