/*
* Driver for the NXP ISP1761 device controller
*
* Copyright 2014 Ideas on Board Oy
*
* Contacts:
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/usb.h>
#include "isp1760-core.h"
#include "isp1760-regs.h"
#include "isp1760-udc.h"
#define ISP1760_VBUS_POLL_INTERVAL msecs_to_jiffies(500)
struct isp1760_request {
struct usb_request req;
struct list_head queue;
struct isp1760_ep *ep;
unsigned int packet_size;
};
static inline struct isp1760_udc *gadget_to_udc(struct usb_gadget *gadget)
{
return container_of(gadget, struct isp1760_udc, gadget);
}
static inline struct isp1760_ep *ep_to_udc_ep(struct usb_ep *ep)
{
return container_of(ep, struct isp1760_ep, ep);
}
static inline struct isp1760_request *req_to_udc_req(struct usb_request *req)
{
return container_of(req, struct isp1760_request, req);
}
static inline u32 isp1760_udc_read(struct isp1760_udc *udc, u16 reg)
{
return isp1760_read32(udc->regs, reg);
}
static inline void isp1760_udc_write(struct isp1760_udc *udc, u16 reg, u32 val)
{
isp1760_write32(udc->regs, reg, val);
}
/* -----------------------------------------------------------------------------
* Endpoint Management
*/
static struct isp1760_ep *isp1760_udc_find_ep(struct isp1760_udc *udc,
u16 index)
{
unsigned int i;
if (index == 0)
return &udc->ep[0];
for (i = 1; i < ARRAY_SIZE(udc->ep); ++i) {
if (udc->ep[i].addr == index)
return udc->ep[i].desc ? &udc->ep[i] : NULL;
}
return NULL;
}
static void __isp1760_udc_select_ep(struct isp1760_ep *ep, int dir)
{
isp1760_udc_write(ep->udc, DC_EPINDEX,
DC_ENDPIDX(ep->addr & USB_ENDPOINT_NUMBER_MASK) |
(dir == USB_DIR_IN ? DC_EPDIR : 0));
}
/**
* isp1760_udc_select_ep - Select an endpoint for register access
* @ep: The endpoint
*
* The ISP1761 endpoint registers are banked. This function selects the target
* endpoint for banked register access. The selection remains valid until the
* next call to this function, the next direct access to the EPINDEX register
* or the next reset, whichever comes first.
*
* Called with the UDC spinlock held.
*/
static void isp1760_udc_select_ep(struct isp1760_ep *ep)
{
__isp1760_udc_select_ep(ep, ep->addr & USB_ENDPOINT_DIR_MASK);
}
/* Called with the UDC spinlock held. */
static void isp1760_udc_ctrl_send_status(struct isp1760_ep *ep, int dir)
{
struct isp1760_udc *udc = ep->udc;
/*
* Proceed to the status stage. The status stage data packet flows in
* the direction opposite to the data stage data packets, we thus need
* to select the OUT/IN endpoint for IN/OUT transfers.
*/
isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) |
(dir == USB_DIR_IN ? 0 : DC_EPDIR));
isp1760_udc_write(udc, DC_CTRLFUNC, DC_STATUS);
/*
* The hardware will terminate the request automatically and go back to
* the setup stage without notifying us.
*/
udc->ep0_state = ISP1760_CTRL_SETUP;
}
/* Called without the UDC spinlock held. */
static void isp1760_udc_request_complete(struct isp1760_ep *ep,
struct isp1760_request *req,
int status)
{
struct isp1760_udc *udc = ep->udc;
unsigned long flags;
dev_dbg(ep->udc->isp->dev, "completing request %p with status %d\n",
req, status);
req->ep = NULL;
req->req.status = status;
req->req.complete(&ep->ep, &req->req);
spin_lock_irqsave(&udc->lock, flags);
/*
* When completing control OUT requests, move to the status stage after
* calling the request complete callback. This gives the gadget an
* opportunity to stall the control transfer if needed.
*/
if (status == 0 && ep->addr == 0 && udc->ep0_dir == USB_DIR_OUT)
isp1760_udc_ctrl_send_status(ep, USB_DIR_OUT);
spin_unlock_irqrestore(&udc->lock, flags);
}
static void isp1760_udc_ctrl_send_stall(struct isp1760_ep *ep)
{
struct isp1760_udc *udc = ep->udc;
unsigned long flags;
dev_dbg(ep->udc->isp->dev, "%s(ep%02x)\n", __func__, ep->addr);
spin_lock_irqsave(&udc->lock, flags);
/* Stall both the IN and OUT endpoints. */
__isp1760_udc_select_ep(ep, USB_DIR_OUT);
isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL);
__isp1760_udc_select_ep(ep, USB_DIR_IN);
isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL);
/* A protocol stall completes the control transaction. */
udc->ep0_state = ISP1760_CTRL_SETUP;
spin_unlock_irqrestore(&udc->lock, flags);
}
/* -----------------------------------------------------------------------------
* Data Endpoints
*/
/* Called with the UDC spinlock held. */
static bool isp1760_udc_receive(struct isp1760_ep *ep,
struct isp1760_request *req)
{
struct isp1760_udc *udc = ep->udc;
unsigned int len;
u32 *buf;
int i;
isp1760_udc_select_ep(ep);
len = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK;
dev_dbg(udc->isp->dev, "%s: received %u bytes (%u/%u done)\n",
__func__, len, req->req.actual, req->req.length);
len = min(len, req->req.length - req->req.actual);
if (!len) {
/*
* There's no data to be read from the FIFO, acknowledge the RX
* interrupt by clearing the buffer.
*
* TODO: What if another packet arrives in the meantime ? The
* datasheet doesn't clearly document how this should be
* handled.
*/
isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
return false;
}
buf = req->req.buf + req->req.actual;
/*
* Make sure not to read more than one extra byte, otherwise data from
* the next packet might be removed from the FIFO.
*/
for (i = len; i > 2; i -= 4, ++buf)
*buf = le32_to_cpu(isp1760_udc_read(udc, DC_DATAPORT));
if (i > 0)
*(u16 *)buf = le16_to_cpu(readw(udc->regs + DC_DATAPORT));
req->req.actual += len;
/*
* TODO: The short_not_ok flag isn't supported yet, but isn't used by
* any gadget driver either.
*/
dev_dbg(udc->isp->dev,
"%s: req %p actual/length %u/%u maxpacket %u packet size %u\n",
__func__, req, req->req.actual, req->req.length, ep->maxpacket,
len);
ep->rx_pending = false;
/*
* Complete the request if all data has been received or if a short
* packet has been received.
*/
if (req->req.actual == req->req.length || len < ep->maxpacket) {
list_del(&req->queue);
return true;
}
return false;
}
static void isp1760_udc_transmit(struct isp1760_ep *ep,
struct isp1760_request *req)
{
struct isp1760_udc *udc = ep->udc;
u32 *buf = req->req.buf + req->req.actual;
int i;
req->packet_size = min(req->req.length - req->req.actual,
ep->maxpacket);
dev_dbg(udc->isp->dev, "%s: transferring %u bytes (%u/%u done)\n",
__func__, req->packet_size, req->req.actual,
req->req.length);
__isp1760_udc_select_ep(ep, USB_DIR_IN);
if (req->packet_size)
isp1760_udc_write(udc, DC_BUFLEN, req->packet_size);
/*
* Make sure not to write more than one extra byte, otherwise extra data
* will stay in the FIFO and will be transmitted during the next control
* request. The endpoint control CLBUF bit is supposed to allow flushing
* the FIFO for this kind of conditions, but doesn't seem to work.
*/
for (i = req->packet_size; i > 2; i -= 4, ++buf)
isp1760_udc_write(udc, DC_DATAPORT, cpu_to_le32(*buf));
if (i > 0)
writew(cpu_to_le16(*(u16 *)buf), udc->regs + DC_DATAPORT);
if (ep->addr == 0)
isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
if (!req->packet_size)
isp1760_udc_write(udc, DC_CTRLFUNC, DC_VENDP);
}
static void isp1760_ep_rx_ready(struct isp1760_ep *ep)
{
struct isp1760_u
|