You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-gadget/next' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
* 'for-gadget/next' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb: (24 commits) usb: dwc3: gadget: add support for SG lists usb: dwc3: gadget: don't force 'LST' always usb: dwc3: gadget: don't return anything on prepare trbs usb: dwc3: gadget: re-factor dwc3_prepare_trbs() usb: gadget: introduce support for sg lists usb: renesas: pipe: convert a long if into a XOR operation usb: gadget: remove useless depends on Kconfig usb: gadget: s3c-hsudc: remove the_controller global usb: gadget: s3c-hsudc: use release_mem_region instead of release_resource usb: gadget: s3c-hsudc: Add regulator handling usb: gadget: s3c-hsudc: use udc_start and udc_stop functions usb: gadget: s3c-hsudc: move device registration to probe usb: gadget: s3c-hsudc: add missing otg_put_transceiver in probe usb: gadget: s3c-hsudc: add __devinit to probe function usb: gadget: s3c-hsudc: move platform_data struct to global header USB: EHCI: Add Marvell Host Controller driver USB: OTG: add Marvell usb OTG driver support usb: gadget: mv_udc: drop ARCH dependency usb: gadget: mv_udc: fix bug in ep_dequeue usb: gadget: enlarge maxburst bit width. ...
This commit is contained in:
@@ -50,6 +50,7 @@
|
||||
#include <plat/nand.h>
|
||||
#include <plat/sdhci.h>
|
||||
#include <plat/udc.h>
|
||||
#include <linux/platform_data/s3c-hsudc.h>
|
||||
|
||||
#include <plat/regs-fb-v4.h>
|
||||
#include <plat/fb.h>
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_data/s3c-hsudc.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/pmu.h>
|
||||
|
||||
@@ -37,20 +37,7 @@ struct s3c2410_udc_mach_info {
|
||||
|
||||
extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *);
|
||||
|
||||
/**
|
||||
* s3c24xx_hsudc_platdata - Platform data for USB High-Speed gadget controller.
|
||||
* @epnum: Number of endpoints to be instantiated by the controller driver.
|
||||
* @gpio_init: Platform specific USB related GPIO initialization.
|
||||
* @gpio_uninit: Platform specific USB releted GPIO uninitialzation.
|
||||
*
|
||||
* Representation of platform data for the S3C24XX USB 2.0 High Speed gadget
|
||||
* controllers.
|
||||
*/
|
||||
struct s3c24xx_hsudc_platdata {
|
||||
unsigned int epnum;
|
||||
void (*gpio_init)(void);
|
||||
void (*gpio_uninit)(void);
|
||||
};
|
||||
struct s3c24xx_hsudc_platdata;
|
||||
|
||||
extern void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd);
|
||||
|
||||
|
||||
+164
-83
@@ -65,6 +65,22 @@ void dwc3_map_buffer_to_dma(struct dwc3_request *req)
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->request.num_sgs) {
|
||||
int mapped;
|
||||
|
||||
mapped = dma_map_sg(dwc->dev, req->request.sg,
|
||||
req->request.num_sgs,
|
||||
req->direction ? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
if (mapped < 0) {
|
||||
dev_err(dwc->dev, "failed to map SGs\n");
|
||||
return;
|
||||
}
|
||||
|
||||
req->request.num_mapped_sgs = mapped;
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->request.dma == DMA_ADDR_INVALID) {
|
||||
req->request.dma = dma_map_single(dwc->dev, req->request.buf,
|
||||
req->request.length, req->direction
|
||||
@@ -82,6 +98,17 @@ void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->request.num_mapped_sgs) {
|
||||
req->request.dma = DMA_ADDR_INVALID;
|
||||
dma_unmap_sg(dwc->dev, req->request.sg,
|
||||
req->request.num_sgs,
|
||||
req->direction ? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
|
||||
req->request.num_mapped_sgs = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->mapped) {
|
||||
dma_unmap_single(dwc->dev, req->request.dma,
|
||||
req->request.length, req->direction
|
||||
@@ -97,7 +124,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
|
||||
if (req->queued) {
|
||||
dep->busy_slot++;
|
||||
if (req->request.num_mapped_sgs)
|
||||
dep->busy_slot += req->request.num_mapped_sgs;
|
||||
else
|
||||
dep->busy_slot++;
|
||||
|
||||
/*
|
||||
* Skip LINK TRB. We can't use req->trb and check for
|
||||
* DWC3_TRBCTL_LINK_TRB because it points the TRB we just
|
||||
@@ -108,6 +139,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
dep->busy_slot++;
|
||||
}
|
||||
list_del(&req->list);
|
||||
req->trb = NULL;
|
||||
|
||||
if (req->request.status == -EINPROGRESS)
|
||||
req->request.status = status;
|
||||
@@ -544,6 +576,85 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
|
||||
kfree(req);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_prepare_one_trb - setup one TRB from one request
|
||||
* @dep: endpoint for which this request is prepared
|
||||
* @req: dwc3_request pointer
|
||||
*/
|
||||
static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
||||
struct dwc3_request *req, dma_addr_t dma,
|
||||
unsigned length, unsigned last, unsigned chain)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
struct dwc3_trb_hw *trb_hw;
|
||||
struct dwc3_trb trb;
|
||||
|
||||
unsigned int cur_slot;
|
||||
|
||||
dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
|
||||
dep->name, req, (unsigned long long) dma,
|
||||
length, last ? " last" : "",
|
||||
chain ? " chain" : "");
|
||||
|
||||
trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
|
||||
cur_slot = dep->free_slot;
|
||||
dep->free_slot++;
|
||||
|
||||
/* Skip the LINK-TRB on ISOC */
|
||||
if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
|
||||
usb_endpoint_xfer_isoc(dep->desc))
|
||||
return;
|
||||
|
||||
memset(&trb, 0, sizeof(trb));
|
||||
if (!req->trb) {
|
||||
dwc3_gadget_move_request_queued(req);
|
||||
req->trb = trb_hw;
|
||||
req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
|
||||
}
|
||||
|
||||
if (usb_endpoint_xfer_isoc(dep->desc)) {
|
||||
trb.isp_imi = true;
|
||||
trb.csp = true;
|
||||
} else {
|
||||
trb.chn = chain;
|
||||
trb.lst = last;
|
||||
}
|
||||
|
||||
if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
|
||||
trb.sid_sofn = req->request.stream_id;
|
||||
|
||||
switch (usb_endpoint_type(dep->desc)) {
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
|
||||
|
||||
/* IOC every DWC3_TRB_NUM / 4 so we can refill */
|
||||
if (!(cur_slot % (DWC3_TRB_NUM / 4)))
|
||||
trb.ioc = last;
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
trb.trbctl = DWC3_TRBCTL_NORMAL;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* This is only possible with faulty memory because we
|
||||
* checked it already :)
|
||||
*/
|
||||
BUG();
|
||||
}
|
||||
|
||||
trb.length = length;
|
||||
trb.bplh = dma;
|
||||
trb.hwo = true;
|
||||
|
||||
dwc3_trb_to_hw(&trb, trb_hw);
|
||||
}
|
||||
|
||||
/*
|
||||
* dwc3_prepare_trbs - setup TRBs from requests
|
||||
* @dep: endpoint for which requests are being prepared
|
||||
@@ -553,18 +664,17 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
|
||||
* transfers. The functions returns once there are not more TRBs available or
|
||||
* it run out of requests.
|
||||
*/
|
||||
static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
|
||||
bool starting)
|
||||
static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
|
||||
{
|
||||
struct dwc3_request *req, *n, *ret = NULL;
|
||||
struct dwc3_trb_hw *trb_hw;
|
||||
struct dwc3_trb trb;
|
||||
struct dwc3_request *req, *n;
|
||||
u32 trbs_left;
|
||||
unsigned int last_one = 0;
|
||||
|
||||
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
|
||||
|
||||
/* the first request must not be queued */
|
||||
trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
|
||||
|
||||
/*
|
||||
* if busy & slot are equal than it is either full or empty. If we are
|
||||
* starting to proceed requests then we are empty. Otherwise we ar
|
||||
@@ -572,7 +682,7 @@ static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
|
||||
*/
|
||||
if (!trbs_left) {
|
||||
if (!starting)
|
||||
return NULL;
|
||||
return;
|
||||
trbs_left = DWC3_TRB_NUM;
|
||||
/*
|
||||
* In case we start from scratch, we queue the ISOC requests
|
||||
@@ -596,94 +706,62 @@ static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
|
||||
|
||||
/* The last TRB is a link TRB, not used for xfer */
|
||||
if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
|
||||
return NULL;
|
||||
return;
|
||||
|
||||
list_for_each_entry_safe(req, n, &dep->request_list, list) {
|
||||
unsigned int last_one = 0;
|
||||
unsigned int cur_slot;
|
||||
unsigned length;
|
||||
dma_addr_t dma;
|
||||
|
||||
trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
|
||||
cur_slot = dep->free_slot;
|
||||
dep->free_slot++;
|
||||
if (req->request.num_mapped_sgs > 0) {
|
||||
struct usb_request *request = &req->request;
|
||||
struct scatterlist *sg = request->sg;
|
||||
struct scatterlist *s;
|
||||
int i;
|
||||
|
||||
/* Skip the LINK-TRB on ISOC */
|
||||
if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
|
||||
usb_endpoint_xfer_isoc(dep->desc))
|
||||
continue;
|
||||
for_each_sg(sg, s, request->num_mapped_sgs, i) {
|
||||
unsigned chain = true;
|
||||
|
||||
dwc3_gadget_move_request_queued(req);
|
||||
memset(&trb, 0, sizeof(trb));
|
||||
trbs_left--;
|
||||
length = sg_dma_len(s);
|
||||
dma = sg_dma_address(s);
|
||||
|
||||
/* Is our TRB pool empty? */
|
||||
if (!trbs_left)
|
||||
last_one = 1;
|
||||
/* Is this the last request? */
|
||||
if (list_empty(&dep->request_list))
|
||||
last_one = 1;
|
||||
if (i == (request->num_mapped_sgs - 1)
|
||||
|| sg_is_last(s)) {
|
||||
last_one = true;
|
||||
chain = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME we shouldn't need to set LST bit always but we are
|
||||
* facing some weird problem with the Hardware where it doesn't
|
||||
* complete even though it has been previously started.
|
||||
*
|
||||
* While we're debugging the problem, as a workaround to
|
||||
* multiple TRBs handling, use only one TRB at a time.
|
||||
*/
|
||||
last_one = 1;
|
||||
trbs_left--;
|
||||
if (!trbs_left)
|
||||
last_one = true;
|
||||
|
||||
req->trb = trb_hw;
|
||||
if (!ret)
|
||||
ret = req;
|
||||
if (last_one)
|
||||
chain = false;
|
||||
|
||||
trb.bplh = req->request.dma;
|
||||
dwc3_prepare_one_trb(dep, req, dma, length,
|
||||
last_one, chain);
|
||||
|
||||
if (usb_endpoint_xfer_isoc(dep->desc)) {
|
||||
trb.isp_imi = true;
|
||||
trb.csp = true;
|
||||
if (last_one)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
trb.lst = last_one;
|
||||
dma = req->request.dma;
|
||||
length = req->request.length;
|
||||
trbs_left--;
|
||||
|
||||
if (!trbs_left)
|
||||
last_one = 1;
|
||||
|
||||
/* Is this the last request? */
|
||||
if (list_is_last(&req->list, &dep->request_list))
|
||||
last_one = 1;
|
||||
|
||||
dwc3_prepare_one_trb(dep, req, dma, length,
|
||||
last_one, false);
|
||||
|
||||
if (last_one)
|
||||
break;
|
||||
}
|
||||
|
||||
if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
|
||||
trb.sid_sofn = req->request.stream_id;
|
||||
|
||||
switch (usb_endpoint_type(dep->desc)) {
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
|
||||
|
||||
/* IOC every DWC3_TRB_NUM / 4 so we can refill */
|
||||
if (!(cur_slot % (DWC3_TRB_NUM / 4)))
|
||||
trb.ioc = last_one;
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
trb.trbctl = DWC3_TRBCTL_NORMAL;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* This is only possible with faulty memory because we
|
||||
* checked it already :)
|
||||
*/
|
||||
BUG();
|
||||
}
|
||||
|
||||
trb.length = req->request.length;
|
||||
trb.hwo = true;
|
||||
|
||||
dwc3_trb_to_hw(&trb, trb_hw);
|
||||
req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
|
||||
|
||||
if (last_one)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
|
||||
@@ -712,11 +790,13 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
|
||||
/* req points to the first request which will be sent */
|
||||
req = next_request(&dep->req_queued);
|
||||
} else {
|
||||
dwc3_prepare_trbs(dep, start_new);
|
||||
|
||||
/*
|
||||
* req points to the first request where HWO changed
|
||||
* from 0 to 1
|
||||
*/
|
||||
req = dwc3_prepare_trbs(dep, start_new);
|
||||
req = next_request(&dep->req_queued);
|
||||
}
|
||||
if (!req) {
|
||||
dep->flags |= DWC3_EP_PENDING_REQUEST;
|
||||
@@ -2093,6 +2173,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
|
||||
dwc->gadget.max_speed = USB_SPEED_SUPER;
|
||||
dwc->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
dwc->gadget.dev.parent = dwc->dev;
|
||||
dwc->gadget.sg_supported = true;
|
||||
|
||||
dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
|
||||
|
||||
|
||||
@@ -125,7 +125,6 @@ config USB_GADGET_STORAGE_NUM_BUFFERS
|
||||
#
|
||||
choice
|
||||
prompt "USB Peripheral Controller"
|
||||
depends on USB_GADGET
|
||||
help
|
||||
A USB device uses a controller to talk to its host.
|
||||
Systems should have only one such upstream link.
|
||||
@@ -310,13 +309,13 @@ config USB_S3C_HSUDC
|
||||
|
||||
This driver has been tested on S3C2416 and S3C2450 processors.
|
||||
|
||||
config USB_PXA_U2O
|
||||
tristate "PXA9xx Processor USB2.0 controller"
|
||||
depends on ARCH_MMP
|
||||
config USB_MV_UDC
|
||||
tristate "Marvell USB2.0 Device Controller"
|
||||
select USB_GADGET_DUALSPEED
|
||||
help
|
||||
PXA9xx Processor series include a high speed USB2.0 device
|
||||
controller, which support high speed and full speed USB peripheral.
|
||||
Marvell Socs (including PXA and MMP series) include a high speed
|
||||
USB2.0 OTG controller, which can be configured as high speed or
|
||||
full speed USB peripheral.
|
||||
|
||||
#
|
||||
# Controllers available in both integrated and discrete versions
|
||||
@@ -532,12 +531,10 @@ endchoice
|
||||
# Selected by UDC drivers that support high-speed operation.
|
||||
config USB_GADGET_DUALSPEED
|
||||
bool
|
||||
depends on USB_GADGET
|
||||
|
||||
# Selected by UDC drivers that support super-speed opperation
|
||||
config USB_GADGET_SUPERSPEED
|
||||
bool
|
||||
depends on USB_GADGET
|
||||
depends on USB_GADGET_DUALSPEED
|
||||
|
||||
#
|
||||
@@ -545,7 +542,6 @@ config USB_GADGET_SUPERSPEED
|
||||
#
|
||||
choice
|
||||
tristate "USB Gadget Drivers"
|
||||
depends on USB_GADGET
|
||||
default USB_ETH
|
||||
help
|
||||
A Linux "Gadget Driver" talks to the USB Peripheral Controller
|
||||
|
||||
@@ -27,7 +27,7 @@ obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
|
||||
obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o
|
||||
obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
|
||||
obj-$(CONFIG_USB_EG20T) += pch_udc.o
|
||||
obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o
|
||||
obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
|
||||
mv_udc-y := mv_udc_core.o
|
||||
obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o
|
||||
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
|
||||
|
||||
@@ -180,7 +180,7 @@ struct mv_udc {
|
||||
|
||||
struct mv_cap_regs __iomem *cap_regs;
|
||||
struct mv_op_regs __iomem *op_regs;
|
||||
unsigned int phy_regs;
|
||||
void __iomem *phy_regs;
|
||||
unsigned int max_eps;
|
||||
struct mv_dqh *ep_dqh;
|
||||
size_t ep_dqh_size;
|
||||
|
||||
@@ -276,11 +276,12 @@ static void done(struct mv_ep *ep, struct mv_req *req, int status)
|
||||
|
||||
static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
|
||||
{
|
||||
u32 tmp, epstatus, bit_pos, direction;
|
||||
struct mv_udc *udc;
|
||||
struct mv_dqh *dqh;
|
||||
u32 bit_pos, direction;
|
||||
u32 usbcmd, epstatus;
|
||||
unsigned int loops;
|
||||
int readsafe, retval = 0;
|
||||
int retval = 0;
|
||||
|
||||
udc = ep->udc;
|
||||
direction = ep_dir(ep);
|
||||
@@ -293,30 +294,18 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
|
||||
lastreq = list_entry(ep->queue.prev, struct mv_req, queue);
|
||||
lastreq->tail->dtd_next =
|
||||
req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
|
||||
if (readl(&udc->op_regs->epprime) & bit_pos) {
|
||||
loops = LOOPS(PRIME_TIMEOUT);
|
||||
while (readl(&udc->op_regs->epprime) & bit_pos) {
|
||||
if (loops == 0) {
|
||||
retval = -ETIME;
|
||||
goto done;
|
||||
}
|
||||
udelay(LOOPS_USEC);
|
||||
loops--;
|
||||
}
|
||||
if (readl(&udc->op_regs->epstatus) & bit_pos)
|
||||
goto done;
|
||||
}
|
||||
readsafe = 0;
|
||||
|
||||
wmb();
|
||||
|
||||
if (readl(&udc->op_regs->epprime) & bit_pos)
|
||||
goto done;
|
||||
|
||||
loops = LOOPS(READSAFE_TIMEOUT);
|
||||
while (readsafe == 0) {
|
||||
if (loops == 0) {
|
||||
retval = -ETIME;
|
||||
goto done;
|
||||
}
|
||||
while (1) {
|
||||
/* start with setting the semaphores */
|
||||
tmp = readl(&udc->op_regs->usbcmd);
|
||||
tmp |= USBCMD_ATDTW_TRIPWIRE_SET;
|
||||
writel(tmp, &udc->op_regs->usbcmd);
|
||||
usbcmd = readl(&udc->op_regs->usbcmd);
|
||||
usbcmd |= USBCMD_ATDTW_TRIPWIRE_SET;
|
||||
writel(usbcmd, &udc->op_regs->usbcmd);
|
||||
|
||||
/* read the endpoint status */
|
||||
epstatus = readl(&udc->op_regs->epstatus) & bit_pos;
|
||||
@@ -329,98 +318,46 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
|
||||
* primed.
|
||||
*/
|
||||
if (readl(&udc->op_regs->usbcmd)
|
||||
& USBCMD_ATDTW_TRIPWIRE_SET) {
|
||||
readsafe = 1;
|
||||
}
|
||||
& USBCMD_ATDTW_TRIPWIRE_SET)
|
||||
break;
|
||||
|
||||
loops--;
|
||||
if (loops == 0) {
|
||||
dev_err(&udc->dev->dev,
|
||||
"Timeout for ATDTW_TRIPWIRE...\n");
|
||||
retval = -ETIME;
|
||||
goto done;
|
||||
}
|
||||
udelay(LOOPS_USEC);
|
||||
}
|
||||
|
||||
/* Clear the semaphore */
|
||||
tmp = readl(&udc->op_regs->usbcmd);
|
||||
tmp &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
|
||||
writel(tmp, &udc->op_regs->usbcmd);
|
||||
usbcmd = readl(&udc->op_regs->usbcmd);
|
||||
usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
|
||||
writel(usbcmd, &udc->op_regs->usbcmd);
|
||||
|
||||
/* If endpoint is not active, we activate it now. */
|
||||
if (!epstatus) {
|
||||
if (direction == EP_DIR_IN) {
|
||||
struct mv_dtd *curr_dtd = dma_to_virt(
|
||||
&udc->dev->dev, dqh->curr_dtd_ptr);
|
||||
|
||||
loops = LOOPS(DTD_TIMEOUT);
|
||||
while (curr_dtd->size_ioc_sts
|
||||
& DTD_STATUS_ACTIVE) {
|
||||
if (loops == 0) {
|
||||
retval = -ETIME;
|
||||
goto done;
|
||||
}
|
||||
loops--;
|
||||
udelay(LOOPS_USEC);
|
||||
}
|
||||
}
|
||||
/* No other transfers on the queue */
|
||||
|
||||
/* Write dQH next pointer and terminate bit to 0 */
|
||||
dqh->next_dtd_ptr = req->head->td_dma
|
||||
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
|
||||
dqh->size_ioc_int_sts = 0;
|
||||
|
||||
/*
|
||||
* Ensure that updates to the QH will
|
||||
* occur before priming.
|
||||
*/
|
||||
wmb();
|
||||
|
||||
/* Prime the Endpoint */
|
||||
writel(bit_pos, &udc->op_regs->epprime);
|
||||
}
|
||||
} else {
|
||||
/* Write dQH next pointer and terminate bit to 0 */
|
||||
dqh->next_dtd_ptr = req->head->td_dma
|
||||
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
|
||||
dqh->size_ioc_int_sts = 0;
|
||||
|
||||
/* Ensure that updates to the QH will occur before priming. */
|
||||
wmb();
|
||||
|
||||
/* Prime the Endpoint */
|
||||
writel(bit_pos, &udc->op_regs->epprime);
|
||||
|
||||
if (direction == EP_DIR_IN) {
|
||||
/* FIXME add status check after prime the IN ep */
|
||||
int prime_again;
|
||||
u32 curr_dtd_ptr = dqh->curr_dtd_ptr;
|
||||
|
||||
loops = LOOPS(DTD_TIMEOUT);
|
||||
prime_again = 0;
|
||||
while ((curr_dtd_ptr != req->head->td_dma)) {
|
||||
curr_dtd_ptr = dqh->curr_dtd_ptr;
|
||||
if (loops == 0) {
|
||||
dev_err(&udc->dev->dev,
|
||||
"failed to prime %s\n",
|
||||
ep->name);
|
||||
retval = -ETIME;
|
||||
goto done;
|
||||
}
|
||||
loops--;
|
||||
udelay(LOOPS_USEC);
|
||||
|
||||
if (loops == (LOOPS(DTD_TIMEOUT) >> 2)) {
|
||||
if (prime_again)
|
||||
goto done;
|
||||
dev_info(&udc->dev->dev,
|
||||
"prime again\n");
|
||||
writel(bit_pos,
|
||||
&udc->op_regs->epprime);
|
||||
prime_again = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (epstatus)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Write dQH next pointer and terminate bit to 0 */
|
||||
dqh->next_dtd_ptr = req->head->td_dma
|
||||
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
|
||||
|
||||
/* clear active and halt bit, in case set from a previous error */
|
||||
dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
|
||||
|
||||
/* Ensure that updates to the QH will occure before priming. */
|
||||
wmb();
|
||||
|
||||
/* Prime the Endpoint */
|
||||
writel(bit_pos, &udc->op_regs->epprime);
|
||||
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
|
||||
dma_addr_t *dma, int *is_last)
|
||||
{
|
||||
@@ -841,6 +778,27 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mv_prime_ep(struct mv_ep *ep, struct mv_req *req)
|
||||
{
|
||||
struct mv_dqh *dqh = ep->dqh;
|
||||
u32 bit_pos;
|
||||
|
||||
/* Write dQH next pointer and terminate bit to 0 */
|
||||
dqh->next_dtd_ptr = req->head->td_dma
|
||||
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
|
||||
|
||||
/* clear active and halt bit, in case set from a previous error */
|
||||
dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
|
||||
|
||||
/* Ensure that updates to the QH will occure before priming. */
|
||||
wmb();
|
||||
|
||||
bit_pos = 1 << (((ep_dir(ep) == EP_DIR_OUT) ? 0 : 16) + ep->ep_num);
|
||||
|
||||
/* Prime the Endpoint */
|
||||
writel(bit_pos, &ep->udc->op_regs->epprime);
|
||||
}
|
||||
|
||||
/* dequeues (cancels, unlinks) an I/O request from an endpoint */
|
||||
static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
|
||||
{
|
||||
@@ -883,15 +841,13 @@ static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
|
||||
|
||||
/* The request isn't the last request in this ep queue */
|
||||
if (req->queue.next != &ep->queue) {
|
||||
struct mv_dqh *qh;
|
||||
struct mv_req *next_req;
|
||||
|
||||
qh = ep->dqh;
|
||||
next_req = list_entry(req->queue.next, struct mv_req,
|
||||
queue);
|
||||
next_req = list_entry(req->queue.next,
|
||||
struct mv_req, queue);
|
||||
|
||||
/* Point the QH to the first TD of next request */
|
||||
writel((u32) next_req->head, &qh->curr_dtd_ptr);
|
||||
mv_prime_ep(ep, next_req);
|
||||
} else {
|
||||
struct mv_dqh *qh;
|
||||
|
||||
@@ -1196,7 +1152,7 @@ static int mv_udc_get_frame(struct usb_gadget *gadget)
|
||||
|
||||
udc = container_of(gadget, struct mv_udc, gadget);
|
||||
|
||||
retval = readl(udc->op_regs->frindex) & USB_FRINDEX_MASKS;
|
||||
retval = readl(&udc->op_regs->frindex) & USB_FRINDEX_MASKS;
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -2172,11 +2128,9 @@ static int __devexit mv_udc_remove(struct platform_device *dev)
|
||||
|
||||
if (udc->cap_regs)
|
||||
iounmap(udc->cap_regs);
|
||||
udc->cap_regs = NULL;
|
||||
|
||||
if (udc->phy_regs)
|
||||
iounmap((void *)udc->phy_regs);
|
||||
udc->phy_regs = 0;
|
||||
iounmap(udc->phy_regs);
|
||||
|
||||
if (udc->status_req) {
|
||||
kfree(udc->status_req->req.buf);
|
||||
@@ -2261,8 +2215,8 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
|
||||
goto err_iounmap_capreg;
|
||||
}
|
||||
|
||||
udc->phy_regs = (unsigned int)ioremap(r->start, resource_size(r));
|
||||
if (udc->phy_regs == 0) {
|
||||
udc->phy_regs = ioremap(r->start, resource_size(r));
|
||||
if (udc->phy_regs == NULL) {
|
||||
dev_err(&dev->dev, "failed to map phy I/O memory\n");
|
||||
retval = -EBUSY;
|
||||
goto err_iounmap_capreg;
|
||||
@@ -2273,7 +2227,8 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
|
||||
if (retval)
|
||||
goto err_iounmap_phyreg;
|
||||
|
||||
udc->op_regs = (struct mv_op_regs __iomem *)((u32)udc->cap_regs
|
||||
udc->op_regs =
|
||||
(struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs
|
||||
+ (readl(&udc->cap_regs->caplength_hciversion)
|
||||
& CAPLENGTH_MASK));
|
||||
udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK;
|
||||
@@ -2433,7 +2388,7 @@ err_free_dma:
|
||||
err_disable_clock:
|
||||
mv_udc_disable_internal(udc);
|
||||
err_iounmap_phyreg:
|
||||
iounmap((void *)udc->phy_regs);
|
||||
iounmap(udc->phy_regs);
|
||||
err_iounmap_capreg:
|
||||
iounmap(udc->cap_regs);
|
||||
err_put_clk:
|
||||
@@ -2524,7 +2479,7 @@ static struct platform_driver udc_driver = {
|
||||
.shutdown = mv_udc_shutdown,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "pxa-u2o",
|
||||
.name = "mv-udc",
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &mv_udc_pm_ops,
|
||||
#endif
|
||||
@@ -2532,9 +2487,8 @@ static struct platform_driver udc_driver = {
|
||||
};
|
||||
|
||||
module_platform_driver(udc_driver);
|
||||
|
||||
MODULE_ALIAS("platform:mv-udc");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:pxa-u2o");
|
||||
|
||||
@@ -28,9 +28,10 @@
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include <linux/platform_data/s3c-hsudc.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <mach/regs-s3c2443-clock.h>
|
||||
#include <plat/udc.h>
|
||||
|
||||
#define S3C_HSUDC_REG(x) (x)
|
||||
|
||||
@@ -87,6 +88,12 @@
|
||||
#define DATA_STATE_XMIT (1)
|
||||
#define DATA_STATE_RECV (2)
|
||||
|
||||
static const char * const s3c_hsudc_supply_names[] = {
|
||||
"vdda", /* analog phy supply, 3.3V */
|
||||
"vddi", /* digital phy supply, 1.2V */
|
||||
"vddosc", /* oscillator supply, 1.8V - 3.3V */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct s3c_hsudc_ep - Endpoint representation used by driver.
|
||||
* @ep: USB gadget layer representation of device endpoint.
|
||||
@@ -139,6 +146,7 @@ struct s3c_hsudc {
|
||||
struct device *dev;
|
||||
struct s3c24xx_hsudc_platdata *pd;
|
||||
struct otg_transceiver *transceiver;
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)];
|
||||
spinlock_t lock;
|
||||
void __iomem *regs;
|
||||
struct resource *mem_rsrc;
|
||||
@@ -153,7 +161,6 @@ struct s3c_hsudc {
|
||||
#define ep_index(_ep) ((_ep)->bEndpointAddress & \
|
||||
USB_ENDPOINT_NUMBER_MASK)
|
||||
|
||||
static struct s3c_hsudc *the_controller;
|
||||
static const char driver_name[] = "s3c-udc";
|
||||
static const char ep0name[] = "ep0-control";
|
||||
|
||||
@@ -282,8 +289,7 @@ static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status)
|
||||
* All the endpoints are stopped and any pending transfer requests if any on
|
||||
* the endpoint are terminated.
|
||||
*/
|
||||
static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc,
|
||||
struct usb_gadget_driver *driver)
|
||||
static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc)
|
||||
{
|
||||
struct s3c_hsudc_ep *hsep;
|
||||
int epnum;
|
||||
@@ -295,10 +301,6 @@ static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc,
|
||||
hsep->stopped = 1;
|
||||
s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
|
||||
}
|
||||
|
||||
spin_unlock(&hsudc->lock);
|
||||
driver->disconnect(&hsudc->gadget);
|
||||
spin_lock(&hsudc->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1135,16 +1137,15 @@ static irqreturn_t s3c_hsudc_irq(int irq, void *_dev)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int s3c_hsudc_start(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
static int s3c_hsudc_start(struct usb_gadget *gadget,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct s3c_hsudc *hsudc = the_controller;
|
||||
struct s3c_hsudc *hsudc = to_hsudc(gadget);
|
||||
int ret;
|
||||
|
||||
if (!driver
|
||||
|| driver->max_speed < USB_SPEED_FULL
|
||||
|| !bind
|
||||
|| !driver->unbind || !driver->disconnect || !driver->setup)
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
|
||||
if (!hsudc)
|
||||
@@ -1155,21 +1156,12 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
|
||||
|
||||
hsudc->driver = driver;
|
||||
hsudc->gadget.dev.driver = &driver->driver;
|
||||
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
ret = device_add(&hsudc->gadget.dev);
|
||||
if (ret) {
|
||||
dev_err(hsudc->dev, "failed to probe gadget device");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bind(&hsudc->gadget);
|
||||
if (ret) {
|
||||
dev_err(hsudc->dev, "%s: bind failed\n", hsudc->gadget.name);
|
||||
device_del(&hsudc->gadget.dev);
|
||||
|
||||
hsudc->driver = NULL;
|
||||
hsudc->gadget.dev.driver = NULL;
|
||||
return ret;
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies),
|
||||
hsudc->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(hsudc->dev, "failed to enable supplies: %d\n", ret);
|
||||
goto err_supplies;
|
||||
}
|
||||
|
||||
/* connect to bus through transceiver */
|
||||
@@ -1178,13 +1170,7 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
|
||||
if (ret) {
|
||||
dev_err(hsudc->dev, "%s: can't bind to transceiver\n",
|
||||
hsudc->gadget.name);
|
||||
driver->unbind(&hsudc->gadget);
|
||||
|
||||
device_del(&hsudc->gadget.dev);
|
||||
|
||||
hsudc->driver = NULL;
|
||||
hsudc->gadget.dev.driver = NULL;
|
||||
return ret;
|
||||
goto err_otg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1197,34 +1183,43 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
|
||||
hsudc->pd->gpio_init();
|
||||
|
||||
return 0;
|
||||
err_otg:
|
||||
regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
|
||||
err_supplies:
|
||||
hsudc->driver = NULL;
|
||||
hsudc->gadget.dev.driver = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
|
||||
static int s3c_hsudc_stop(struct usb_gadget *gadget,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct s3c_hsudc *hsudc = the_controller;
|
||||
struct s3c_hsudc *hsudc = to_hsudc(gadget);
|
||||
unsigned long flags;
|
||||
|
||||
if (!hsudc)
|
||||
return -ENODEV;
|
||||
|
||||
if (!driver || driver != hsudc->driver || !driver->unbind)
|
||||
if (!driver || driver != hsudc->driver)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&hsudc->lock, flags);
|
||||
hsudc->driver = 0;
|
||||
hsudc->driver = NULL;
|
||||
hsudc->gadget.dev.driver = NULL;
|
||||
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
s3c_hsudc_uninit_phy();
|
||||
if (hsudc->pd->gpio_uninit)
|
||||
hsudc->pd->gpio_uninit();
|
||||
s3c_hsudc_stop_activity(hsudc, driver);
|
||||
s3c_hsudc_stop_activity(hsudc);
|
||||
spin_unlock_irqrestore(&hsudc->lock, flags);
|
||||
|
||||
if (hsudc->transceiver)
|
||||
(void) otg_set_peripheral(hsudc->transceiver, NULL);
|
||||
|
||||
driver->unbind(&hsudc->gadget);
|
||||
device_del(&hsudc->gadget.dev);
|
||||
disable_irq(hsudc->irq);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
|
||||
|
||||
dev_info(hsudc->dev, "unregistered gadget driver '%s'\n",
|
||||
driver->driver.name);
|
||||
return 0;
|
||||
@@ -1242,7 +1237,7 @@ static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget)
|
||||
|
||||
static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
|
||||
{
|
||||
struct s3c_hsudc *hsudc = the_controller;
|
||||
struct s3c_hsudc *hsudc = to_hsudc(gadget);
|
||||
|
||||
if (!hsudc)
|
||||
return -ENODEV;
|
||||
@@ -1255,18 +1250,18 @@ static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
|
||||
|
||||
static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
|
||||
.get_frame = s3c_hsudc_gadget_getframe,
|
||||
.start = s3c_hsudc_start,
|
||||
.stop = s3c_hsudc_stop,
|
||||
.udc_start = s3c_hsudc_start,
|
||||
.udc_stop = s3c_hsudc_stop,
|
||||
.vbus_draw = s3c_hsudc_vbus_draw,
|
||||
};
|
||||
|
||||
static int s3c_hsudc_probe(struct platform_device *pdev)
|
||||
static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
struct s3c_hsudc *hsudc;
|
||||
struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
hsudc = kzalloc(sizeof(struct s3c_hsudc) +
|
||||
sizeof(struct s3c_hsudc_ep) * pd->epnum,
|
||||
@@ -1276,13 +1271,22 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
the_controller = hsudc;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
hsudc->dev = dev;
|
||||
hsudc->pd = pdev->dev.platform_data;
|
||||
|
||||
hsudc->transceiver = otg_get_transceiver();
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
|
||||
hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
|
||||
|
||||
ret = regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies),
|
||||
hsudc->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "failed to request supplies: %d\n", ret);
|
||||
goto err_supplies;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "unable to obtain driver resource data\n");
|
||||
@@ -1307,7 +1311,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
|
||||
|
||||
spin_lock_init(&hsudc->lock);
|
||||
|
||||
device_initialize(&hsudc->gadget.dev);
|
||||
dev_set_name(&hsudc->gadget.dev, "gadget");
|
||||
|
||||
hsudc->gadget.max_speed = USB_SPEED_HIGH;
|
||||
@@ -1319,6 +1322,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
|
||||
|
||||
hsudc->gadget.is_otg = 0;
|
||||
hsudc->gadget.is_a_peripheral = 0;
|
||||
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
|
||||
s3c_hsudc_setup_ep(hsudc);
|
||||
|
||||
@@ -1348,12 +1352,20 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
|
||||
disable_irq(hsudc->irq);
|
||||
local_irq_enable();
|
||||
|
||||
ret = device_register(&hsudc->gadget.dev);
|
||||
if (ret) {
|
||||
put_device(&hsudc->gadget.dev);
|
||||
goto err_add_device;
|
||||
}
|
||||
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
|
||||
if (ret)
|
||||
goto err_add_udc;
|
||||
|
||||
return 0;
|
||||
err_add_udc:
|
||||
device_unregister(&hsudc->gadget.dev);
|
||||
err_add_device:
|
||||
clk_disable(hsudc->uclk);
|
||||
clk_put(hsudc->uclk);
|
||||
err_clk:
|
||||
@@ -1362,10 +1374,13 @@ err_irq:
|
||||
iounmap(hsudc->regs);
|
||||
|
||||
err_remap:
|
||||
release_resource(hsudc->mem_rsrc);
|
||||
kfree(hsudc->mem_rsrc);
|
||||
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
err_res:
|
||||
if (hsudc->transceiver)
|
||||
otg_put_transceiver(hsudc->transceiver);
|
||||
|
||||
regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
|
||||
err_supplies:
|
||||
kfree(hsudc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -194,6 +194,15 @@ config USB_EHCI_S5P
|
||||
help
|
||||
Enable support for the S5P SOC's on-chip EHCI controller.
|
||||
|
||||
config USB_EHCI_MV
|
||||
bool "EHCI support for Marvell on-chip controller"
|
||||
depends on USB_EHCI_HCD
|
||||
select USB_EHCI_ROOT_HUB_TT
|
||||
---help---
|
||||
Enables support for Marvell (including PXA and MMP series) on-chip
|
||||
USB SPH and OTG controller. SPH is a single port host, and it can
|
||||
only be EHCI host. OTG is controller that can switch to host mode.
|
||||
|
||||
config USB_W90X900_EHCI
|
||||
bool "W90X900(W90P910) EHCI support"
|
||||
depends on USB_EHCI_HCD && ARCH_W90X900
|
||||
|
||||
@@ -1371,6 +1371,11 @@ MODULE_LICENSE ("GPL");
|
||||
#define PLATFORM_DRIVER ehci_xls_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_EHCI_MV
|
||||
#include "ehci-mv.c"
|
||||
#define PLATFORM_DRIVER ehci_mv_driver
|
||||
#endif
|
||||
|
||||
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
|
||||
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
|
||||
!defined(XILINX_OF_PLATFORM_DRIVER)
|
||||
|
||||
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Marvell International Ltd. All rights reserved.
|
||||
* Author: Chao Xie <chao.xie@marvell.com>
|
||||
* Neil Zhang <zhangwm@marvell.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; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/platform_data/mv_usb.h>
|
||||
|
||||
#define CAPLENGTH_MASK (0xff)
|
||||
|
||||
struct ehci_hcd_mv {
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
/* Which mode does this ehci running OTG/Host ? */
|
||||
int mode;
|
||||
|
||||
void __iomem *phy_regs;
|
||||
void __iomem *cap_regs;
|
||||
void __iomem *op_regs;
|
||||
|
||||
struct otg_transceiver *otg;
|
||||
|
||||
struct mv_usb_platform_data *pdata;
|
||||
|
||||
/* clock source and total clock number */
|
||||
unsigned int clknum;
|
||||
struct clk *clk[0];
|
||||
};
|
||||
|
||||
static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ehci_mv->clknum; i++)
|
||||
clk_enable(ehci_mv->clk[i]);
|
||||
}
|
||||
|
||||
static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ehci_mv->clknum; i++)
|
||||
clk_disable(ehci_mv->clk[i]);
|
||||
}
|
||||
|
||||
static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
|
||||
{
|
||||
int retval;
|
||||
|
||||
ehci_clock_enable(ehci_mv);
|
||||
if (ehci_mv->pdata->phy_init) {
|
||||
retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv)
|
||||
{
|
||||
if (ehci_mv->pdata->phy_deinit)
|
||||
ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs);
|
||||
ehci_clock_disable(ehci_mv);
|
||||
}
|
||||
|
||||
static int mv_ehci_reset(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct device *dev = hcd->self.controller;
|
||||
struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev);
|
||||
int retval;
|
||||
|
||||
if (ehci_mv == NULL) {
|
||||
dev_err(dev, "Can not find private ehci data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* data structure init
|
||||
*/
|
||||
retval = ehci_init(hcd);
|
||||
if (retval) {
|
||||
dev_err(dev, "ehci_init failed %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
hcd->has_tt = 1;
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
retval = ehci_reset(ehci);
|
||||
if (retval) {
|
||||
dev_err(dev, "ehci_reset failed %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hc_driver mv_ehci_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "Marvell EHCI",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
|
||||
/*
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB2,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = mv_ehci_reset,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
*/
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
.bus_suspend = ehci_bus_suspend,
|
||||
.bus_resume = ehci_bus_resume,
|
||||
};
|
||||
|
||||
static int mv_ehci_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci;
|
||||
struct ehci_hcd_mv *ehci_mv;
|
||||
struct resource *r;
|
||||
int clk_i, retval = -ENODEV;
|
||||
u32 offset;
|
||||
size_t size;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "missing platform_data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci");
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
|
||||
size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum;
|
||||
ehci_mv = kzalloc(size, GFP_KERNEL);
|
||||
if (ehci_mv == NULL) {
|
||||
dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n");
|
||||
retval = -ENOMEM;
|
||||
goto err_put_hcd;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, ehci_mv);
|
||||
ehci_mv->pdata = pdata;
|
||||
ehci_mv->hcd = hcd;
|
||||
|
||||
ehci_mv->clknum = pdata->clknum;
|
||||
for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) {
|
||||
ehci_mv->clk[clk_i] =
|
||||
clk_get(&pdev->dev, pdata->clkname[clk_i]);
|
||||
if (IS_ERR(ehci_mv->clk[clk_i])) {
|
||||
dev_err(&pdev->dev, "error get clck \"%s\"\n",
|
||||
pdata->clkname[clk_i]);
|
||||
retval = PTR_ERR(ehci_mv->clk[clk_i]);
|
||||
goto err_put_clk;
|
||||
}
|
||||
}
|
||||
|
||||
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs");
|
||||
if (r == NULL) {
|
||||
dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
|
||||
retval = -ENODEV;
|
||||
goto err_put_clk;
|
||||
}
|
||||
|
||||
ehci_mv->phy_regs = ioremap(r->start, resource_size(r));
|
||||
if (ehci_mv->phy_regs == 0) {
|
||||
dev_err(&pdev->dev, "failed to map phy I/O memory\n");
|
||||
retval = -EFAULT;
|
||||
goto err_put_clk;
|
||||
}
|
||||
|
||||
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs");
|
||||
if (!r) {
|
||||
dev_err(&pdev->dev, "no I/O memory resource defined\n");
|
||||
retval = -ENODEV;
|
||||
goto err_iounmap_phyreg;
|
||||
}
|
||||
|
||||
ehci_mv->cap_regs = ioremap(r->start, resource_size(r));
|
||||
if (ehci_mv->cap_regs == NULL) {
|
||||
dev_err(&pdev->dev, "failed to map I/O memory\n");
|
||||
retval = -EFAULT;
|
||||
goto err_iounmap_phyreg;
|
||||
}
|
||||
|
||||
retval = mv_ehci_enable(ehci_mv);
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev, "init phy error %d\n", retval);
|
||||
goto err_iounmap_capreg;
|
||||
}
|
||||
|
||||
offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK;
|
||||
ehci_mv->op_regs =
|
||||
(void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset);
|
||||
|
||||
hcd->rsrc_start = r->start;
|
||||
hcd->rsrc_len = r->end - r->start + 1;
|
||||
hcd->regs = ehci_mv->op_regs;
|
||||
|
||||
hcd->irq = platform_get_irq(pdev, 0);
|
||||
if (!hcd->irq) {
|
||||
dev_err(&pdev->dev, "Cannot get irq.");
|
||||
retval = -ENODEV;
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs;
|
||||
ehci->regs = (struct ehci_regs *) ehci_mv->op_regs;
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
ehci_mv->mode = pdata->mode;
|
||||
if (ehci_mv->mode == MV_USB_MODE_OTG) {
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
ehci_mv->otg = otg_get_transceiver();
|
||||
if (!ehci_mv->otg) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to find transceiver\n");
|
||||
retval = -ENODEV;
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
retval = otg_set_host(ehci_mv->otg, &hcd->self);
|
||||
if (retval < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to register with transceiver\n");
|
||||
retval = -ENODEV;
|
||||
goto err_put_transceiver;
|
||||
}
|
||||
/* otg will enable clock before use as host */
|
||||
mv_ehci_disable(ehci_mv);
|
||||
#else
|
||||
dev_info(&pdev->dev, "MV_USB_MODE_OTG "
|
||||
"must have CONFIG_USB_OTG_UTILS enabled\n");
|
||||
goto err_disable_clk;
|
||||
#endif
|
||||
} else {
|
||||
if (pdata->set_vbus)
|
||||
pdata->set_vbus(1);
|
||||
|
||||
retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to add hcd with err %d\n", retval);
|
||||
goto err_set_vbus;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->private_init)
|
||||
pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs);
|
||||
|
||||
dev_info(&pdev->dev,
|
||||
"successful find EHCI device with regs 0x%p irq %d"
|
||||
" working in %s mode\n", hcd->regs, hcd->irq,
|
||||
ehci_mv->mode == MV_USB_MODE_OTG ? "OTG" : "Host");
|
||||
|
||||
return 0;
|
||||
|
||||
err_set_vbus:
|
||||
if (pdata->set_vbus)
|
||||
pdata->set_vbus(0);
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
err_put_transceiver:
|
||||
if (ehci_mv->otg)
|
||||
otg_put_transceiver(ehci_mv->otg);
|
||||
#endif
|
||||
err_disable_clk:
|
||||
mv_ehci_disable(ehci_mv);
|
||||
err_iounmap_capreg:
|
||||
iounmap(ehci_mv->cap_regs);
|
||||
err_iounmap_phyreg:
|
||||
iounmap(ehci_mv->phy_regs);
|
||||
err_put_clk:
|
||||
for (clk_i--; clk_i >= 0; clk_i--)
|
||||
clk_put(ehci_mv->clk[clk_i]);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(ehci_mv);
|
||||
err_put_hcd:
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int mv_ehci_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
|
||||
struct usb_hcd *hcd = ehci_mv->hcd;
|
||||
int clk_i;
|
||||
|
||||
if (hcd->rh_registered)
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
if (ehci_mv->otg) {
|
||||
otg_set_host(ehci_mv->otg, NULL);
|
||||
otg_put_transceiver(ehci_mv->otg);
|
||||
}
|
||||
|
||||
if (ehci_mv->mode == MV_USB_MODE_HOST) {
|
||||
if (ehci_mv->pdata->set_vbus)
|
||||
ehci_mv->pdata->set_vbus(0);
|
||||
|
||||
mv_ehci_disable(ehci_mv);
|
||||
}
|
||||
|
||||
iounmap(ehci_mv->cap_regs);
|
||||
iounmap(ehci_mv->phy_regs);
|
||||
|
||||
for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++)
|
||||
clk_put(ehci_mv->clk[clk_i]);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
kfree(ehci_mv);
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("mv-ehci");
|
||||
|
||||
static const struct platform_device_id ehci_id_table[] = {
|
||||
{"pxa-u2oehci", PXA_U2OEHCI},
|
||||
{"pxa-sph", PXA_SPH},
|
||||
{"mmp3-hsic", MMP3_HSIC},
|
||||
{"mmp3-fsic", MMP3_FSIC},
|
||||
{},
|
||||
};
|
||||
|
||||
static void mv_ehci_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
|
||||
struct usb_hcd *hcd = ehci_mv->hcd;
|
||||
|
||||
if (!hcd->rh_registered)
|
||||
return;
|
||||
|
||||
if (hcd->driver->shutdown)
|
||||
hcd->driver->shutdown(hcd);
|
||||
}
|
||||
|
||||
static struct platform_driver ehci_mv_driver = {
|
||||
.probe = mv_ehci_probe,
|
||||
.remove = mv_ehci_remove,
|
||||
.shutdown = mv_ehci_shutdown,
|
||||
.driver = {
|
||||
.name = "mv-ehci",
|
||||
.bus = &platform_bus_type,
|
||||
},
|
||||
.id_table = ehci_id_table,
|
||||
};
|
||||
@@ -130,4 +130,16 @@ config FSL_USB2_OTG
|
||||
help
|
||||
Enable this to support Freescale USB OTG transceiver.
|
||||
|
||||
config USB_MV_OTG
|
||||
tristate "Marvell USB OTG support"
|
||||
depends on USB_MV_UDC
|
||||
select USB_OTG
|
||||
select USB_OTG_UTILS
|
||||
help
|
||||
Say Y here if you want to build Marvell USB OTG transciever
|
||||
driver in kernel (including PXA and MMP series). This driver
|
||||
implements role switch between EHCI host driver and gadget driver.
|
||||
|
||||
To compile this driver as a module, choose M here.
|
||||
|
||||
endif # USB || OTG
|
||||
|
||||
@@ -21,3 +21,4 @@ obj-$(CONFIG_USB_MSM_OTG) += msm_otg.o
|
||||
obj-$(CONFIG_AB8500_USB) += ab8500-usb.o
|
||||
fsl_usb2_otg-objs := fsl_otg.o otg_fsm.o
|
||||
obj-$(CONFIG_FSL_USB2_OTG) += fsl_usb2_otg.o
|
||||
obj-$(CONFIG_USB_MV_OTG) += mv_otg.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Marvell International Ltd. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __MV_USB_OTG_CONTROLLER__
|
||||
#define __MV_USB_OTG_CONTROLLER__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* Command Register Bit Masks */
|
||||
#define USBCMD_RUN_STOP (0x00000001)
|
||||
#define USBCMD_CTRL_RESET (0x00000002)
|
||||
|
||||
/* otgsc Register Bit Masks */
|
||||
#define OTGSC_CTRL_VUSB_DISCHARGE 0x00000001
|
||||
#define OTGSC_CTRL_VUSB_CHARGE 0x00000002
|
||||
#define OTGSC_CTRL_OTG_TERM 0x00000008
|
||||
#define OTGSC_CTRL_DATA_PULSING 0x00000010
|
||||
#define OTGSC_STS_USB_ID 0x00000100
|
||||
#define OTGSC_STS_A_VBUS_VALID 0x00000200
|
||||
#define OTGSC_STS_A_SESSION_VALID 0x00000400
|
||||
#define OTGSC_STS_B_SESSION_VALID 0x00000800
|
||||
#define OTGSC_STS_B_SESSION_END 0x00001000
|
||||
#define OTGSC_STS_1MS_TOGGLE 0x00002000
|
||||
#define OTGSC_STS_DATA_PULSING 0x00004000
|
||||
#define OTGSC_INTSTS_USB_ID 0x00010000
|
||||
#define OTGSC_INTSTS_A_VBUS_VALID 0x00020000
|
||||
#define OTGSC_INTSTS_A_SESSION_VALID 0x00040000
|
||||
#define OTGSC_INTSTS_B_SESSION_VALID 0x00080000
|
||||
#define OTGSC_INTSTS_B_SESSION_END 0x00100000
|
||||
#define OTGSC_INTSTS_1MS 0x00200000
|
||||
#define OTGSC_INTSTS_DATA_PULSING 0x00400000
|
||||
#define OTGSC_INTR_USB_ID 0x01000000
|
||||
#define OTGSC_INTR_A_VBUS_VALID 0x02000000
|
||||
#define OTGSC_INTR_A_SESSION_VALID 0x04000000
|
||||
#define OTGSC_INTR_B_SESSION_VALID 0x08000000
|
||||
#define OTGSC_INTR_B_SESSION_END 0x10000000
|
||||
#define OTGSC_INTR_1MS_TIMER 0x20000000
|
||||
#define OTGSC_INTR_DATA_PULSING 0x40000000
|
||||
|
||||
#define CAPLENGTH_MASK (0xff)
|
||||
|
||||
/* Timer's interval, unit 10ms */
|
||||
#define T_A_WAIT_VRISE 100
|
||||
#define T_A_WAIT_BCON 2000
|
||||
#define T_A_AIDL_BDIS 100
|
||||
#define T_A_BIDL_ADIS 20
|
||||
#define T_B_ASE0_BRST 400
|
||||
#define T_B_SE0_SRP 300
|
||||
#define T_B_SRP_FAIL 2000
|
||||
#define T_B_DATA_PLS 10
|
||||
#define T_B_SRP_INIT 100
|
||||
#define T_A_SRP_RSPNS 10
|
||||
#define T_A_DRV_RSM 5
|
||||
|
||||
enum otg_function {
|
||||
OTG_B_DEVICE = 0,
|
||||
OTG_A_DEVICE
|
||||
};
|
||||
|
||||
enum mv_otg_timer {
|
||||
A_WAIT_BCON_TIMER = 0,
|
||||
OTG_TIMER_NUM
|
||||
};
|
||||
|
||||
/* PXA OTG state machine */
|
||||
struct mv_otg_ctrl {
|
||||
/* internal variables */
|
||||
u8 a_set_b_hnp_en; /* A-Device set b_hnp_en */
|
||||
u8 b_srp_done;
|
||||
u8 b_hnp_en;
|
||||
|
||||
/* OTG inputs */
|
||||
u8 a_bus_drop;
|
||||
u8 a_bus_req;
|
||||
u8 a_clr_err;
|
||||
u8 a_bus_resume;
|
||||
u8 a_bus_suspend;
|
||||
u8 a_conn;
|
||||
u8 a_sess_vld;
|
||||
u8 a_srp_det;
|
||||
u8 a_vbus_vld;
|
||||
u8 b_bus_req; /* B-Device Require Bus */
|
||||
u8 b_bus_resume;
|
||||
u8 b_bus_suspend;
|
||||
u8 b_conn;
|
||||
u8 b_se0_srp;
|
||||
u8 b_sess_end;
|
||||
u8 b_sess_vld;
|
||||
u8 id;
|
||||
u8 a_suspend_req;
|
||||
|
||||
/*Timer event */
|
||||
u8 a_aidl_bdis_timeout;
|
||||
u8 b_ase0_brst_timeout;
|
||||
u8 a_bidl_adis_timeout;
|
||||
u8 a_wait_bcon_timeout;
|
||||
|
||||
struct timer_list timer[OTG_TIMER_NUM];
|
||||
};
|
||||
|
||||
#define VUSBHS_MAX_PORTS 8
|
||||
|
||||
struct mv_otg_regs {
|
||||
u32 usbcmd; /* Command register */
|
||||
u32 usbsts; /* Status register */
|
||||
u32 usbintr; /* Interrupt enable */
|
||||
u32 frindex; /* Frame index */
|
||||
u32 reserved1[1];
|
||||
u32 deviceaddr; /* Device Address */
|
||||
u32 eplistaddr; /* Endpoint List Address */
|
||||
u32 ttctrl; /* HOST TT status and control */
|
||||
u32 burstsize; /* Programmable Burst Size */
|
||||
u32 txfilltuning; /* Host Transmit Pre-Buffer Packet Tuning */
|
||||
u32 reserved[4];
|
||||
u32 epnak; /* Endpoint NAK */
|
||||
u32 epnaken; /* Endpoint NAK Enable */
|
||||
u32 configflag; /* Configured Flag register */
|
||||
u32 portsc[VUSBHS_MAX_PORTS]; /* Port Status/Control x, x = 1..8 */
|
||||
u32 otgsc;
|
||||
u32 usbmode; /* USB Host/Device mode */
|
||||
u32 epsetupstat; /* Endpoint Setup Status */
|
||||
u32 epprime; /* Endpoint Initialize */
|
||||
u32 epflush; /* Endpoint De-initialize */
|
||||
u32 epstatus; /* Endpoint Status */
|
||||
u32 epcomplete; /* Endpoint Interrupt On Complete */
|
||||
u32 epctrlx[16]; /* Endpoint Control, where x = 0.. 15 */
|
||||
u32 mcr; /* Mux Control */
|
||||
u32 isr; /* Interrupt Status */
|
||||
u32 ier; /* Interrupt Enable */
|
||||
};
|
||||
|
||||
struct mv_otg {
|
||||
struct otg_transceiver otg;
|
||||
struct mv_otg_ctrl otg_ctrl;
|
||||
|
||||
/* base address */
|
||||
void __iomem *phy_regs;
|
||||
void __iomem *cap_regs;
|
||||
struct mv_otg_regs __iomem *op_regs;
|
||||
|
||||
struct platform_device *pdev;
|
||||
int irq;
|
||||
u32 irq_status;
|
||||
u32 irq_en;
|
||||
|
||||
struct delayed_work work;
|
||||
struct workqueue_struct *qwork;
|
||||
|
||||
spinlock_t wq_lock;
|
||||
|
||||
struct mv_usb_platform_data *pdata;
|
||||
|
||||
unsigned int active;
|
||||
unsigned int clock_gating;
|
||||
unsigned int clknum;
|
||||
struct clk *clk[0];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -185,7 +185,7 @@ static int usbhsg_dma_map(struct device *dev,
|
||||
}
|
||||
|
||||
if (dma_mapping_error(dev, pkt->dma)) {
|
||||
dev_err(dev, "dma mapping error %x\n", pkt->dma);
|
||||
dev_err(dev, "dma mapping error %llx\n", (u64)pkt->dma);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
@@ -633,7 +633,6 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
|
||||
struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
|
||||
struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
|
||||
struct urb *urb = ureq->urb;
|
||||
struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep);
|
||||
struct device *dev = usbhs_priv_to_dev(priv);
|
||||
int status = 0;
|
||||
|
||||
@@ -651,7 +650,7 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
|
||||
usbhsh_ureq_free(hpriv, ureq);
|
||||
|
||||
usbhsh_endpoint_sequence_save(hpriv, urb, pkt);
|
||||
usbhsh_pipe_detach(hpriv, uep);
|
||||
usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep));
|
||||
|
||||
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
||||
usb_hcd_giveback_urb(hcd, urb, status);
|
||||
|
||||
@@ -330,8 +330,7 @@ static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
|
||||
if (dir_in)
|
||||
usbhsp_flags_set(pipe, IS_DIR_HOST);
|
||||
|
||||
if ((is_host && !dir_in) ||
|
||||
(!is_host && dir_in))
|
||||
if (!!is_host ^ !!dir_in)
|
||||
dir |= DIR_OUT;
|
||||
|
||||
if (!dir)
|
||||
|
||||
@@ -42,9 +42,23 @@ struct mv_usb_platform_data {
|
||||
/* only valid for HCD. OTG or Host only*/
|
||||
unsigned int mode;
|
||||
|
||||
int (*phy_init)(unsigned int regbase);
|
||||
void (*phy_deinit)(unsigned int regbase);
|
||||
/* This flag is used for that needs id pin checked by otg */
|
||||
unsigned int disable_otg_clock_gating:1;
|
||||
/* Force a_bus_req to be asserted */
|
||||
unsigned int otg_force_a_bus_req:1;
|
||||
|
||||
int (*phy_init)(void __iomem *regbase);
|
||||
void (*phy_deinit)(void __iomem *regbase);
|
||||
int (*set_vbus)(unsigned int vbus);
|
||||
int (*private_init)(void __iomem *opregs, void __iomem *phyregs);
|
||||
};
|
||||
|
||||
#ifndef CONFIG_HAVE_CLK
|
||||
/* Dummy stub for clk framework */
|
||||
#define clk_get(dev, id) NULL
|
||||
#define clk_put(clock) do {} while (0)
|
||||
#define clk_enable(clock) do {} while (0)
|
||||
#define clk_disable(clock) do {} while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user