Merge 3.1-rc4 into usb-next
This was done to resolve a conflict in this file: drivers/usb/host/xhci-ring.c Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Коммит
6ed962a208
|
@ -0,0 +1,53 @@
|
|||
|
||||
TODO
|
||||
~~~~~~
|
||||
Please pick something while reading :)
|
||||
|
||||
- Implement streaming support for BULK endpoints
|
||||
Tatyana's patch "usb: Add streams support to the gadget framework"
|
||||
introduces streaming support for the gadget driver.
|
||||
Every usb_request has new field called stream_id which holds its id.
|
||||
Every usb_ep has a field num_supported_strms which describes the max
|
||||
number of streams supported (for this ep).
|
||||
UAS is AFAIK the only gadget with streaming support.
|
||||
|
||||
- Convert interrupt handler to per-ep-thread-irq
|
||||
|
||||
As it turns out some DWC3-commands ~1ms to complete. Currently we spin
|
||||
until the command completes which is bad.
|
||||
|
||||
Implementation idea:
|
||||
- dwc core implements a demultiplexing irq chip for interrupts per
|
||||
endpoint. The interrupt numbers are allocated during probe and belong
|
||||
to the device. If MSI provides per-endpoint interrupt this dummy
|
||||
interrupt chip can be replaced with "real" interrupts.
|
||||
- interrupts are requested / allocated on usb_ep_enable() and removed on
|
||||
usb_ep_disable(). Worst case are 32 interrupts, the lower limit is two
|
||||
for ep0/1.
|
||||
- dwc3_send_gadget_ep_cmd() will sleep in wait_for_completion_timeout()
|
||||
until the command completes.
|
||||
- the interrupt handler is split into the following pieces:
|
||||
- primary handler of the device
|
||||
goes through every event and calls generic_handle_irq() for event
|
||||
it. On return from generic_handle_irq() in acknowledges the event
|
||||
counter so interrupt goes away (eventually).
|
||||
|
||||
- threaded handler of the device
|
||||
none
|
||||
|
||||
- primary handler of the EP-interrupt
|
||||
reads the event and tries to process it. Everything that requries
|
||||
sleeping is handed over to the Thread. The event is saved in an
|
||||
per-endpoint data-structure.
|
||||
We probably have to pay attention not to process events once we
|
||||
handed something to thread so we don't process event X prio Y
|
||||
where X > Y.
|
||||
|
||||
- threaded handler of the EP-interrupt
|
||||
handles the remaining EP work which might sleep such as waiting
|
||||
for command completion.
|
||||
|
||||
Latency:
|
||||
There should be no increase in latency since the interrupt-thread has a
|
||||
high priority and will be run before an average task in user land
|
||||
(except the user changed priorities).
|
|
@ -2139,6 +2139,14 @@ M: Matthew Garrett <mjg59@srcf.ucam.org>
|
|||
S: Maintained
|
||||
F: drivers/platform/x86/dell-wmi.c
|
||||
|
||||
DESIGNWARE USB3 DRD IP DRIVER
|
||||
M: Felipe Balbi <balbi@ti.com>
|
||||
L: linux-usb@vger.kernel.org
|
||||
L: linux-omap@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
|
||||
S: Maintained
|
||||
F: drivers/usb/dwc3/
|
||||
|
||||
DEVICE NUMBER REGISTRY
|
||||
M: Torben Mathiasen <device@lanana.org>
|
||||
W: http://lanana.org/docs/device-list/index.html
|
||||
|
|
|
@ -35,6 +35,13 @@ extern struct pxa_device_desc pxa168_device_fb;
|
|||
extern struct pxa_device_desc pxa168_device_keypad;
|
||||
extern struct pxa_device_desc pxa168_device_eth;
|
||||
|
||||
struct pxa168_usb_pdata {
|
||||
/* If NULL, default phy init routine for PXA168 would be called */
|
||||
int (*phy_init)(void __iomem *usb_phy_reg_base);
|
||||
};
|
||||
/* pdata can be NULL */
|
||||
int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata);
|
||||
|
||||
static inline int pxa168_add_uart(int id)
|
||||
{
|
||||
struct pxa_device_desc *d = NULL;
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
#include <mach/dma.h>
|
||||
#include <mach/devices.h>
|
||||
#include <mach/mfp.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <mach/pxa168.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "clock.h"
|
||||
|
@ -83,6 +86,7 @@ static APBC_CLK(keypad, PXA168_KPC, 0, 32000);
|
|||
static APMU_CLK(nand, NAND, 0x19b, 156000000);
|
||||
static APMU_CLK(lcd, LCD, 0x7f, 312000000);
|
||||
static APMU_CLK(eth, ETH, 0x09, 0);
|
||||
static APMU_CLK(usb, USB, 0x12, 0);
|
||||
|
||||
/* device and clock bindings */
|
||||
static struct clk_lookup pxa168_clkregs[] = {
|
||||
|
@ -104,6 +108,7 @@ static struct clk_lookup pxa168_clkregs[] = {
|
|||
INIT_CLKREG(&clk_lcd, "pxa168-fb", NULL),
|
||||
INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
|
||||
INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"),
|
||||
INIT_CLKREG(&clk_usb, "pxa168-ehci", "PXA168-USBCLK"),
|
||||
};
|
||||
|
||||
static int __init pxa168_init(void)
|
||||
|
@ -169,3 +174,44 @@ PXA168_DEVICE(ssp5, "pxa168-ssp", 4, SSP5, 0xd4021000, 0x40, 60, 61);
|
|||
PXA168_DEVICE(fb, "pxa168-fb", -1, LCD, 0xd420b000, 0x1c8);
|
||||
PXA168_DEVICE(keypad, "pxa27x-keypad", -1, KEYPAD, 0xd4012000, 0x4c);
|
||||
PXA168_DEVICE(eth, "pxa168-eth", -1, MFU, 0xc0800000, 0x0fff);
|
||||
|
||||
struct resource pxa168_usb_host_resources[] = {
|
||||
/* USB Host conroller register base */
|
||||
[0] = {
|
||||
.start = 0xd4209000,
|
||||
.end = 0xd4209000 + 0x200,
|
||||
.flags = IORESOURCE_MEM,
|
||||
.name = "pxa168-usb-host",
|
||||
},
|
||||
/* USB PHY register base */
|
||||
[1] = {
|
||||
.start = 0xd4206000,
|
||||
.end = 0xd4206000 + 0xff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
.name = "pxa168-usb-phy",
|
||||
},
|
||||
[2] = {
|
||||
.start = IRQ_PXA168_USB2,
|
||||
.end = IRQ_PXA168_USB2,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static u64 pxa168_usb_host_dmamask = DMA_BIT_MASK(32);
|
||||
struct platform_device pxa168_device_usb_host = {
|
||||
.name = "pxa168-ehci",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.dma_mask = &pxa168_usb_host_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
|
||||
.num_resources = ARRAY_SIZE(pxa168_usb_host_resources),
|
||||
.resource = pxa168_usb_host_resources,
|
||||
};
|
||||
|
||||
int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata)
|
||||
{
|
||||
pxa168_device_usb_host.dev.platform_data = pdata;
|
||||
return platform_device_register(&pxa168_device_usb_host);
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ config USB_ARCH_HAS_EHCI
|
|||
default y if ARCH_MSM
|
||||
default y if MICROBLAZE
|
||||
default y if SPARC_LEON
|
||||
default y if ARCH_MMP
|
||||
default PCI
|
||||
|
||||
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
|
||||
|
@ -110,6 +111,8 @@ config USB
|
|||
|
||||
source "drivers/usb/core/Kconfig"
|
||||
|
||||
source "drivers/usb/dwc3/Kconfig"
|
||||
|
||||
source "drivers/usb/mon/Kconfig"
|
||||
|
||||
source "drivers/usb/wusbcore/Kconfig"
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
obj-$(CONFIG_USB) += core/
|
||||
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3/
|
||||
|
||||
obj-$(CONFIG_USB_MON) += mon/
|
||||
|
||||
obj-$(CONFIG_PCI) += host/
|
||||
|
|
|
@ -1058,11 +1058,11 @@ made_compressed_probe:
|
|||
goto alloc_fail;
|
||||
}
|
||||
|
||||
ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
|
||||
readsize = le16_to_cpu(epread->wMaxPacketSize) *
|
||||
ctrlsize = usb_endpoint_maxp(epctrl);
|
||||
readsize = usb_endpoint_maxp(epread) *
|
||||
(quirks == SINGLE_RX_URB ? 1 : 2);
|
||||
acm->combined_interfaces = combined_interfaces;
|
||||
acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
|
||||
acm->writesize = usb_endpoint_maxp(epwrite) * 20;
|
||||
acm->control = control_interface;
|
||||
acm->data = data_interface;
|
||||
acm->minor = minor;
|
||||
|
|
|
@ -682,7 +682,7 @@ next_desc:
|
|||
if (!ep || !usb_endpoint_is_int_in(ep))
|
||||
goto err;
|
||||
|
||||
desc->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize);
|
||||
desc->wMaxPacketSize = usb_endpoint_maxp(ep);
|
||||
desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;
|
||||
|
||||
desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
|
||||
|
|
|
@ -186,8 +186,7 @@ static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
|
|||
for (n = 0; n < current_setting->desc.bNumEndpoints; n++)
|
||||
if (current_setting->endpoint[n].desc.bEndpointAddress ==
|
||||
data->bulk_in)
|
||||
max_size = le16_to_cpu(current_setting->endpoint[n].
|
||||
desc.wMaxPacketSize);
|
||||
max_size = usb_endpoint_maxp(¤t_setting->endpoint[n].desc);
|
||||
|
||||
if (max_size == 0) {
|
||||
dev_err(dev, "Couldn't get wMaxPacketSize\n");
|
||||
|
@ -636,7 +635,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
|
|||
for (n = 0; n < current_setting->desc.bNumEndpoints; n++) {
|
||||
desc = ¤t_setting->endpoint[n].desc;
|
||||
if (desc->bEndpointAddress == data->bulk_in)
|
||||
max_size = le16_to_cpu(desc->wMaxPacketSize);
|
||||
max_size = usb_endpoint_maxp(desc);
|
||||
}
|
||||
|
||||
if (max_size == 0) {
|
||||
|
|
|
@ -124,9 +124,9 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
|
|||
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc))
|
||||
max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) *
|
||||
le16_to_cpu(ep->desc.wMaxPacketSize);
|
||||
usb_endpoint_maxp(&ep->desc);
|
||||
else if (usb_endpoint_xfer_int(&ep->desc))
|
||||
max_tx = le16_to_cpu(ep->desc.wMaxPacketSize) *
|
||||
max_tx = usb_endpoint_maxp(&ep->desc) *
|
||||
(desc->bMaxBurst + 1);
|
||||
else
|
||||
max_tx = 999999;
|
||||
|
@ -241,7 +241,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
|
|||
cfgno, inum, asnum, d->bEndpointAddress);
|
||||
endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
|
||||
endpoint->desc.bInterval = 1;
|
||||
if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8)
|
||||
if (usb_endpoint_maxp(&endpoint->desc) > 8)
|
||||
endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
|
|||
&& usb_endpoint_xfer_bulk(d)) {
|
||||
unsigned maxp;
|
||||
|
||||
maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize) & 0x07ff;
|
||||
maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff;
|
||||
if (maxp != 512)
|
||||
dev_warn(ddev, "config %d interface %d altsetting %d "
|
||||
"bulk endpoint 0x%X has invalid maxpacket %d\n",
|
||||
|
|
|
@ -190,7 +190,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
|
|||
dir = usb_endpoint_dir_in(desc) ? 'I' : 'O';
|
||||
|
||||
if (speed == USB_SPEED_HIGH) {
|
||||
switch (le16_to_cpu(desc->wMaxPacketSize) & (0x03 << 11)) {
|
||||
switch (usb_endpoint_maxp(desc) & (0x03 << 11)) {
|
||||
case 1 << 11:
|
||||
bandwidth = 2; break;
|
||||
case 2 << 11:
|
||||
|
@ -240,7 +240,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
|
|||
|
||||
start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
|
||||
desc->bmAttributes, type,
|
||||
(le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) *
|
||||
(usb_endpoint_maxp(desc) & 0x07ff) *
|
||||
bandwidth,
|
||||
interval, unit);
|
||||
return start;
|
||||
|
|
|
@ -56,7 +56,7 @@ static ssize_t show_ep_wMaxPacketSize(struct device *dev,
|
|||
{
|
||||
struct ep_device *ep = to_ep_device(dev);
|
||||
return sprintf(buf, "%04x\n",
|
||||
le16_to_cpu(ep->desc->wMaxPacketSize) & 0x07ff);
|
||||
usb_endpoint_maxp(ep->desc) & 0x07ff);
|
||||
}
|
||||
static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL);
|
||||
|
||||
|
|
|
@ -1636,11 +1636,6 @@ void usb_disconnect(struct usb_device **pdev)
|
|||
int i;
|
||||
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
||||
|
||||
if (!udev) {
|
||||
pr_debug ("%s nodev\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* mark the device as inactive, so any further urb submissions for
|
||||
* this device (and any of its children) will fail immediately.
|
||||
* this quiesces everything except pending urbs.
|
||||
|
@ -3023,7 +3018,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
|||
i = 512;
|
||||
else
|
||||
i = udev->descriptor.bMaxPacketSize0;
|
||||
if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
|
||||
if (usb_endpoint_maxp(&udev->ep0.desc) != i) {
|
||||
if (udev->speed == USB_SPEED_LOW ||
|
||||
!(i == 8 || i == 16 || i == 32 || i == 64)) {
|
||||
dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);
|
||||
|
|
|
@ -350,7 +350,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
|||
dev->state < USB_STATE_CONFIGURED)
|
||||
return -ENODEV;
|
||||
|
||||
max = le16_to_cpu(ep->desc.wMaxPacketSize);
|
||||
max = usb_endpoint_maxp(&ep->desc);
|
||||
if (max <= 0) {
|
||||
dev_dbg(&dev->dev,
|
||||
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
config USB_DWC3
|
||||
tristate "DesignWare USB3 DRD Core Support"
|
||||
depends on (USB || USB_GADGET)
|
||||
select USB_OTG_UTILS
|
||||
help
|
||||
Say Y or M here if your system has a Dual Role SuperSpeed
|
||||
USB controller based on the DesignWare USB3 IP Core.
|
||||
|
||||
If you choose to build this driver is a dynamically linked
|
||||
module, the module will be called dwc3.ko.
|
||||
|
||||
if USB_DWC3
|
||||
|
||||
config USB_DWC3_DEBUG
|
||||
bool "Enable Debugging Messages"
|
||||
help
|
||||
Say Y here to enable debugging messages on DWC3 Driver.
|
||||
|
||||
config USB_DWC3_VERBOSE
|
||||
bool "Enable Verbose Debugging Messages"
|
||||
depends on USB_DWC3_DEBUG
|
||||
help
|
||||
Say Y here to enable verbose debugging messages on DWC3 Driver.
|
||||
|
||||
endif
|
|
@ -0,0 +1,36 @@
|
|||
ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
|
||||
ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
|
||||
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3.o
|
||||
|
||||
dwc3-y := core.o
|
||||
|
||||
ifneq ($(CONFIG_USB_GADGET_DWC3),)
|
||||
dwc3-y += gadget.o ep0.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_DEBUG_FS),)
|
||||
dwc3-y += debugfs.o
|
||||
endif
|
||||
|
||||
##
|
||||
# Platform-specific glue layers go here
|
||||
#
|
||||
# NOTICE: Make sure your glue layer doesn't depend on anything
|
||||
# which is arch-specific and that it compiles on all situations.
|
||||
#
|
||||
# We want to keep this requirement in order to be able to compile
|
||||
# the entire driver (with all its glue layers) on several architectures
|
||||
# and make sure it compiles fine. This will also help with allmodconfig
|
||||
# and allyesconfig builds.
|
||||
#
|
||||
# The only exception is the PCI glue layer, but that's only because
|
||||
# PCI doesn't provide nops if CONFIG_PCI isn't enabled.
|
||||
##
|
||||
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3-omap.o
|
||||
|
||||
ifneq ($(CONFIG_PCI),)
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3-pci.o
|
||||
endif
|
||||
|
|
@ -0,0 +1,467 @@
|
|||
/**
|
||||
* core.c - DesignWare USB3 DRD Controller Core file
|
||||
*
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* Authors: Felipe Balbi <balbi@ti.com>,
|
||||
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The names of the above-listed copyright holders may not be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* ALTERNATIVELY, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2, as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "gadget.h"
|
||||
#include "io.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* dwc3_core_soft_reset - Issues core soft reset and PHY reset
|
||||
* @dwc: pointer to our context structure
|
||||
*/
|
||||
static void dwc3_core_soft_reset(struct dwc3 *dwc)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/* Before Resetting PHY, put Core in Reset */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
reg |= DWC3_GCTL_CORESOFTRESET;
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
|
||||
/* Assert USB3 PHY reset */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
|
||||
|
||||
/* Assert USB2 PHY reset */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
/* Clear USB3 PHY reset */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
|
||||
|
||||
/* Clear USB2 PHY reset */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
|
||||
/* After PHYs are stable we can take Core out of reset state */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
reg &= ~DWC3_GCTL_CORESOFTRESET;
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_free_one_event_buffer - Frees one event buffer
|
||||
* @dwc: Pointer to our controller context structure
|
||||
* @evt: Pointer to event buffer to be freed
|
||||
*/
|
||||
static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
|
||||
struct dwc3_event_buffer *evt)
|
||||
{
|
||||
dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
|
||||
kfree(evt);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_alloc_one_event_buffer - Allocated one event buffer structure
|
||||
* @dwc: Pointer to our controller context structure
|
||||
* @length: size of the event buffer
|
||||
*
|
||||
* Returns a pointer to the allocated event buffer structure on succes
|
||||
* otherwise ERR_PTR(errno).
|
||||
*/
|
||||
static struct dwc3_event_buffer *__devinit
|
||||
dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
|
||||
evt = kzalloc(sizeof(*evt), GFP_KERNEL);
|
||||
if (!evt)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
evt->dwc = dwc;
|
||||
evt->length = length;
|
||||
evt->buf = dma_alloc_coherent(dwc->dev, length,
|
||||
&evt->dma, GFP_KERNEL);
|
||||
if (!evt->buf) {
|
||||
kfree(evt);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
return evt;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_free_event_buffers - frees all allocated event buffers
|
||||
* @dwc: Pointer to our controller context structure
|
||||
*/
|
||||
static void dwc3_free_event_buffers(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
|
||||
evt = dwc->ev_buffs[i];
|
||||
if (evt) {
|
||||
dwc3_free_one_event_buffer(dwc, evt);
|
||||
dwc->ev_buffs[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
|
||||
* @dwc: Pointer to out controller context structure
|
||||
* @num: number of event buffers to allocate
|
||||
* @length: size of event buffer
|
||||
*
|
||||
* Returns 0 on success otherwise negative errno. In error the case, dwc
|
||||
* may contain some buffers allocated but not all which were requested.
|
||||
*/
|
||||
static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num,
|
||||
unsigned length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct dwc3_event_buffer *evt;
|
||||
|
||||
evt = dwc3_alloc_one_event_buffer(dwc, length);
|
||||
if (IS_ERR(evt)) {
|
||||
dev_err(dwc->dev, "can't allocate event buffer\n");
|
||||
return PTR_ERR(evt);
|
||||
}
|
||||
dwc->ev_buffs[i] = evt;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_event_buffers_setup - setup our allocated event buffers
|
||||
* @dwc: Pointer to out controller context structure
|
||||
*
|
||||
* Returns 0 on success otherwise negative errno.
|
||||
*/
|
||||
static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
|
||||
evt = dwc->ev_buffs[n];
|
||||
dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
|
||||
evt->buf, (unsigned long long) evt->dma,
|
||||
evt->length);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
|
||||
lower_32_bits(evt->dma));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
|
||||
upper_32_bits(evt->dma));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
|
||||
evt->length & 0xffff);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
|
||||
evt = dwc->ev_buffs[n];
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_core_init - Low-level initialization of DWC3 Core
|
||||
* @dwc: Pointer to our controller context structure
|
||||
*
|
||||
* Returns 0 on success otherwise negative errno.
|
||||
*/
|
||||
static int __devinit dwc3_core_init(struct dwc3 *dwc)
|
||||
{
|
||||
unsigned long timeout;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
dwc3_core_soft_reset(dwc);
|
||||
|
||||
/* issue device SoftReset too */
|
||||
timeout = jiffies + msecs_to_jiffies(500);
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
|
||||
do {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
if (!(reg & DWC3_DCTL_CSFTRST))
|
||||
break;
|
||||
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_err(dwc->dev, "Reset Timed Out\n");
|
||||
ret = -ETIMEDOUT;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
cpu_relax();
|
||||
} while (true);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
|
||||
/* This should read as U3 followed by revision number */
|
||||
if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
|
||||
dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
|
||||
ret = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
dwc->revision = reg & DWC3_GSNPSREV_MASK;
|
||||
|
||||
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM,
|
||||
DWC3_EVENT_BUFFERS_SIZE);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to allocate event buffers\n");
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
ret = dwc3_event_buffers_setup(dwc);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to setup event buffers\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
dwc3_free_event_buffers(dwc);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwc3_core_exit(struct dwc3 *dwc)
|
||||
{
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
dwc3_free_event_buffers(dwc);
|
||||
}
|
||||
|
||||
#define DWC3_ALIGN_MASK (16 - 1)
|
||||
|
||||
static int __devinit dwc3_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct platform_device_id *id = platform_get_device_id(pdev);
|
||||
struct resource *res;
|
||||
struct dwc3 *dwc;
|
||||
void __iomem *regs;
|
||||
unsigned int features = id->driver_data;
|
||||
int ret = -ENOMEM;
|
||||
int irq;
|
||||
void *mem;
|
||||
|
||||
mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
|
||||
if (!mem) {
|
||||
dev_err(&pdev->dev, "not enough memory\n");
|
||||
goto err0;
|
||||
}
|
||||
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
|
||||
dwc->mem = mem;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "missing resource\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
res = request_mem_region(res->start, resource_size(res),
|
||||
dev_name(&pdev->dev));
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "can't request mem region\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
regs = ioremap(res->start, resource_size(res));
|
||||
if (!regs) {
|
||||
dev_err(&pdev->dev, "ioremap failed\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "missing IRQ\n");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
spin_lock_init(&dwc->lock);
|
||||
platform_set_drvdata(pdev, dwc);
|
||||
|
||||
dwc->regs = regs;
|
||||
dwc->regs_size = resource_size(res);
|
||||
dwc->dev = &pdev->dev;
|
||||
dwc->irq = irq;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
pm_runtime_forbid(&pdev->dev);
|
||||
|
||||
ret = dwc3_core_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize core\n");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
if (features & DWC3_HAS_PERIPHERAL) {
|
||||
ret = dwc3_gadget_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialized gadget\n");
|
||||
goto err4;
|
||||
}
|
||||
}
|
||||
|
||||
ret = dwc3_debugfs_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize debugfs\n");
|
||||
goto err5;
|
||||
}
|
||||
|
||||
pm_runtime_allow(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err5:
|
||||
if (features & DWC3_HAS_PERIPHERAL)
|
||||
dwc3_gadget_exit(dwc);
|
||||
|
||||
err4:
|
||||
dwc3_core_exit(dwc);
|
||||
|
||||
err3:
|
||||
iounmap(regs);
|
||||
|
||||
err2:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
err1:
|
||||
kfree(dwc->mem);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit dwc3_remove(struct platform_device *pdev)
|
||||
{
|
||||
const struct platform_device_id *id = platform_get_device_id(pdev);
|
||||
struct dwc3 *dwc = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
unsigned int features = id->driver_data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
pm_runtime_put(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
dwc3_debugfs_exit(dwc);
|
||||
|
||||
if (features & DWC3_HAS_PERIPHERAL)
|
||||
dwc3_gadget_exit(dwc);
|
||||
|
||||
dwc3_core_exit(dwc);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
iounmap(dwc->regs);
|
||||
kfree(dwc->mem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id dwc3_id_table[] __devinitconst = {
|
||||
{
|
||||
.name = "dwc3-omap",
|
||||
.driver_data = (DWC3_HAS_PERIPHERAL
|
||||
| DWC3_HAS_XHCI
|
||||
| DWC3_HAS_OTG),
|
||||
},
|
||||
{
|
||||
.name = "dwc3-pci",
|
||||
.driver_data = DWC3_HAS_PERIPHERAL,
|
||||
},
|
||||
{ }, /* Terminating Entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, dwc3_id_table);
|
||||
|
||||
static struct platform_driver dwc3_driver = {
|
||||
.probe = dwc3_probe,
|
||||
.remove = __devexit_p(dwc3_remove),
|
||||
.driver = {
|
||||
.name = "dwc3",
|
||||
},
|
||||
.id_table = dwc3_id_table,
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
|
||||
|
||||
static int __devinit dwc3_init(void)
|
||||
{
|
||||
return platform_driver_register(&dwc3_driver);
|
||||
}
|
||||
module_init(dwc3_init);
|
||||
|
||||
static void __exit dwc3_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&dwc3_driver);
|
||||
}
|
||||
module_exit(dwc3_exit);
|
|
@ -0,0 +1,709 @@
|
|||
/**
|
||||
* core.h - DesignWare USB3 DRD Core Header
|
||||
*
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* Authors: Felipe Balbi <balbi@ti.com>,
|
||||
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The names of the above-listed copyright holders may not be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* ALTERNATIVELY, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2, as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_USB_DWC3_CORE_H
|
||||
#define __DRIVERS_USB_DWC3_CORE_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
/* Global constants */
|
||||
#define DWC3_ENDPOINTS_NUM 32
|
||||
|
||||
#define DWC3_EVENT_BUFFERS_NUM 2
|
||||
#define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE
|
||||
#define DWC3_EVENT_TYPE_MASK 0xfe
|
||||
|
||||
#define DWC3_EVENT_TYPE_DEV 0
|
||||
#define DWC3_EVENT_TYPE_CARKIT 3
|
||||
#define DWC3_EVENT_TYPE_I2C 4
|
||||
|
||||
#define DWC3_DEVICE_EVENT_DISCONNECT 0
|
||||
#define DWC3_DEVICE_EVENT_RESET 1
|
||||
#define DWC3_DEVICE_EVENT_CONNECT_DONE 2
|
||||
#define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE 3
|
||||
#define DWC3_DEVICE_EVENT_WAKEUP 4
|
||||
#define DWC3_DEVICE_EVENT_EOPF 6
|
||||
#define DWC3_DEVICE_EVENT_SOF 7
|
||||
#define DWC3_DEVICE_EVENT_ERRATIC_ERROR 9
|
||||
#define DWC3_DEVICE_EVENT_CMD_CMPL 10
|
||||
#define DWC3_DEVICE_EVENT_OVERFLOW 11
|
||||
|
||||
#define DWC3_GEVNTCOUNT_MASK 0xfffc
|
||||
#define DWC3_GSNPSID_MASK 0xffff0000
|
||||
#define DWC3_GSNPSREV_MASK 0xffff
|
||||
|
||||
/* Global Registers */
|
||||
#define DWC3_GSBUSCFG0 0xc100
|
||||
#define DWC3_GSBUSCFG1 0xc104
|
||||
#define DWC3_GTXTHRCFG 0xc108
|
||||
#define DWC3_GRXTHRCFG 0xc10c
|
||||
#define DWC3_GCTL 0xc110
|
||||
#define DWC3_GEVTEN 0xc114
|
||||
#define DWC3_GSTS 0xc118
|
||||
#define DWC3_GSNPSID 0xc120
|
||||
#define DWC3_GGPIO 0xc124
|
||||
#define DWC3_GUID 0xc128
|
||||
#define DWC3_GUCTL 0xc12c
|
||||
#define DWC3_GBUSERRADDR0 0xc130
|
||||
#define DWC3_GBUSERRADDR1 0xc134
|
||||
#define DWC3_GPRTBIMAP0 0xc138
|
||||
#define DWC3_GPRTBIMAP1 0xc13c
|
||||
#define DWC3_GHWPARAMS0 0xc140
|
||||
#define DWC3_GHWPARAMS1 0xc144
|
||||
#define DWC3_GHWPARAMS2 0xc148
|
||||
#define DWC3_GHWPARAMS3 0xc14c
|
||||
#define DWC3_GHWPARAMS4 0xc150
|
||||
#define DWC3_GHWPARAMS5 0xc154
|
||||
#define DWC3_GHWPARAMS6 0xc158
|
||||
#define DWC3_GHWPARAMS7 0xc15c
|
||||
#define DWC3_GDBGFIFOSPACE 0xc160
|
||||
#define DWC3_GDBGLTSSM 0xc164
|
||||
#define DWC3_GPRTBIMAP_HS0 0xc180
|
||||
#define DWC3_GPRTBIMAP_HS1 0xc184
|
||||
#define DWC3_GPRTBIMAP_FS0 0xc188
|
||||
#define DWC3_GPRTBIMAP_FS1 0xc18c
|
||||
|
||||
#define DWC3_GUSB2PHYCFG(n) (0xc200 + (n * 0x04))
|
||||
#define DWC3_GUSB2I2CCTL(n) (0xc240 + (n * 0x04))
|
||||
|
||||
#define DWC3_GUSB2PHYACC(n) (0xc280 + (n * 0x04))
|
||||
|
||||
#define DWC3_GUSB3PIPECTL(n) (0xc2c0 + (n * 0x04))
|
||||
|
||||
#define DWC3_GTXFIFOSIZ(n) (0xc300 + (n * 0x04))
|
||||
#define DWC3_GRXFIFOSIZ(n) (0xc380 + (n * 0x04))
|
||||
|
||||
#define DWC3_GEVNTADRLO(n) (0xc400 + (n * 0x10))
|
||||
#define DWC3_GEVNTADRHI(n) (0xc404 + (n * 0x10))
|
||||
#define DWC3_GEVNTSIZ(n) (0xc408 + (n * 0x10))
|
||||
#define DWC3_GEVNTCOUNT(n) (0xc40c + (n * 0x10))
|
||||
|
||||
#define DWC3_GHWPARAMS8 0xc600
|
||||
|
||||
/* Device Registers */
|
||||
#define DWC3_DCFG 0xc700
|
||||
#define DWC3_DCTL 0xc704
|
||||
#define DWC3_DEVTEN 0xc708
|
||||
#define DWC3_DSTS 0xc70c
|
||||
#define DWC3_DGCMDPAR 0xc710
|
||||
#define DWC3_DGCMD 0xc714
|
||||
#define DWC3_DALEPENA 0xc720
|
||||
#define DWC3_DEPCMDPAR2(n) (0xc800 + (n * 0x10))
|
||||
#define DWC3_DEPCMDPAR1(n) (0xc804 + (n * 0x10))
|
||||
#define DWC3_DEPCMDPAR0(n) (0xc808 + (n * 0x10))
|
||||
#define DWC3_DEPCMD(n) (0xc80c + (n * 0x10))
|
||||
|
||||
/* OTG Registers */
|
||||
#define DWC3_OCFG 0xcc00
|
||||
#define DWC3_OCTL 0xcc04
|
||||
#define DWC3_OEVTEN 0xcc08
|
||||
#define DWC3_OSTS 0xcc0C
|
||||
|
||||
/* Bit fields */
|
||||
|
||||
/* Global Configuration Register */
|
||||
#define DWC3_GCTL_PWRDNSCALE(n) (n << 19)
|
||||
#define DWC3_GCTL_U2RSTECN 16
|
||||
#define DWC3_GCTL_RAMCLKSEL(x) ((x & DWC3_GCTL_CLK_MASK) << 6)
|
||||
#define DWC3_GCTL_CLK_BUS (0)
|
||||
#define DWC3_GCTL_CLK_PIPE (1)
|
||||
#define DWC3_GCTL_CLK_PIPEHALF (2)
|
||||
#define DWC3_GCTL_CLK_MASK (3)
|
||||
|
||||
#define DWC3_GCTL_PRTCAPDIR(n) (n << 12)
|
||||
#define DWC3_GCTL_PRTCAP_HOST 1
|
||||
#define DWC3_GCTL_PRTCAP_DEVICE 2
|
||||
#define DWC3_GCTL_PRTCAP_OTG 3
|
||||
|
||||
#define DWC3_GCTL_CORESOFTRESET (1 << 11)
|
||||
#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
|
||||
|
||||
/* Global USB2 PHY Configuration Register */
|
||||
#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
|
||||
#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
|
||||
|
||||
/* Global USB3 PIPE Control Register */
|
||||
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
|
||||
#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
|
||||
|
||||
/* Device Configuration Register */
|
||||
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
|
||||
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
|
||||
|
||||
#define DWC3_DCFG_SPEED_MASK (7 << 0)
|
||||
#define DWC3_DCFG_SUPERSPEED (4 << 0)
|
||||
#define DWC3_DCFG_HIGHSPEED (0 << 0)
|
||||
#define DWC3_DCFG_FULLSPEED2 (1 << 0)
|
||||
#define DWC3_DCFG_LOWSPEED (2 << 0)
|
||||
#define DWC3_DCFG_FULLSPEED1 (3 << 0)
|
||||
|
||||
/* Device Control Register */
|
||||
#define DWC3_DCTL_RUN_STOP (1 << 31)
|
||||
#define DWC3_DCTL_CSFTRST (1 << 30)
|
||||
#define DWC3_DCTL_LSFTRST (1 << 29)
|
||||
|
||||
#define DWC3_DCTL_HIRD_THRES_MASK (0x1f << 24)
|
||||
#define DWC3_DCTL_HIRD_THRES(n) (((n) & DWC3_DCTL_HIRD_THRES_MASK) >> 24)
|
||||
|
||||
#define DWC3_DCTL_APPL1RES (1 << 23)
|
||||
|
||||
#define DWC3_DCTL_INITU2ENA (1 << 12)
|
||||
#define DWC3_DCTL_ACCEPTU2ENA (1 << 11)
|
||||
#define DWC3_DCTL_INITU1ENA (1 << 10)
|
||||
#define DWC3_DCTL_ACCEPTU1ENA (1 << 9)
|
||||
#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1)
|
||||
|
||||
#define DWC3_DCTL_ULSTCHNGREQ_MASK (0x0f << 5)
|
||||
#define DWC3_DCTL_ULSTCHNGREQ(n) (((n) << 5) & DWC3_DCTL_ULSTCHNGREQ_MASK)
|
||||
|
||||
#define DWC3_DCTL_ULSTCHNG_NO_ACTION (DWC3_DCTL_ULSTCHNGREQ(0))
|
||||
#define DWC3_DCTL_ULSTCHNG_SS_DISABLED (DWC3_DCTL_ULSTCHNGREQ(4))
|
||||
#define DWC3_DCTL_ULSTCHNG_RX_DETECT (DWC3_DCTL_ULSTCHNGREQ(5))
|
||||
#define DWC3_DCTL_ULSTCHNG_SS_INACTIVE (DWC3_DCTL_ULSTCHNGREQ(6))
|
||||
#define DWC3_DCTL_ULSTCHNG_RECOVERY (DWC3_DCTL_ULSTCHNGREQ(8))
|
||||
#define DWC3_DCTL_ULSTCHNG_COMPLIANCE (DWC3_DCTL_ULSTCHNGREQ(10))
|
||||
#define DWC3_DCTL_ULSTCHNG_LOOPBACK (DWC3_DCTL_ULSTCHNGREQ(11))
|
||||
|
||||
/* Device Event Enable Register */
|
||||
#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN (1 << 12)
|
||||
#define DWC3_DEVTEN_EVNTOVERFLOWEN (1 << 11)
|
||||
#define DWC3_DEVTEN_CMDCMPLTEN (1 << 10)
|
||||
#define DWC3_DEVTEN_ERRTICERREN (1 << 9)
|
||||
#define DWC3_DEVTEN_SOFEN (1 << 7)
|
||||
#define DWC3_DEVTEN_EOPFEN (1 << 6)
|
||||
#define DWC3_DEVTEN_WKUPEVTEN (1 << 4)
|
||||
#define DWC3_DEVTEN_ULSTCNGEN (1 << 3)
|
||||
#define DWC3_DEVTEN_CONNECTDONEEN (1 << 2)
|
||||
#define DWC3_DEVTEN_USBRSTEN (1 << 1)
|
||||
#define DWC3_DEVTEN_DISCONNEVTEN (1 << 0)
|
||||
|
||||
/* Device Status Register */
|
||||
#define DWC3_DSTS_PWRUPREQ (1 << 24)
|
||||
#define DWC3_DSTS_COREIDLE (1 << 23)
|
||||
#define DWC3_DSTS_DEVCTRLHLT (1 << 22)
|
||||
|
||||
#define DWC3_DSTS_USBLNKST_MASK (0x0f << 18)
|
||||
#define DWC3_DSTS_USBLNKST(n) (((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
|
||||
|
||||
#define DWC3_DSTS_RXFIFOEMPTY (1 << 17)
|
||||
|
||||
#define DWC3_DSTS_SOFFN_MASK (0x3ff << 3)
|
||||
#define DWC3_DSTS_SOFFN(n) (((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
|
||||
|
||||
#define DWC3_DSTS_CONNECTSPD (7 << 0)
|
||||
|
||||
#define DWC3_DSTS_SUPERSPEED (4 << 0)
|
||||
#define DWC3_DSTS_HIGHSPEED (0 << 0)
|
||||
#define DWC3_DSTS_FULLSPEED2 (1 << 0)
|
||||
#define DWC3_DSTS_LOWSPEED (2 << 0)
|
||||
#define DWC3_DSTS_FULLSPEED1 (3 << 0)
|
||||
|
||||
/* Device Generic Command Register */
|
||||
#define DWC3_DGCMD_SET_LMP 0x01
|
||||
#define DWC3_DGCMD_SET_PERIODIC_PAR 0x02
|
||||
#define DWC3_DGCMD_XMIT_FUNCTION 0x03
|
||||
#define DWC3_DGCMD_SELECTED_FIFO_FLUSH 0x09
|
||||
#define DWC3_DGCMD_ALL_FIFO_FLUSH 0x0a
|
||||
#define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c
|
||||
#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10
|
||||
|
||||
/* Device Endpoint Command Register */
|
||||
#define DWC3_DEPCMD_PARAM_SHIFT 16
|
||||
#define DWC3_DEPCMD_PARAM(x) (x << DWC3_DEPCMD_PARAM_SHIFT)
|
||||
#define DWC3_DEPCMD_GET_RSC_IDX(x) ((x >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
|
||||
#define DWC3_DEPCMD_STATUS_MASK (0x0f << 12)
|
||||
#define DWC3_DEPCMD_STATUS(x) ((x & DWC3_DEPCMD_STATUS_MASK) >> 12)
|
||||
#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
|
||||
#define DWC3_DEPCMD_CMDACT (1 << 10)
|
||||
#define DWC3_DEPCMD_CMDIOC (1 << 8)
|
||||
|
||||
#define DWC3_DEPCMD_DEPSTARTCFG (0x09 << 0)
|
||||
#define DWC3_DEPCMD_ENDTRANSFER (0x08 << 0)
|
||||
#define DWC3_DEPCMD_UPDATETRANSFER (0x07 << 0)
|
||||
#define DWC3_DEPCMD_STARTTRANSFER (0x06 << 0)
|
||||
#define DWC3_DEPCMD_CLEARSTALL (0x05 << 0)
|
||||
#define DWC3_DEPCMD_SETSTALL (0x04 << 0)
|
||||
#define DWC3_DEPCMD_GETSEQNUMBER (0x03 << 0)
|
||||
#define DWC3_DEPCMD_SETTRANSFRESOURCE (0x02 << 0)
|
||||
#define DWC3_DEPCMD_SETEPCONFIG (0x01 << 0)
|
||||
|
||||
/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
|
||||
#define DWC3_DALEPENA_EP(n) (1 << n)
|
||||
|
||||
#define DWC3_DEPCMD_TYPE_CONTROL 0
|
||||
#define DWC3_DEPCMD_TYPE_ISOC 1
|
||||
#define DWC3_DEPCMD_TYPE_BULK 2
|
||||
#define DWC3_DEPCMD_TYPE_INTR 3
|
||||
|
||||
/* Structures */
|
||||
|
||||
struct dwc3_trb_hw;
|
||||
|
||||
/**
|
||||
* struct dwc3_event_buffer - Software event buffer representation
|
||||
* @list: a list of event buffers
|
||||
* @buf: _THE_ buffer
|
||||
* @length: size of this buffer
|
||||
* @dma: dma_addr_t
|
||||
* @dwc: pointer to DWC controller
|
||||
*/
|
||||
struct dwc3_event_buffer {
|
||||
void *buf;
|
||||
unsigned length;
|
||||
unsigned int lpos;
|
||||
|
||||
dma_addr_t dma;
|
||||
|
||||
struct dwc3 *dwc;
|
||||
};
|
||||
|
||||
#define DWC3_EP_FLAG_STALLED (1 << 0)
|
||||
#define DWC3_EP_FLAG_WEDGED (1 << 1)
|
||||
|
||||
#define DWC3_EP_DIRECTION_TX true
|
||||
#define DWC3_EP_DIRECTION_RX false
|
||||
|
||||
#define DWC3_TRB_NUM 32
|
||||
#define DWC3_TRB_MASK (DWC3_TRB_NUM - 1)
|
||||
|
||||
/**
|
||||
* struct dwc3_ep - device side endpoint representation
|
||||
* @endpoint: usb endpoint
|
||||
* @request_list: list of requests for this endpoint
|
||||
* @req_queued: list of requests on this ep which have TRBs setup
|
||||
* @trb_pool: array of transaction buffers
|
||||
* @trb_pool_dma: dma address of @trb_pool
|
||||
* @free_slot: next slot which is going to be used
|
||||
* @busy_slot: first slot which is owned by HW
|
||||
* @desc: usb_endpoint_descriptor pointer
|
||||
* @dwc: pointer to DWC controller
|
||||
* @flags: endpoint flags (wedged, stalled, ...)
|
||||
* @current_trb: index of current used trb
|
||||
* @number: endpoint number (1 - 15)
|
||||
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
|
||||
* @res_trans_idx: Resource transfer index
|
||||
* @interval: the intervall on which the ISOC transfer is started
|
||||
* @name: a human readable name e.g. ep1out-bulk
|
||||
* @direction: true for TX, false for RX
|
||||
*/
|
||||
struct dwc3_ep {
|
||||
struct usb_ep endpoint;
|
||||
struct list_head request_list;
|
||||
struct list_head req_queued;
|
||||
|
||||
struct dwc3_trb_hw *trb_pool;
|
||||
dma_addr_t trb_pool_dma;
|
||||
u32 free_slot;
|
||||
u32 busy_slot;
|
||||
const struct usb_endpoint_descriptor *desc;
|
||||
struct dwc3 *dwc;
|
||||
|
||||
unsigned flags;
|
||||
#define DWC3_EP_ENABLED (1 << 0)
|
||||
#define DWC3_EP_STALL (1 << 1)
|
||||
#define DWC3_EP_WEDGE (1 << 2)
|
||||
#define DWC3_EP_BUSY (1 << 4)
|
||||
#define DWC3_EP_PENDING_REQUEST (1 << 5)
|
||||
#define DWC3_EP_WILL_SHUTDOWN (1 << 6)
|
||||
|
||||
unsigned current_trb;
|
||||
|
||||
u8 number;
|
||||
u8 type;
|
||||
u8 res_trans_idx;
|
||||
u32 interval;
|
||||
|
||||
char name[20];
|
||||
|
||||
unsigned direction:1;
|
||||
};
|
||||
|
||||
enum dwc3_phy {
|
||||
DWC3_PHY_UNKNOWN = 0,
|
||||
DWC3_PHY_USB3,
|
||||
DWC3_PHY_USB2,
|
||||
};
|
||||
|
||||
enum dwc3_ep0_state {
|
||||
EP0_UNCONNECTED = 0,
|
||||
EP0_IDLE,
|
||||
EP0_IN_DATA_PHASE,
|
||||
EP0_OUT_DATA_PHASE,
|
||||
EP0_IN_WAIT_GADGET,
|
||||
EP0_OUT_WAIT_GADGET,
|
||||
EP0_IN_WAIT_NRDY,
|
||||
EP0_OUT_WAIT_NRDY,
|
||||
EP0_IN_STATUS_PHASE,
|
||||
EP0_OUT_STATUS_PHASE,
|
||||
EP0_STALL,
|
||||
};
|
||||
|
||||
enum dwc3_link_state {
|
||||
/* In SuperSpeed */
|
||||
DWC3_LINK_STATE_U0 = 0x00, /* in HS, means ON */
|
||||
DWC3_LINK_STATE_U1 = 0x01,
|
||||
DWC3_LINK_STATE_U2 = 0x02, /* in HS, means SLEEP */
|
||||
DWC3_LINK_STATE_U3 = 0x03, /* in HS, means SUSPEND */
|
||||
DWC3_LINK_STATE_SS_DIS = 0x04,
|
||||
DWC3_LINK_STATE_RX_DET = 0x05, /* in HS, means Early Suspend */
|
||||
DWC3_LINK_STATE_SS_INACT = 0x06,
|
||||
DWC3_LINK_STATE_POLL = 0x07,
|
||||
DWC3_LINK_STATE_RECOV = 0x08,
|
||||
DWC3_LINK_STATE_HRESET = 0x09,
|
||||
DWC3_LINK_STATE_CMPLY = 0x0a,
|
||||
DWC3_LINK_STATE_LPBK = 0x0b,
|
||||
DWC3_LINK_STATE_MASK = 0x0f,
|
||||
};
|
||||
|
||||
enum dwc3_device_state {
|
||||
DWC3_DEFAULT_STATE,
|
||||
DWC3_ADDRESS_STATE,
|
||||
DWC3_CONFIGURED_STATE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dwc3_trb - transfer request block
|
||||
* @bpl: lower 32bit of the buffer
|
||||
* @bph: higher 32bit of the buffer
|
||||
* @length: buffer size (up to 16mb - 1)
|
||||
* @pcm1: packet count m1
|
||||
* @trbsts: trb status
|
||||
* 0 = ok
|
||||
* 1 = missed isoc
|
||||
* 2 = setup pending
|
||||
* @hwo: hardware owner of descriptor
|
||||
* @lst: last trb
|
||||
* @chn: chain buffers
|
||||
* @csp: continue on short packets (only supported on isoc eps)
|
||||
* @trbctl: trb control
|
||||
* 1 = normal
|
||||
* 2 = control-setup
|
||||
* 3 = control-status-2
|
||||
* 4 = control-status-3
|
||||
* 5 = control-data (first trb of data stage)
|
||||
* 6 = isochronous-first (first trb of service interval)
|
||||
* 7 = isochronous
|
||||
* 8 = link trb
|
||||
* others = reserved
|
||||
* @isp_imi: interrupt on short packet / interrupt on missed isoc
|
||||
* @ioc: interrupt on complete
|
||||
* @sid_sofn: Stream ID / SOF Number
|
||||
*/
|
||||
struct dwc3_trb {
|
||||
u64 bplh;
|
||||
|
||||
union {
|
||||
struct {
|
||||
u32 length:24;
|
||||
u32 pcm1:2;
|
||||
u32 reserved27_26:2;
|
||||
u32 trbsts:4;
|
||||
#define DWC3_TRB_STS_OKAY 0
|
||||
#define DWC3_TRB_STS_MISSED_ISOC 1
|
||||
#define DWC3_TRB_STS_SETUP_PENDING 2
|
||||
};
|
||||
u32 len_pcm;
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
u32 hwo:1;
|
||||
u32 lst:1;
|
||||
u32 chn:1;
|
||||
u32 csp:1;
|
||||
u32 trbctl:6;
|
||||
u32 isp_imi:1;
|
||||
u32 ioc:1;
|
||||
u32 reserved13_12:2;
|
||||
u32 sid_sofn:16;
|
||||
u32 reserved31_30:2;
|
||||
};
|
||||
u32 control;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct dwc3_trb_hw - transfer request block (hw format)
|
||||
* @bpl: DW0-3
|
||||
* @bph: DW4-7
|
||||
* @size: DW8-B
|
||||
* @trl: DWC-F
|
||||
*/
|
||||
struct dwc3_trb_hw {
|
||||
__le32 bpl;
|
||||
__le32 bph;
|
||||
__le32 size;
|
||||
__le32 ctrl;
|
||||
} __packed;
|
||||
|
||||
static inline void dwc3_trb_to_hw(struct dwc3_trb *nat, struct dwc3_trb_hw *hw)
|
||||
{
|
||||
hw->bpl = cpu_to_le32(lower_32_bits(nat->bplh));
|
||||
hw->bph = cpu_to_le32(upper_32_bits(nat->bplh));
|
||||
hw->size = cpu_to_le32p(&nat->len_pcm);
|
||||
/* HWO is written last */
|
||||
hw->ctrl = cpu_to_le32p(&nat->control);
|
||||
}
|
||||
|
||||
static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
|
||||
{
|
||||
u64 bplh;
|
||||
|
||||
bplh = le32_to_cpup(&hw->bpl);
|
||||
bplh |= (u64) le32_to_cpup(&hw->bph) << 32;
|
||||
nat->bplh = bplh;
|
||||
|
||||
nat->len_pcm = le32_to_cpup(&hw->size);
|
||||
nat->control = le32_to_cpup(&hw->ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct dwc3 - representation of our controller
|
||||
* ctrl_req: usb control request which is used for ep0
|
||||
* ep0_trb: trb which is used for the ctrl_req
|
||||
* setup_buf: used while precessing STD USB requests
|
||||
* ctrl_req_addr: dma address of ctrl_req
|
||||
* ep0_trb: dma address of ep0_trb
|
||||
* ep0_usb_req: dummy req used while handling STD USB requests
|
||||
* setup_buf_addr: dma address of setup_buf
|
||||
* @lock: for synchronizing
|
||||
* @dev: pointer to our struct device
|
||||
* @event_buffer_list: a list of event buffers
|
||||
* @gadget: device side representation of the peripheral controller
|
||||
* @gadget_driver: pointer to the gadget driver
|
||||
* @regs: base address for our registers
|
||||
* @regs_size: address space size
|
||||
* @irq: IRQ number
|
||||
* @revision: revision register contents
|
||||
* @is_selfpowered: true when we are selfpowered
|
||||
* @three_stage_setup: set if we perform a three phase setup
|
||||
* @ep0_status_pending: ep0 status response without a req is pending
|
||||
* @ep0state: state of endpoint zero
|
||||
* @link_state: link state
|
||||
* @speed: device speed (super, high, full, low)
|
||||
* @mem: points to start of memory which is used for this struct.
|
||||
* @root: debugfs root folder pointer
|
||||
*/
|
||||
struct dwc3 {
|
||||
struct usb_ctrlrequest *ctrl_req;
|
||||
struct dwc3_trb_hw *ep0_trb;
|
||||
u8 *setup_buf;
|
||||
dma_addr_t ctrl_req_addr;
|
||||
dma_addr_t ep0_trb_addr;
|
||||
dma_addr_t setup_buf_addr;
|
||||
struct usb_request ep0_usb_req;
|
||||
/* device lock */
|
||||
spinlock_t lock;
|
||||
struct device *dev;
|
||||
|
||||
struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_NUM];
|
||||
struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
|
||||
|
||||
struct usb_gadget gadget;
|
||||
struct usb_gadget_driver *gadget_driver;
|
||||
|
||||
void __iomem *regs;
|
||||
size_t regs_size;
|
||||
|
||||
int irq;
|
||||
|
||||
u32 revision;
|
||||
|
||||
#define DWC3_REVISION_173A 0x5533173a
|
||||
#define DWC3_REVISION_175A 0x5533175a
|
||||
#define DWC3_REVISION_180A 0x5533180a
|
||||
#define DWC3_REVISION_183A 0x5533183a
|
||||
#define DWC3_REVISION_185A 0x5533185a
|
||||
#define DWC3_REVISION_188A 0x5533188a
|
||||
#define DWC3_REVISION_190A 0x5533190a
|
||||
|
||||
unsigned is_selfpowered:1;
|
||||
unsigned three_stage_setup:1;
|
||||
unsigned ep0_status_pending:1;
|
||||
|
||||
enum dwc3_ep0_state ep0state;
|
||||
enum dwc3_link_state link_state;
|
||||
enum dwc3_device_state dev_state;
|
||||
|
||||
u8 speed;
|
||||
void *mem;
|
||||
|
||||
struct dentry *root;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define DWC3_TRBSTS_OK 0
|
||||
#define DWC3_TRBSTS_MISSED_ISOC 1
|
||||
#define DWC3_TRBSTS_SETUP_PENDING 2
|
||||
|
||||
#define DWC3_TRBCTL_NORMAL 1
|
||||
#define DWC3_TRBCTL_CONTROL_SETUP 2
|
||||
#define DWC3_TRBCTL_CONTROL_STATUS2 3
|
||||
#define DWC3_TRBCTL_CONTROL_STATUS3 4
|
||||
#define DWC3_TRBCTL_CONTROL_DATA 5
|
||||
#define DWC3_TRBCTL_ISOCHRONOUS_FIRST 6
|
||||
#define DWC3_TRBCTL_ISOCHRONOUS 7
|
||||
#define DWC3_TRBCTL_LINK_TRB 8
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
struct dwc3_event_type {
|
||||
u32 is_devspec:1;
|
||||
u32 type:6;
|
||||
u32 reserved8_31:25;
|
||||
} __packed;
|
||||
|
||||
#define DWC3_DEPEVT_XFERCOMPLETE 0x01
|
||||
#define DWC3_DEPEVT_XFERINPROGRESS 0x02
|
||||
#define DWC3_DEPEVT_XFERNOTREADY 0x03
|
||||
#define DWC3_DEPEVT_RXTXFIFOEVT 0x04
|
||||
#define DWC3_DEPEVT_STREAMEVT 0x06
|
||||
#define DWC3_DEPEVT_EPCMDCMPLT 0x07
|
||||
|
||||
/**
|
||||
* struct dwc3_event_depvt - Device Endpoint Events
|
||||
* @one_bit: indicates this is an endpoint event (not used)
|
||||
* @endpoint_number: number of the endpoint
|
||||
* @endpoint_event: The event we have:
|
||||
* 0x00 - Reserved
|
||||
* 0x01 - XferComplete
|
||||
* 0x02 - XferInProgress
|
||||
* 0x03 - XferNotReady
|
||||
* 0x04 - RxTxFifoEvt (IN->Underrun, OUT->Overrun)
|
||||
* 0x05 - Reserved
|
||||
* 0x06 - StreamEvt
|
||||
* 0x07 - EPCmdCmplt
|
||||
* @reserved11_10: Reserved, don't use.
|
||||
* @status: Indicates the status of the event. Refer to databook for
|
||||
* more information.
|
||||
* @parameters: Parameters of the current event. Refer to databook for
|
||||
* more information.
|
||||
*/
|
||||
struct dwc3_event_depevt {
|
||||
u32 one_bit:1;
|
||||
u32 endpoint_number:5;
|
||||
u32 endpoint_event:4;
|
||||
u32 reserved11_10:2;
|
||||
u32 status:4;
|
||||
#define DEPEVT_STATUS_BUSERR (1 << 0)
|
||||
#define DEPEVT_STATUS_SHORT (1 << 1)
|
||||
#define DEPEVT_STATUS_IOC (1 << 2)
|
||||
#define DEPEVT_STATUS_LST (1 << 3)
|
||||
u32 parameters:16;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct dwc3_event_devt - Device Events
|
||||
* @one_bit: indicates this is a non-endpoint event (not used)
|
||||
* @device_event: indicates it's a device event. Should read as 0x00
|
||||
* @type: indicates the type of device event.
|
||||
* 0 - DisconnEvt
|
||||
* 1 - USBRst
|
||||
* 2 - ConnectDone
|
||||
* 3 - ULStChng
|
||||
* 4 - WkUpEvt
|
||||
* 5 - Reserved
|
||||
* 6 - EOPF
|
||||
* 7 - SOF
|
||||
* 8 - Reserved
|
||||
* 9 - ErrticErr
|
||||
* 10 - CmdCmplt
|
||||
* 11 - EvntOverflow
|
||||
* 12 - VndrDevTstRcved
|
||||
* @reserved15_12: Reserved, not used
|
||||
* @event_info: Information about this event
|
||||
* @reserved31_24: Reserved, not used
|
||||
*/
|
||||
struct dwc3_event_devt {
|
||||
u32 one_bit:1;
|
||||
u32 device_event:7;
|
||||
u32 type:4;
|
||||
u32 reserved15_12:4;
|
||||
u32 event_info:8;
|
||||
u32 reserved31_24:8;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct dwc3_event_gevt - Other Core Events
|
||||
* @one_bit: indicates this is a non-endpoint event (not used)
|
||||
* @device_event: indicates it's (0x03) Carkit or (0x04) I2C event.
|
||||
* @phy_port_number: self-explanatory
|
||||
* @reserved31_12: Reserved, not used.
|
||||
*/
|
||||
struct dwc3_event_gevt {
|
||||
u32 one_bit:1;
|
||||
u32 device_event:7;
|
||||
u32 phy_port_number:4;
|
||||
u32 reserved31_12:20;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* union dwc3_event - representation of Event Buffer contents
|
||||
* @raw: raw 32-bit event
|
||||
* @type: the type of the event
|
||||
* @depevt: Device Endpoint Event
|
||||
* @devt: Device Event
|
||||
* @gevt: Global Event
|
||||
*/
|
||||
union dwc3_event {
|
||||
u32 raw;
|
||||
struct dwc3_event_type type;
|
||||
struct dwc3_event_depevt depevt;
|
||||
struct dwc3_event_devt devt;
|
||||
struct dwc3_event_gevt gevt;
|
||||
};
|
||||
|
||||
/*
|
||||
* DWC3 Features to be used as Driver Data
|
||||
*/
|
||||
|
||||
#define DWC3_HAS_PERIPHERAL BIT(0)
|
||||
#define DWC3_HAS_XHCI BIT(1)
|
||||
#define DWC3_HAS_OTG BIT(3)
|
||||
|
||||
#endif /* __DRIVERS_USB_DWC3_CORE_H */
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* debug.h - DesignWare USB3 DRD Controller Debug Header
|
||||
*
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* Authors: Felipe Balbi <balbi@ti.com>,
|
||||
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The names of the above-listed copyright holders may not be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* ALTERNATIVELY, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2, as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
extern int dwc3_debugfs_init(struct dwc3 *);
|
||||
extern void dwc3_debugfs_exit(struct dwc3 *);
|
||||
#else
|
||||
static inline int dwc3_debugfs_init(struct dwc3 *d)
|
||||
{ return 0; }
|
||||
static inline void dwc3_debugfs_exit(struct dwc3 *d)
|
||||
{ }
|
||||
#endif
|
||||
|
|
@ -0,0 +1,534 @@
|
|||
/**
|
||||
* debugfs.c - DesignWare USB3 DRD Controller DebugFS file
|
||||
*
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* Authors: Felipe Balbi <balbi@ti.com>,
|
||||
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The names of the above-listed copyright holders may not be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* ALTERNATIVELY, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2, as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "gadget.h"
|
||||
#include "io.h"
|
||||
|
||||
struct dwc3_register {
|
||||
const char *name;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
#define dump_register(nm) \
|
||||
{ \
|
||||
.name = __stringify(nm), \
|
||||
.offset = DWC3_ ##nm, \
|
||||
}
|
||||
|
||||
static const struct dwc3_register dwc3_regs[] = {
|
||||
dump_register(GSBUSCFG0),
|
||||
dump_register(GSBUSCFG1),
|
||||
dump_register(GTXTHRCFG),
|
||||
dump_register(GRXTHRCFG),
|
||||
dump_register(GCTL),
|
||||
dump_register(GEVTEN),
|
||||
dump_register(GSTS),
|
||||
dump_register(GSNPSID),
|
||||
dump_register(GGPIO),
|
||||
dump_register(GUID),
|
||||
dump_register(GUCTL),
|
||||
dump_register(GBUSERRADDR0),
|
||||
dump_register(GBUSERRADDR1),
|
||||
dump_register(GPRTBIMAP0),
|
||||
dump_register(GPRTBIMAP1),
|
||||
dump_register(GHWPARAMS0),
|
||||
dump_register(GHWPARAMS1),
|
||||
dump_register(GHWPARAMS2),
|
||||
dump_register(GHWPARAMS3),
|
||||
dump_register(GHWPARAMS4),
|
||||
dump_register(GHWPARAMS5),
|
||||
dump_register(GHWPARAMS6),
|
||||
dump_register(GHWPARAMS7),
|
||||
dump_register(GDBGFIFOSPACE),
|
||||
dump_register(GDBGLTSSM),
|
||||
dump_register(GPRTBIMAP_HS0),
|
||||
dump_register(GPRTBIMAP_HS1),
|
||||
dump_register(GPRTBIMAP_FS0),
|
||||
dump_register(GPRTBIMAP_FS1),
|
||||
|
||||
dump_register(GUSB2PHYCFG(0)),
|
||||
dump_register(GUSB2PHYCFG(1)),
|
||||
dump_register(GUSB2PHYCFG(2)),
|
||||
dump_register(GUSB2PHYCFG(3)),
|
||||
dump_register(GUSB2PHYCFG(4)),
|
||||
dump_register(GUSB2PHYCFG(5)),
|
||||
dump_register(GUSB2PHYCFG(6)),
|
||||
dump_register(GUSB2PHYCFG(7)),
|
||||
dump_register(GUSB2PHYCFG(8)),
|
||||
dump_register(GUSB2PHYCFG(9)),
|
||||
dump_register(GUSB2PHYCFG(10)),
|
||||
dump_register(GUSB2PHYCFG(11)),
|
||||
dump_register(GUSB2PHYCFG(12)),
|
||||
dump_register(GUSB2PHYCFG(13)),
|
||||
dump_register(GUSB2PHYCFG(14)),
|
||||
dump_register(GUSB2PHYCFG(15)),
|
||||
|
||||
dump_register(GUSB2I2CCTL(0)),
|
||||
dump_register(GUSB2I2CCTL(1)),
|
||||
dump_register(GUSB2I2CCTL(2)),
|
||||
dump_register(GUSB2I2CCTL(3)),
|
||||
dump_register(GUSB2I2CCTL(4)),
|
||||
dump_register(GUSB2I2CCTL(5)),
|
||||
dump_register(GUSB2I2CCTL(6)),
|
||||
dump_register(GUSB2I2CCTL(7)),
|
||||
dump_register(GUSB2I2CCTL(8)),
|
||||
dump_register(GUSB2I2CCTL(9)),
|
||||
dump_register(GUSB2I2CCTL(10)),
|
||||
dump_register(GUSB2I2CCTL(11)),
|
||||
dump_register(GUSB2I2CCTL(12)),
|
||||
dump_register(GUSB2I2CCTL(13)),
|
||||
dump_register(GUSB2I2CCTL(14)),
|
||||
dump_register(GUSB2I2CCTL(15)),
|
||||
|
||||
dump_register(GUSB2PHYACC(0)),
|
||||
dump_register(GUSB2PHYACC(1)),
|
||||
dump_register(GUSB2PHYACC(2)),
|
||||
dump_register(GUSB2PHYACC(3)),
|
||||
dump_register(GUSB2PHYACC(4)),
|
||||
dump_register(GUSB2PHYACC(5)),
|
||||
dump_register(GUSB2PHYACC(6)),
|
||||
dump_register(GUSB2PHYACC(7)),
|
||||
dump_register(GUSB2PHYACC(8)),
|
||||
dump_register(GUSB2PHYACC(9)),
|
||||
dump_register(GUSB2PHYACC(10)),
|
||||
dump_register(GUSB2PHYACC(11)),
|
||||
dump_register(GUSB2PHYACC(12)),
|
||||
dump_register(GUSB2PHYACC(13)),
|
||||
dump_register(GUSB2PHYACC(14)),
|
||||
dump_register(GUSB2PHYACC(15)),
|
||||
|
||||
dump_register(GUSB3PIPECTL(0)),
|
||||
dump_register(GUSB3PIPECTL(1)),
|
||||
dump_register(GUSB3PIPECTL(2)),
|
||||
dump_register(GUSB3PIPECTL(3)),
|
||||
dump_register(GUSB3PIPECTL(4)),
|
||||
dump_register(GUSB3PIPECTL(5)),
|
||||
dump_register(GUSB3PIPECTL(6)),
|
||||
dump_register(GUSB3PIPECTL(7)),
|
||||
dump_register(GUSB3PIPECTL(8)),
|
||||
dump_register(GUSB3PIPECTL(9)),
|
||||
dump_register(GUSB3PIPECTL(10)),
|
||||
dump_register(GUSB3PIPECTL(11)),
|
||||
dump_register(GUSB3PIPECTL(12)),
|
||||
dump_register(GUSB3PIPECTL(13)),
|
||||
dump_register(GUSB3PIPECTL(14)),
|
||||
dump_register(GUSB3PIPECTL(15)),
|
||||
|
||||
dump_register(GTXFIFOSIZ(0)),
|
||||
dump_register(GTXFIFOSIZ(1)),
|
||||
dump_register(GTXFIFOSIZ(2)),
|
||||
dump_register(GTXFIFOSIZ(3)),
|
||||
dump_register(GTXFIFOSIZ(4)),
|
||||
dump_register(GTXFIFOSIZ(5)),
|
||||
dump_register(GTXFIFOSIZ(6)),
|
||||
dump_register(GTXFIFOSIZ(7)),
|
||||
dump_register(GTXFIFOSIZ(8)),
|
||||
dump_register(GTXFIFOSIZ(9)),
|
||||
dump_register(GTXFIFOSIZ(10)),
|
||||
dump_register(GTXFIFOSIZ(11)),
|
||||
dump_register(GTXFIFOSIZ(12)),
|
||||
dump_register(GTXFIFOSIZ(13)),
|
||||
dump_register(GTXFIFOSIZ(14)),
|
||||
dump_register(GTXFIFOSIZ(15)),
|
||||
dump_register(GTXFIFOSIZ(16)),
|
||||
dump_register(GTXFIFOSIZ(17)),
|
||||
dump_register(GTXFIFOSIZ(18)),
|
||||
dump_register(GTXFIFOSIZ(19)),
|
||||
dump_register(GTXFIFOSIZ(20)),
|
||||
dump_register(GTXFIFOSIZ(21)),
|
||||
dump_register(GTXFIFOSIZ(22)),
|
||||
dump_register(GTXFIFOSIZ(23)),
|
||||
dump_register(GTXFIFOSIZ(24)),
|
||||
dump_register(GTXFIFOSIZ(25)),
|
||||
dump_register(GTXFIFOSIZ(26)),
|
||||
dump_register(GTXFIFOSIZ(27)),
|
||||
dump_register(GTXFIFOSIZ(28)),
|
||||
dump_register(GTXFIFOSIZ(29)),
|
||||
dump_register(GTXFIFOSIZ(30)),
|
||||
dump_register(GTXFIFOSIZ(31)),
|
||||
|
||||
dump_register(GRXFIFOSIZ(0)),
|
||||
dump_register(GRXFIFOSIZ(1)),
|
||||
dump_register(GRXFIFOSIZ(2)),
|
||||
dump_register(GRXFIFOSIZ(3)),
|
||||
dump_register(GRXFIFOSIZ(4)),
|
||||
dump_register(GRXFIFOSIZ(5)),
|
||||
dump_register(GRXFIFOSIZ(6)),
|
||||
dump_register(GRXFIFOSIZ(7)),
|
||||
dump_register(GRXFIFOSIZ(8)),
|
||||
dump_register(GRXFIFOSIZ(9)),
|
||||
dump_register(GRXFIFOSIZ(10)),
|
||||
dump_register(GRXFIFOSIZ(11)),
|
||||
dump_register(GRXFIFOSIZ(12)),
|
||||
dump_register(GRXFIFOSIZ(13)),
|
||||
dump_register(GRXFIFOSIZ(14)),
|
||||
dump_register(GRXFIFOSIZ(15)),
|
||||
dump_register(GRXFIFOSIZ(16)),
|
||||
dump_register(GRXFIFOSIZ(17)),
|
||||
dump_register(GRXFIFOSIZ(18)),
|
||||
dump_register(GRXFIFOSIZ(19)),
|
||||
dump_register(GRXFIFOSIZ(20)),
|
||||
dump_register(GRXFIFOSIZ(21)),
|
||||
dump_register(GRXFIFOSIZ(22)),
|
||||
dump_register(GRXFIFOSIZ(23)),
|
||||
dump_register(GRXFIFOSIZ(24)),
|
||||
dump_register(GRXFIFOSIZ(25)),
|
||||
dump_register(GRXFIFOSIZ(26)),
|
||||
dump_register(GRXFIFOSIZ(27)),
|
||||
dump_register(GRXFIFOSIZ(28)),
|
||||
dump_register(GRXFIFOSIZ(29)),
|
||||
dump_register(GRXFIFOSIZ(30)),
|
||||
dump_register(GRXFIFOSIZ(31)),
|
||||
|
||||
dump_register(GEVNTADRLO(0)),
|
||||
dump_register(GEVNTADRHI(0)),
|
||||
dump_register(GEVNTSIZ(0)),
|
||||
dump_register(GEVNTCOUNT(0)),
|
||||
|
||||
dump_register(GHWPARAMS8),
|
||||
dump_register(DCFG),
|
||||
dump_register(DCTL),
|
||||
dump_register(DEVTEN),
|
||||
dump_register(DSTS),
|
||||
dump_register(DGCMDPAR),
|
||||
dump_register(DGCMD),
|
||||
dump_register(DALEPENA),
|
||||
|
||||
dump_register(DEPCMDPAR2(0)),
|
||||
dump_register(DEPCMDPAR2(1)),
|
||||
dump_register(DEPCMDPAR2(2)),
|
||||
dump_register(DEPCMDPAR2(3)),
|
||||
dump_register(DEPCMDPAR2(4)),
|
||||
dump_register(DEPCMDPAR2(5)),
|
||||
dump_register(DEPCMDPAR2(6)),
|
||||
dump_register(DEPCMDPAR2(7)),
|
||||
dump_register(DEPCMDPAR2(8)),
|
||||
dump_register(DEPCMDPAR2(9)),
|
||||
dump_register(DEPCMDPAR2(10)),
|
||||
dump_register(DEPCMDPAR2(11)),
|
||||
dump_register(DEPCMDPAR2(12)),
|
||||
dump_register(DEPCMDPAR2(13)),
|
||||
dump_register(DEPCMDPAR2(14)),
|
||||
dump_register(DEPCMDPAR2(15)),
|
||||
dump_register(DEPCMDPAR2(16)),
|
||||
dump_register(DEPCMDPAR2(17)),
|
||||
dump_register(DEPCMDPAR2(18)),
|
||||
dump_register(DEPCMDPAR2(19)),
|
||||
dump_register(DEPCMDPAR2(20)),
|
||||
dump_register(DEPCMDPAR2(21)),
|
||||
dump_register(DEPCMDPAR2(22)),
|
||||
dump_register(DEPCMDPAR2(23)),
|
||||
dump_register(DEPCMDPAR2(24)),
|
||||
dump_register(DEPCMDPAR2(25)),
|
||||
dump_register(DEPCMDPAR2(26)),
|
||||
dump_register(DEPCMDPAR2(27)),
|
||||
dump_register(DEPCMDPAR2(28)),
|
||||
dump_register(DEPCMDPAR2(29)),
|
||||
dump_register(DEPCMDPAR2(30)),
|
||||
dump_register(DEPCMDPAR2(31)),
|
||||
|
||||
dump_register(DEPCMDPAR1(0)),
|
||||
dump_register(DEPCMDPAR1(1)),
|
||||
dump_register(DEPCMDPAR1(2)),
|
||||
dump_register(DEPCMDPAR1(3)),
|
||||
dump_register(DEPCMDPAR1(4)),
|
||||
dump_register(DEPCMDPAR1(5)),
|
||||
dump_register(DEPCMDPAR1(6)),
|
||||
dump_register(DEPCMDPAR1(7)),
|
||||
dump_register(DEPCMDPAR1(8)),
|
||||
dump_register(DEPCMDPAR1(9)),
|
||||
dump_register(DEPCMDPAR1(10)),
|
||||
dump_register(DEPCMDPAR1(11)),
|
||||
dump_register(DEPCMDPAR1(12)),
|
||||
dump_register(DEPCMDPAR1(13)),
|
||||
dump_register(DEPCMDPAR1(14)),
|
||||
dump_register(DEPCMDPAR1(15)),
|
||||
dump_register(DEPCMDPAR1(16)),
|
||||
dump_register(DEPCMDPAR1(17)),
|
||||
dump_register(DEPCMDPAR1(18)),
|
||||
dump_register(DEPCMDPAR1(19)),
|
||||
dump_register(DEPCMDPAR1(20)),
|
||||
dump_register(DEPCMDPAR1(21)),
|
||||
dump_register(DEPCMDPAR1(22)),
|
||||
dump_register(DEPCMDPAR1(23)),
|
||||
dump_register(DEPCMDPAR1(24)),
|
||||
dump_register(DEPCMDPAR1(25)),
|
||||
dump_register(DEPCMDPAR1(26)),
|
||||
dump_register(DEPCMDPAR1(27)),
|
||||
dump_register(DEPCMDPAR1(28)),
|
||||
dump_register(DEPCMDPAR1(29)),
|
||||
dump_register(DEPCMDPAR1(30)),
|
||||
dump_register(DEPCMDPAR1(31)),
|
||||
|
||||
dump_register(DEPCMDPAR0(0)),
|
||||
dump_register(DEPCMDPAR0(1)),
|
||||
dump_register(DEPCMDPAR0(2)),
|
||||
dump_register(DEPCMDPAR0(3)),
|
||||
dump_register(DEPCMDPAR0(4)),
|
||||
dump_register(DEPCMDPAR0(5)),
|
||||
dump_register(DEPCMDPAR0(6)),
|
||||
dump_register(DEPCMDPAR0(7)),
|
||||
dump_register(DEPCMDPAR0(8)),
|
||||
dump_register(DEPCMDPAR0(9)),
|
||||
dump_register(DEPCMDPAR0(10)),
|
||||
dump_register(DEPCMDPAR0(11)),
|
||||
dump_register(DEPCMDPAR0(12)),
|
||||
dump_register(DEPCMDPAR0(13)),
|
||||
dump_register(DEPCMDPAR0(14)),
|
||||
dump_register(DEPCMDPAR0(15)),
|
||||
dump_register(DEPCMDPAR0(16)),
|
||||
dump_register(DEPCMDPAR0(17)),
|
||||
dump_register(DEPCMDPAR0(18)),
|
||||
dump_register(DEPCMDPAR0(19)),
|
||||
dump_register(DEPCMDPAR0(20)),
|
||||
dump_register(DEPCMDPAR0(21)),
|
||||
dump_register(DEPCMDPAR0(22)),
|
||||
dump_register(DEPCMDPAR0(23)),
|
||||
dump_register(DEPCMDPAR0(24)),
|
||||
dump_register(DEPCMDPAR0(25)),
|
||||
dump_register(DEPCMDPAR0(26)),
|
||||
dump_register(DEPCMDPAR0(27)),
|
||||
dump_register(DEPCMDPAR0(28)),
|
||||
dump_register(DEPCMDPAR0(29)),
|
||||
dump_register(DEPCMDPAR0(30)),
|
||||
dump_register(DEPCMDPAR0(31)),
|
||||
|
||||
dump_register(DEPCMD(0)),
|
||||
dump_register(DEPCMD(1)),
|
||||
dump_register(DEPCMD(2)),
|
||||
dump_register(DEPCMD(3)),
|
||||
dump_register(DEPCMD(4)),
|
||||
dump_register(DEPCMD(5)),
|
||||
dump_register(DEPCMD(6)),
|
||||
dump_register(DEPCMD(7)),
|
||||
dump_register(DEPCMD(8)),
|
||||
dump_register(DEPCMD(9)),
|
||||
dump_register(DEPCMD(10)),
|
||||
dump_register(DEPCMD(11)),
|
||||
dump_register(DEPCMD(12)),
|
||||
dump_register(DEPCMD(13)),
|
||||
dump_register(DEPCMD(14)),
|
||||
dump_register(DEPCMD(15)),
|
||||
dump_register(DEPCMD(16)),
|
||||
dump_register(DEPCMD(17)),
|
||||
dump_register(DEPCMD(18)),
|
||||
dump_register(DEPCMD(19)),
|
||||
dump_register(DEPCMD(20)),
|
||||
dump_register(DEPCMD(21)),
|
||||
dump_register(DEPCMD(22)),
|
||||
dump_register(DEPCMD(23)),
|
||||
dump_register(DEPCMD(24)),
|
||||
dump_register(DEPCMD(25)),
|
||||
dump_register(DEPCMD(26)),
|
||||
dump_register(DEPCMD(27)),
|
||||
dump_register(DEPCMD(28)),
|
||||
dump_register(DEPCMD(29)),
|
||||
dump_register(DEPCMD(30)),
|
||||
dump_register(DEPCMD(31)),
|
||||
|
||||
dump_register(OCFG),
|
||||
dump_register(OCTL),
|
||||
dump_register(OEVTEN),
|
||||
dump_register(OSTS),
|
||||
};
|
||||
|
||||
static int dwc3_regdump_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3 *dwc = s->private;
|
||||
int i;
|
||||
|
||||
seq_printf(s, "DesignWare USB3 Core Register Dump\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dwc3_regs); i++) {
|
||||
seq_printf(s, "%-20s : %08x\n", dwc3_regs[i].name,
|
||||
dwc3_readl(dwc->regs, dwc3_regs[i].offset));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_regdump_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, dwc3_regdump_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations dwc3_regdump_fops = {
|
||||
.open = dwc3_regdump_open,
|
||||
.read = seq_read,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
|
||||
static int dwc3_send_testmode_cmd(struct dwc3 *dwc, int mode)
|
||||
{
|
||||
u32 timeout = 250;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_DGCMDPAR, mode);
|
||||
dwc3_writel(dwc->regs, DWC3_DGCMD, DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK |
|
||||
DWC3_DEPCMD_CMDACT);
|
||||
do {
|
||||
u32 reg;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
|
||||
if (!(reg & DWC3_DEPCMD_CMDACT))
|
||||
return 0;
|
||||
timeout--;
|
||||
if (!timeout)
|
||||
return -ETIMEDOUT;
|
||||
mdelay(1);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static struct dwc3_trb_hw trb_0 __aligned(16);
|
||||
static struct dwc3_trb_hw trb_1 __aligned(16);
|
||||
|
||||
#define BUF_SIZE 4096
|
||||
static int dwc3_testmode_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dwc3 *dwc = inode->i_private;
|
||||
struct dwc3_gadget_ep_cmd_params par0;
|
||||
struct dwc3_gadget_ep_cmd_params par1;
|
||||
struct dwc3_trb trb;
|
||||
int ret;
|
||||
u8 *buf0;
|
||||
u8 *buf1;
|
||||
|
||||
buf0 = kmalloc(BUF_SIZE, GFP_KERNEL);
|
||||
if (!buf0)
|
||||
return -ENOMEM;
|
||||
buf1 = kmalloc(BUF_SIZE, GFP_KERNEL);
|
||||
if (!buf1)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(buf0, 0xaa, BUF_SIZE);
|
||||
memset(buf1, 0x33, BUF_SIZE);
|
||||
|
||||
memset(&trb, 0, sizeof(trb));
|
||||
memset(&par0, 0, sizeof(par0));
|
||||
memset(&par1, 0, sizeof(par1));
|
||||
|
||||
trb.lst = 1;
|
||||
trb.trbctl = DWC3_TRBCTL_NORMAL;
|
||||
trb.length = BUF_SIZE;
|
||||
trb.hwo = 1;
|
||||
|
||||
trb.bplh = virt_to_phys(buf0);
|
||||
dwc3_trb_to_hw(&trb, &trb_0);
|
||||
|
||||
trb.bplh = virt_to_phys(buf1);
|
||||
dwc3_trb_to_hw(&trb, &trb_1);
|
||||
|
||||
par0.param0.depstrtxfer.transfer_desc_addr_high =
|
||||
upper_32_bits(virt_to_phys(&trb_0));
|
||||
par0.param1.depstrtxfer.transfer_desc_addr_low =
|
||||
lower_32_bits(virt_to_phys(&trb_0));
|
||||
|
||||
par1.param0.depstrtxfer.transfer_desc_addr_high =
|
||||
upper_32_bits(virt_to_phys(&trb_1));
|
||||
par1.param1.depstrtxfer.transfer_desc_addr_low =
|
||||
lower_32_bits(virt_to_phys(&trb_1));
|
||||
|
||||
dwc3_send_testmode_cmd(dwc, 1);
|
||||
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, 0, DWC3_DEPCMD_STARTTRANSFER, &par0);
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, 1, DWC3_DEPCMD_STARTTRANSFER, &par1);
|
||||
|
||||
dwc3_send_testmode_cmd(dwc, 0);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static const struct file_operations dwc3_testmode_fops = {
|
||||
.open = dwc3_testmode_open,
|
||||
.read = seq_read,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
|
||||
{
|
||||
struct dentry *root;
|
||||
struct dentry *file;
|
||||
int ret;
|
||||
|
||||
root = debugfs_create_dir(dev_name(dwc->dev), NULL);
|
||||
if (IS_ERR(root)){
|
||||
ret = PTR_ERR(root);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
dwc->root = root;
|
||||
|
||||
file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
|
||||
&dwc3_regdump_fops);
|
||||
if (IS_ERR(file)) {
|
||||
ret = PTR_ERR(file);
|
||||
goto err1;
|
||||
}
|
||||
file = debugfs_create_file("testmode", S_IRUGO, root, dwc,
|
||||
&dwc3_testmode_fops);
|
||||
if (IS_ERR(file)) {
|
||||
ret = PTR_ERR(file);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
debugfs_remove_recursive(root);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __devexit dwc3_debugfs_exit(struct dwc3 *dwc)
|
||||
{
|
||||
debugfs_remove_recursive(dwc->root);
|
||||
dwc->root = NULL;
|
||||
}
|
|
@ -0,0 +1,410 @@
|
|||
/**
|
||||
* dwc3-omap.c - OMAP Specific Glue layer
|
||||
*
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* Authors: Felipe Balbi <balbi@ti.com>,
|
||||
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The names of the above-listed copyright holders may not be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* ALTERNATIVELY, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2, as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "io.h"
|
||||
|
||||
/*
|
||||
* All these registers belong to OMAP's Wrapper around the
|
||||
* DesignWare USB3 Core.
|
||||
*/
|
||||
|
||||
#define USBOTGSS_REVISION 0x0000
|
||||
#define USBOTGSS_SYSCONFIG 0x0010
|
||||
#define USBOTGSS_IRQ_EOI 0x0020
|
||||
#define USBOTGSS_IRQSTATUS_RAW_0 0x0024
|
||||
#define USBOTGSS_IRQSTATUS_0 0x0028
|
||||
#define USBOTGSS_IRQENABLE_SET_0 0x002c
|
||||
#define USBOTGSS_IRQENABLE_CLR_0 0x0030
|
||||
#define USBOTGSS_IRQSTATUS_RAW_1 0x0034
|
||||
#define USBOTGSS_IRQSTATUS_1 0x0038
|
||||
#define USBOTGSS_IRQENABLE_SET_1 0x003c
|
||||
#define USBOTGSS_IRQENABLE_CLR_1 0x0040
|
||||
#define USBOTGSS_UTMI_OTG_CTRL 0x0080
|
||||
#define USBOTGSS_UTMI_OTG_STATUS 0x0084
|
||||
#define USBOTGSS_MMRAM_OFFSET 0x0100
|
||||
#define USBOTGSS_FLADJ 0x0104
|
||||
#define USBOTGSS_DEBUG_CFG 0x0108
|
||||
#define USBOTGSS_DEBUG_DATA 0x010c
|
||||
|
||||
/* SYSCONFIG REGISTER */
|
||||
#define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16)
|
||||
#define USBOTGSS_SYSCONFIG_STANDBYMODE(x) ((x) << 4)
|
||||
#define USBOTGSS_SYSCONFIG_IDLEMODE(x) ((x) << 2)
|
||||
|
||||
/* IRQ_EOI REGISTER */
|
||||
#define USBOTGSS_IRQ_EOI_LINE_NUMBER (1 << 0)
|
||||
|
||||
/* IRQS0 BITS */
|
||||
#define USBOTGSS_IRQO_COREIRQ_ST (1 << 0)
|
||||
|
||||
/* IRQ1 BITS */
|
||||
#define USBOTGSS_IRQ1_DMADISABLECLR (1 << 17)
|
||||
#define USBOTGSS_IRQ1_OEVT (1 << 16)
|
||||
#define USBOTGSS_IRQ1_DRVVBUS_RISE (1 << 13)
|
||||
#define USBOTGSS_IRQ1_CHRGVBUS_RISE (1 << 12)
|
||||
#define USBOTGSS_IRQ1_DISCHRGVBUS_RISE (1 << 11)
|
||||
#define USBOTGSS_IRQ1_IDPULLUP_RISE (1 << 8)
|
||||
#define USBOTGSS_IRQ1_DRVVBUS_FALL (1 << 5)
|
||||
#define USBOTGSS_IRQ1_CHRGVBUS_FALL (1 << 4)
|
||||
#define USBOTGSS_IRQ1_DISCHRGVBUS_FALL (1 << 3)
|
||||
#define USBOTGSS_IRQ1_IDPULLUP_FALL (1 << 0)
|
||||
|
||||
/* UTMI_OTG_CTRL REGISTER */
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_DRVVBUS (1 << 5)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS (1 << 4)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS (1 << 3)
|
||||
#define USBOTGSS_UTMI_OTG_CTRL_IDPULLUP (1 << 0)
|
||||
|
||||
/* UTMI_OTG_STATUS REGISTER */
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE (1 << 31)
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT (1 << 9)
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE (1 << 8)
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_IDDIG (1 << 4)
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_SESSEND (1 << 3)
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID (1 << 2)
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID (1 << 1)
|
||||
|
||||
struct dwc3_omap {
|
||||
/* device lock */
|
||||
spinlock_t lock;
|
||||
|
||||
struct platform_device *dwc3;
|
||||
struct device *dev;
|
||||
|
||||
int irq;
|
||||
void __iomem *base;
|
||||
|
||||
void *context;
|
||||
u32 resource_size;
|
||||
|
||||
u32 dma_status:1;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int dwc3_omap_suspend(struct device *dev)
|
||||
{
|
||||
struct dwc3_omap *omap = dev_get_drvdata(dev);
|
||||
|
||||
memcpy_fromio(omap->context, omap->base, omap->resource_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_omap_resume(struct device *dev)
|
||||
{
|
||||
struct dwc3_omap *omap = dev_get_drvdata(dev);
|
||||
|
||||
memcpy_toio(omap->base, omap->context, omap->resource_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_omap_idle(struct device *dev)
|
||||
{
|
||||
struct dwc3_omap *omap = dev_get_drvdata(dev);
|
||||
u32 reg;
|
||||
|
||||
/* stop DMA Engine */
|
||||
reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
|
||||
reg &= ~(USBOTGSS_SYSCONFIG_DMADISABLE);
|
||||
dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UNIVERSAL_DEV_PM_OPS(dwc3_omap_pm_ops, dwc3_omap_suspend,
|
||||
dwc3_omap_resume, dwc3_omap_idle);
|
||||
|
||||
#define DEV_PM_OPS (&dwc3_omap_pm_ops)
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
|
||||
{
|
||||
struct dwc3_omap *omap = _omap;
|
||||
u32 reg;
|
||||
u32 ctrl;
|
||||
|
||||
spin_lock(&omap->lock);
|
||||
|
||||
reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
|
||||
ctrl = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_CTRL);
|
||||
|
||||
if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
|
||||
dev_dbg(omap->base, "DMA Disable was Cleared\n");
|
||||
omap->dma_status = false;
|
||||
}
|
||||
|
||||
if (reg & USBOTGSS_IRQ1_OEVT)
|
||||
dev_dbg(omap->base, "OTG Event\n");
|
||||
|
||||
if (reg & USBOTGSS_IRQ1_DRVVBUS_RISE) {
|
||||
dev_dbg(omap->base, "DRVVBUS Rise\n");
|
||||
ctrl |= USBOTGSS_UTMI_OTG_CTRL_DRVVBUS;
|
||||
}
|
||||
|
||||
if (reg & USBOTGSS_IRQ1_CHRGVBUS_RISE) {
|
||||
dev_dbg(omap->base, "CHRGVBUS Rise\n");
|
||||
ctrl |= USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS;
|
||||
}
|
||||
|
||||
if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_RISE) {
|
||||
dev_dbg(omap->base, "DISCHRGVBUS Rise\n");
|
||||
ctrl |= USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS;
|
||||
}
|
||||
|
||||
if (reg & USBOTGSS_IRQ1_IDPULLUP_RISE) {
|
||||
dev_dbg(omap->base, "IDPULLUP Rise\n");
|
||||
ctrl |= USBOTGSS_UTMI_OTG_CTRL_IDPULLUP;
|
||||
}
|
||||
|
||||
if (reg & USBOTGSS_IRQ1_DRVVBUS_FALL) {
|
||||
dev_dbg(omap->base, "DRVVBUS Fall\n");
|
||||
ctrl &= ~USBOTGSS_UTMI_OTG_CTRL_DRVVBUS;
|
||||
}
|
||||
|
||||
if (reg & USBOTGSS_IRQ1_CHRGVBUS_FALL) {
|
||||
dev_dbg(omap->base, "CHRGVBUS Fall\n");
|
||||
ctrl &= ~USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS;
|
||||
}
|
||||
|
||||
if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_FALL) {
|
||||
dev_dbg(omap->base, "DISCHRGVBUS Fall\n");
|
||||
ctrl &= ~USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS;
|
||||
}
|
||||
|
||||
if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL) {
|
||||
dev_dbg(omap->base, "IDPULLUP Fall\n");
|
||||
ctrl &= ~USBOTGSS_UTMI_OTG_CTRL_IDPULLUP;
|
||||
}
|
||||
|
||||
dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_CTRL, ctrl);
|
||||
|
||||
spin_unlock(&omap->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit dwc3_omap_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_device *dwc3;
|
||||
struct dwc3_omap *omap;
|
||||
struct resource *res;
|
||||
|
||||
int ret = -ENOMEM;
|
||||
int irq;
|
||||
|
||||
u32 reg;
|
||||
|
||||
void __iomem *base;
|
||||
void *context;
|
||||
|
||||
omap = kzalloc(sizeof(*omap), GFP_KERNEL);
|
||||
if (!omap) {
|
||||
dev_err(&pdev->dev, "not enough memory\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, omap);
|
||||
|
||||
irq = platform_get_irq(pdev, 1);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "missing IRQ resource\n");
|
||||
ret = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "missing memory base resource\n");
|
||||
ret = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
base = ioremap_nocache(res->start, resource_size(res));
|
||||
if (!base) {
|
||||
dev_err(&pdev->dev, "ioremap failed\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
dwc3 = platform_device_alloc("dwc3-omap", -1);
|
||||
if (!dwc3) {
|
||||
dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
context = kzalloc(resource_size(res), GFP_KERNEL);
|
||||
if (!context) {
|
||||
dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
spin_lock_init(&omap->lock);
|
||||
dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
|
||||
|
||||
dwc3->dev.parent = &pdev->dev;
|
||||
dwc3->dev.dma_mask = pdev->dev.dma_mask;
|
||||
dwc3->dev.dma_parms = pdev->dev.dma_parms;
|
||||
omap->resource_size = resource_size(res);
|
||||
omap->context = context;
|
||||
omap->dev = &pdev->dev;
|
||||
omap->irq = irq;
|
||||
omap->base = base;
|
||||
omap->dwc3 = dwc3;
|
||||
|
||||
/* check the DMA Status */
|
||||
reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
|
||||
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
|
||||
|
||||
ret = request_irq(omap->irq, dwc3_omap_interrupt, 0,
|
||||
"dwc3-wrapper", omap);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
|
||||
omap->irq, ret);
|
||||
goto err4;
|
||||
}
|
||||
|
||||
/* enable all IRQs */
|
||||
dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, 0x01);
|
||||
|
||||
reg = (USBOTGSS_IRQ1_DMADISABLECLR |
|
||||
USBOTGSS_IRQ1_OEVT |
|
||||
USBOTGSS_IRQ1_DRVVBUS_RISE |
|
||||
USBOTGSS_IRQ1_CHRGVBUS_RISE |
|
||||
USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
|
||||
USBOTGSS_IRQ1_IDPULLUP_RISE |
|
||||
USBOTGSS_IRQ1_DRVVBUS_FALL |
|
||||
USBOTGSS_IRQ1_CHRGVBUS_FALL |
|
||||
USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
|
||||
USBOTGSS_IRQ1_IDPULLUP_FALL);
|
||||
|
||||
dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
|
||||
|
||||
ret = platform_device_add_resources(dwc3, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
|
||||
goto err5;
|
||||
}
|
||||
|
||||
ret = platform_device_add(dwc3);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register dwc3 device\n");
|
||||
goto err5;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err5:
|
||||
free_irq(omap->irq, omap);
|
||||
|
||||
err4:
|
||||
kfree(omap->context);
|
||||
|
||||
err3:
|
||||
platform_device_put(dwc3);
|
||||
|
||||
err2:
|
||||
iounmap(base);
|
||||
|
||||
err1:
|
||||
kfree(omap);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit dwc3_omap_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_omap *omap = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_unregister(omap->dwc3);
|
||||
|
||||
free_irq(omap->irq, omap);
|
||||
iounmap(omap->base);
|
||||
|
||||
kfree(omap->context);
|
||||
kfree(omap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_dwc3_matach[] = {
|
||||
{
|
||||
"ti,dwc3",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_dwc3_matach);
|
||||
|
||||
static struct platform_driver dwc3_omap_driver = {
|
||||
.probe = dwc3_omap_probe,
|
||||
.remove = __devexit_p(dwc3_omap_remove),
|
||||
.driver = {
|
||||
.name = "omap-dwc3",
|
||||
.pm = DEV_PM_OPS,
|
||||
.of_match_table = of_dwc3_matach,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
|
||||
|
||||
static int __devinit dwc3_omap_init(void)
|
||||
{
|
||||
return platform_driver_register(&dwc3_omap_driver);
|
||||
}
|
||||
module_init(dwc3_omap_init);
|
||||
|
||||
static void __exit dwc3_omap_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&dwc3_omap_driver);
|
||||
}
|
||||
module_exit(dwc3_omap_exit);
|
|
@ -0,0 +1,220 @@
|
|||
/**
|
||||
* dwc3-pci.c - PCI Specific glue layer
|
||||
*
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* Authors: Felipe Balbi <balbi@ti.com>,
|
||||
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The names of the above-listed copyright holders may not be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* ALTERNATIVELY, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2, as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/* FIXME define these in <linux/pci_ids.h> */
|
||||
#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
|
||||
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
|
||||
|
||||
#define DWC3_PCI_DEVS_POSSIBLE 32
|
||||
|
||||
struct dwc3_pci {
|
||||
struct device *dev;
|
||||
struct platform_device *dwc3;
|
||||
};
|
||||
|
||||
static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
|
||||
|
||||
static int dwc3_pci_get_device_id(struct dwc3_pci *glue)
|
||||
{
|
||||
int id;
|
||||
|
||||
again:
|
||||
id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
|
||||
if (id < DWC3_PCI_DEVS_POSSIBLE) {
|
||||
int old;
|
||||
|
||||
old = test_and_set_bit(id, dwc3_pci_devs);
|
||||
if (old)
|
||||
goto again;
|
||||
} else {
|
||||
dev_err(glue->dev, "no space for new device\n");
|
||||
id = -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (id < 0)
|
||||
return;
|
||||
|
||||
ret = test_bit(id, dwc3_pci_devs);
|
||||
WARN(!ret, "Device: %s\nID %d not in use\n",
|
||||
dev_driver_string(glue->dev), id);
|
||||
clear_bit(id, dwc3_pci_devs);
|
||||
}
|
||||
|
||||
static int __devinit dwc3_pci_probe(struct pci_dev *pci,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct resource res[2];
|
||||
struct platform_device *dwc3;
|
||||
struct dwc3_pci *glue;
|
||||
int ret = -ENOMEM;
|
||||
int devid;
|
||||
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&pci->dev, "not enough memory\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
glue->dev = &pci->dev;
|
||||
|
||||
ret = pci_enable_device(pci);
|
||||
if (ret) {
|
||||
dev_err(&pci->dev, "failed to enable pci device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
pci_set_power_state(pci, PCI_D0);
|
||||
pci_set_master(pci);
|
||||
|
||||
devid = dwc3_pci_get_device_id(glue);
|
||||
if (devid < 0)
|
||||
goto err2;
|
||||
|
||||
dwc3 = platform_device_alloc("dwc3-pci", devid);
|
||||
if (!dwc3) {
|
||||
dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
|
||||
|
||||
res[0].start = pci_resource_start(pci, 0);
|
||||
res[0].end = pci_resource_end(pci, 0);
|
||||
res[0].name = "dwc_usb3";
|
||||
res[0].flags = IORESOURCE_MEM;
|
||||
|
||||
res[1].start = pci->irq;
|
||||
res[1].name = "dwc_usb3";
|
||||
res[1].flags = IORESOURCE_IRQ;
|
||||
|
||||
ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
|
||||
if (ret) {
|
||||
dev_err(&pci->dev, "couldn't add resources to dwc3 device\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pci, glue);
|
||||
|
||||
dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
|
||||
|
||||
dwc3->dev.dma_mask = pci->dev.dma_mask;
|
||||
dwc3->dev.dma_parms = pci->dev.dma_parms;
|
||||
dwc3->dev.parent = &pci->dev;
|
||||
glue->dwc3 = dwc3;
|
||||
|
||||
ret = platform_device_add(dwc3);
|
||||
if (ret) {
|
||||
dev_err(&pci->dev, "failed to register dwc3 device\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
pci_set_drvdata(pci, NULL);
|
||||
platform_device_put(dwc3);
|
||||
|
||||
err3:
|
||||
dwc3_pci_put_device_id(glue, devid);
|
||||
|
||||
err2:
|
||||
pci_disable_device(pci);
|
||||
|
||||
err1:
|
||||
kfree(pci);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit dwc3_pci_remove(struct pci_dev *pci)
|
||||
{
|
||||
struct dwc3_pci *glue = pci_get_drvdata(pci);
|
||||
|
||||
dwc3_pci_put_device_id(glue, glue->dwc3->id);
|
||||
platform_device_unregister(glue->dwc3);
|
||||
pci_set_drvdata(pci, NULL);
|
||||
pci_disable_device(pci);
|
||||
kfree(glue);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
|
||||
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
|
||||
},
|
||||
{ } /* Terminating Entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
|
||||
|
||||
static struct pci_driver dwc3_pci_driver = {
|
||||
.name = "pci-dwc3",
|
||||
.id_table = dwc3_pci_id_table,
|
||||
.probe = dwc3_pci_probe,
|
||||
.remove = __devexit_p(dwc3_pci_remove),
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
|
||||
|
||||
static int __devinit dwc3_pci_init(void)
|
||||
{
|
||||
return pci_register_driver(&dwc3_pci_driver);
|
||||
}
|
||||
module_init(dwc3_pci_init);
|
||||
|
||||
static void __exit dwc3_pci_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&dwc3_pci_driver);
|
||||
}
|
||||
module_exit(dwc3_pci_exit);
|
|
@ -0,0 +1,782 @@
|
|||
/**
|
||||
* ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling
|
||||
*
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* Authors: Felipe Balbi <balbi@ti.com>,
|
||||
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The names of the above-listed copyright holders may not be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* ALTERNATIVELY, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2, as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "gadget.h"
|
||||
#include "io.h"
|
||||
|
||||
static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event);
|
||||
|
||||
static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case EP0_UNCONNECTED:
|
||||
return "Unconnected";
|
||||
case EP0_IDLE:
|
||||
return "Idle";
|
||||
case EP0_IN_DATA_PHASE:
|
||||
return "IN Data Phase";
|
||||
case EP0_OUT_DATA_PHASE:
|
||||
return "OUT Data Phase";
|
||||
case EP0_IN_WAIT_GADGET:
|
||||
return "IN Wait Gadget";
|
||||
case EP0_OUT_WAIT_GADGET:
|
||||
return "OUT Wait Gadget";
|
||||
case EP0_IN_WAIT_NRDY:
|
||||
return "IN Wait NRDY";
|
||||
case EP0_OUT_WAIT_NRDY:
|
||||
return "OUT Wait NRDY";
|
||||
case EP0_IN_STATUS_PHASE:
|
||||
return "IN Status Phase";
|
||||
case EP0_OUT_STATUS_PHASE:
|
||||
return "OUT Status Phase";
|
||||
case EP0_STALL:
|
||||
return "Stall";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
|
||||
u32 len)
|
||||
{
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
struct dwc3_trb_hw *trb_hw;
|
||||
struct dwc3_trb trb;
|
||||
struct dwc3_ep *dep;
|
||||
|
||||
int ret;
|
||||
|
||||
dep = dwc->eps[epnum];
|
||||
|
||||
trb_hw = dwc->ep0_trb;
|
||||
memset(&trb, 0, sizeof(trb));
|
||||
|
||||
switch (dwc->ep0state) {
|
||||
case EP0_IDLE:
|
||||
trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
|
||||
break;
|
||||
|
||||
case EP0_IN_WAIT_NRDY:
|
||||
case EP0_OUT_WAIT_NRDY:
|
||||
case EP0_IN_STATUS_PHASE:
|
||||
case EP0_OUT_STATUS_PHASE:
|
||||
if (dwc->three_stage_setup)
|
||||
trb.trbctl = DWC3_TRBCTL_CONTROL_STATUS3;
|
||||
else
|
||||
trb.trbctl = DWC3_TRBCTL_CONTROL_STATUS2;
|
||||
|
||||
if (dwc->ep0state == EP0_IN_WAIT_NRDY)
|
||||
dwc->ep0state = EP0_IN_STATUS_PHASE;
|
||||
else if (dwc->ep0state == EP0_OUT_WAIT_NRDY)
|
||||
dwc->ep0state = EP0_OUT_STATUS_PHASE;
|
||||
break;
|
||||
|
||||
case EP0_IN_WAIT_GADGET:
|
||||
dwc->ep0state = EP0_IN_WAIT_NRDY;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case EP0_OUT_WAIT_GADGET:
|
||||
dwc->ep0state = EP0_OUT_WAIT_NRDY;
|
||||
return 0;
|
||||
|
||||
break;
|
||||
|
||||
case EP0_IN_DATA_PHASE:
|
||||
case EP0_OUT_DATA_PHASE:
|
||||
trb.trbctl = DWC3_TRBCTL_CONTROL_DATA;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(dwc->dev, "%s() can't in state %d\n", __func__,
|
||||
dwc->ep0state);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
trb.bplh = buf_dma;
|
||||
trb.length = len;
|
||||
|
||||
trb.hwo = 1;
|
||||
trb.lst = 1;
|
||||
trb.ioc = 1;
|
||||
trb.isp_imi = 1;
|
||||
|
||||
dwc3_trb_to_hw(&trb, trb_hw);
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.param0.depstrtxfer.transfer_desc_addr_high =
|
||||
upper_32_bits(dwc->ep0_trb_addr);
|
||||
params.param1.depstrtxfer.transfer_desc_addr_low =
|
||||
lower_32_bits(dwc->ep0_trb_addr);
|
||||
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
|
||||
DWC3_DEPCMD_STARTTRANSFER, ¶ms);
|
||||
if (ret < 0) {
|
||||
dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
|
||||
dep->number);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
|
||||
struct dwc3_request *req)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
int ret;
|
||||
|
||||
req->request.actual = 0;
|
||||
req->request.status = -EINPROGRESS;
|
||||
req->direction = dep->direction;
|
||||
req->epnum = dep->number;
|
||||
|
||||
list_add_tail(&req->list, &dep->request_list);
|
||||
dwc3_map_buffer_to_dma(req);
|
||||
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma,
|
||||
req->request.length);
|
||||
if (ret < 0) {
|
||||
list_del(&req->list);
|
||||
dwc3_unmap_buffer_from_dma(req);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct dwc3_request *req = to_dwc3_request(request);
|
||||
struct dwc3_ep *dep = to_dwc3_ep(ep);
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
int ret;
|
||||
|
||||
switch (dwc->ep0state) {
|
||||
case EP0_IN_DATA_PHASE:
|
||||
case EP0_IN_WAIT_GADGET:
|
||||
case EP0_IN_WAIT_NRDY:
|
||||
case EP0_IN_STATUS_PHASE:
|
||||
dep = dwc->eps[1];
|
||||
break;
|
||||
|
||||
case EP0_OUT_DATA_PHASE:
|
||||
case EP0_OUT_WAIT_GADGET:
|
||||
case EP0_OUT_WAIT_NRDY:
|
||||
case EP0_OUT_STATUS_PHASE:
|
||||
dep = dwc->eps[0];
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
if (!dep->desc) {
|
||||
dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
|
||||
request, dep->name);
|
||||
ret = -ESHUTDOWN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* we share one TRB for ep0/1 */
|
||||
if (!list_empty(&dwc->eps[0]->request_list) ||
|
||||
!list_empty(&dwc->eps[1]->request_list) ||
|
||||
dwc->ep0_status_pending) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev_vdbg(dwc->dev, "queueing request %p to %s length %d, state '%s'\n",
|
||||
request, dep->name, request->length,
|
||||
dwc3_ep0_state_string(dwc->ep0state));
|
||||
|
||||
ret = __dwc3_gadget_ep0_queue(dep, req);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
|
||||
{
|
||||
/* stall is always issued on EP0 */
|
||||
__dwc3_gadget_ep_set_halt(dwc->eps[0], 1);
|
||||
dwc->eps[0]->flags &= ~DWC3_EP_STALL;
|
||||
dwc->ep0state = EP0_IDLE;
|
||||
dwc3_ep0_out_start(dwc);
|
||||
}
|
||||
|
||||
void dwc3_ep0_out_start(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
int ret;
|
||||
|
||||
dep = dwc->eps[0];
|
||||
|
||||
ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8);
|
||||
WARN_ON(ret < 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a zero length packet for the status phase of the control transfer
|
||||
*/
|
||||
static void dwc3_ep0_do_setup_status(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
int ret;
|
||||
u32 epnum;
|
||||
|
||||
epnum = event->endpoint_number;
|
||||
dep = dwc->eps[epnum];
|
||||
|
||||
if (epnum)
|
||||
dwc->ep0state = EP0_IN_STATUS_PHASE;
|
||||
else
|
||||
dwc->ep0state = EP0_OUT_STATUS_PHASE;
|
||||
|
||||
/*
|
||||
* Not sure Why I need a buffer for a zero transfer. Maybe the
|
||||
* HW reacts strange on a NULL pointer
|
||||
*/
|
||||
ret = dwc3_ep0_start_trans(dwc, epnum, dwc->ctrl_req_addr, 0);
|
||||
if (ret) {
|
||||
dev_dbg(dwc->dev, "failed to start transfer, stalling\n");
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
}
|
||||
}
|
||||
|
||||
static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
u32 windex = le16_to_cpu(wIndex_le);
|
||||
u32 epnum;
|
||||
|
||||
epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1;
|
||||
if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
|
||||
epnum |= 1;
|
||||
|
||||
dep = dwc->eps[epnum];
|
||||
if (dep->flags & DWC3_EP_ENABLED)
|
||||
return dep;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void dwc3_ep0_send_status_response(struct dwc3 *dwc)
|
||||
{
|
||||
u32 epnum;
|
||||
|
||||
if (dwc->ep0state == EP0_IN_DATA_PHASE)
|
||||
epnum = 1;
|
||||
else
|
||||
epnum = 0;
|
||||
|
||||
dwc3_ep0_start_trans(dwc, epnum, dwc->ctrl_req_addr,
|
||||
dwc->ep0_usb_req.length);
|
||||
dwc->ep0_status_pending = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ch 9.4.5
|
||||
*/
|
||||
static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
u32 recip;
|
||||
u16 usb_status = 0;
|
||||
__le16 *response_pkt;
|
||||
|
||||
recip = ctrl->bRequestType & USB_RECIP_MASK;
|
||||
switch (recip) {
|
||||
case USB_RECIP_DEVICE:
|
||||
/*
|
||||
* We are self-powered. U1/U2/LTM will be set later
|
||||
* once we handle this states. RemoteWakeup is 0 on SS
|
||||
*/
|
||||
usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
|
||||
break;
|
||||
|
||||
case USB_RECIP_INTERFACE:
|
||||
/*
|
||||
* Function Remote Wake Capable D0
|
||||
* Function Remote Wakeup D1
|
||||
*/
|
||||
break;
|
||||
|
||||
case USB_RECIP_ENDPOINT:
|
||||
dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
|
||||
if (!dep)
|
||||
return -EINVAL;
|
||||
|
||||
if (dep->flags & DWC3_EP_STALL)
|
||||
usb_status = 1 << USB_ENDPOINT_HALT;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
response_pkt = (__le16 *) dwc->setup_buf;
|
||||
*response_pkt = cpu_to_le16(usb_status);
|
||||
dwc->ep0_usb_req.length = sizeof(*response_pkt);
|
||||
dwc3_ep0_send_status_response(dwc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
|
||||
struct usb_ctrlrequest *ctrl, int set)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
u32 recip;
|
||||
u32 wValue;
|
||||
u32 wIndex;
|
||||
u32 reg;
|
||||
int ret;
|
||||
u32 mode;
|
||||
|
||||
wValue = le16_to_cpu(ctrl->wValue);
|
||||
wIndex = le16_to_cpu(ctrl->wIndex);
|
||||
recip = ctrl->bRequestType & USB_RECIP_MASK;
|
||||
switch (recip) {
|
||||
case USB_RECIP_DEVICE:
|
||||
|
||||
/*
|
||||
* 9.4.1 says only only for SS, in AddressState only for
|
||||
* default control pipe
|
||||
*/
|
||||
switch (wValue) {
|
||||
case USB_DEVICE_U1_ENABLE:
|
||||
case USB_DEVICE_U2_ENABLE:
|
||||
case USB_DEVICE_LTM_ENABLE:
|
||||
if (dwc->dev_state != DWC3_CONFIGURED_STATE)
|
||||
return -EINVAL;
|
||||
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* XXX add U[12] & LTM */
|
||||
switch (wValue) {
|
||||
case USB_DEVICE_REMOTE_WAKEUP:
|
||||
break;
|
||||
case USB_DEVICE_U1_ENABLE:
|
||||
break;
|
||||
case USB_DEVICE_U2_ENABLE:
|
||||
break;
|
||||
case USB_DEVICE_LTM_ENABLE:
|
||||
break;
|
||||
|
||||
case USB_DEVICE_TEST_MODE:
|
||||
if ((wIndex & 0xff) != 0)
|
||||
return -EINVAL;
|
||||
if (!set)
|
||||
return -EINVAL;
|
||||
|
||||
mode = wIndex >> 8;
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
|
||||
|
||||
switch (mode) {
|
||||
case TEST_J:
|
||||
case TEST_K:
|
||||
case TEST_SE0_NAK:
|
||||
case TEST_PACKET:
|
||||
case TEST_FORCE_EN:
|
||||
reg |= mode << 1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_RECIP_INTERFACE:
|
||||
switch (wValue) {
|
||||
case USB_INTRF_FUNC_SUSPEND:
|
||||
if (wIndex & USB_INTRF_FUNC_SUSPEND_LP)
|
||||
/* XXX enable Low power suspend */
|
||||
;
|
||||
if (wIndex & USB_INTRF_FUNC_SUSPEND_RW)
|
||||
/* XXX enable remote wakeup */
|
||||
;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_RECIP_ENDPOINT:
|
||||
switch (wValue) {
|
||||
case USB_ENDPOINT_HALT:
|
||||
|
||||
dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
|
||||
if (!dep)
|
||||
return -EINVAL;
|
||||
ret = __dwc3_gadget_ep_set_halt(dep, set);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
dwc->ep0state = EP0_IN_WAIT_NRDY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 addr;
|
||||
u32 reg;
|
||||
|
||||
addr = le16_to_cpu(ctrl->wValue);
|
||||
if (addr > 127)
|
||||
return -EINVAL;
|
||||
|
||||
switch (dwc->dev_state) {
|
||||
case DWC3_DEFAULT_STATE:
|
||||
case DWC3_ADDRESS_STATE:
|
||||
/*
|
||||
* Not sure if we should program DevAddr now or later
|
||||
*/
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
|
||||
reg &= ~(DWC3_DCFG_DEVADDR_MASK);
|
||||
reg |= DWC3_DCFG_DEVADDR(addr);
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
||||
if (addr)
|
||||
dwc->dev_state = DWC3_ADDRESS_STATE;
|
||||
else
|
||||
dwc->dev_state = DWC3_DEFAULT_STATE;
|
||||
break;
|
||||
|
||||
case DWC3_CONFIGURED_STATE:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
dwc->ep0state = EP0_IN_WAIT_NRDY;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
spin_unlock(&dwc->lock);
|
||||
ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl);
|
||||
spin_lock(&dwc->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
u32 cfg;
|
||||
int ret;
|
||||
|
||||
cfg = le16_to_cpu(ctrl->wValue);
|
||||
|
||||
switch (dwc->dev_state) {
|
||||
case DWC3_DEFAULT_STATE:
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
||||
case DWC3_ADDRESS_STATE:
|
||||
ret = dwc3_ep0_delegate_req(dwc, ctrl);
|
||||
/* if the cfg matches and the cfg is non zero */
|
||||
if (!ret && cfg)
|
||||
dwc->dev_state = DWC3_CONFIGURED_STATE;
|
||||
break;
|
||||
|
||||
case DWC3_CONFIGURED_STATE:
|
||||
ret = dwc3_ep0_delegate_req(dwc, ctrl);
|
||||
if (!cfg)
|
||||
dwc->dev_state = DWC3_ADDRESS_STATE;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (ctrl->bRequest) {
|
||||
case USB_REQ_GET_STATUS:
|
||||
dev_vdbg(dwc->dev, "USB_REQ_GET_STATUS\n");
|
||||
ret = dwc3_ep0_handle_status(dwc, ctrl);
|
||||
break;
|
||||
case USB_REQ_CLEAR_FEATURE:
|
||||
dev_vdbg(dwc->dev, "USB_REQ_CLEAR_FEATURE\n");
|
||||
ret = dwc3_ep0_handle_feature(dwc, ctrl, 0);
|
||||
break;
|
||||
case USB_REQ_SET_FEATURE:
|
||||
dev_vdbg(dwc->dev, "USB_REQ_SET_FEATURE\n");
|
||||
ret = dwc3_ep0_handle_feature(dwc, ctrl, 1);
|
||||
break;
|
||||
case USB_REQ_SET_ADDRESS:
|
||||
dev_vdbg(dwc->dev, "USB_REQ_SET_ADDRESS\n");
|
||||
ret = dwc3_ep0_set_address(dwc, ctrl);
|
||||
break;
|
||||
case USB_REQ_SET_CONFIGURATION:
|
||||
dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
|
||||
ret = dwc3_ep0_set_config(dwc, ctrl);
|
||||
break;
|
||||
default:
|
||||
dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
|
||||
ret = dwc3_ep0_delegate_req(dwc, ctrl);
|
||||
break;
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
|
||||
int ret;
|
||||
u32 len;
|
||||
|
||||
if (!dwc->gadget_driver)
|
||||
goto err;
|
||||
|
||||
len = le16_to_cpu(ctrl->wLength);
|
||||
if (!len) {
|
||||
dwc->ep0state = EP0_IN_WAIT_GADGET;
|
||||
dwc->three_stage_setup = 0;
|
||||
} else {
|
||||
dwc->three_stage_setup = 1;
|
||||
if (ctrl->bRequestType & USB_DIR_IN)
|
||||
dwc->ep0state = EP0_IN_DATA_PHASE;
|
||||
else
|
||||
dwc->ep0state = EP0_OUT_DATA_PHASE;
|
||||
}
|
||||
|
||||
if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
|
||||
ret = dwc3_ep0_std_request(dwc, ctrl);
|
||||
else
|
||||
ret = dwc3_ep0_delegate_req(dwc, ctrl);
|
||||
|
||||
if (ret >= 0)
|
||||
return;
|
||||
|
||||
err:
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
}
|
||||
|
||||
static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
struct dwc3_request *r = NULL;
|
||||
struct usb_request *ur;
|
||||
struct dwc3_trb trb;
|
||||
struct dwc3_ep *dep;
|
||||
u32 transfered;
|
||||
u8 epnum;
|
||||
|
||||
epnum = event->endpoint_number;
|
||||
dep = dwc->eps[epnum];
|
||||
|
||||
if (!dwc->ep0_status_pending) {
|
||||
r = next_request(&dep->request_list);
|
||||
ur = &r->request;
|
||||
} else {
|
||||
ur = &dwc->ep0_usb_req;
|
||||
dwc->ep0_status_pending = 0;
|
||||
}
|
||||
|
||||
dwc3_trb_to_nat(dwc->ep0_trb, &trb);
|
||||
|
||||
transfered = ur->length - trb.length;
|
||||
ur->actual += transfered;
|
||||
|
||||
if ((epnum & 1) && ur->actual < ur->length) {
|
||||
/* for some reason we did not get everything out */
|
||||
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
dwc3_gadget_giveback(dep, r, -ECONNRESET);
|
||||
} else {
|
||||
/*
|
||||
* handle the case where we have to send a zero packet. This
|
||||
* seems to be case when req.length > maxpacket. Could it be?
|
||||
*/
|
||||
/* The transfer is complete, wait for HOST */
|
||||
if (epnum & 1)
|
||||
dwc->ep0state = EP0_IN_WAIT_NRDY;
|
||||
else
|
||||
dwc->ep0state = EP0_OUT_WAIT_NRDY;
|
||||
|
||||
if (r)
|
||||
dwc3_gadget_giveback(dep, r, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_ep0_complete_req(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
struct dwc3_request *r;
|
||||
struct dwc3_ep *dep;
|
||||
u8 epnum;
|
||||
|
||||
epnum = event->endpoint_number;
|
||||
dep = dwc->eps[epnum];
|
||||
|
||||
if (!list_empty(&dep->request_list)) {
|
||||
r = next_request(&dep->request_list);
|
||||
|
||||
dwc3_gadget_giveback(dep, r, 0);
|
||||
}
|
||||
|
||||
dwc->ep0state = EP0_IDLE;
|
||||
dwc3_ep0_out_start(dwc);
|
||||
}
|
||||
|
||||
static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
switch (dwc->ep0state) {
|
||||
case EP0_IDLE:
|
||||
dwc3_ep0_inspect_setup(dwc, event);
|
||||
break;
|
||||
|
||||
case EP0_IN_DATA_PHASE:
|
||||
case EP0_OUT_DATA_PHASE:
|
||||
dwc3_ep0_complete_data(dwc, event);
|
||||
break;
|
||||
|
||||
case EP0_IN_STATUS_PHASE:
|
||||
case EP0_OUT_STATUS_PHASE:
|
||||
dwc3_ep0_complete_req(dwc, event);
|
||||
break;
|
||||
|
||||
case EP0_IN_WAIT_NRDY:
|
||||
case EP0_OUT_WAIT_NRDY:
|
||||
case EP0_IN_WAIT_GADGET:
|
||||
case EP0_OUT_WAIT_GADGET:
|
||||
case EP0_UNCONNECTED:
|
||||
case EP0_STALL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
switch (dwc->ep0state) {
|
||||
case EP0_IN_WAIT_GADGET:
|
||||
dwc->ep0state = EP0_IN_WAIT_NRDY;
|
||||
break;
|
||||
case EP0_OUT_WAIT_GADGET:
|
||||
dwc->ep0state = EP0_OUT_WAIT_NRDY;
|
||||
break;
|
||||
|
||||
case EP0_IN_WAIT_NRDY:
|
||||
case EP0_OUT_WAIT_NRDY:
|
||||
dwc3_ep0_do_setup_status(dwc, event);
|
||||
break;
|
||||
|
||||
case EP0_IDLE:
|
||||
case EP0_IN_STATUS_PHASE:
|
||||
case EP0_OUT_STATUS_PHASE:
|
||||
case EP0_IN_DATA_PHASE:
|
||||
case EP0_OUT_DATA_PHASE:
|
||||
case EP0_UNCONNECTED:
|
||||
case EP0_STALL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void dwc3_ep0_interrupt(struct dwc3 *dwc,
|
||||
const const struct dwc3_event_depevt *event)
|
||||
{
|
||||
u8 epnum = event->endpoint_number;
|
||||
|
||||
dev_dbg(dwc->dev, "%s while ep%d%s in state '%s'\n",
|
||||
dwc3_ep_event_string(event->endpoint_event),
|
||||
epnum, (epnum & 1) ? "in" : "out",
|
||||
dwc3_ep0_state_string(dwc->ep0state));
|
||||
|
||||
switch (event->endpoint_event) {
|
||||
case DWC3_DEPEVT_XFERCOMPLETE:
|
||||
dwc3_ep0_xfer_complete(dwc, event);
|
||||
break;
|
||||
|
||||
case DWC3_DEPEVT_XFERNOTREADY:
|
||||
dwc3_ep0_xfernotready(dwc, event);
|
||||
break;
|
||||
|
||||
case DWC3_DEPEVT_XFERINPROGRESS:
|
||||
case DWC3_DEPEVT_RXTXFIFOEVT:
|
||||
case DWC3_DEPEVT_STREAMEVT:
|
||||
case DWC3_DEPEVT_EPCMDCMPLT:
|
||||
break;
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,297 @@
|
|||
/**
|
||||
* gadget.h - DesignWare USB3 DRD Gadget Header
|
||||
*
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* Authors: Felipe Balbi <balbi@ti.com>,
|
||||
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The names of the above-listed copyright holders may not be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* ALTERNATIVELY, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2, as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_USB_DWC3_GADGET_H
|
||||
#define __DRIVERS_USB_DWC3_GADGET_H
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include "io.h"
|
||||
|
||||
struct dwc3;
|
||||
#define to_dwc3_ep(ep) (container_of(ep, struct dwc3_ep, endpoint))
|
||||
#define gadget_to_dwc(g) (container_of(g, struct dwc3, gadget))
|
||||
|
||||
/**
|
||||
* struct dwc3_gadget_ep_depcfg_param1 - DEPCMDPAR0 for DEPCFG command
|
||||
* @interrupt_number: self-explanatory
|
||||
* @reserved7_5: set to zero
|
||||
* @xfer_complete_enable: event generated when transfer completed
|
||||
* @xfer_in_progress_enable: event generated when transfer in progress
|
||||
* @xfer_not_ready_enable: event generated when transfer not read
|
||||
* @fifo_error_enable: generates events when FIFO Underrun (IN eps)
|
||||
* or FIFO Overrun (OUT) eps
|
||||
* @reserved_12: set to zero
|
||||
* @stream_event_enable: event generated on stream
|
||||
* @reserved14_15: set to zero
|
||||
* @binterval_m1: bInterval minus 1
|
||||
* @stream_capable: this EP is capable of handling streams
|
||||
* @ep_number: self-explanatory
|
||||
* @bulk_based: Set to ‘1’ if this isochronous endpoint represents a bulk
|
||||
* data stream that ignores the relationship of bus time to the
|
||||
* intervals programmed in TRBs.
|
||||
* @fifo_based: Set to ‘1’ if this isochronous endpoint represents a
|
||||
* FIFO-based data stream where TRBs have fixed values and are never
|
||||
* written back by the core.
|
||||
*/
|
||||
struct dwc3_gadget_ep_depcfg_param1 {
|
||||
u32 interrupt_number:5;
|
||||
u32 reserved7_5:3; /* set to zero */
|
||||
u32 xfer_complete_enable:1;
|
||||
u32 xfer_in_progress_enable:1;
|
||||
u32 xfer_not_ready_enable:1;
|
||||
u32 fifo_error_enable:1; /* IN-underrun, OUT-overrun */
|
||||
u32 reserved12:1; /* set to zero */
|
||||
u32 stream_event_enable:1;
|
||||
u32 reserved14_15:2;
|
||||
u32 binterval_m1:8; /* bInterval minus 1 */
|
||||
u32 stream_capable:1;
|
||||
u32 ep_number:5;
|
||||
u32 bulk_based:1;
|
||||
u32 fifo_based:1;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct dwc3_gadget_ep_depcfg_param0 - Parameter 0 for DEPCFG
|
||||
* @reserved0: set to zero
|
||||
* @ep_type: Endpoint Type (control, bulk, iso, interrupt)
|
||||
* @max_packet_size: max packet size in bytes
|
||||
* @reserved16_14: set to zero
|
||||
* @fifo_number: self-explanatory
|
||||
* @burst_size: burst size minus 1
|
||||
* @data_sequence_number: Must be 0 when an endpoint is initially configured
|
||||
* May be non-zero when an endpoint is configured after a power transition
|
||||
* that requires a save/restore.
|
||||
* @ignore_sequence_number: Set to ‘1’ to avoid resetting the sequence
|
||||
* number. This setting is used by software to modify the DEPEVTEN
|
||||
* event enable bits without modifying other endpoint settings.
|
||||
*/
|
||||
struct dwc3_gadget_ep_depcfg_param0 {
|
||||
u32 reserved0:1;
|
||||
u32 ep_type:2;
|
||||
u32 max_packet_size:11;
|
||||
u32 reserved16_14:3;
|
||||
u32 fifo_number:5;
|
||||
u32 burst_size:4;
|
||||
u32 data_sequence_number:5;
|
||||
u32 ignore_sequence_number:1;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct dwc3_gadget_ep_depxfercfg_param0 - Parameter 0 of DEPXFERCFG
|
||||
* @number_xfer_resources: Defines the number of Transfer Resources allocated
|
||||
* to this endpoint. This field must be set to 1.
|
||||
* @reserved16_31: set to zero;
|
||||
*/
|
||||
struct dwc3_gadget_ep_depxfercfg_param0 {
|
||||
u32 number_xfer_resources:16;
|
||||
u32 reserved16_31:16;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct dwc3_gadget_ep_depstrtxfer_param1 - Parameter 1 of DEPSTRTXFER
|
||||
* @transfer_desc_addr_low: Indicates the lower 32 bits of the external
|
||||
* memory's start address for the transfer descriptor. Because TRBs
|
||||
* must be aligned to a 16-byte boundary, the lower 4 bits of this
|
||||
* address must be 0.
|
||||
*/
|
||||
struct dwc3_gadget_ep_depstrtxfer_param1 {
|
||||
u32 transfer_desc_addr_low;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct dwc3_gadget_ep_depstrtxfer_param1 - Parameter 1 of DEPSTRTXFER
|
||||
* @transfer_desc_addr_high: Indicates the higher 32 bits of the external
|
||||
* memory’s start address for the transfer descriptor.
|
||||
*/
|
||||
struct dwc3_gadget_ep_depstrtxfer_param0 {
|
||||
u32 transfer_desc_addr_high;
|
||||
} __packed;
|
||||
|
||||
struct dwc3_gadget_ep_cmd_params {
|
||||
union {
|
||||
u32 raw;
|
||||
} param2;
|
||||
|
||||
union {
|
||||
u32 raw;
|
||||
struct dwc3_gadget_ep_depcfg_param1 depcfg;
|
||||
struct dwc3_gadget_ep_depstrtxfer_param1 depstrtxfer;
|
||||
} param1;
|
||||
|
||||
union {
|
||||
u32 raw;
|
||||
struct dwc3_gadget_ep_depcfg_param0 depcfg;
|
||||
struct dwc3_gadget_ep_depxfercfg_param0 depxfercfg;
|
||||
struct dwc3_gadget_ep_depstrtxfer_param0 depstrtxfer;
|
||||
} param0;
|
||||
} __packed;
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
struct dwc3_request {
|
||||
struct usb_request request;
|
||||
struct list_head list;
|
||||
struct dwc3_ep *dep;
|
||||
|
||||
u8 epnum;
|
||||
struct dwc3_trb_hw *trb;
|
||||
dma_addr_t trb_dma;
|
||||
|
||||
unsigned direction:1;
|
||||
unsigned mapped:1;
|
||||
unsigned queued:1;
|
||||
};
|
||||
#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))
|
||||
|
||||
static inline struct dwc3_request *next_request(struct list_head *list)
|
||||
{
|
||||
if (list_empty(list))
|
||||
return NULL;
|
||||
|
||||
return list_first_entry(list, struct dwc3_request, list);
|
||||
}
|
||||
|
||||
static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
|
||||
{
|
||||
struct dwc3_ep *dep = req->dep;
|
||||
|
||||
req->queued = true;
|
||||
list_move_tail(&req->list, &dep->req_queued);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USB_GADGET_DWC3) || defined(CONFIG_USB_GADGET_DWC3_MODULE)
|
||||
int dwc3_gadget_init(struct dwc3 *dwc);
|
||||
void dwc3_gadget_exit(struct dwc3 *dwc);
|
||||
#else
|
||||
static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; }
|
||||
static inline void dwc3_gadget_exit(struct dwc3 *dwc) { }
|
||||
static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
||||
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
int status);
|
||||
|
||||
void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event);
|
||||
void dwc3_ep0_out_start(struct dwc3 *dwc);
|
||||
int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
|
||||
gfp_t gfp_flags);
|
||||
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
|
||||
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
||||
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
|
||||
void dwc3_map_buffer_to_dma(struct dwc3_request *req);
|
||||
void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
|
||||
|
||||
/**
|
||||
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
|
||||
* @dwc: DesignWare USB3 Pointer
|
||||
* @number: DWC endpoint number
|
||||
*
|
||||
* Caller should take care of locking
|
||||
*/
|
||||
static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number)
|
||||
{
|
||||
u32 res_id;
|
||||
|
||||
res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number));
|
||||
|
||||
return DWC3_DEPCMD_GET_RSC_IDX(res_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_gadget_event_string - returns event name
|
||||
* @event: the event code
|
||||
*/
|
||||
static inline const char *dwc3_gadget_event_string(u8 event)
|
||||
{
|
||||
switch (event) {
|
||||
case DWC3_DEVICE_EVENT_DISCONNECT:
|
||||
return "Disconnect";
|
||||
case DWC3_DEVICE_EVENT_RESET:
|
||||
return "Reset";
|
||||
case DWC3_DEVICE_EVENT_CONNECT_DONE:
|
||||
return "Connection Done";
|
||||
case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
|
||||
return "Link Status Change";
|
||||
case DWC3_DEVICE_EVENT_WAKEUP:
|
||||
return "WakeUp";
|
||||
case DWC3_DEVICE_EVENT_EOPF:
|
||||
return "End-Of-Frame";
|
||||
case DWC3_DEVICE_EVENT_SOF:
|
||||
return "Start-Of-Frame";
|
||||
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
|
||||
return "Erratic Error";
|
||||
case DWC3_DEVICE_EVENT_CMD_CMPL:
|
||||
return "Command Complete";
|
||||
case DWC3_DEVICE_EVENT_OVERFLOW:
|
||||
return "Overflow";
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_ep_event_string - returns event name
|
||||
* @event: then event code
|
||||
*/
|
||||
static inline const char *dwc3_ep_event_string(u8 event)
|
||||
{
|
||||
switch (event) {
|
||||
case DWC3_DEPEVT_XFERCOMPLETE:
|
||||
return "Transfer Complete";
|
||||
case DWC3_DEPEVT_XFERINPROGRESS:
|
||||
return "Transfer In-Progress";
|
||||
case DWC3_DEPEVT_XFERNOTREADY:
|
||||
return "Transfer Not Ready";
|
||||
case DWC3_DEPEVT_RXTXFIFOEVT:
|
||||
return "FIFO";
|
||||
case DWC3_DEPEVT_STREAMEVT:
|
||||
return "Stream";
|
||||
case DWC3_DEPEVT_EPCMDCMPLT:
|
||||
return "Endpoint Command Complete";
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
#endif /* __DRIVERS_USB_DWC3_GADGET_H */
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* io.h - DesignWare USB3 DRD IO Header
|
||||
*
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* Authors: Felipe Balbi <balbi@ti.com>,
|
||||
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The names of the above-listed copyright holders may not be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* ALTERNATIVELY, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2, as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_USB_DWC3_IO_H
|
||||
#define __DRIVERS_USB_DWC3_IO_H
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
static inline u32 dwc3_readl(void __iomem *base, u32 offset)
|
||||
{
|
||||
return readl(base + offset);
|
||||
}
|
||||
|
||||
static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
|
||||
{
|
||||
writel(value, base + offset);
|
||||
}
|
||||
|
||||
#endif /* __DRIVERS_USB_DWC3_IO_H */
|
|
@ -255,12 +255,11 @@ config USB_S3C_HSOTG
|
|||
integrated into the S3C64XX series SoC.
|
||||
|
||||
config USB_IMX
|
||||
tristate "Freescale IMX USB Peripheral Controller"
|
||||
depends on ARCH_MX1
|
||||
tristate "Freescale i.MX1 USB Peripheral Controller"
|
||||
depends on ARCH_MXC
|
||||
help
|
||||
Freescale's IMX series include an integrated full speed
|
||||
USB 1.1 device controller. The controller in the IMX series
|
||||
is register-compatible.
|
||||
Freescale's i.MX1 includes an integrated full speed
|
||||
USB 1.1 device controller.
|
||||
|
||||
It has Six fixed-function endpoints, as well as endpoint
|
||||
zero (for control transfers).
|
||||
|
@ -303,6 +302,18 @@ config USB_PXA_U2O
|
|||
PXA9xx Processor series include a high speed USB2.0 device
|
||||
controller, which support high speed and full speed USB peripheral.
|
||||
|
||||
config USB_GADGET_DWC3
|
||||
tristate "DesignWare USB3.0 (DRD) Controller"
|
||||
depends on USB_DWC3
|
||||
select USB_GADGET_DUALSPEED
|
||||
select USB_GADGET_SUPERSPEED
|
||||
help
|
||||
DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
|
||||
which can be configured for peripheral-only, host-only, hub-only
|
||||
and Dual-Role operation. This Controller was first integrated into
|
||||
the OMAP5 series of processors. More information about the OMAP5
|
||||
version of this controller, refer to http://www.ti.com/omap5.
|
||||
|
||||
#
|
||||
# Controllers available in both integrated and discrete versions
|
||||
#
|
||||
|
|
|
@ -354,7 +354,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
|
|||
writel(tmp, &dev->ep[ep->num].regs->ctl);
|
||||
|
||||
/* set max packet size */
|
||||
maxpacket = le16_to_cpu(desc->wMaxPacketSize);
|
||||
maxpacket = usb_endpoint_maxp(desc);
|
||||
tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
|
||||
tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE);
|
||||
ep->ep.maxpacket = maxpacket;
|
||||
|
|
|
@ -487,7 +487,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
|
|||
|| !desc || ep->desc
|
||||
|| _ep->name == ep0name
|
||||
|| desc->bDescriptorType != USB_DT_ENDPOINT
|
||||
|| (maxpacket = le16_to_cpu(desc->wMaxPacketSize)) == 0
|
||||
|| (maxpacket = usb_endpoint_maxp(desc)) == 0
|
||||
|| maxpacket > ep->maxpacket) {
|
||||
DBG("bad ep or descriptor\n");
|
||||
return -EINVAL;
|
||||
|
|
|
@ -527,7 +527,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
|||
|
||||
DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
|
||||
|
||||
maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
|
||||
maxpacket = usb_endpoint_maxp(desc) & 0x7ff;
|
||||
|
||||
if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
|
||||
|| ep->index == 0
|
||||
|
@ -571,7 +571,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
|||
* Bits 11:12 specify number of _additional_
|
||||
* transactions per microframe.
|
||||
*/
|
||||
nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
|
||||
nr_trans = ((usb_endpoint_maxp(desc) >> 11) & 3) + 1;
|
||||
if (nr_trans > 3)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -2101,7 +2101,7 @@ static int ep_enable(struct usb_ep *ep,
|
|||
mEp->num = usb_endpoint_num(desc);
|
||||
mEp->type = usb_endpoint_type(desc);
|
||||
|
||||
mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize);
|
||||
mEp->ep.maxpacket = usb_endpoint_maxp(desc);
|
||||
|
||||
dbg_event(_usb_addr(mEp), "ENABLE", 0);
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ int config_ep_by_speed(struct usb_gadget *g,
|
|||
|
||||
ep_found:
|
||||
/* commit results */
|
||||
_ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize);
|
||||
_ep->maxpacket = usb_endpoint_maxp(chosen_desc);
|
||||
_ep->desc = chosen_desc;
|
||||
_ep->comp_desc = NULL;
|
||||
_ep->maxburst = 0;
|
||||
|
|
|
@ -439,7 +439,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
|||
* maximum packet size.
|
||||
* For SS devices the wMaxPacketSize is limited by 1024.
|
||||
*/
|
||||
max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
|
||||
max = usb_endpoint_maxp(desc) & 0x7ff;
|
||||
|
||||
/* drivers must not request bad settings, since lower levels
|
||||
* (hardware or its drivers) may not check. some endpoints
|
||||
|
@ -1277,7 +1277,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
|
|||
int tmp;
|
||||
|
||||
/* high bandwidth mode */
|
||||
tmp = le16_to_cpu(ep->desc->wMaxPacketSize);
|
||||
tmp = usb_endpoint_maxp(ep->desc);
|
||||
tmp = (tmp >> 11) & 0x03;
|
||||
tmp *= 8 /* applies to entire frame */;
|
||||
limit += limit * tmp;
|
||||
|
|
|
@ -158,7 +158,7 @@ ep_matches (
|
|||
* where it's an output parameter representing the full speed limit.
|
||||
* the usb spec fixes high speed bulk maxpacket at 512 bytes.
|
||||
*/
|
||||
max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
|
||||
max = 0x7ff & usb_endpoint_maxp(desc);
|
||||
switch (type) {
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
/* INT: limit 64 bytes full speed, 1024 high/super speed */
|
||||
|
|
|
@ -2401,8 +2401,7 @@ reset:
|
|||
goto reset;
|
||||
fsg->bulk_out->driver_data = common;
|
||||
fsg->bulk_out_enabled = 1;
|
||||
common->bulk_out_maxpacket =
|
||||
le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize);
|
||||
common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc);
|
||||
clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
|
||||
|
||||
/* Allocate the requests */
|
||||
|
|
|
@ -2801,7 +2801,7 @@ reset:
|
|||
if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
|
||||
goto reset;
|
||||
fsg->bulk_out_enabled = 1;
|
||||
fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
|
||||
fsg->bulk_out_maxpacket = usb_endpoint_maxp(d);
|
||||
clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
|
||||
|
||||
if (transport_is_cbi()) {
|
||||
|
|
|
@ -540,7 +540,7 @@ static int qe_ep_init(struct qe_udc *udc,
|
|||
int reval = 0;
|
||||
u16 max = 0;
|
||||
|
||||
max = le16_to_cpu(desc->wMaxPacketSize);
|
||||
max = usb_endpoint_maxp(desc);
|
||||
|
||||
/* check the max package size validate for this endpoint */
|
||||
/* Refer to USB2.0 spec table 9-13,
|
||||
|
|
|
@ -559,7 +559,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
|
|||
if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN))
|
||||
return -ESHUTDOWN;
|
||||
|
||||
max = le16_to_cpu(desc->wMaxPacketSize);
|
||||
max = usb_endpoint_maxp(desc);
|
||||
|
||||
/* Disable automatic zlp generation. Driver is responsible to indicate
|
||||
* explicitly through req->req.zero. This is needed to enable multi-td
|
||||
|
|
|
@ -220,7 +220,7 @@ static int config_ep(struct fusb300_ep *ep,
|
|||
|
||||
info.type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
|
||||
info.dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
|
||||
info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
|
||||
info.maxpacket = usb_endpoint_maxp(desc);
|
||||
info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
|
||||
|
||||
if ((info.type == USB_ENDPOINT_XFER_INT) ||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name))
|
||||
#define gadget_is_ci13xxx_pci(g) (!strcmp("ci13xxx_pci", (g)->name))
|
||||
#define gadget_is_dummy(g) (!strcmp("dummy_udc", (g)->name))
|
||||
#define gadget_is_dwc3(g) (!strcmp("dwc3-gadget", (g)->name))
|
||||
#define gadget_is_fsl_qe(g) (!strcmp("fsl_qe_udc", (g)->name))
|
||||
#define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name))
|
||||
#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name))
|
||||
|
@ -115,6 +116,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
|
|||
return 0x30;
|
||||
else if (gadget_is_net2272(gadget))
|
||||
return 0x31;
|
||||
else if (gadget_is_dwc3(gadget))
|
||||
return 0x32;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
|
|
@ -689,7 +689,7 @@ static int imx_ep_enable(struct usb_ep *usb_ep,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (imx_ep->fifosize < le16_to_cpu(desc->wMaxPacketSize)) {
|
||||
if (imx_ep->fifosize < usb_endpoint_maxp(desc)) {
|
||||
D_ERR(imx_usb->dev,
|
||||
"<%s> bad %s maxpacket\n", __func__, usb_ep->name);
|
||||
return -ERANGE;
|
||||
|
|
|
@ -283,7 +283,7 @@ static int langwell_ep_enable(struct usb_ep *_ep,
|
|||
if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
|
||||
return -ESHUTDOWN;
|
||||
|
||||
max = le16_to_cpu(desc->wMaxPacketSize);
|
||||
max = usb_endpoint_maxp(desc);
|
||||
|
||||
/*
|
||||
* disable HW zero length termination select
|
||||
|
|
|
@ -370,7 +370,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
|
|||
|
||||
ep->pipectr = get_pipectr_addr(pipenum);
|
||||
ep->pipenum = pipenum;
|
||||
ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
|
||||
ep->ep.maxpacket = usb_endpoint_maxp(desc);
|
||||
m66592->pipenum2ep[pipenum] = ep;
|
||||
m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep;
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
|
@ -447,7 +447,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
|
|||
ep->type = info.type;
|
||||
|
||||
info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
|
||||
info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
|
||||
info.maxpacket = usb_endpoint_maxp(desc);
|
||||
info.interval = desc->bInterval;
|
||||
if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
|
||||
info.dir_in = 1;
|
||||
|
|
|
@ -493,7 +493,7 @@ static int mv_ep_enable(struct usb_ep *_ep,
|
|||
return -ESHUTDOWN;
|
||||
|
||||
direction = ep_dir(ep);
|
||||
max = le16_to_cpu(desc->wMaxPacketSize);
|
||||
max = usb_endpoint_maxp(desc);
|
||||
|
||||
/*
|
||||
* disable HW zero length termination select
|
||||
|
|
|
@ -204,7 +204,7 @@ net2272_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
|||
if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
|
||||
return -ESHUTDOWN;
|
||||
|
||||
max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff;
|
||||
max = usb_endpoint_maxp(desc) & 0x1fff;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
_ep->maxpacket = max & 0x7fff;
|
||||
|
|
|
@ -169,7 +169,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
|||
return -EDOM;
|
||||
|
||||
/* sanity check ep-e/ep-f since their fifos are small */
|
||||
max = le16_to_cpu (desc->wMaxPacketSize) & 0x1fff;
|
||||
max = usb_endpoint_maxp (desc) & 0x1fff;
|
||||
if (ep->num > 4 && max > 64)
|
||||
return -ERANGE;
|
||||
|
||||
|
@ -1640,7 +1640,7 @@ show_queues (struct device *_dev, struct device_attribute *attr, char *buf)
|
|||
default:
|
||||
val = "iso"; break;
|
||||
}; val; }),
|
||||
le16_to_cpu (d->wMaxPacketSize) & 0x1fff,
|
||||
usb_endpoint_maxp (d) & 0x1fff,
|
||||
ep->dma ? "dma" : "pio", ep->fifo_size
|
||||
);
|
||||
} else /* ep0 should only have one transfer queued */
|
||||
|
|
|
@ -166,15 +166,14 @@ static int omap_ep_enable(struct usb_ep *_ep,
|
|||
if (!_ep || !desc || ep->desc
|
||||
|| desc->bDescriptorType != USB_DT_ENDPOINT
|
||||
|| ep->bEndpointAddress != desc->bEndpointAddress
|
||||
|| ep->maxpacket < le16_to_cpu
|
||||
(desc->wMaxPacketSize)) {
|
||||
|| ep->maxpacket < usb_endpoint_maxp(desc)) {
|
||||
DBG("%s, bad ep or descriptor\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
maxp = le16_to_cpu (desc->wMaxPacketSize);
|
||||
maxp = usb_endpoint_maxp(desc);
|
||||
if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
|
||||
&& maxp != ep->maxpacket)
|
||||
|| le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket
|
||||
|| usb_endpoint_maxp(desc) > ep->maxpacket
|
||||
|| !desc->wMaxPacketSize) {
|
||||
DBG("%s, bad %s maxpacket\n", __func__, _ep->name);
|
||||
return -ERANGE;
|
||||
|
|
|
@ -947,7 +947,7 @@ static void pch_udc_ep_enable(struct pch_udc_ep *ep,
|
|||
else
|
||||
buff_size = UDC_EPOUT_BUFF_SIZE;
|
||||
pch_udc_ep_set_bufsz(ep, buff_size, ep->in);
|
||||
pch_udc_ep_set_maxpkt(ep, le16_to_cpu(desc->wMaxPacketSize));
|
||||
pch_udc_ep_set_maxpkt(ep, usb_endpoint_maxp(desc));
|
||||
pch_udc_ep_set_nak(ep);
|
||||
pch_udc_ep_fifo_flush(ep, ep->in);
|
||||
/* Configure the endpoint */
|
||||
|
@ -957,7 +957,7 @@ static void pch_udc_ep_enable(struct pch_udc_ep *ep,
|
|||
(cfg->cur_cfg << UDC_CSR_NE_CFG_SHIFT) |
|
||||
(cfg->cur_intf << UDC_CSR_NE_INTF_SHIFT) |
|
||||
(cfg->cur_alt << UDC_CSR_NE_ALT_SHIFT) |
|
||||
le16_to_cpu(desc->wMaxPacketSize) << UDC_CSR_NE_MAX_PKT_SHIFT;
|
||||
usb_endpoint_maxp(desc) << UDC_CSR_NE_MAX_PKT_SHIFT;
|
||||
|
||||
if (ep->in)
|
||||
pch_udc_write_csr(ep->dev, val, UDC_EPIN_IDX(ep->num));
|
||||
|
@ -1466,7 +1466,7 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep,
|
|||
ep->desc = desc;
|
||||
ep->halted = 0;
|
||||
pch_udc_ep_enable(ep, &ep->dev->cfg_data, desc);
|
||||
ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
|
||||
ep->ep.maxpacket = usb_endpoint_maxp(desc);
|
||||
pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
|
||||
spin_unlock_irqrestore(&dev->lock, iflags);
|
||||
return 0;
|
||||
|
|
|
@ -232,8 +232,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
|
|||
if (!_ep || !desc || ep->desc || _ep->name == ep0name
|
||||
|| desc->bDescriptorType != USB_DT_ENDPOINT
|
||||
|| ep->bEndpointAddress != desc->bEndpointAddress
|
||||
|| ep->fifo_size < le16_to_cpu
|
||||
(desc->wMaxPacketSize)) {
|
||||
|| ep->fifo_size < usb_endpoint_maxp (desc)) {
|
||||
DMSG("%s, bad ep or descriptor\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -248,7 +247,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
|
|||
|
||||
/* hardware _could_ do smaller, but driver doesn't */
|
||||
if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
|
||||
&& le16_to_cpu (desc->wMaxPacketSize)
|
||||
&& usb_endpoint_maxp (desc)
|
||||
!= BULK_FIFO_SIZE)
|
||||
|| !desc->wMaxPacketSize) {
|
||||
DMSG("%s, bad %s maxpacket\n", __func__, _ep->name);
|
||||
|
@ -264,7 +263,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
|
|||
ep->desc = desc;
|
||||
ep->stopped = 0;
|
||||
ep->pio_irqs = 0;
|
||||
ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);
|
||||
ep->ep.maxpacket = usb_endpoint_maxp (desc);
|
||||
|
||||
/* flush fifo (mostly for OUT buffers) */
|
||||
pxa25x_ep_fifo_flush (_ep);
|
||||
|
@ -401,7 +400,7 @@ write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
|
|||
{
|
||||
unsigned max;
|
||||
|
||||
max = le16_to_cpu(ep->desc->wMaxPacketSize);
|
||||
max = usb_endpoint_maxp(ep->desc);
|
||||
do {
|
||||
unsigned count;
|
||||
int is_last, is_short;
|
||||
|
@ -671,8 +670,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
|||
* we can report per-packet status. that also helps with dma.
|
||||
*/
|
||||
if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
|
||||
&& req->req.length > le16_to_cpu
|
||||
(ep->desc->wMaxPacketSize)))
|
||||
&& req->req.length > usb_endpoint_maxp (ep->desc)))
|
||||
return -EMSGSIZE;
|
||||
|
||||
DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
|
||||
|
@ -1105,7 +1103,7 @@ udc_seq_show(struct seq_file *m, void *_d)
|
|||
tmp = *dev->ep [i].reg_udccs;
|
||||
seq_printf(m,
|
||||
"%s max %d %s udccs %02x irqs %lu\n",
|
||||
ep->ep.name, le16_to_cpu(desc->wMaxPacketSize),
|
||||
ep->ep.name, usb_endpoint_maxp(desc),
|
||||
"pio", tmp, ep->pio_irqs);
|
||||
/* TODO translate all five groups of udccs bits! */
|
||||
|
||||
|
|
|
@ -1439,7 +1439,7 @@ static int pxa_ep_enable(struct usb_ep *_ep,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) {
|
||||
if (ep->fifo_size < usb_endpoint_maxp(desc)) {
|
||||
ep_err(ep, "bad maxpacket\n");
|
||||
return -ERANGE;
|
||||
}
|
||||
|
|
|
@ -341,7 +341,7 @@ static void r8a66597_ep_setting(struct r8a66597 *r8a66597,
|
|||
|
||||
ep->pipectr = get_pipectr_addr(pipenum);
|
||||
ep->pipenum = pipenum;
|
||||
ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
|
||||
ep->ep.maxpacket = usb_endpoint_maxp(desc);
|
||||
r8a66597->pipenum2ep[pipenum] = ep;
|
||||
r8a66597->epaddr2ep[desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK]
|
||||
= ep;
|
||||
|
@ -420,7 +420,7 @@ static int alloc_pipe_config(struct r8a66597_ep *ep,
|
|||
ep->type = info.type;
|
||||
|
||||
info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
|
||||
info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
|
||||
info.maxpacket = usb_endpoint_maxp(desc);
|
||||
info.interval = desc->bInterval;
|
||||
if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
|
||||
info.dir_in = 1;
|
||||
|
|
|
@ -2297,7 +2297,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
mps = le16_to_cpu(desc->wMaxPacketSize);
|
||||
mps = usb_endpoint_maxp(desc);
|
||||
|
||||
/* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/prefetch.h>
|
||||
|
||||
#include <mach/regs-s3c2443-clock.h>
|
||||
|
@ -137,6 +138,7 @@ struct s3c_hsudc {
|
|||
struct usb_gadget_driver *driver;
|
||||
struct device *dev;
|
||||
struct s3c24xx_hsudc_platdata *pd;
|
||||
struct otg_transceiver *transceiver;
|
||||
spinlock_t lock;
|
||||
void __iomem *regs;
|
||||
struct resource *mem_rsrc;
|
||||
|
@ -759,11 +761,11 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep,
|
|||
if (!_ep || !desc || hsep->desc || _ep->name == ep0name
|
||||
|| desc->bDescriptorType != USB_DT_ENDPOINT
|
||||
|| hsep->bEndpointAddress != desc->bEndpointAddress
|
||||
|| ep_maxpacket(hsep) < le16_to_cpu(desc->wMaxPacketSize))
|
||||
|| ep_maxpacket(hsep) < usb_endpoint_maxp(desc))
|
||||
return -EINVAL;
|
||||
|
||||
if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
|
||||
&& le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(hsep))
|
||||
&& usb_endpoint_maxp(desc) != ep_maxpacket(hsep))
|
||||
|| !desc->wMaxPacketSize)
|
||||
return -ERANGE;
|
||||
|
||||
|
@ -779,7 +781,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep,
|
|||
|
||||
hsep->stopped = hsep->wedge = 0;
|
||||
hsep->desc = desc;
|
||||
hsep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
|
||||
hsep->ep.maxpacket = usb_endpoint_maxp(desc);
|
||||
|
||||
s3c_hsudc_set_halt(_ep, 0);
|
||||
__set_bit(ep_index(hsep), hsudc->regs + S3C_EIER);
|
||||
|
@ -1171,6 +1173,22 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* connect to bus through transceiver */
|
||||
if (hsudc->transceiver) {
|
||||
ret = otg_set_peripheral(hsudc->transceiver, &hsudc->gadget);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
enable_irq(hsudc->irq);
|
||||
dev_info(hsudc->dev, "bound driver %s\n", driver->driver.name);
|
||||
|
||||
|
@ -1201,6 +1219,9 @@ static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
|
|||
s3c_hsudc_stop_activity(hsudc, driver);
|
||||
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);
|
||||
|
@ -1247,6 +1268,8 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
|
|||
hsudc->dev = dev;
|
||||
hsudc->pd = pdev->dev.platform_data;
|
||||
|
||||
hsudc->transceiver = otg_get_transceiver();
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "unable to obtain driver resource data\n");
|
||||
|
@ -1269,19 +1292,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
|
|||
goto err_remap;
|
||||
}
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to obtain IRQ number\n");
|
||||
goto err_irq;
|
||||
}
|
||||
hsudc->irq = ret;
|
||||
|
||||
ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "irq request failed\n");
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
spin_lock_init(&hsudc->lock);
|
||||
|
||||
device_initialize(&hsudc->gadget.dev);
|
||||
|
@ -1299,6 +1309,19 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
|
|||
|
||||
s3c_hsudc_setup_ep(hsudc);
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to obtain IRQ number\n");
|
||||
goto err_irq;
|
||||
}
|
||||
hsudc->irq = ret;
|
||||
|
||||
ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "irq request failed\n");
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
hsudc->uclk = clk_get(&pdev->dev, "usb-device");
|
||||
if (IS_ERR(hsudc->uclk)) {
|
||||
dev_err(dev, "failed to find usb-device clock source\n");
|
||||
|
|
|
@ -1082,7 +1082,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep,
|
|||
if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
|
||||
return -ESHUTDOWN;
|
||||
|
||||
max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff;
|
||||
max = usb_endpoint_maxp(desc) & 0x1fff;
|
||||
|
||||
local_irq_save (flags);
|
||||
_ep->maxpacket = max & 0x7ff;
|
||||
|
|
|
@ -544,11 +544,11 @@ config USB_HWA_HCD
|
|||
will be called "hwa-hc".
|
||||
|
||||
config USB_IMX21_HCD
|
||||
tristate "iMX21 HCD support"
|
||||
depends on USB && ARM && MACH_MX21
|
||||
tristate "i.MX21 HCD support"
|
||||
depends on USB && ARM && ARCH_MXC
|
||||
help
|
||||
This driver enables support for the on-chip USB host in the
|
||||
iMX21 processor.
|
||||
i.MX21 processor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called "imx21-hcd".
|
||||
|
@ -578,3 +578,10 @@ config USB_OCTEON_OHCI
|
|||
config USB_OCTEON2_COMMON
|
||||
bool
|
||||
default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
|
||||
|
||||
config USB_PXA168_EHCI
|
||||
bool "Marvell PXA168 on-chip EHCI HCD support"
|
||||
depends on USB_EHCI_HCD && ARCH_MMP
|
||||
help
|
||||
Enable support for Marvell PXA168 SoC's on-chip EHCI
|
||||
host controller
|
||||
|
|
|
@ -293,7 +293,7 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
|
|||
/* here we "know" root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -697,6 +697,19 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
|
|||
}
|
||||
#undef DBG_SCHED_LIMIT
|
||||
|
||||
static const char *rh_state_string(struct ehci_hcd *ehci)
|
||||
{
|
||||
switch (ehci->rh_state) {
|
||||
case EHCI_RH_HALTED:
|
||||
return "halted";
|
||||
case EHCI_RH_SUSPENDED:
|
||||
return "suspended";
|
||||
case EHCI_RH_RUNNING:
|
||||
return "running";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
static ssize_t fill_registers_buffer(struct debug_buffer *buf)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
|
@ -730,11 +743,11 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
|
|||
temp = scnprintf (next, size,
|
||||
"bus %s, device %s\n"
|
||||
"%s\n"
|
||||
"EHCI %x.%02x, hcd state %d\n",
|
||||
"EHCI %x.%02x, rh state %s\n",
|
||||
hcd->self.controller->bus->name,
|
||||
dev_name(hcd->self.controller),
|
||||
hcd->product_desc,
|
||||
i >> 8, i & 0x0ff, hcd->state);
|
||||
i >> 8, i & 0x0ff, rh_state_string(ehci));
|
||||
size -= temp;
|
||||
next += temp;
|
||||
|
||||
|
|
|
@ -392,7 +392,7 @@ static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
|
|||
|
||||
dev_dbg(dev, "suspending...\n");
|
||||
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
dev->power.power_state = PMSG_SUSPEND;
|
||||
|
||||
/* ignore non-host interrupts */
|
||||
|
@ -481,7 +481,7 @@ static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
|
|||
ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
|
||||
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
ehci->rh_state = EHCI_RH_RUNNING;
|
||||
dev->power.power_state = PMSG_ON;
|
||||
|
||||
tmp = ehci_readl(ehci, &ehci->regs->command);
|
||||
|
|
|
@ -238,7 +238,7 @@ static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
|
|||
error = handshake(ehci, ptr, mask, done, usec);
|
||||
if (error) {
|
||||
ehci_halt(ehci);
|
||||
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
|
||||
ehci->rh_state = EHCI_RH_HALTED;
|
||||
ehci_err(ehci, "force halt; handshake %p %08x %08x -> %d\n",
|
||||
ptr, mask, done, error);
|
||||
}
|
||||
|
@ -278,7 +278,7 @@ static int ehci_reset (struct ehci_hcd *ehci)
|
|||
command |= CMD_RESET;
|
||||
dbg_cmd (ehci, "reset", command);
|
||||
ehci_writel(ehci, command, &ehci->regs->command);
|
||||
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
|
||||
ehci->rh_state = EHCI_RH_HALTED;
|
||||
ehci->next_statechange = jiffies;
|
||||
retval = handshake (ehci, &ehci->regs->command,
|
||||
CMD_RESET, 0, 250 * 1000);
|
||||
|
@ -307,7 +307,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
|
|||
u32 temp;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING)
|
||||
BUG ();
|
||||
#endif
|
||||
|
||||
|
@ -356,7 +356,7 @@ static void ehci_iaa_watchdog(unsigned long param)
|
|||
*/
|
||||
if (ehci->reclaim
|
||||
&& !timer_pending(&ehci->iaa_watchdog)
|
||||
&& HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
|
||||
&& ehci->rh_state == EHCI_RH_RUNNING) {
|
||||
u32 cmd, status;
|
||||
|
||||
/* If we get here, IAA is *REALLY* late. It's barely
|
||||
|
@ -496,7 +496,7 @@ static void ehci_work (struct ehci_hcd *ehci)
|
|||
* misplace IRQs, and should let us run completely without IRQs.
|
||||
* such lossage has been observed on both VT6202 and VT8235.
|
||||
*/
|
||||
if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) &&
|
||||
if (ehci->rh_state == EHCI_RH_RUNNING &&
|
||||
(ehci->async->qh_next.ptr != NULL ||
|
||||
ehci->periodic_sched != 0))
|
||||
timer_action (ehci, TIMER_IO_WATCHDOG);
|
||||
|
@ -516,7 +516,7 @@ static void ehci_stop (struct usb_hcd *hcd)
|
|||
del_timer_sync(&ehci->iaa_watchdog);
|
||||
|
||||
spin_lock_irq(&ehci->lock);
|
||||
if (HC_IS_RUNNING (hcd->state))
|
||||
if (ehci->rh_state == EHCI_RH_RUNNING)
|
||||
ehci_quiesce (ehci);
|
||||
|
||||
ehci_silence_controller(ehci);
|
||||
|
@ -741,7 +741,7 @@ static int ehci_run (struct usb_hcd *hcd)
|
|||
* be started before the port switching actions could complete.
|
||||
*/
|
||||
down_write(&ehci_cf_port_reset_rwsem);
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
ehci->rh_state = EHCI_RH_RUNNING;
|
||||
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
|
||||
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
|
||||
msleep(5);
|
||||
|
@ -788,7 +788,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
|||
|
||||
/* Shared IRQ? */
|
||||
masked_status = status & INTR_MASK;
|
||||
if (!masked_status || unlikely(hcd->state == HC_STATE_HALT)) {
|
||||
if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) {
|
||||
spin_unlock(&ehci->lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
@ -952,7 +952,7 @@ static int ehci_urb_enqueue (
|
|||
static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
{
|
||||
/* failfast */
|
||||
if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim)
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING && ehci->reclaim)
|
||||
end_unlink_async(ehci);
|
||||
|
||||
/* If the QH isn't linked then there's nothing we can do
|
||||
|
@ -1079,7 +1079,7 @@ rescan:
|
|||
goto idle_timeout;
|
||||
}
|
||||
|
||||
if (!HC_IS_RUNNING (hcd->state))
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING)
|
||||
qh->qh_state = QH_STATE_IDLE;
|
||||
switch (qh->qh_state) {
|
||||
case QH_STATE_LINKED:
|
||||
|
@ -1291,6 +1291,16 @@ MODULE_LICENSE ("GPL");
|
|||
#define PLATFORM_DRIVER ehci_grlib_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_PXA168_EHCI
|
||||
#include "ehci-pxa168.c"
|
||||
#define PLATFORM_DRIVER ehci_pxa168_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NLM_XLR
|
||||
#include "ehci-xls.c"
|
||||
#define PLATFORM_DRIVER ehci_xls_driver
|
||||
#endif
|
||||
|
||||
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
|
||||
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
|
||||
!defined(XILINX_OF_PLATFORM_DRIVER)
|
||||
|
|
|
@ -236,10 +236,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
|
|||
}
|
||||
|
||||
/* stop schedules, clean any completed work */
|
||||
if (HC_IS_RUNNING(hcd->state)) {
|
||||
if (ehci->rh_state == EHCI_RH_RUNNING)
|
||||
ehci_quiesce (ehci);
|
||||
hcd->state = HC_STATE_QUIESCING;
|
||||
}
|
||||
ehci->command = ehci_readl(ehci, &ehci->regs->command);
|
||||
ehci_work(ehci);
|
||||
|
||||
|
@ -313,7 +311,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
|
|||
|
||||
/* turn off now-idle HC */
|
||||
ehci_halt (ehci);
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
|
||||
if (ehci->reclaim)
|
||||
end_unlink_async(ehci);
|
||||
|
@ -382,6 +380,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
|
|||
|
||||
/* restore CMD_RUN, framelist size, and irq threshold */
|
||||
ehci_writel(ehci, ehci->command, &ehci->regs->command);
|
||||
ehci->rh_state = EHCI_RH_RUNNING;
|
||||
|
||||
/* Some controller/firmware combinations need a delay during which
|
||||
* they set up the port statuses. See Bugzilla #8190. */
|
||||
|
@ -451,7 +450,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
|
|||
}
|
||||
|
||||
ehci->next_statechange = jiffies + msecs_to_jiffies(5);
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
|
||||
/* Now we can safely re-enable irqs */
|
||||
ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
|
||||
|
@ -563,7 +561,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
|
|||
u32 ppcd = 0;
|
||||
|
||||
/* if !USB_SUSPEND, root hub timers won't get shut down ... */
|
||||
if (!HC_IS_RUNNING(hcd->state))
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING)
|
||||
return 0;
|
||||
|
||||
/* init status to no-changes */
|
||||
|
|
|
@ -439,7 +439,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
|||
/* here we "know" root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* drivers/usb/host/ehci-pxa168.c
|
||||
*
|
||||
* Tanmay Upadhyay <tanmay.upadhyay@einfochips.com>
|
||||
*
|
||||
* Based on drivers/usb/host/ehci-orion.c
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <mach/pxa168.h>
|
||||
|
||||
#define USB_PHY_CTRL_REG 0x4
|
||||
#define USB_PHY_PLL_REG 0x8
|
||||
#define USB_PHY_TX_REG 0xc
|
||||
|
||||
#define FBDIV_SHIFT 4
|
||||
|
||||
#define ICP_SHIFT 12
|
||||
#define ICP_15 2
|
||||
#define ICP_20 3
|
||||
#define ICP_25 4
|
||||
|
||||
#define KVCO_SHIFT 15
|
||||
|
||||
#define PLLCALI12_SHIFT 25
|
||||
#define CALI12_VDD 0
|
||||
#define CALI12_09 1
|
||||
#define CALI12_10 2
|
||||
#define CALI12_11 3
|
||||
|
||||
#define PLLVDD12_SHIFT 27
|
||||
#define VDD12_VDD 0
|
||||
#define VDD12_10 1
|
||||
#define VDD12_11 2
|
||||
#define VDD12_12 3
|
||||
|
||||
#define PLLVDD18_SHIFT 29
|
||||
#define VDD18_19 0
|
||||
#define VDD18_20 1
|
||||
#define VDD18_21 2
|
||||
#define VDD18_22 3
|
||||
|
||||
|
||||
#define PLL_READY (1 << 23)
|
||||
#define VCOCAL_START (1 << 21)
|
||||
#define REG_RCAL_START (1 << 12)
|
||||
|
||||
struct pxa168_usb_drv_data {
|
||||
struct ehci_hcd ehci;
|
||||
struct clk *pxa168_usb_clk;
|
||||
struct resource *usb_phy_res;
|
||||
void __iomem *usb_phy_reg_base;
|
||||
};
|
||||
|
||||
static int ehci_pxa168_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
|
||||
ehci_reset(ehci);
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* data structure init
|
||||
*/
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
hcd->has_tt = 1;
|
||||
|
||||
ehci_port_power(ehci, 0);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const struct hc_driver ehci_pxa168_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "Marvell PXA168 EHCI",
|
||||
.hcd_priv_size = sizeof(struct pxa168_usb_drv_data),
|
||||
|
||||
/*
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB2,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_pxa168_setup,
|
||||
.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,
|
||||
|
||||
/*
|
||||
* 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,
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||
};
|
||||
|
||||
static int pxa168_usb_phy_init(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
void __iomem *usb_phy_reg_base;
|
||||
struct pxa168_usb_pdata *pdata;
|
||||
struct pxa168_usb_drv_data *drv_data;
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
unsigned long reg_val;
|
||||
int pll_retry_cont = 10000, err = 0;
|
||||
|
||||
drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv;
|
||||
pdata = (struct pxa168_usb_pdata *)pdev->dev.platform_data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev,
|
||||
"Found HC with no PHY register addr. Check %s setup!\n",
|
||||
dev_name(&pdev->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res->start, resource_size(res),
|
||||
ehci_pxa168_hc_driver.description)) {
|
||||
dev_dbg(&pdev->dev, "controller already in use\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
usb_phy_reg_base = ioremap(res->start, resource_size(res));
|
||||
if (usb_phy_reg_base == NULL) {
|
||||
dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||
err = -EFAULT;
|
||||
goto err1;
|
||||
}
|
||||
drv_data->usb_phy_reg_base = usb_phy_reg_base;
|
||||
drv_data->usb_phy_res = res;
|
||||
|
||||
/* If someone wants to init USB phy in board specific way */
|
||||
if (pdata && pdata->phy_init)
|
||||
return pdata->phy_init(usb_phy_reg_base);
|
||||
|
||||
/* Power up the PHY and PLL */
|
||||
writel(readl(usb_phy_reg_base + USB_PHY_CTRL_REG) | 0x3,
|
||||
usb_phy_reg_base + USB_PHY_CTRL_REG);
|
||||
|
||||
/* Configure PHY PLL */
|
||||
reg_val = readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~(0x7e03ffff);
|
||||
reg_val |= (VDD18_22 << PLLVDD18_SHIFT | VDD12_12 << PLLVDD12_SHIFT |
|
||||
CALI12_11 << PLLCALI12_SHIFT | 3 << KVCO_SHIFT |
|
||||
ICP_15 << ICP_SHIFT | 0xee << FBDIV_SHIFT | 0xb);
|
||||
writel(reg_val, usb_phy_reg_base + USB_PHY_PLL_REG);
|
||||
|
||||
/* Make sure PHY PLL is ready */
|
||||
while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) {
|
||||
if (!(pll_retry_cont--)) {
|
||||
dev_dbg(&pdev->dev, "USB PHY PLL not ready\n");
|
||||
err = -EIO;
|
||||
goto err2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Toggle VCOCAL_START bit of U2PLL for PLL calibration */
|
||||
udelay(200);
|
||||
writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) | VCOCAL_START,
|
||||
usb_phy_reg_base + USB_PHY_PLL_REG);
|
||||
udelay(40);
|
||||
writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~VCOCAL_START,
|
||||
usb_phy_reg_base + USB_PHY_PLL_REG);
|
||||
|
||||
/* Toggle REG_RCAL_START bit of U2PTX for impedance calibration */
|
||||
udelay(400);
|
||||
writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) | REG_RCAL_START,
|
||||
usb_phy_reg_base + USB_PHY_TX_REG);
|
||||
udelay(40);
|
||||
writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) & ~REG_RCAL_START,
|
||||
usb_phy_reg_base + USB_PHY_TX_REG);
|
||||
|
||||
/* Make sure PHY PLL is ready again */
|
||||
pll_retry_cont = 0;
|
||||
while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) {
|
||||
if (!(pll_retry_cont--)) {
|
||||
dev_dbg(&pdev->dev, "USB PHY PLL not ready\n");
|
||||
err = -EIO;
|
||||
goto err2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
err2:
|
||||
iounmap(usb_phy_reg_base);
|
||||
err1:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devinit ehci_pxa168_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci;
|
||||
struct pxa168_usb_drv_data *drv_data;
|
||||
void __iomem *regs;
|
||||
int irq, err = 0;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
pr_debug("Initializing pxa168-SoC USB Host Controller\n");
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq <= 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Found HC with no IRQ. Check %s setup!\n",
|
||||
dev_name(&pdev->dev));
|
||||
err = -ENODEV;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev,
|
||||
"Found HC with no register addr. Check %s setup!\n",
|
||||
dev_name(&pdev->dev));
|
||||
err = -ENODEV;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
if (!request_mem_region(res->start, resource_size(res),
|
||||
ehci_pxa168_hc_driver.description)) {
|
||||
dev_dbg(&pdev->dev, "controller already in use\n");
|
||||
err = -EBUSY;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
regs = ioremap(res->start, resource_size(res));
|
||||
if (regs == NULL) {
|
||||
dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||
err = -EFAULT;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
hcd = usb_create_hcd(&ehci_pxa168_hc_driver,
|
||||
&pdev->dev, dev_name(&pdev->dev));
|
||||
if (!hcd) {
|
||||
err = -ENOMEM;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv;
|
||||
|
||||
/* Enable USB clock */
|
||||
drv_data->pxa168_usb_clk = clk_get(&pdev->dev, "PXA168-USBCLK");
|
||||
if (IS_ERR(drv_data->pxa168_usb_clk)) {
|
||||
dev_err(&pdev->dev, "Couldn't get USB clock\n");
|
||||
err = PTR_ERR(drv_data->pxa168_usb_clk);
|
||||
goto err4;
|
||||
}
|
||||
clk_enable(drv_data->pxa168_usb_clk);
|
||||
|
||||
err = pxa168_usb_phy_init(pdev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "USB PHY initialization failed\n");
|
||||
goto err5;
|
||||
}
|
||||
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = resource_size(res);
|
||||
hcd->regs = regs;
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
hcd->has_tt = 1;
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
|
||||
if (err)
|
||||
goto err5;
|
||||
|
||||
return 0;
|
||||
|
||||
err5:
|
||||
clk_disable(drv_data->pxa168_usb_clk);
|
||||
clk_put(drv_data->pxa168_usb_clk);
|
||||
err4:
|
||||
usb_put_hcd(hcd);
|
||||
err3:
|
||||
iounmap(regs);
|
||||
err2:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
err1:
|
||||
dev_err(&pdev->dev, "init %s fail, %d\n",
|
||||
dev_name(&pdev->dev), err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __exit ehci_pxa168_drv_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct pxa168_usb_drv_data *drv_data =
|
||||
(struct pxa168_usb_drv_data *)hcd->hcd_priv;
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
/* Power down PHY & PLL */
|
||||
writel(readl(drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG) & (~0x3),
|
||||
drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG);
|
||||
|
||||
clk_disable(drv_data->pxa168_usb_clk);
|
||||
clk_put(drv_data->pxa168_usb_clk);
|
||||
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
|
||||
iounmap(drv_data->usb_phy_reg_base);
|
||||
release_mem_region(drv_data->usb_phy_res->start,
|
||||
resource_size(drv_data->usb_phy_res));
|
||||
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("platform:pxa168-ehci");
|
||||
|
||||
static struct platform_driver ehci_pxa168_driver = {
|
||||
.probe = ehci_pxa168_drv_probe,
|
||||
.remove = __exit_p(ehci_pxa168_drv_remove),
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver.name = "pxa168-ehci",
|
||||
};
|
|
@ -153,7 +153,7 @@ static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
|
|||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
qh->clearing_tt = 0;
|
||||
if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
|
||||
&& HC_IS_RUNNING(hcd->state))
|
||||
&& ehci->rh_state == EHCI_RH_RUNNING)
|
||||
qh_link_async(ehci, qh);
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
}
|
||||
|
@ -425,7 +425,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
|||
|
||||
/* stop scanning when we reach qtds the hc is using */
|
||||
} else if (likely (!stopped
|
||||
&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) {
|
||||
&& ehci->rh_state == EHCI_RH_RUNNING)) {
|
||||
break;
|
||||
|
||||
/* scan the whole queue for unlinks whenever it stops */
|
||||
|
@ -433,7 +433,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
|||
stopped = 1;
|
||||
|
||||
/* cancel everything if we halt, suspend, etc */
|
||||
if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING)
|
||||
last_status = -ESHUTDOWN;
|
||||
|
||||
/* this qtd is active; skip it unless a previous qtd
|
||||
|
@ -977,9 +977,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
|||
/* in case a clear of CMD_ASE didn't take yet */
|
||||
(void)handshake(ehci, &ehci->regs->status,
|
||||
STS_ASS, 0, 150);
|
||||
cmd |= CMD_ASE | CMD_RUN;
|
||||
cmd |= CMD_ASE;
|
||||
ehci_writel(ehci, cmd, &ehci->regs->command);
|
||||
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
|
||||
/* posted write need not be known to HC yet ... */
|
||||
}
|
||||
}
|
||||
|
@ -1168,14 +1167,13 @@ static void end_unlink_async (struct ehci_hcd *ehci)
|
|||
|
||||
qh_completions (ehci, qh);
|
||||
|
||||
if (!list_empty (&qh->qtd_list)
|
||||
&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
|
||||
if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
|
||||
qh_link_async (ehci, qh);
|
||||
else {
|
||||
} else {
|
||||
/* it's not free to turn the async schedule on/off; leave it
|
||||
* active but idle for a while once it empties.
|
||||
*/
|
||||
if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
|
||||
if (ehci->rh_state == EHCI_RH_RUNNING
|
||||
&& ehci->async->qh_next.qh == NULL)
|
||||
timer_action (ehci, TIMER_ASYNC_OFF);
|
||||
}
|
||||
|
@ -1211,7 +1209,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
|||
/* stop async schedule right now? */
|
||||
if (unlikely (qh == ehci->async)) {
|
||||
/* can't get here without STS_ASS set */
|
||||
if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
|
||||
if (ehci->rh_state != EHCI_RH_HALTED
|
||||
&& !ehci->reclaim) {
|
||||
/* ... and CMD_IAAD clear */
|
||||
ehci_writel(ehci, cmd & ~CMD_ASE,
|
||||
|
@ -1237,7 +1235,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
|||
wmb ();
|
||||
|
||||
/* If the controller isn't running, we don't have to wait for it */
|
||||
if (unlikely(!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))) {
|
||||
if (unlikely(ehci->rh_state != EHCI_RH_RUNNING)) {
|
||||
/* if (unlikely (qh->reclaim != 0))
|
||||
* this will recurse, probably not much
|
||||
*/
|
||||
|
@ -1260,7 +1258,7 @@ static void scan_async (struct ehci_hcd *ehci)
|
|||
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
|
||||
|
||||
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
|
||||
stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
|
||||
stopped = (ehci->rh_state != EHCI_RH_RUNNING);
|
||||
|
||||
ehci->qh_scan_next = ehci->async->qh_next.qh;
|
||||
while (ehci->qh_scan_next) {
|
||||
|
|
|
@ -270,7 +270,7 @@ static int s5p_ehci_resume(struct device *dev)
|
|||
/* here we "know" root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -479,7 +479,6 @@ static int enable_periodic (struct ehci_hcd *ehci)
|
|||
cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
|
||||
ehci_writel(ehci, cmd, &ehci->regs->command);
|
||||
/* posted write ... PSS happens later */
|
||||
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
|
||||
|
||||
/* make sure ehci_work scans these */
|
||||
ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
|
||||
|
@ -677,7 +676,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
|||
|
||||
/* reschedule QH iff another request is queued */
|
||||
if (!list_empty(&qh->qtd_list) &&
|
||||
HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
|
||||
ehci->rh_state == EHCI_RH_RUNNING) {
|
||||
rc = qh_schedule(ehci, qh);
|
||||
|
||||
/* An error here likely indicates handshake failure
|
||||
|
@ -2275,7 +2274,7 @@ scan_periodic (struct ehci_hcd *ehci)
|
|||
* Touches as few pages as possible: cache-friendly.
|
||||
*/
|
||||
now_uframe = ehci->next_uframe;
|
||||
if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
|
||||
if (ehci->rh_state == EHCI_RH_RUNNING) {
|
||||
clock = ehci_readl(ehci, &ehci->regs->frame_index);
|
||||
clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
|
||||
} else {
|
||||
|
@ -2310,7 +2309,7 @@ restart:
|
|||
union ehci_shadow temp;
|
||||
int live;
|
||||
|
||||
live = HC_IS_RUNNING (ehci_to_hcd(ehci)->state);
|
||||
live = (ehci->rh_state == EHCI_RH_RUNNING);
|
||||
switch (hc32_to_cpu(ehci, type)) {
|
||||
case Q_TYPE_QH:
|
||||
/* handle any completions */
|
||||
|
@ -2435,7 +2434,7 @@ restart:
|
|||
* We can't advance our scan without collecting the ISO
|
||||
* transfers that are still pending in this frame.
|
||||
*/
|
||||
if (incomplete && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
|
||||
if (incomplete && ehci->rh_state == EHCI_RH_RUNNING) {
|
||||
ehci->next_uframe = now_uframe;
|
||||
break;
|
||||
}
|
||||
|
@ -2451,7 +2450,7 @@ restart:
|
|||
if (now_uframe == clock) {
|
||||
unsigned now;
|
||||
|
||||
if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
|
||||
if (ehci->rh_state != EHCI_RH_RUNNING
|
||||
|| ehci->periodic_sched == 0)
|
||||
break;
|
||||
ehci->next_uframe = now_uframe;
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* EHCI HCD for Netlogic XLS processors.
|
||||
*
|
||||
* (C) Copyright 2011 Netlogic Microsystems Inc.
|
||||
*
|
||||
* Based on various ehci-*.c drivers
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static int ehci_xls_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
int retval;
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* data structure init */
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ehci_xls_probe_internal(const struct hc_driver *driver,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct resource *res;
|
||||
int retval, irq;
|
||||
|
||||
/* Get our IRQ from an earlier registered Platform Resource */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "Found HC with no IRQ. Check %s setup!\n",
|
||||
dev_name(&pdev->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Get our Memory Handle */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Error: MMIO Handle %s setup!\n",
|
||||
dev_name(&pdev->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
|
||||
if (!hcd) {
|
||||
retval = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = res->end - res->start + 1;
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
|
||||
driver->description)) {
|
||||
dev_dbg(&pdev->dev, "controller already in use\n");
|
||||
retval = -EBUSY;
|
||||
goto err2;
|
||||
}
|
||||
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
|
||||
|
||||
if (hcd->regs == NULL) {
|
||||
dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||
retval = -EFAULT;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (retval != 0)
|
||||
goto err4;
|
||||
return retval;
|
||||
|
||||
err4:
|
||||
iounmap(hcd->regs);
|
||||
err3:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err2:
|
||||
usb_put_hcd(hcd);
|
||||
err1:
|
||||
dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev),
|
||||
retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct hc_driver ehci_xls_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "XLS EHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_USB2 | HCD_MEMORY,
|
||||
.reset = ehci_xls_setup,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
.bus_suspend = ehci_bus_suspend,
|
||||
.bus_resume = ehci_bus_resume,
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||
};
|
||||
|
||||
static int ehci_xls_probe(struct platform_device *pdev)
|
||||
{
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
return ehci_xls_probe_internal(&ehci_xls_hc_driver, pdev);
|
||||
}
|
||||
|
||||
static int ehci_xls_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_ALIAS("ehci-xls");
|
||||
|
||||
static struct platform_driver ehci_xls_driver = {
|
||||
.probe = ehci_xls_probe,
|
||||
.remove = ehci_xls_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "ehci-xls",
|
||||
},
|
||||
};
|
|
@ -62,6 +62,12 @@ struct ehci_stats {
|
|||
|
||||
#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
|
||||
|
||||
enum ehci_rh_state {
|
||||
EHCI_RH_HALTED,
|
||||
EHCI_RH_SUSPENDED,
|
||||
EHCI_RH_RUNNING
|
||||
};
|
||||
|
||||
struct ehci_hcd { /* one per controller */
|
||||
/* glue to PCI and HCD framework */
|
||||
struct ehci_caps __iomem *caps;
|
||||
|
@ -70,6 +76,7 @@ struct ehci_hcd { /* one per controller */
|
|||
|
||||
__u32 hcs_params; /* cached register copy */
|
||||
spinlock_t lock;
|
||||
enum ehci_rh_state rh_state;
|
||||
|
||||
/* async schedule support */
|
||||
struct ehci_qh *async;
|
||||
|
|
|
@ -621,12 +621,15 @@ static int __devinit of_fhci_probe(struct platform_device *ofdev)
|
|||
goto err_pram;
|
||||
}
|
||||
|
||||
pram_addr = cpm_muram_alloc_fixed(iprop[2], FHCI_PRAM_SIZE);
|
||||
pram_addr = cpm_muram_alloc(FHCI_PRAM_SIZE, 64);
|
||||
if (IS_ERR_VALUE(pram_addr)) {
|
||||
dev_err(dev, "failed to allocate usb pram\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_pram;
|
||||
}
|
||||
|
||||
qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, QE_CR_SUBBLOCK_USB,
|
||||
QE_CR_PROTOCOL_UNSPECIFIED, pram_addr);
|
||||
fhci->pram = cpm_muram_addr(pram_addr);
|
||||
|
||||
/* GPIOs and pins */
|
||||
|
|
|
@ -2358,7 +2358,7 @@ static int isp1362_hc_reset(struct usb_hcd *hcd)
|
|||
unsigned long flags;
|
||||
int clkrdy = 0;
|
||||
|
||||
pr_info("%s:\n", __func__);
|
||||
pr_debug("%s:\n", __func__);
|
||||
|
||||
if (isp1362_hcd->board && isp1362_hcd->board->reset) {
|
||||
isp1362_hcd->board->reset(hcd->self.controller, 1);
|
||||
|
@ -2395,7 +2395,7 @@ static void isp1362_hc_stop(struct usb_hcd *hcd)
|
|||
unsigned long flags;
|
||||
u32 tmp;
|
||||
|
||||
pr_info("%s:\n", __func__);
|
||||
pr_debug("%s:\n", __func__);
|
||||
|
||||
del_timer_sync(&hcd->rh_timer);
|
||||
|
||||
|
@ -2523,7 +2523,7 @@ static int isp1362_hc_start(struct usb_hcd *hcd)
|
|||
u16 chipid;
|
||||
unsigned long flags;
|
||||
|
||||
pr_info("%s:\n", __func__);
|
||||
pr_debug("%s:\n", __func__);
|
||||
|
||||
spin_lock_irqsave(&isp1362_hcd->lock, flags);
|
||||
chipid = isp1362_read_reg16(isp1362_hcd, HCCHIPID);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/uaccess.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/timer.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
|
@ -39,7 +40,6 @@ struct isp1760_hcd {
|
|||
int int_done_map;
|
||||
struct memory_chunk memory_pool[BLOCKS];
|
||||
struct list_head controlqhs, bulkqhs, interruptqhs;
|
||||
int active_ptds;
|
||||
|
||||
/* periodic schedule support */
|
||||
#define DEFAULT_I_TDPS 1024
|
||||
|
@ -114,6 +114,7 @@ struct isp1760_qh {
|
|||
u32 toggle;
|
||||
u32 ping;
|
||||
int slot;
|
||||
int tt_buffer_dirty; /* See USB2.0 spec section 11.17.5 */
|
||||
};
|
||||
|
||||
struct urb_listitem {
|
||||
|
@ -489,10 +490,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
|
|||
16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ?
|
||||
"analog" : "digital");
|
||||
|
||||
/* This is weird: at the first plug-in of a device there seems to be
|
||||
one packet queued that never gets returned? */
|
||||
priv->active_ptds = -1;
|
||||
|
||||
/* ATL reset */
|
||||
reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
|
||||
mdelay(10);
|
||||
|
@ -514,83 +511,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
|
|||
return priv_init(hcd);
|
||||
}
|
||||
|
||||
static void isp1760_init_maps(struct usb_hcd *hcd)
|
||||
{
|
||||
/*set last maps, for iso its only 1, else 32 tds bitmap*/
|
||||
reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
|
||||
reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
|
||||
reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
|
||||
|
||||
reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
|
||||
|
||||
reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
|
||||
ATL_BUF_FILL | INT_BUF_FILL);
|
||||
}
|
||||
|
||||
static void isp1760_enable_interrupts(struct usb_hcd *hcd)
|
||||
{
|
||||
reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
|
||||
reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
|
||||
reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
|
||||
reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
|
||||
/* step 23 passed */
|
||||
}
|
||||
|
||||
static int isp1760_run(struct usb_hcd *hcd)
|
||||
{
|
||||
int retval;
|
||||
u32 temp;
|
||||
u32 command;
|
||||
u32 chipid;
|
||||
|
||||
hcd->uses_new_polling = 1;
|
||||
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
isp1760_enable_interrupts(hcd);
|
||||
temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
|
||||
reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
|
||||
|
||||
command = reg_read32(hcd->regs, HC_USBCMD);
|
||||
command &= ~(CMD_LRESET|CMD_RESET);
|
||||
command |= CMD_RUN;
|
||||
reg_write32(hcd->regs, HC_USBCMD, command);
|
||||
|
||||
retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Spec says to write FLAG_CF as last config action, priv code grabs
|
||||
* the semaphore while doing so.
|
||||
*/
|
||||
down_write(&ehci_cf_port_reset_rwsem);
|
||||
reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
|
||||
|
||||
retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
|
||||
up_write(&ehci_cf_port_reset_rwsem);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
|
||||
dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
|
||||
chipid & 0xffff, chipid >> 16);
|
||||
|
||||
/* PTD Register Init Part 2, Step 28 */
|
||||
/* enable INTs */
|
||||
isp1760_init_maps(hcd);
|
||||
|
||||
/* GRR this is run-once init(), being done every time the HC starts.
|
||||
* So long as they're part of class devices, we can't do it init()
|
||||
* since the class device isn't created that early.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 base_to_chip(u32 base)
|
||||
{
|
||||
return ((base - 0x400) >> 3);
|
||||
|
@ -813,28 +733,29 @@ static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
|
|||
WARN_ON(slots[slot].qh);
|
||||
WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
|
||||
|
||||
slots[slot].qtd = qtd;
|
||||
slots[slot].qh = qh;
|
||||
qh->slot = slot;
|
||||
qtd->status = QTD_XFER_STARTED; /* Set this before writing ptd, since
|
||||
interrupt routine may preempt and expects this value. */
|
||||
ptd_write(hcd->regs, ptd_offset, slot, ptd);
|
||||
priv->active_ptds++;
|
||||
|
||||
/* Make sure done map has not triggered from some unlinked transfer */
|
||||
if (ptd_offset == ATL_PTD_OFFSET) {
|
||||
priv->atl_done_map |= reg_read32(hcd->regs,
|
||||
HC_ATL_PTD_DONEMAP_REG);
|
||||
priv->atl_done_map &= ~(1 << qh->slot);
|
||||
priv->atl_done_map &= ~(1 << slot);
|
||||
} else {
|
||||
priv->int_done_map |= reg_read32(hcd->regs,
|
||||
HC_INT_PTD_DONEMAP_REG);
|
||||
priv->int_done_map &= ~(1 << slot);
|
||||
}
|
||||
|
||||
qh->slot = slot;
|
||||
qtd->status = QTD_XFER_STARTED;
|
||||
slots[slot].timestamp = jiffies;
|
||||
slots[slot].qtd = qtd;
|
||||
slots[slot].qh = qh;
|
||||
ptd_write(hcd->regs, ptd_offset, slot, ptd);
|
||||
|
||||
if (ptd_offset == ATL_PTD_OFFSET) {
|
||||
skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
|
||||
skip_map &= ~(1 << qh->slot);
|
||||
reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
|
||||
} else {
|
||||
priv->int_done_map |= reg_read32(hcd->regs,
|
||||
HC_INT_PTD_DONEMAP_REG);
|
||||
priv->int_done_map &= ~(1 << qh->slot);
|
||||
|
||||
skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
|
||||
skip_map &= ~(1 << qh->slot);
|
||||
reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
|
||||
|
@ -858,10 +779,7 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
|
|||
if (qtd->status < QTD_XFER_COMPLETE)
|
||||
break;
|
||||
|
||||
if (list_is_last(&qtd->qtd_list, &qh->qtd_list))
|
||||
last_qtd = 1;
|
||||
else
|
||||
last_qtd = qtd->urb != qtd_next->urb;
|
||||
last_qtd = last_qtd_of_urb(qtd, qh);
|
||||
|
||||
if ((!last_qtd) && (qtd->status == QTD_RETIRE))
|
||||
qtd_next->status = QTD_RETIRE;
|
||||
|
@ -902,7 +820,7 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
|
|||
urb_listitem = kmem_cache_zalloc(urb_listitem_cachep,
|
||||
GFP_ATOMIC);
|
||||
if (unlikely(!urb_listitem))
|
||||
break;
|
||||
break; /* Try again on next call */
|
||||
urb_listitem->urb = qtd->urb;
|
||||
list_add_tail(&urb_listitem->urb_list, urb_list);
|
||||
}
|
||||
|
@ -928,6 +846,10 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Make sure this endpoint's TT buffer is clean before queueing ptds */
|
||||
if (qh->tt_buffer_dirty)
|
||||
return;
|
||||
|
||||
if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd,
|
||||
qtd_list)->urb->pipe)) {
|
||||
ptd_offset = INT_PTD_OFFSET;
|
||||
|
@ -1168,11 +1090,9 @@ static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd,
|
|||
return PTD_STATE_QTD_DONE;
|
||||
}
|
||||
|
||||
static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
|
||||
static void handle_done_ptds(struct usb_hcd *hcd)
|
||||
{
|
||||
struct isp1760_hcd *priv = hcd_to_priv(hcd);
|
||||
u32 imask;
|
||||
irqreturn_t irqret = IRQ_NONE;
|
||||
struct ptd ptd;
|
||||
struct isp1760_qh *qh;
|
||||
int slot;
|
||||
|
@ -1181,27 +1101,14 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
|
|||
u32 ptd_offset;
|
||||
struct isp1760_qtd *qtd;
|
||||
int modified;
|
||||
static int last_active_ptds;
|
||||
int int_skip_map, atl_skip_map;
|
||||
int skip_map;
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
|
||||
priv->int_done_map &= ~skip_map;
|
||||
skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
|
||||
priv->atl_done_map &= ~skip_map;
|
||||
|
||||
if (!(hcd->state & HC_STATE_RUNNING))
|
||||
goto leave;
|
||||
|
||||
imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
|
||||
if (unlikely(!imask))
|
||||
goto leave;
|
||||
reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
|
||||
|
||||
int_skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
|
||||
atl_skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
|
||||
priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
|
||||
priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
|
||||
priv->int_done_map &= ~int_skip_map;
|
||||
priv->atl_done_map &= ~atl_skip_map;
|
||||
|
||||
modified = priv->int_done_map | priv->atl_done_map;
|
||||
modified = priv->int_done_map || priv->atl_done_map;
|
||||
|
||||
while (priv->int_done_map || priv->atl_done_map) {
|
||||
if (priv->int_done_map) {
|
||||
|
@ -1240,7 +1147,6 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
|
|||
slots[slot].qtd = NULL;
|
||||
qh = slots[slot].qh;
|
||||
slots[slot].qh = NULL;
|
||||
priv->active_ptds--;
|
||||
qh->slot = -1;
|
||||
|
||||
WARN_ON(qtd->status != QTD_XFER_STARTED);
|
||||
|
@ -1281,6 +1187,15 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
|
|||
|
||||
case PTD_STATE_URB_RETIRE:
|
||||
qtd->status = QTD_RETIRE;
|
||||
if ((qtd->urb->dev->speed != USB_SPEED_HIGH) &&
|
||||
(qtd->urb->status != -EPIPE) &&
|
||||
(qtd->urb->status != -EREMOTEIO)) {
|
||||
qh->tt_buffer_dirty = 1;
|
||||
if (usb_hub_clear_tt_buffer(qtd->urb))
|
||||
/* Clear failed; let's hope things work
|
||||
anyway */
|
||||
qh->tt_buffer_dirty = 0;
|
||||
}
|
||||
qtd = NULL;
|
||||
qh->toggle = 0;
|
||||
qh->ping = 0;
|
||||
|
@ -1311,22 +1226,28 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
|
|||
|
||||
if (modified)
|
||||
schedule_ptds(hcd);
|
||||
}
|
||||
|
||||
/* ISP1760 Errata 2 explains that interrupts may be missed (or not
|
||||
happen?) if two USB devices are running simultaneously. Perhaps
|
||||
this happens when a PTD is finished during interrupt handling;
|
||||
enable SOF interrupts if PTDs are still scheduled when exiting this
|
||||
interrupt handler, just to be safe. */
|
||||
static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
|
||||
{
|
||||
struct isp1760_hcd *priv = hcd_to_priv(hcd);
|
||||
u32 imask;
|
||||
irqreturn_t irqret = IRQ_NONE;
|
||||
|
||||
if (priv->active_ptds != last_active_ptds) {
|
||||
if (priv->active_ptds > 0)
|
||||
reg_write32(hcd->regs, HC_INTERRUPT_ENABLE,
|
||||
INTERRUPT_ENABLE_SOT_MASK);
|
||||
else
|
||||
reg_write32(hcd->regs, HC_INTERRUPT_ENABLE,
|
||||
INTERRUPT_ENABLE_MASK);
|
||||
last_active_ptds = priv->active_ptds;
|
||||
}
|
||||
spin_lock(&priv->lock);
|
||||
|
||||
if (!(hcd->state & HC_STATE_RUNNING))
|
||||
goto leave;
|
||||
|
||||
imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
|
||||
if (unlikely(!imask))
|
||||
goto leave;
|
||||
reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
|
||||
|
||||
priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
|
||||
priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
|
||||
|
||||
handle_done_ptds(hcd);
|
||||
|
||||
irqret = IRQ_HANDLED;
|
||||
leave:
|
||||
|
@ -1335,6 +1256,138 @@ leave:
|
|||
return irqret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Workaround for problem described in chip errata 2:
|
||||
*
|
||||
* Sometimes interrupts are not generated when ATL (not INT?) completion occurs.
|
||||
* One solution suggested in the errata is to use SOF interrupts _instead_of_
|
||||
* ATL done interrupts (the "instead of" might be important since it seems
|
||||
* enabling ATL interrupts also causes the chip to sometimes - rarely - "forget"
|
||||
* to set the PTD's done bit in addition to not generating an interrupt!).
|
||||
*
|
||||
* So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their
|
||||
* done bit is not being set. This is bad - it blocks the endpoint until reboot.
|
||||
*
|
||||
* If we use SOF interrupts only, we get latency between ptd completion and the
|
||||
* actual handling. This is very noticeable in testusb runs which takes several
|
||||
* minutes longer without ATL interrupts.
|
||||
*
|
||||
* A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it
|
||||
* finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the
|
||||
* slot's ACTIVE and VALID bits. If these are not set, the ptd is considered
|
||||
* completed and its done map bit is set.
|
||||
*
|
||||
* The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen
|
||||
* not to cause too much lag when this HW bug occurs, while still hopefully
|
||||
* ensuring that the check does not falsely trigger.
|
||||
*/
|
||||
#define SLOT_TIMEOUT 300
|
||||
#define SLOT_CHECK_PERIOD 200
|
||||
static struct timer_list errata2_timer;
|
||||
|
||||
void errata2_function(unsigned long data)
|
||||
{
|
||||
struct usb_hcd *hcd = (struct usb_hcd *) data;
|
||||
struct isp1760_hcd *priv = hcd_to_priv(hcd);
|
||||
int slot;
|
||||
struct ptd ptd;
|
||||
unsigned long spinflags;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, spinflags);
|
||||
|
||||
for (slot = 0; slot < 32; slot++)
|
||||
if (priv->atl_slots[slot].qh && time_after(jiffies,
|
||||
priv->atl_slots[slot].timestamp +
|
||||
SLOT_TIMEOUT * HZ / 1000)) {
|
||||
ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
|
||||
if (!FROM_DW0_VALID(ptd.dw0) &&
|
||||
!FROM_DW3_ACTIVE(ptd.dw3))
|
||||
priv->atl_done_map |= 1 << slot;
|
||||
}
|
||||
|
||||
if (priv->atl_done_map)
|
||||
handle_done_ptds(hcd);
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, spinflags);
|
||||
|
||||
errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
|
||||
add_timer(&errata2_timer);
|
||||
}
|
||||
|
||||
static int isp1760_run(struct usb_hcd *hcd)
|
||||
{
|
||||
int retval;
|
||||
u32 temp;
|
||||
u32 command;
|
||||
u32 chipid;
|
||||
|
||||
hcd->uses_new_polling = 1;
|
||||
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
|
||||
/* Set PTD interrupt AND & OR maps */
|
||||
reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
|
||||
reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
|
||||
reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
|
||||
reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
|
||||
/* step 23 passed */
|
||||
|
||||
temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
|
||||
reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
|
||||
|
||||
command = reg_read32(hcd->regs, HC_USBCMD);
|
||||
command &= ~(CMD_LRESET|CMD_RESET);
|
||||
command |= CMD_RUN;
|
||||
reg_write32(hcd->regs, HC_USBCMD, command);
|
||||
|
||||
retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* Spec says to write FLAG_CF as last config action, priv code grabs
|
||||
* the semaphore while doing so.
|
||||
*/
|
||||
down_write(&ehci_cf_port_reset_rwsem);
|
||||
reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
|
||||
|
||||
retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
|
||||
up_write(&ehci_cf_port_reset_rwsem);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
init_timer(&errata2_timer);
|
||||
errata2_timer.function = errata2_function;
|
||||
errata2_timer.data = (unsigned long) hcd;
|
||||
errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
|
||||
add_timer(&errata2_timer);
|
||||
|
||||
chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
|
||||
dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
|
||||
chipid & 0xffff, chipid >> 16);
|
||||
|
||||
/* PTD Register Init Part 2, Step 28 */
|
||||
|
||||
/* Setup registers controlling PTD checking */
|
||||
reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
|
||||
reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
|
||||
reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
|
||||
reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
|
||||
reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
|
||||
ATL_BUF_FILL | INT_BUF_FILL);
|
||||
|
||||
/* GRR this is run-once init(), being done every time the HC starts.
|
||||
* So long as they're part of class devices, we can't do it init()
|
||||
* since the class device isn't created that early.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
|
||||
{
|
||||
qtd->data_buffer = databuffer;
|
||||
|
@ -1503,7 +1556,6 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
|
|||
packetize_urb(hcd, urb, &new_qtds, mem_flags);
|
||||
if (list_empty(&new_qtds))
|
||||
return -ENOMEM;
|
||||
urb->hcpriv = NULL; /* Used to signal unlink to interrupt handler */
|
||||
|
||||
retval = 0;
|
||||
spin_lock_irqsave(&priv->lock, spinflags);
|
||||
|
@ -1531,6 +1583,7 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
|
|||
qh = qh_alloc(GFP_ATOMIC);
|
||||
if (!qh) {
|
||||
retval = -ENOMEM;
|
||||
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
||||
goto out;
|
||||
}
|
||||
list_add_tail(&qh->qh_list, ep_queue);
|
||||
|
@ -1570,7 +1623,41 @@ static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
|
|||
}
|
||||
|
||||
qh->slot = -1;
|
||||
priv->active_ptds--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing
|
||||
* any active transfer belonging to the urb in the process.
|
||||
*/
|
||||
static void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh,
|
||||
struct isp1760_qtd *qtd)
|
||||
{
|
||||
struct urb *urb;
|
||||
int urb_was_running;
|
||||
|
||||
urb = qtd->urb;
|
||||
urb_was_running = 0;
|
||||
list_for_each_entry_from(qtd, &qh->qtd_list, qtd_list) {
|
||||
if (qtd->urb != urb)
|
||||
break;
|
||||
|
||||
if (qtd->status >= QTD_XFER_STARTED)
|
||||
urb_was_running = 1;
|
||||
if (last_qtd_of_urb(qtd, qh) &&
|
||||
(qtd->status >= QTD_XFER_COMPLETE))
|
||||
urb_was_running = 0;
|
||||
|
||||
if (qtd->status == QTD_XFER_STARTED)
|
||||
kill_transfer(hcd, urb, qh);
|
||||
qtd->status = QTD_RETIRE;
|
||||
}
|
||||
|
||||
if ((urb->dev->speed != USB_SPEED_HIGH) && urb_was_running) {
|
||||
qh->tt_buffer_dirty = 1;
|
||||
if (usb_hub_clear_tt_buffer(urb))
|
||||
/* Clear failed; let's hope things work anyway */
|
||||
qh->tt_buffer_dirty = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
|
||||
|
@ -1595,9 +1682,8 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
|
|||
|
||||
list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
|
||||
if (qtd->urb == urb) {
|
||||
if (qtd->status == QTD_XFER_STARTED)
|
||||
kill_transfer(hcd, urb, qh);
|
||||
qtd->status = QTD_RETIRE;
|
||||
dequeue_urb_from_qtd(hcd, qh, qtd);
|
||||
break;
|
||||
}
|
||||
|
||||
urb->status = status;
|
||||
|
@ -1622,12 +1708,11 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,
|
|||
if (!qh)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
|
||||
if (qtd->status == QTD_XFER_STARTED)
|
||||
kill_transfer(hcd, qtd->urb, qh);
|
||||
qtd->status = QTD_RETIRE;
|
||||
qtd->urb->status = -ECONNRESET;
|
||||
}
|
||||
list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
|
||||
if (qtd->status != QTD_RETIRE) {
|
||||
dequeue_urb_from_qtd(hcd, qh, qtd);
|
||||
qtd->urb->status = -ECONNRESET;
|
||||
}
|
||||
|
||||
ep->hcpriv = NULL;
|
||||
/* Cannot free qh here since it will be parsed by schedule_ptds() */
|
||||
|
@ -2021,6 +2106,8 @@ static void isp1760_stop(struct usb_hcd *hcd)
|
|||
struct isp1760_hcd *priv = hcd_to_priv(hcd);
|
||||
u32 temp;
|
||||
|
||||
del_timer(&errata2_timer);
|
||||
|
||||
isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1,
|
||||
NULL, 0);
|
||||
mdelay(20);
|
||||
|
@ -2048,6 +2135,23 @@ static void isp1760_shutdown(struct usb_hcd *hcd)
|
|||
reg_write32(hcd->regs, HC_USBCMD, command);
|
||||
}
|
||||
|
||||
static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
|
||||
struct usb_host_endpoint *ep)
|
||||
{
|
||||
struct isp1760_hcd *priv = hcd_to_priv(hcd);
|
||||
struct isp1760_qh *qh = ep->hcpriv;
|
||||
unsigned long spinflags;
|
||||
|
||||
if (!qh)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, spinflags);
|
||||
qh->tt_buffer_dirty = 0;
|
||||
schedule_ptds(hcd);
|
||||
spin_unlock_irqrestore(&priv->lock, spinflags);
|
||||
}
|
||||
|
||||
|
||||
static const struct hc_driver isp1760_hc_driver = {
|
||||
.description = "isp1760-hcd",
|
||||
.product_desc = "NXP ISP1760 USB Host Controller",
|
||||
|
@ -2064,6 +2168,7 @@ static const struct hc_driver isp1760_hc_driver = {
|
|||
.get_frame_number = isp1760_get_frame,
|
||||
.hub_status_data = isp1760_hub_status_data,
|
||||
.hub_control = isp1760_hub_control,
|
||||
.clear_tt_buffer_complete = isp1760_clear_tt_buffer_complete,
|
||||
};
|
||||
|
||||
int __init init_kmem_once(void)
|
||||
|
|
|
@ -73,7 +73,6 @@ void deinit_kmem_cache(void);
|
|||
#define HC_EOT_INT (1 << 3)
|
||||
#define HC_SOT_INT (1 << 1)
|
||||
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
|
||||
#define INTERRUPT_ENABLE_SOT_MASK (HC_SOT_INT)
|
||||
|
||||
#define HC_ISO_IRQ_MASK_OR_REG 0x318
|
||||
#define HC_INT_IRQ_MASK_OR_REG 0x31C
|
||||
|
@ -107,6 +106,7 @@ struct ptd {
|
|||
struct slotinfo {
|
||||
struct isp1760_qh *qh;
|
||||
struct isp1760_qtd *qtd;
|
||||
unsigned long timestamp;
|
||||
};
|
||||
|
||||
|
||||
|
@ -188,6 +188,7 @@ struct memory_chunk {
|
|||
#define DW3_BABBLE_BIT (1 << 29)
|
||||
#define DW3_HALT_BIT (1 << 30)
|
||||
#define DW3_ACTIVE_BIT (1 << 31)
|
||||
#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01)
|
||||
|
||||
#define INT_UNDERRUN (1 << 2)
|
||||
#define INT_BABBLE (1 << 1)
|
||||
|
|
|
@ -1114,6 +1114,11 @@ MODULE_LICENSE ("GPL");
|
|||
#define PLATFORM_DRIVER ohci_hcd_ath79_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NLM_XLR
|
||||
#include "ohci-xls.c"
|
||||
#define PLATFORM_DRIVER ohci_xls_driver
|
||||
#endif
|
||||
|
||||
#if !defined(PCI_DRIVER) && \
|
||||
!defined(PLATFORM_DRIVER) && \
|
||||
!defined(OMAP1_PLATFORM_DRIVER) && \
|
||||
|
|
|
@ -149,7 +149,7 @@ static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev)
|
|||
|
||||
res = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_MEM, "ohci");
|
||||
if (!ret) {
|
||||
if (!res) {
|
||||
dev_err(dev, "UHH OHCI get resource failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
|
@ -428,7 +428,7 @@ static struct ed *ed_get (
|
|||
ed->type = usb_pipetype(pipe);
|
||||
|
||||
info |= (ep->desc.bEndpointAddress & ~USB_DIR_IN) << 7;
|
||||
info |= le16_to_cpu(ep->desc.wMaxPacketSize) << 16;
|
||||
info |= usb_endpoint_maxp(&ep->desc) << 16;
|
||||
if (udev->speed == USB_SPEED_LOW)
|
||||
info |= ED_LOWSPEED;
|
||||
/* only control transfers store pids in tds */
|
||||
|
@ -444,7 +444,7 @@ static struct ed *ed_get (
|
|||
ed->load = usb_calc_bus_time (
|
||||
udev->speed, !is_out,
|
||||
ed->type == PIPE_ISOCHRONOUS,
|
||||
le16_to_cpu(ep->desc.wMaxPacketSize))
|
||||
usb_endpoint_maxp(&ep->desc))
|
||||
/ 1000;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* OHCI HCD for Netlogic XLS processors.
|
||||
*
|
||||
* (C) Copyright 2011 Netlogic Microsystems Inc.
|
||||
*
|
||||
* Based on ohci-au1xxx.c, and other Linux OHCI drivers.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/signal.h>
|
||||
|
||||
static int ohci_xls_probe_internal(const struct hc_driver *driver,
|
||||
struct platform_device *dev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct usb_hcd *hcd;
|
||||
int retval, irq;
|
||||
|
||||
/* Get our IRQ from an earlier registered Platform Resource */
|
||||
irq = platform_get_irq(dev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&dev->dev, "Found HC with no IRQ\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Get our Memory Handle */
|
||||
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&dev->dev, "MMIO Handle incorrect!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hcd = usb_create_hcd(driver, &dev->dev, "XLS");
|
||||
if (!hcd) {
|
||||
retval = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = res->end - res->start + 1;
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
|
||||
driver->description)) {
|
||||
dev_dbg(&dev->dev, "Controller already in use\n");
|
||||
retval = -EBUSY;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (hcd->regs == NULL) {
|
||||
dev_dbg(&dev->dev, "error mapping memory\n");
|
||||
retval = -EFAULT;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
if (retval != 0)
|
||||
goto err4;
|
||||
return retval;
|
||||
|
||||
err4:
|
||||
iounmap(hcd->regs);
|
||||
err3:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err2:
|
||||
usb_put_hcd(hcd);
|
||||
err1:
|
||||
dev_err(&dev->dev, "init fail, %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int ohci_xls_reset(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
|
||||
ohci_hcd_init(ohci);
|
||||
return ohci_init(ohci);
|
||||
}
|
||||
|
||||
static int __devinit ohci_xls_start(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ohci_hcd *ohci;
|
||||
int ret;
|
||||
|
||||
ohci = hcd_to_ohci(hcd);
|
||||
ret = ohci_run(ohci);
|
||||
if (ret < 0) {
|
||||
err("can't start %s", hcd->self.bus_name);
|
||||
ohci_stop(hcd);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hc_driver ohci_xls_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "XLS OHCI Host Controller",
|
||||
.hcd_priv_size = sizeof(struct ohci_hcd),
|
||||
.irq = ohci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB11,
|
||||
.reset = ohci_xls_reset,
|
||||
.start = ohci_xls_start,
|
||||
.stop = ohci_stop,
|
||||
.shutdown = ohci_shutdown,
|
||||
.urb_enqueue = ohci_urb_enqueue,
|
||||
.urb_dequeue = ohci_urb_dequeue,
|
||||
.endpoint_disable = ohci_endpoint_disable,
|
||||
.get_frame_number = ohci_get_frame,
|
||||
.hub_status_data = ohci_hub_status_data,
|
||||
.hub_control = ohci_hub_control,
|
||||
#ifdef CONFIG_PM
|
||||
.bus_suspend = ohci_bus_suspend,
|
||||
.bus_resume = ohci_bus_resume,
|
||||
#endif
|
||||
.start_port_reset = ohci_start_port_reset,
|
||||
};
|
||||
|
||||
static int ohci_xls_probe(struct platform_device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_debug("In ohci_xls_probe");
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
ret = ohci_xls_probe_internal(&ohci_xls_hc_driver, dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ohci_xls_remove(struct platform_device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ohci_xls_driver = {
|
||||
.probe = ohci_xls_probe,
|
||||
.remove = ohci_xls_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "ohci-xls-0",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
|
@ -959,7 +959,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
|
|||
info.pipenum = get_empty_pipenum(r8a66597, ep);
|
||||
info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
|
||||
info.epnum = usb_endpoint_num(ep);
|
||||
info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
|
||||
info.maxpacket = usb_endpoint_maxp(ep);
|
||||
info.type = get_r8a66597_type(usb_endpoint_type(ep));
|
||||
info.bufnum = get_bufnum(info.pipenum);
|
||||
info.buf_bsize = get_buf_bsize(info.pipenum);
|
||||
|
|
|
@ -280,7 +280,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
|
|||
qh->load = usb_calc_bus_time(udev->speed,
|
||||
usb_endpoint_dir_in(&hep->desc),
|
||||
qh->type == USB_ENDPOINT_XFER_ISOC,
|
||||
le16_to_cpu(hep->desc.wMaxPacketSize))
|
||||
usb_endpoint_maxp(&hep->desc))
|
||||
/ 1000 + 1;
|
||||
|
||||
} else { /* Skeleton QH */
|
||||
|
@ -792,7 +792,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
|
|||
{
|
||||
struct uhci_td *td;
|
||||
unsigned long destination, status;
|
||||
int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
|
||||
int maxsze = usb_endpoint_maxp(&qh->hep->desc);
|
||||
int len = urb->transfer_buffer_length;
|
||||
dma_addr_t data = urb->transfer_dma;
|
||||
__hc32 *plink;
|
||||
|
@ -918,7 +918,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
|
|||
{
|
||||
struct uhci_td *td;
|
||||
unsigned long destination, status;
|
||||
int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
|
||||
int maxsze = usb_endpoint_maxp(&qh->hep->desc);
|
||||
int len = urb->transfer_buffer_length;
|
||||
int this_sg_len;
|
||||
dma_addr_t data;
|
||||
|
|
|
@ -1141,8 +1141,8 @@ static u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
|
|||
if (udev->speed == USB_SPEED_SUPER)
|
||||
return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
|
||||
|
||||
max_packet = GET_MAX_PACKET(le16_to_cpu(ep->desc.wMaxPacketSize));
|
||||
max_burst = (le16_to_cpu(ep->desc.wMaxPacketSize) & 0x1800) >> 11;
|
||||
max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
|
||||
max_burst = (usb_endpoint_maxp(&ep->desc) & 0x1800) >> 11;
|
||||
/* A 0 in max burst means 1 transfer per ESIT */
|
||||
return max_packet * (max_burst + 1);
|
||||
}
|
||||
|
@ -1211,7 +1211,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
|
|||
/* Set the max packet size and max burst */
|
||||
switch (udev->speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
max_packet = le16_to_cpu(ep->desc.wMaxPacketSize);
|
||||
max_packet = usb_endpoint_maxp(&ep->desc);
|
||||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
|
||||
/* dig out max burst from ep companion desc */
|
||||
max_packet = ep->ss_ep_comp.bMaxBurst;
|
||||
|
@ -1223,14 +1223,14 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
|
|||
*/
|
||||
if (usb_endpoint_xfer_isoc(&ep->desc) ||
|
||||
usb_endpoint_xfer_int(&ep->desc)) {
|
||||
max_burst = (le16_to_cpu(ep->desc.wMaxPacketSize)
|
||||
max_burst = (usb_endpoint_maxp(&ep->desc)
|
||||
& 0x1800) >> 11;
|
||||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_burst));
|
||||
}
|
||||
/* Fall through */
|
||||
case USB_SPEED_FULL:
|
||||
case USB_SPEED_LOW:
|
||||
max_packet = GET_MAX_PACKET(le16_to_cpu(ep->desc.wMaxPacketSize));
|
||||
max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
|
||||
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -2692,7 +2692,7 @@ static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len,
|
|||
* running_total.
|
||||
*/
|
||||
packets_transferred = (running_total + trb_buff_len) /
|
||||
le16_to_cpu(urb->ep->desc.wMaxPacketSize);
|
||||
usb_endpoint_maxp(&urb->ep->desc);
|
||||
|
||||
return xhci_td_remainder(total_packet_count - packets_transferred);
|
||||
}
|
||||
|
@ -2722,7 +2722,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
num_trbs = count_sg_trbs_needed(xhci, urb);
|
||||
num_sgs = urb->num_sgs;
|
||||
total_packet_count = roundup(urb->transfer_buffer_length,
|
||||
le16_to_cpu(urb->ep->desc.wMaxPacketSize));
|
||||
usb_endpoint_maxp(&urb->ep->desc));
|
||||
|
||||
trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id],
|
||||
ep_index, urb->stream_id,
|
||||
|
@ -2929,7 +2929,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
|
||||
running_total = 0;
|
||||
total_packet_count = roundup(urb->transfer_buffer_length,
|
||||
le16_to_cpu(urb->ep->desc.wMaxPacketSize));
|
||||
usb_endpoint_maxp(&urb->ep->desc));
|
||||
/* How much data is in the first TRB? */
|
||||
addr = (u64) urb->transfer_dma;
|
||||
trb_buff_len = TRB_MAX_BUFF_SIZE -
|
||||
|
@ -3250,7 +3250,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
td_len = urb->iso_frame_desc[i].length;
|
||||
td_remain_len = td_len;
|
||||
total_packet_count = roundup(td_len,
|
||||
le16_to_cpu(urb->ep->desc.wMaxPacketSize));
|
||||
usb_endpoint_maxp(&urb->ep->desc));
|
||||
/* A zero-length transfer still involves at least one packet. */
|
||||
if (total_packet_count == 0)
|
||||
total_packet_count++;
|
||||
|
|
|
@ -987,7 +987,7 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
|
|||
out_ctx = xhci->devs[slot_id]->out_ctx;
|
||||
ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
|
||||
hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
|
||||
max_packet_size = le16_to_cpu(urb->dev->ep0.desc.wMaxPacketSize);
|
||||
max_packet_size = usb_endpoint_maxp(&urb->dev->ep0.desc);
|
||||
if (hw_max_packet_size != max_packet_size) {
|
||||
xhci_dbg(xhci, "Max Packet Size for ep 0 changed.\n");
|
||||
xhci_dbg(xhci, "Max packet size in usb_device = %d\n",
|
||||
|
|
|
@ -213,7 +213,7 @@ static void adu_interrupt_in_callback(struct urb *urb)
|
|||
|
||||
if (urb->actual_length > 0 && dev->interrupt_in_buffer[0] != 0x00) {
|
||||
if (dev->read_buffer_length <
|
||||
(4 * le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize)) -
|
||||
(4 * usb_endpoint_maxp(dev->interrupt_in_endpoint)) -
|
||||
(urb->actual_length)) {
|
||||
memcpy (dev->read_buffer_primary +
|
||||
dev->read_buffer_length,
|
||||
|
@ -315,7 +315,7 @@ static int adu_open(struct inode *inode, struct file *file)
|
|||
usb_rcvintpipe(dev->udev,
|
||||
dev->interrupt_in_endpoint->bEndpointAddress),
|
||||
dev->interrupt_in_buffer,
|
||||
le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
|
||||
usb_endpoint_maxp(dev->interrupt_in_endpoint),
|
||||
adu_interrupt_in_callback, dev,
|
||||
dev->interrupt_in_endpoint->bInterval);
|
||||
dev->read_urb_finished = 0;
|
||||
|
@ -483,7 +483,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
|
|||
usb_rcvintpipe(dev->udev,
|
||||
dev->interrupt_in_endpoint->bEndpointAddress),
|
||||
dev->interrupt_in_buffer,
|
||||
le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
|
||||
usb_endpoint_maxp(dev->interrupt_in_endpoint),
|
||||
adu_interrupt_in_callback,
|
||||
dev,
|
||||
dev->interrupt_in_endpoint->bInterval);
|
||||
|
@ -536,7 +536,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
|
|||
usb_rcvintpipe(dev->udev,
|
||||
dev->interrupt_in_endpoint->bEndpointAddress),
|
||||
dev->interrupt_in_buffer,
|
||||
le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
|
||||
usb_endpoint_maxp(dev->interrupt_in_endpoint),
|
||||
adu_interrupt_in_callback,
|
||||
dev,
|
||||
dev->interrupt_in_endpoint->bInterval);
|
||||
|
@ -622,7 +622,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
|
|||
dbg(4," %s : sending, count = %Zd", __func__, count);
|
||||
|
||||
/* write the data into interrupt_out_buffer from userspace */
|
||||
buffer_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);
|
||||
buffer_size = usb_endpoint_maxp(dev->interrupt_out_endpoint);
|
||||
bytes_to_write = count > buffer_size ? buffer_size : count;
|
||||
dbg(4," %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd",
|
||||
__func__, buffer_size, count, bytes_to_write);
|
||||
|
@ -752,8 +752,8 @@ static int adu_probe(struct usb_interface *interface,
|
|||
goto error;
|
||||
}
|
||||
|
||||
in_end_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
|
||||
out_end_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);
|
||||
in_end_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
|
||||
out_end_size = usb_endpoint_maxp(dev->interrupt_out_endpoint);
|
||||
|
||||
dev->read_buffer_primary = kmalloc((4 * in_end_size), GFP_KERNEL);
|
||||
if (!dev->read_buffer_primary) {
|
||||
|
|
|
@ -2777,7 +2777,7 @@ static int ftdi_elan_probe(struct usb_interface *interface,
|
|||
endpoint = &iface_desc->endpoint[i].desc;
|
||||
if (!ftdi->bulk_in_endpointAddr &&
|
||||
usb_endpoint_is_bulk_in(endpoint)) {
|
||||
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
|
||||
buffer_size = usb_endpoint_maxp(endpoint);
|
||||
ftdi->bulk_in_size = buffer_size;
|
||||
ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress;
|
||||
ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
|
||||
|
|
|
@ -359,7 +359,7 @@ static int idmouse_probe(struct usb_interface *interface,
|
|||
endpoint = &iface_desc->endpoint[0].desc;
|
||||
if (!dev->bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) {
|
||||
/* we found a bulk in endpoint */
|
||||
dev->orig_bi_size = le16_to_cpu(endpoint->wMaxPacketSize);
|
||||
dev->orig_bi_size = usb_endpoint_maxp(endpoint);
|
||||
dev->bulk_in_size = 0x200; /* works _much_ faster */
|
||||
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
|
||||
dev->bulk_in_buffer =
|
||||
|
|
|
@ -803,7 +803,7 @@ static int iowarrior_probe(struct usb_interface *interface,
|
|||
dev->int_out_endpoint = endpoint;
|
||||
}
|
||||
/* we have to check the report_size often, so remember it in the endianess suitable for our machine */
|
||||
dev->report_size = le16_to_cpu(dev->int_in_endpoint->wMaxPacketSize);
|
||||
dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint);
|
||||
if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) &&
|
||||
(dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56))
|
||||
/* IOWarrior56 has wMaxPacketSize different from report size */
|
||||
|
|
|
@ -721,7 +721,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
|
|||
if (dev->interrupt_out_endpoint == NULL)
|
||||
dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");
|
||||
|
||||
dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
|
||||
dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
|
||||
dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL);
|
||||
if (!dev->ring_buffer) {
|
||||
dev_err(&intf->dev, "Couldn't allocate ring_buffer\n");
|
||||
|
@ -737,7 +737,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
|
|||
dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n");
|
||||
goto error;
|
||||
}
|
||||
dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) :
|
||||
dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? usb_endpoint_maxp(dev->interrupt_out_endpoint) :
|
||||
udev->descriptor.bMaxPacketSize0;
|
||||
dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL);
|
||||
if (!dev->interrupt_out_buffer) {
|
||||
|
|
|
@ -409,7 +409,7 @@ static int tower_open (struct inode *inode, struct file *file)
|
|||
dev->udev,
|
||||
usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAddress),
|
||||
dev->interrupt_in_buffer,
|
||||
le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
|
||||
usb_endpoint_maxp(dev->interrupt_in_endpoint),
|
||||
tower_interrupt_in_callback,
|
||||
dev,
|
||||
dev->interrupt_in_interval);
|
||||
|
@ -928,7 +928,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
|
|||
err("Couldn't allocate read_buffer");
|
||||
goto error;
|
||||
}
|
||||
dev->interrupt_in_buffer = kmalloc (le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize), GFP_KERNEL);
|
||||
dev->interrupt_in_buffer = kmalloc (usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL);
|
||||
if (!dev->interrupt_in_buffer) {
|
||||
err("Couldn't allocate interrupt_in_buffer");
|
||||
goto error;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#define DRIVER_VERSION "USBLCD Driver Version 1.05"
|
||||
|
@ -34,22 +34,29 @@ static const struct usb_device_id id_table[] = {
|
|||
{ .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, id_table);
|
||||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
|
||||
static DEFINE_MUTEX(open_disc_mutex);
|
||||
|
||||
|
||||
struct usb_lcd {
|
||||
struct usb_device * udev; /* init: probe_lcd */
|
||||
struct usb_interface * interface; /* the interface for this device */
|
||||
unsigned char * bulk_in_buffer; /* the buffer to receive data */
|
||||
size_t bulk_in_size; /* the size of the receive buffer */
|
||||
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
|
||||
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
|
||||
struct usb_device *udev; /* init: probe_lcd */
|
||||
struct usb_interface *interface; /* the interface for
|
||||
this device */
|
||||
unsigned char *bulk_in_buffer; /* the buffer to receive
|
||||
data */
|
||||
size_t bulk_in_size; /* the size of the
|
||||
receive buffer */
|
||||
__u8 bulk_in_endpointAddr; /* the address of the
|
||||
bulk in endpoint */
|
||||
__u8 bulk_out_endpointAddr; /* the address of the
|
||||
bulk out endpoint */
|
||||
struct kref kref;
|
||||
struct semaphore limit_sem; /* to stop writes at full throttle from
|
||||
* using up all RAM */
|
||||
struct usb_anchor submitted; /* URBs to wait for before suspend */
|
||||
struct semaphore limit_sem; /* to stop writes at
|
||||
full throttle from
|
||||
using up all RAM */
|
||||
struct usb_anchor submitted; /* URBs to wait for
|
||||
before suspend */
|
||||
};
|
||||
#define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
|
||||
|
||||
|
@ -63,8 +70,8 @@ static void lcd_delete(struct kref *kref)
|
|||
struct usb_lcd *dev = to_lcd_dev(kref);
|
||||
|
||||
usb_put_dev(dev->udev);
|
||||
kfree (dev->bulk_in_buffer);
|
||||
kfree (dev);
|
||||
kfree(dev->bulk_in_buffer);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
|
||||
|
@ -80,7 +87,7 @@ static int lcd_open(struct inode *inode, struct file *file)
|
|||
interface = usb_find_interface(&lcd_driver, subminor);
|
||||
if (!interface) {
|
||||
mutex_unlock(&lcd_mutex);
|
||||
err ("USBLCD: %s - error, can't find device for minor %d",
|
||||
err("USBLCD: %s - error, can't find device for minor %d",
|
||||
__func__, subminor);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -126,7 +133,8 @@ static int lcd_release(struct inode *inode, struct file *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t lcd_read(struct file *file, char __user * buffer, size_t count, loff_t *ppos)
|
||||
static ssize_t lcd_read(struct file *file, char __user * buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct usb_lcd *dev;
|
||||
int retval = 0;
|
||||
|
@ -136,7 +144,8 @@ static ssize_t lcd_read(struct file *file, char __user * buffer, size_t count, l
|
|||
|
||||
/* do a blocking bulk read to get data from the device */
|
||||
retval = usb_bulk_msg(dev->udev,
|
||||
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
|
||||
usb_rcvbulkpipe(dev->udev,
|
||||
dev->bulk_in_endpointAddr),
|
||||
dev->bulk_in_buffer,
|
||||
min(dev->bulk_in_size, count),
|
||||
&bytes_read, 10000);
|
||||
|
@ -166,18 +175,18 @@ static long lcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
case IOCTL_GET_HARD_VERSION:
|
||||
mutex_lock(&lcd_mutex);
|
||||
bcdDevice = le16_to_cpu((dev->udev)->descriptor.bcdDevice);
|
||||
sprintf(buf,"%1d%1d.%1d%1d",
|
||||
sprintf(buf, "%1d%1d.%1d%1d",
|
||||
(bcdDevice & 0xF000)>>12,
|
||||
(bcdDevice & 0xF00)>>8,
|
||||
(bcdDevice & 0xF0)>>4,
|
||||
(bcdDevice & 0xF));
|
||||
mutex_unlock(&lcd_mutex);
|
||||
if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0)
|
||||
if (copy_to_user((void __user *)arg, buf, strlen(buf)) != 0)
|
||||
return -EFAULT;
|
||||
break;
|
||||
case IOCTL_GET_DRV_VERSION:
|
||||
sprintf(buf,DRIVER_VERSION);
|
||||
if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0)
|
||||
sprintf(buf, DRIVER_VERSION);
|
||||
if (copy_to_user((void __user *)arg, buf, strlen(buf)) != 0)
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
|
@ -199,7 +208,7 @@ static void lcd_write_bulk_callback(struct urb *urb)
|
|||
if (status &&
|
||||
!(status == -ENOENT ||
|
||||
status == -ECONNRESET ||
|
||||
status == -ESHUTDOWN)) {
|
||||
status == -ESHUTDOWN)) {
|
||||
dbg("USBLCD: %s - nonzero write bulk status received: %d",
|
||||
__func__, status);
|
||||
}
|
||||
|
@ -210,10 +219,11 @@ static void lcd_write_bulk_callback(struct urb *urb)
|
|||
up(&dev->limit_sem);
|
||||
}
|
||||
|
||||
static ssize_t lcd_write(struct file *file, const char __user * user_buffer, size_t count, loff_t *ppos)
|
||||
static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct usb_lcd *dev;
|
||||
int retval = 0, r;
|
||||
int retval = 0, r;
|
||||
struct urb *urb = NULL;
|
||||
char *buf = NULL;
|
||||
|
||||
|
@ -234,7 +244,8 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
|
|||
goto err_no_buf;
|
||||
}
|
||||
|
||||
buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
|
||||
buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL,
|
||||
&urb->transfer_dma);
|
||||
if (!buf) {
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
|
@ -247,7 +258,8 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
|
|||
|
||||
/* initialize the urb properly */
|
||||
usb_fill_bulk_urb(urb, dev->udev,
|
||||
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
|
||||
usb_sndbulkpipe(dev->udev,
|
||||
dev->bulk_out_endpointAddr),
|
||||
buf, count, lcd_write_bulk_callback, dev);
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
|
@ -256,11 +268,13 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
|
|||
/* send the data out the bulk port */
|
||||
retval = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (retval) {
|
||||
err("USBLCD: %s - failed submitting write urb, error %d", __func__, retval);
|
||||
err("USBLCD: %s - failed submitting write urb, error %d",
|
||||
__func__, retval);
|
||||
goto error_unanchor;
|
||||
}
|
||||
|
||||
/* release our reference to this urb, the USB core will eventually free it entirely */
|
||||
/* release our reference to this urb,
|
||||
the USB core will eventually free it entirely */
|
||||
usb_free_urb(urb);
|
||||
|
||||
exit:
|
||||
|
@ -276,13 +290,13 @@ err_no_buf:
|
|||
}
|
||||
|
||||
static const struct file_operations lcd_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = lcd_read,
|
||||
.write = lcd_write,
|
||||
.open = lcd_open,
|
||||
.owner = THIS_MODULE,
|
||||
.read = lcd_read,
|
||||
.write = lcd_write,
|
||||
.open = lcd_open,
|
||||
.unlocked_ioctl = lcd_ioctl,
|
||||
.release = lcd_release,
|
||||
.llseek = noop_llseek,
|
||||
.release = lcd_release,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -290,12 +304,13 @@ static const struct file_operations lcd_fops = {
|
|||
* and to have the device registered with the driver core
|
||||
*/
|
||||
static struct usb_class_driver lcd_class = {
|
||||
.name = "lcd%d",
|
||||
.fops = &lcd_fops,
|
||||
.minor_base = USBLCD_MINOR,
|
||||
.name = "lcd%d",
|
||||
.fops = &lcd_fops,
|
||||
.minor_base = USBLCD_MINOR,
|
||||
};
|
||||
|
||||
static int lcd_probe(struct usb_interface *interface, const struct usb_device_id *id)
|
||||
static int lcd_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_lcd *dev = NULL;
|
||||
struct usb_host_interface *iface_desc;
|
||||
|
@ -332,7 +347,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
|
|||
if (!dev->bulk_in_endpointAddr &&
|
||||
usb_endpoint_is_bulk_in(endpoint)) {
|
||||
/* we found a bulk in endpoint */
|
||||
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
|
||||
buffer_size = usb_endpoint_maxp(endpoint);
|
||||
dev->bulk_in_size = buffer_size;
|
||||
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
|
||||
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
|
||||
|
@ -369,7 +384,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
|
|||
|
||||
dev_info(&interface->dev, "USBLCD Version %1d%1d.%1d%1d found "
|
||||
"at address %d\n", (i & 0xF000)>>12, (i & 0xF00)>>8,
|
||||
(i & 0xF0)>>4,(i & 0xF), dev->udev->devnum);
|
||||
(i & 0xF0)>>4, (i & 0xF), dev->udev->devnum);
|
||||
|
||||
/* let the user know what node this device is now attached to */
|
||||
dev_info(&interface->dev, "USB LCD device now attached to USBLCD-%d\n",
|
||||
|
@ -401,7 +416,7 @@ static int lcd_suspend(struct usb_interface *intf, pm_message_t message)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lcd_resume (struct usb_interface *intf)
|
||||
static int lcd_resume(struct usb_interface *intf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -409,15 +424,15 @@ static int lcd_resume (struct usb_interface *intf)
|
|||
static void lcd_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_lcd *dev;
|
||||
int minor = interface->minor;
|
||||
int minor = interface->minor;
|
||||
|
||||
mutex_lock(&open_disc_mutex);
|
||||
dev = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
dev = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
mutex_unlock(&open_disc_mutex);
|
||||
|
||||
/* give back our minor */
|
||||
usb_deregister_dev(interface, &lcd_class);
|
||||
/* give back our minor */
|
||||
usb_deregister_dev(interface, &lcd_class);
|
||||
|
||||
/* decrement our usage count */
|
||||
kref_put(&dev->kref, lcd_delete);
|
||||
|
|
|
@ -33,10 +33,10 @@ static const struct usb_device_id id_table[] = {
|
|||
.driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, id_table);
|
||||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
|
||||
struct usb_led {
|
||||
struct usb_device * udev;
|
||||
struct usb_device *udev;
|
||||
unsigned char blue;
|
||||
unsigned char red;
|
||||
unsigned char green;
|
||||
|
@ -113,14 +113,16 @@ static void change_color(struct usb_led *led)
|
|||
}
|
||||
|
||||
#define show_set(value) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr,\
|
||||
char *buf) \
|
||||
{ \
|
||||
struct usb_interface *intf = to_usb_interface(dev); \
|
||||
struct usb_led *led = usb_get_intfdata(intf); \
|
||||
\
|
||||
return sprintf(buf, "%d\n", led->value); \
|
||||
} \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr,\
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct usb_interface *intf = to_usb_interface(dev); \
|
||||
struct usb_led *led = usb_get_intfdata(intf); \
|
||||
|
@ -135,7 +137,8 @@ show_set(blue);
|
|||
show_set(red);
|
||||
show_set(green);
|
||||
|
||||
static int led_probe(struct usb_interface *interface, const struct usb_device_id *id)
|
||||
static int led_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(interface);
|
||||
struct usb_led *dev = NULL;
|
||||
|
@ -150,7 +153,7 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id
|
|||
dev->udev = usb_get_dev(udev);
|
||||
dev->type = id->driver_info;
|
||||
|
||||
usb_set_intfdata (interface, dev);
|
||||
usb_set_intfdata(interface, dev);
|
||||
|
||||
retval = device_create_file(&interface->dev, &dev_attr_blue);
|
||||
if (retval)
|
||||
|
@ -194,7 +197,7 @@ error:
|
|||
device_remove_file(&interface->dev, &dev_attr_blue);
|
||||
device_remove_file(&interface->dev, &dev_attr_red);
|
||||
device_remove_file(&interface->dev, &dev_attr_green);
|
||||
usb_set_intfdata (interface, NULL);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
usb_put_dev(dev->udev);
|
||||
kfree(dev);
|
||||
error_mem:
|
||||
|
@ -205,14 +208,14 @@ static void led_disconnect(struct usb_interface *interface)
|
|||
{
|
||||
struct usb_led *dev;
|
||||
|
||||
dev = usb_get_intfdata (interface);
|
||||
dev = usb_get_intfdata(interface);
|
||||
|
||||
device_remove_file(&interface->dev, &dev_attr_blue);
|
||||
device_remove_file(&interface->dev, &dev_attr_red);
|
||||
device_remove_file(&interface->dev, &dev_attr_green);
|
||||
|
||||
/* first remove the files, then set the pointer to NULL */
|
||||
usb_set_intfdata (interface, NULL);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
usb_put_dev(dev->udev);
|
||||
|
||||
|
@ -243,8 +246,8 @@ static void __exit usb_led_exit(void)
|
|||
usb_deregister(&led_driver);
|
||||
}
|
||||
|
||||
module_init (usb_led_init);
|
||||
module_exit (usb_led_exit);
|
||||
module_init(usb_led_init);
|
||||
module_exit(usb_led_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
|
|
|
@ -359,8 +359,10 @@ static int simple_io(
|
|||
urb->context = &completion;
|
||||
while (retval == 0 && iterations-- > 0) {
|
||||
init_completion(&completion);
|
||||
if (usb_pipeout(urb->pipe))
|
||||
if (usb_pipeout(urb->pipe)) {
|
||||
simple_fill_buf(urb);
|
||||
urb->transfer_flags |= URB_ZERO_PACKET;
|
||||
}
|
||||
retval = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (retval != 0)
|
||||
break;
|
||||
|
@ -1583,8 +1585,8 @@ static struct urb *iso_alloc_urb(
|
|||
|
||||
if (bytes < 0 || !desc)
|
||||
return NULL;
|
||||
maxp = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
|
||||
maxp *= 1 + (0x3 & (le16_to_cpu(desc->wMaxPacketSize) >> 11));
|
||||
maxp = 0x7ff & usb_endpoint_maxp(desc);
|
||||
maxp *= 1 + (0x3 & (usb_endpoint_maxp(desc) >> 11));
|
||||
packets = DIV_ROUND_UP(bytes, maxp);
|
||||
|
||||
urb = usb_alloc_urb(packets, GFP_KERNEL);
|
||||
|
@ -1654,7 +1656,7 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,
|
|||
"... iso period %d %sframes, wMaxPacket %04x\n",
|
||||
1 << (desc->bInterval - 1),
|
||||
(udev->speed == USB_SPEED_HIGH) ? "micro" : "",
|
||||
le16_to_cpu(desc->wMaxPacketSize));
|
||||
usb_endpoint_maxp(desc));
|
||||
|
||||
for (i = 0; i < param->sglen; i++) {
|
||||
urbs[i] = iso_alloc_urb(udev, pipe, desc,
|
||||
|
|
|
@ -1020,7 +1020,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
|
|||
goto fail;
|
||||
|
||||
/* REVISIT this rules out high bandwidth periodic transfers */
|
||||
tmp = le16_to_cpu(desc->wMaxPacketSize);
|
||||
tmp = usb_endpoint_maxp(desc);
|
||||
if (tmp & ~0x07ff) {
|
||||
int ok;
|
||||
|
||||
|
|
|
@ -1932,7 +1932,7 @@ static int musb_urb_enqueue(
|
|||
INIT_LIST_HEAD(&qh->ring);
|
||||
qh->is_ready = 1;
|
||||
|
||||
qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize);
|
||||
qh->maxpacket = usb_endpoint_maxp(epd);
|
||||
qh->type = usb_endpoint_type(epd);
|
||||
|
||||
/* Bits 11 & 12 of wMaxPacketSize encode high bandwidth multiplier.
|
||||
|
|
|
@ -137,22 +137,6 @@ static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int twl6030_set_phy_clk(struct otg_transceiver *x, int on)
|
||||
{
|
||||
struct twl6030_usb *twl;
|
||||
struct device *dev;
|
||||
struct twl4030_usb_data *pdata;
|
||||
|
||||
twl = xceiv_to_twl(x);
|
||||
dev = twl->dev;
|
||||
pdata = dev->platform_data;
|
||||
|
||||
pdata->phy_set_clock(twl->dev, on);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int twl6030_phy_init(struct otg_transceiver *x)
|
||||
{
|
||||
struct twl6030_usb *twl;
|
||||
|
|
|
@ -392,7 +392,7 @@ static u16 usbhsp_setup_pipemaxp(struct usbhs_pipe *pipe,
|
|||
/* host should set DEVSEL */
|
||||
|
||||
/* reutn MXPS */
|
||||
return PIPE_MAXP_MASK & le16_to_cpu(desc->wMaxPacketSize);
|
||||
return PIPE_MAXP_MASK & usb_endpoint_maxp(desc);
|
||||
}
|
||||
|
||||
static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe,
|
||||
|
|
|
@ -252,6 +252,7 @@ config USB_SERIAL_GARMIN
|
|||
|
||||
config USB_SERIAL_IPW
|
||||
tristate "USB IPWireless (3G UMTS TDD) Driver"
|
||||
select USB_SERIAL_WWAN
|
||||
help
|
||||
Say Y here if you want to use a IPWireless USB modem such as
|
||||
the ones supplied by Axity3G/Sentech South Africa.
|
||||
|
|
|
@ -1486,7 +1486,7 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port)
|
|||
}
|
||||
|
||||
/* set max packet size based on descriptor */
|
||||
priv->max_packet_size = le16_to_cpu(ep_desc->wMaxPacketSize);
|
||||
priv->max_packet_size = usb_endpoint_maxp(ep_desc);
|
||||
|
||||
dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
|
||||
}
|
||||
|
|
|
@ -3042,7 +3042,7 @@ static int edge_startup(struct usb_serial *serial)
|
|||
|
||||
endpoint = &serial->interface->altsetting[0].
|
||||
endpoint[i].desc;
|
||||
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
|
||||
buffer_size = usb_endpoint_maxp(endpoint);
|
||||
if (!interrupt_in_found &&
|
||||
(usb_endpoint_is_int_in(endpoint))) {
|
||||
/* we found a interrupt in endpoint */
|
||||
|
@ -3107,7 +3107,7 @@ static int edge_startup(struct usb_serial *serial)
|
|||
usb_rcvbulkpipe(dev,
|
||||
endpoint->bEndpointAddress),
|
||||
edge_serial->bulk_in_buffer,
|
||||
le16_to_cpu(endpoint->wMaxPacketSize),
|
||||
usb_endpoint_maxp(endpoint),
|
||||
edge_bulk_in_callback,
|
||||
edge_serial);
|
||||
bulk_in_found = true;
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include <linux/usb.h>
|
||||
#include <linux/usb/serial.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include "usb-wwan.h"
|
||||
|
||||
/*
|
||||
* Version Information
|
||||
|
@ -185,7 +186,7 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|||
|
||||
/*--2: Start reading from the device */
|
||||
dbg("%s: setting up bulk read callback", __func__);
|
||||
usb_serial_generic_open(tty, port);
|
||||
usb_wwan_open(tty, port);
|
||||
|
||||
/*--3: Tell the modem to open the floodgates on the rx bulk channel */
|
||||
dbg("%s:asking modem for RxRead (RXBULK_ON)", __func__);
|
||||
|
@ -219,6 +220,29 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* fake probe - only to allocate data structures */
|
||||
static int ipw_probe(struct usb_serial *serial, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_wwan_intf_private *data;
|
||||
|
||||
data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&data->susp_lock);
|
||||
usb_set_serial_data(serial, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipw_release(struct usb_serial *serial)
|
||||
{
|
||||
struct usb_wwan_intf_private *data = usb_get_serial_data(serial);
|
||||
|
||||
usb_wwan_release(serial);
|
||||
usb_set_serial_data(serial, NULL);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static void ipw_dtr_rts(struct usb_serial_port *port, int on)
|
||||
{
|
||||
struct usb_device *dev = port->serial->dev;
|
||||
|
@ -285,7 +309,7 @@ static void ipw_close(struct usb_serial_port *port)
|
|||
dev_err(&port->dev,
|
||||
"Disabling bulk RxRead failed (error = %d)\n", result);
|
||||
|
||||
usb_serial_generic_close(port);
|
||||
usb_wwan_close(port);
|
||||
}
|
||||
|
||||
static struct usb_serial_driver ipw_device = {
|
||||
|
@ -297,9 +321,14 @@ static struct usb_serial_driver ipw_device = {
|
|||
.usb_driver = &usb_ipw_driver,
|
||||
.id_table = usb_ipw_ids,
|
||||
.num_ports = 1,
|
||||
.disconnect = usb_wwan_disconnect,
|
||||
.open = ipw_open,
|
||||
.close = ipw_close,
|
||||
.probe = ipw_probe,
|
||||
.attach = usb_wwan_startup,
|
||||
.release = ipw_release,
|
||||
.dtr_rts = ipw_dtr_rts,
|
||||
.write = usb_wwan_write,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -523,7 +523,7 @@ static int opticon_startup(struct usb_serial *serial)
|
|||
goto error;
|
||||
}
|
||||
|
||||
priv->buffer_size = le16_to_cpu(endpoint->wMaxPacketSize) * 2;
|
||||
priv->buffer_size = usb_endpoint_maxp(endpoint) * 2;
|
||||
priv->bulk_in_buffer = kmalloc(priv->buffer_size, GFP_KERNEL);
|
||||
if (!priv->bulk_in_buffer) {
|
||||
dev_err(&priv->udev->dev, "out of memory\n");
|
||||
|
|
|
@ -360,9 +360,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
|
|||
tmp >>= 2;
|
||||
buf[1] <<= 1;
|
||||
}
|
||||
if (tmp > 256) {
|
||||
tmp %= 256;
|
||||
}
|
||||
buf[0] = tmp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -226,7 +226,7 @@ static int symbol_startup(struct usb_serial *serial)
|
|||
goto error;
|
||||
}
|
||||
|
||||
priv->buffer_size = le16_to_cpu(endpoint->wMaxPacketSize) * 2;
|
||||
priv->buffer_size = usb_endpoint_maxp(endpoint) * 2;
|
||||
priv->int_buffer = kmalloc(priv->buffer_size, GFP_KERNEL);
|
||||
if (!priv->int_buffer) {
|
||||
dev_err(&priv->udev->dev, "out of memory\n");
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче