mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
USB patches for 3.20-rc1
Here's the big pull request for the USB driver tree for 3.20-rc1. Nothing major happening here, just lots of gadget driver updates, new device ids, and a bunch of cleanups. All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <[email protected]> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlTgtrcACgkQMUfUDdst+yn0tACgygJPNvu1l3ukNJCCpWuOErIj 3KsAnjiEXv90DLYJiVLJ4EbLPw0V9wAv =DrJx -----END PGP SIGNATURE----- Merge tag 'usb-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB patches from Greg KH: "Here's the big pull request for the USB driver tree for 3.20-rc1. Nothing major happening here, just lots of gadget driver updates, new device ids, and a bunch of cleanups. All of these have been in linux-next for a while with no reported issues" * tag 'usb-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (299 commits) usb: musb: fix device hotplug behind hub usb: dwc2: Fix a bug in reading the endpoint directions from reg. staging: emxx_udc: fix the build error usb: Retry port status check on resume to work around RH bugs Revert "usb: Reset USB-3 devices on USB-3 link bounce" uhci-hub: use HUB_CHAR_* usb: kconfig: replace PPC_OF with PPC ehci-pci: disable for Intel MID platforms (update) usb: gadget: Kconfig: use bool instead of boolean usb: musb: blackfin: remove incorrect __exit_p() USB: fix use-after-free bug in usb_hcd_unlink_urb() ehci-pci: disable for Intel MID platforms usb: host: pci_quirks: joing string literals USB: add flag for HCDs that can't receive wakeup requests (isp1760-hcd) USB: usbfs: allow URBs to be reaped after disconnection cdc-acm: kill unnecessary messages cdc-acm: add sanity checks usb: phy: phy-generic: Fix USB PHY gpio reset usb: dwc2: fix USB core dependencies usb: renesas_usbhs: fix NULL pointer dereference in dma_release_channel() ...
This commit is contained in:
commit
e29876723f
184 changed files with 9309 additions and 3050 deletions
|
|
@ -104,6 +104,8 @@ source "drivers/usb/dwc2/Kconfig"
|
|||
|
||||
source "drivers/usb/chipidea/Kconfig"
|
||||
|
||||
source "drivers/usb/isp1760/Kconfig"
|
||||
|
||||
comment "USB port drivers"
|
||||
|
||||
if USB
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ obj-$(CONFIG_USB) += core/
|
|||
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3/
|
||||
obj-$(CONFIG_USB_DWC2) += dwc2/
|
||||
obj-$(CONFIG_USB_ISP1760) += isp1760/
|
||||
|
||||
obj-$(CONFIG_USB_MON) += mon/
|
||||
|
||||
|
|
@ -23,7 +24,6 @@ obj-$(CONFIG_USB_ISP1362_HCD) += host/
|
|||
obj-$(CONFIG_USB_U132_HCD) += host/
|
||||
obj-$(CONFIG_USB_R8A66597_HCD) += host/
|
||||
obj-$(CONFIG_USB_HWA_HCD) += host/
|
||||
obj-$(CONFIG_USB_ISP1760_HCD) += host/
|
||||
obj-$(CONFIG_USB_IMX21_HCD) += host/
|
||||
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
|
||||
obj-$(CONFIG_USB_FUSBH200_HCD) += host/
|
||||
|
|
|
|||
|
|
@ -111,6 +111,9 @@ static void ci_hdrc_pci_remove(struct pci_dev *pdev)
|
|||
* PCI device structure
|
||||
*
|
||||
* Check "pci.h" for details
|
||||
*
|
||||
* Note: ehci-pci driver may try to probe the device first. You have to add an
|
||||
* ID to the bypass_pci_id_table in ehci-pci driver to prevent this.
|
||||
*/
|
||||
static const struct pci_device_id ci_hdrc_pci_id_table[] = {
|
||||
{
|
||||
|
|
|
|||
|
|
@ -819,8 +819,8 @@ __acquires(hwep->lock)
|
|||
}
|
||||
|
||||
if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
|
||||
/* Assume that device is bus powered for now. */
|
||||
*(u16 *)req->buf = ci->remote_wakeup << 1;
|
||||
*(u16 *)req->buf = (ci->remote_wakeup << 1) |
|
||||
ci->gadget.is_selfpowered;
|
||||
} else if ((setup->bRequestType & USB_RECIP_MASK) \
|
||||
== USB_RECIP_ENDPOINT) {
|
||||
dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
|
||||
|
|
@ -1520,6 +1520,19 @@ static int ci_udc_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int ci_udc_selfpowered(struct usb_gadget *_gadget, int is_on)
|
||||
{
|
||||
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
|
||||
struct ci_hw_ep *hwep = ci->ep0in;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(hwep->lock, flags);
|
||||
_gadget->is_selfpowered = (is_on != 0);
|
||||
spin_unlock_irqrestore(hwep->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Change Data+ pullup status
|
||||
* this func is used by usb_gadget_connect/disconnet
|
||||
*/
|
||||
|
|
@ -1549,6 +1562,7 @@ static int ci_udc_stop(struct usb_gadget *gadget);
|
|||
static const struct usb_gadget_ops usb_gadget_ops = {
|
||||
.vbus_session = ci_udc_vbus_session,
|
||||
.wakeup = ci_udc_wakeup,
|
||||
.set_selfpowered = ci_udc_selfpowered,
|
||||
.pullup = ci_udc_pullup,
|
||||
.vbus_draw = ci_udc_vbus_draw,
|
||||
.udc_start = ci_udc_start,
|
||||
|
|
|
|||
|
|
@ -1091,6 +1091,7 @@ static int acm_probe(struct usb_interface *intf,
|
|||
unsigned long quirks;
|
||||
int num_rx_buf;
|
||||
int i;
|
||||
unsigned int elength = 0;
|
||||
int combined_interfaces = 0;
|
||||
struct device *tty_dev;
|
||||
int rv = -ENOMEM;
|
||||
|
|
@ -1136,9 +1137,12 @@ static int acm_probe(struct usb_interface *intf,
|
|||
dev_err(&intf->dev, "skipping garbage\n");
|
||||
goto next_desc;
|
||||
}
|
||||
elength = buffer[0];
|
||||
|
||||
switch (buffer[2]) {
|
||||
case USB_CDC_UNION_TYPE: /* we've found it */
|
||||
if (elength < sizeof(struct usb_cdc_union_desc))
|
||||
goto next_desc;
|
||||
if (union_header) {
|
||||
dev_err(&intf->dev, "More than one "
|
||||
"union descriptor, skipping ...\n");
|
||||
|
|
@ -1147,29 +1151,36 @@ static int acm_probe(struct usb_interface *intf,
|
|||
union_header = (struct usb_cdc_union_desc *)buffer;
|
||||
break;
|
||||
case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
|
||||
if (elength < sizeof(struct usb_cdc_country_functional_desc))
|
||||
goto next_desc;
|
||||
cfd = (struct usb_cdc_country_functional_desc *)buffer;
|
||||
break;
|
||||
case USB_CDC_HEADER_TYPE: /* maybe check version */
|
||||
break; /* for now we ignore it */
|
||||
case USB_CDC_ACM_TYPE:
|
||||
if (elength < 4)
|
||||
goto next_desc;
|
||||
ac_management_function = buffer[3];
|
||||
break;
|
||||
case USB_CDC_CALL_MANAGEMENT_TYPE:
|
||||
if (elength < 5)
|
||||
goto next_desc;
|
||||
call_management_function = buffer[3];
|
||||
call_interface_num = buffer[4];
|
||||
break;
|
||||
default:
|
||||
/* there are LOTS more CDC descriptors that
|
||||
/*
|
||||
* there are LOTS more CDC descriptors that
|
||||
* could legitimately be found here.
|
||||
*/
|
||||
dev_dbg(&intf->dev, "Ignoring descriptor: "
|
||||
"type %02x, length %d\n",
|
||||
buffer[2], buffer[0]);
|
||||
"type %02x, length %ud\n",
|
||||
buffer[2], elength);
|
||||
break;
|
||||
}
|
||||
next_desc:
|
||||
buflen -= buffer[0];
|
||||
buffer += buffer[0];
|
||||
buflen -= elength;
|
||||
buffer += elength;
|
||||
}
|
||||
|
||||
if (!union_header) {
|
||||
|
|
@ -1287,10 +1298,8 @@ made_compressed_probe:
|
|||
dev_dbg(&intf->dev, "interfaces are valid\n");
|
||||
|
||||
acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
|
||||
if (acm == NULL) {
|
||||
dev_err(&intf->dev, "out of memory (acm kzalloc)\n");
|
||||
if (acm == NULL)
|
||||
goto alloc_fail;
|
||||
}
|
||||
|
||||
minor = acm_alloc_minor(acm);
|
||||
if (minor == ACM_TTY_MINORS) {
|
||||
|
|
@ -1329,42 +1338,32 @@ made_compressed_probe:
|
|||
acm->quirks = quirks;
|
||||
|
||||
buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
|
||||
if (!buf) {
|
||||
dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n");
|
||||
if (!buf)
|
||||
goto alloc_fail2;
|
||||
}
|
||||
acm->ctrl_buffer = buf;
|
||||
|
||||
if (acm_write_buffers_alloc(acm) < 0) {
|
||||
dev_err(&intf->dev, "out of memory (write buffer alloc)\n");
|
||||
if (acm_write_buffers_alloc(acm) < 0)
|
||||
goto alloc_fail4;
|
||||
}
|
||||
|
||||
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!acm->ctrlurb) {
|
||||
dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
|
||||
if (!acm->ctrlurb)
|
||||
goto alloc_fail5;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_rx_buf; i++) {
|
||||
struct acm_rb *rb = &(acm->read_buffers[i]);
|
||||
struct urb *urb;
|
||||
|
||||
rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
|
||||
&rb->dma);
|
||||
if (!rb->base) {
|
||||
dev_err(&intf->dev, "out of memory "
|
||||
"(read bufs usb_alloc_coherent)\n");
|
||||
if (!rb->base)
|
||||
goto alloc_fail6;
|
||||
}
|
||||
rb->index = i;
|
||||
rb->instance = acm;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb) {
|
||||
dev_err(&intf->dev,
|
||||
"out of memory (read urbs usb_alloc_urb)\n");
|
||||
if (!urb)
|
||||
goto alloc_fail6;
|
||||
}
|
||||
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
urb->transfer_dma = rb->dma;
|
||||
if (acm->is_int_ep) {
|
||||
|
|
@ -1389,11 +1388,8 @@ made_compressed_probe:
|
|||
struct acm_wb *snd = &(acm->wb[i]);
|
||||
|
||||
snd->urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (snd->urb == NULL) {
|
||||
dev_err(&intf->dev,
|
||||
"out of memory (write urbs usb_alloc_urb)\n");
|
||||
if (snd->urb == NULL)
|
||||
goto alloc_fail7;
|
||||
}
|
||||
|
||||
if (usb_endpoint_xfer_int(epwrite))
|
||||
usb_fill_int_urb(snd->urb, usb_dev,
|
||||
|
|
|
|||
|
|
@ -22,17 +22,25 @@
|
|||
*/
|
||||
|
||||
/* FIXME tune these based on pool statistics ... */
|
||||
static const size_t pool_max[HCD_BUFFER_POOLS] = {
|
||||
/* platforms without dma-friendly caches might need to
|
||||
* prevent cacheline sharing...
|
||||
*/
|
||||
32,
|
||||
128,
|
||||
512,
|
||||
PAGE_SIZE / 2
|
||||
/* bigger --> allocate pages */
|
||||
static size_t pool_max[HCD_BUFFER_POOLS] = {
|
||||
32, 128, 512, 2048,
|
||||
};
|
||||
|
||||
void __init usb_init_pool_max(void)
|
||||
{
|
||||
/*
|
||||
* The pool_max values must never be smaller than
|
||||
* ARCH_KMALLOC_MINALIGN.
|
||||
*/
|
||||
if (ARCH_KMALLOC_MINALIGN <= 32)
|
||||
; /* Original value is okay */
|
||||
else if (ARCH_KMALLOC_MINALIGN <= 64)
|
||||
pool_max[0] = 64;
|
||||
else if (ARCH_KMALLOC_MINALIGN <= 128)
|
||||
pool_max[0] = 0; /* Don't use this pool */
|
||||
else
|
||||
BUILD_BUG(); /* We don't allow this */
|
||||
}
|
||||
|
||||
/* SETUP primitives */
|
||||
|
||||
|
|
|
|||
|
|
@ -1689,7 +1689,7 @@ static struct async *reap_as(struct usb_dev_state *ps)
|
|||
for (;;) {
|
||||
__set_current_state(TASK_INTERRUPTIBLE);
|
||||
as = async_getcompleted(ps);
|
||||
if (as)
|
||||
if (as || !connected(ps))
|
||||
break;
|
||||
if (signal_pending(current))
|
||||
break;
|
||||
|
|
@ -1712,7 +1712,7 @@ static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
|
|||
}
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
return -EIO;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
|
||||
|
|
@ -1721,10 +1721,11 @@ static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
|
|||
struct async *as;
|
||||
|
||||
as = async_getcompleted(ps);
|
||||
retval = -EAGAIN;
|
||||
if (as) {
|
||||
retval = processcompl(as, (void __user * __user *)arg);
|
||||
free_async(as);
|
||||
} else {
|
||||
retval = (connected(ps) ? -EAGAIN : -ENODEV);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -1854,7 +1855,7 @@ static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
|
|||
}
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
return -EIO;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg)
|
||||
|
|
@ -1862,11 +1863,12 @@ static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *ar
|
|||
int retval;
|
||||
struct async *as;
|
||||
|
||||
retval = -EAGAIN;
|
||||
as = async_getcompleted(ps);
|
||||
if (as) {
|
||||
retval = processcompl_compat(as, (void __user * __user *)arg);
|
||||
free_async(as);
|
||||
} else {
|
||||
retval = (connected(ps) ? -EAGAIN : -ENODEV);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -2038,7 +2040,8 @@ static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
|
|||
{
|
||||
__u32 caps;
|
||||
|
||||
caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM;
|
||||
caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
|
||||
USBDEVFS_CAP_REAP_AFTER_DISCONNECT;
|
||||
if (!ps->dev->bus->no_stop_on_short)
|
||||
caps |= USBDEVFS_CAP_BULK_CONTINUATION;
|
||||
if (ps->dev->bus->sg_tablesize)
|
||||
|
|
@ -2138,6 +2141,32 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
|
|||
return -EPERM;
|
||||
|
||||
usb_lock_device(dev);
|
||||
|
||||
/* Reap operations are allowed even after disconnection */
|
||||
switch (cmd) {
|
||||
case USBDEVFS_REAPURB:
|
||||
snoop(&dev->dev, "%s: REAPURB\n", __func__);
|
||||
ret = proc_reapurb(ps, p);
|
||||
goto done;
|
||||
|
||||
case USBDEVFS_REAPURBNDELAY:
|
||||
snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
|
||||
ret = proc_reapurbnonblock(ps, p);
|
||||
goto done;
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
case USBDEVFS_REAPURB32:
|
||||
snoop(&dev->dev, "%s: REAPURB32\n", __func__);
|
||||
ret = proc_reapurb_compat(ps, p);
|
||||
goto done;
|
||||
|
||||
case USBDEVFS_REAPURBNDELAY32:
|
||||
snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
|
||||
ret = proc_reapurbnonblock_compat(ps, p);
|
||||
goto done;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!connected(ps)) {
|
||||
usb_unlock_device(dev);
|
||||
return -ENODEV;
|
||||
|
|
@ -2231,16 +2260,6 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
|
|||
inode->i_mtime = CURRENT_TIME;
|
||||
break;
|
||||
|
||||
case USBDEVFS_REAPURB32:
|
||||
snoop(&dev->dev, "%s: REAPURB32\n", __func__);
|
||||
ret = proc_reapurb_compat(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_REAPURBNDELAY32:
|
||||
snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
|
||||
ret = proc_reapurbnonblock_compat(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_IOCTL32:
|
||||
snoop(&dev->dev, "%s: IOCTL32\n", __func__);
|
||||
ret = proc_ioctl_compat(ps, ptr_to_compat(p));
|
||||
|
|
@ -2252,16 +2271,6 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
|
|||
ret = proc_unlinkurb(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_REAPURB:
|
||||
snoop(&dev->dev, "%s: REAPURB\n", __func__);
|
||||
ret = proc_reapurb(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_REAPURBNDELAY:
|
||||
snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
|
||||
ret = proc_reapurbnonblock(ps, p);
|
||||
break;
|
||||
|
||||
case USBDEVFS_DISCSIGNAL:
|
||||
snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__);
|
||||
ret = proc_disconnectsignal(ps, p);
|
||||
|
|
@ -2304,6 +2313,8 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
|
|||
ret = proc_free_streams(ps, p);
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
usb_unlock_device(dev);
|
||||
if (ret >= 0)
|
||||
inode->i_atime = CURRENT_TIME;
|
||||
|
|
|
|||
|
|
@ -275,21 +275,6 @@ static int usb_unbind_device(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cancel any pending scheduled resets
|
||||
*
|
||||
* [see usb_queue_reset_device()]
|
||||
*
|
||||
* Called after unconfiguring / when releasing interfaces. See
|
||||
* comments in __usb_queue_reset_device() regarding
|
||||
* udev->reset_running.
|
||||
*/
|
||||
static void usb_cancel_queued_reset(struct usb_interface *iface)
|
||||
{
|
||||
if (iface->reset_running == 0)
|
||||
cancel_work_sync(&iface->reset_ws);
|
||||
}
|
||||
|
||||
/* called from driver core with dev locked */
|
||||
static int usb_probe_interface(struct device *dev)
|
||||
{
|
||||
|
|
@ -380,7 +365,6 @@ static int usb_probe_interface(struct device *dev)
|
|||
usb_set_intfdata(intf, NULL);
|
||||
intf->needs_remote_wakeup = 0;
|
||||
intf->condition = USB_INTERFACE_UNBOUND;
|
||||
usb_cancel_queued_reset(intf);
|
||||
|
||||
/* If the LPM disable succeeded, balance the ref counts. */
|
||||
if (!lpm_disable_error)
|
||||
|
|
@ -425,7 +409,6 @@ static int usb_unbind_interface(struct device *dev)
|
|||
usb_disable_interface(udev, intf, false);
|
||||
|
||||
driver->disconnect(intf);
|
||||
usb_cancel_queued_reset(intf);
|
||||
|
||||
/* Free streams */
|
||||
for (i = 0, j = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
|
||||
|
|
@ -1797,6 +1780,18 @@ static int autosuspend_check(struct usb_device *udev)
|
|||
dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the device is a direct child of the root hub and the HCD
|
||||
* doesn't handle wakeup requests, don't allow autosuspend when
|
||||
* wakeup is needed.
|
||||
*/
|
||||
if (w && udev->parent == udev->bus->root_hub &&
|
||||
bus_to_hcd(udev->bus)->cant_recv_wakeups) {
|
||||
dev_dbg(&udev->dev, "HCD doesn't handle wakeup requests\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
udev->do_remote_wakeup = w;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1618,6 +1618,7 @@ static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
|
|||
int usb_hcd_unlink_urb (struct urb *urb, int status)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct usb_device *udev = urb->dev;
|
||||
int retval = -EIDRM;
|
||||
unsigned long flags;
|
||||
|
||||
|
|
@ -1629,20 +1630,19 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
|
|||
spin_lock_irqsave(&hcd_urb_unlink_lock, flags);
|
||||
if (atomic_read(&urb->use_count) > 0) {
|
||||
retval = 0;
|
||||
usb_get_dev(urb->dev);
|
||||
usb_get_dev(udev);
|
||||
}
|
||||
spin_unlock_irqrestore(&hcd_urb_unlink_lock, flags);
|
||||
if (retval == 0) {
|
||||
hcd = bus_to_hcd(urb->dev->bus);
|
||||
retval = unlink1(hcd, urb, status);
|
||||
usb_put_dev(urb->dev);
|
||||
if (retval == 0)
|
||||
retval = -EINPROGRESS;
|
||||
else if (retval != -EIDRM && retval != -EBUSY)
|
||||
dev_dbg(&udev->dev, "hcd_unlink_urb %p fail %d\n",
|
||||
urb, retval);
|
||||
usb_put_dev(udev);
|
||||
}
|
||||
|
||||
if (retval == 0)
|
||||
retval = -EINPROGRESS;
|
||||
else if (retval != -EIDRM && retval != -EBUSY)
|
||||
dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
|
||||
urb, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2896,10 +2896,12 @@ static int port_is_suspended(struct usb_hub *hub, unsigned portstatus)
|
|||
*/
|
||||
static int check_port_resume_type(struct usb_device *udev,
|
||||
struct usb_hub *hub, int port1,
|
||||
int status, unsigned portchange, unsigned portstatus)
|
||||
int status, u16 portchange, u16 portstatus)
|
||||
{
|
||||
struct usb_port *port_dev = hub->ports[port1 - 1];
|
||||
int retries = 3;
|
||||
|
||||
retry:
|
||||
/* Is a warm reset needed to recover the connection? */
|
||||
if (status == 0 && udev->reset_resume
|
||||
&& hub_port_warm_reset_required(hub, port1, portstatus)) {
|
||||
|
|
@ -2907,10 +2909,17 @@ static int check_port_resume_type(struct usb_device *udev,
|
|||
}
|
||||
/* Is the device still present? */
|
||||
else if (status || port_is_suspended(hub, portstatus) ||
|
||||
!port_is_power_on(hub, portstatus) ||
|
||||
!(portstatus & USB_PORT_STAT_CONNECTION)) {
|
||||
!port_is_power_on(hub, portstatus)) {
|
||||
if (status >= 0)
|
||||
status = -ENODEV;
|
||||
} else if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
|
||||
if (retries--) {
|
||||
usleep_range(200, 300);
|
||||
status = hub_port_status(hub, port1, &portstatus,
|
||||
&portchange);
|
||||
goto retry;
|
||||
}
|
||||
status = -ENODEV;
|
||||
}
|
||||
|
||||
/* Can't do a normal resume if the port isn't enabled,
|
||||
|
|
@ -4643,9 +4652,13 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
|
|||
if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
|
||||
test_bit(port1, hub->removed_bits)) {
|
||||
|
||||
/* maybe switch power back on (e.g. root hub was reset) */
|
||||
/*
|
||||
* maybe switch power back on (e.g. root hub was reset)
|
||||
* but only if the port isn't owned by someone else.
|
||||
*/
|
||||
if (hub_is_port_power_switchable(hub)
|
||||
&& !port_is_power_on(hub, portstatus))
|
||||
&& !port_is_power_on(hub, portstatus)
|
||||
&& !port_dev->port_owner)
|
||||
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
|
||||
|
||||
if (portstatus & USB_PORT_STAT_ENABLE)
|
||||
|
|
@ -4870,7 +4883,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
|||
static void port_event(struct usb_hub *hub, int port1)
|
||||
__must_hold(&port_dev->status_lock)
|
||||
{
|
||||
int connect_change, reset_device = 0;
|
||||
int connect_change;
|
||||
struct usb_port *port_dev = hub->ports[port1 - 1];
|
||||
struct usb_device *udev = port_dev->child;
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
|
|
@ -4958,30 +4971,14 @@ static void port_event(struct usb_hub *hub, int port1)
|
|||
if (hub_port_reset(hub, port1, NULL,
|
||||
HUB_BH_RESET_TIME, true) < 0)
|
||||
hub_port_disable(hub, port1, 1);
|
||||
} else
|
||||
reset_device = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* On disconnect USB3 protocol ports transit from U0 to
|
||||
* SS.Inactive to Rx.Detect. If this happens a warm-
|
||||
* reset is not needed, but a (re)connect may happen
|
||||
* before hub_wq runs and sees the disconnect, and the
|
||||
* device may be an unknown state.
|
||||
*
|
||||
* If the port went through SS.Inactive without hub_wq
|
||||
* seeing it the C_LINK_STATE change flag will be set,
|
||||
* and we reset the dev to put it in a known state.
|
||||
*/
|
||||
if (reset_device || (udev && hub_is_superspeed(hub->hdev)
|
||||
&& (portchange & USB_PORT_STAT_C_LINK_STATE)
|
||||
&& (portstatus & USB_PORT_STAT_CONNECTION))) {
|
||||
usb_unlock_port(port_dev);
|
||||
usb_lock_device(udev);
|
||||
usb_reset_device(udev);
|
||||
usb_unlock_device(udev);
|
||||
usb_lock_port(port_dev);
|
||||
connect_change = 0;
|
||||
} else {
|
||||
usb_unlock_port(port_dev);
|
||||
usb_lock_device(udev);
|
||||
usb_reset_device(udev);
|
||||
usb_unlock_device(udev);
|
||||
usb_lock_port(port_dev);
|
||||
connect_change = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (connect_change)
|
||||
|
|
@ -5577,26 +5574,19 @@ EXPORT_SYMBOL_GPL(usb_reset_device);
|
|||
* possible; depending on how the driver attached to each interface
|
||||
* handles ->pre_reset(), the second reset might happen or not.
|
||||
*
|
||||
* - If a driver is unbound and it had a pending reset, the reset will
|
||||
* be cancelled.
|
||||
* - If the reset is delayed so long that the interface is unbound from
|
||||
* its driver, the reset will be skipped.
|
||||
*
|
||||
* - This function can be called during .probe() or .disconnect()
|
||||
* times. On return from .disconnect(), any pending resets will be
|
||||
* cancelled.
|
||||
*
|
||||
* There is no no need to lock/unlock the @reset_ws as schedule_work()
|
||||
* does its own.
|
||||
*
|
||||
* NOTE: We don't do any reference count tracking because it is not
|
||||
* needed. The lifecycle of the work_struct is tied to the
|
||||
* usb_interface. Before destroying the interface we cancel the
|
||||
* work_struct, so the fact that work_struct is queued and or
|
||||
* running means the interface (and thus, the device) exist and
|
||||
* are referenced.
|
||||
* - This function can be called during .probe(). It can also be called
|
||||
* during .disconnect(), but doing so is pointless because the reset
|
||||
* will not occur. If you really want to reset the device during
|
||||
* .disconnect(), call usb_reset_device() directly -- but watch out
|
||||
* for nested unbinding issues!
|
||||
*/
|
||||
void usb_queue_reset_device(struct usb_interface *iface)
|
||||
{
|
||||
schedule_work(&iface->reset_ws);
|
||||
if (schedule_work(&iface->reset_ws))
|
||||
usb_get_intf(iface);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_queue_reset_device);
|
||||
|
||||
|
|
|
|||
|
|
@ -1551,6 +1551,7 @@ static void usb_release_interface(struct device *dev)
|
|||
altsetting_to_usb_interface_cache(intf->altsetting);
|
||||
|
||||
kref_put(&intfc->ref, usb_release_interface_cache);
|
||||
usb_put_dev(interface_to_usbdev(intf));
|
||||
kfree(intf);
|
||||
}
|
||||
|
||||
|
|
@ -1626,24 +1627,6 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
|
|||
|
||||
/*
|
||||
* Internal function to queue a device reset
|
||||
*
|
||||
* This is initialized into the workstruct in 'struct
|
||||
* usb_device->reset_ws' that is launched by
|
||||
* message.c:usb_set_configuration() when initializing each 'struct
|
||||
* usb_interface'.
|
||||
*
|
||||
* It is safe to get the USB device without reference counts because
|
||||
* the life cycle of @iface is bound to the life cycle of @udev. Then,
|
||||
* this function will be ran only if @iface is alive (and before
|
||||
* freeing it any scheduled instances of it will have been cancelled).
|
||||
*
|
||||
* We need to set a flag (usb_dev->reset_running) because when we call
|
||||
* the reset, the interfaces might be unbound. The current interface
|
||||
* cannot try to remove the queued work as it would cause a deadlock
|
||||
* (you cannot remove your work from within your executing
|
||||
* workqueue). This flag lets it know, so that
|
||||
* usb_cancel_queued_reset() doesn't try to do it.
|
||||
*
|
||||
* See usb_queue_reset_device() for more details
|
||||
*/
|
||||
static void __usb_queue_reset_device(struct work_struct *ws)
|
||||
|
|
@ -1655,11 +1638,10 @@ static void __usb_queue_reset_device(struct work_struct *ws)
|
|||
|
||||
rc = usb_lock_device_for_reset(udev, iface);
|
||||
if (rc >= 0) {
|
||||
iface->reset_running = 1;
|
||||
usb_reset_device(udev);
|
||||
iface->reset_running = 0;
|
||||
usb_unlock_device(udev);
|
||||
}
|
||||
usb_put_intf(iface); /* Undo _get_ in usb_queue_reset_device() */
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1854,6 +1836,7 @@ free_interfaces:
|
|||
dev_set_name(&intf->dev, "%d-%s:%d.%d",
|
||||
dev->bus->busnum, dev->devpath,
|
||||
configuration, alt->desc.bInterfaceNumber);
|
||||
usb_get_dev(dev);
|
||||
}
|
||||
kfree(new_interfaces);
|
||||
|
||||
|
|
|
|||
|
|
@ -1049,6 +1049,7 @@ static int __init usb_init(void)
|
|||
pr_info("%s: USB support disabled\n", usbcore_name);
|
||||
return 0;
|
||||
}
|
||||
usb_init_pool_max();
|
||||
|
||||
retval = usb_debugfs_init();
|
||||
if (retval)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ choice
|
|||
|
||||
config USB_DWC2_HOST
|
||||
bool "Host only mode"
|
||||
depends on USB
|
||||
depends on USB=y || (USB_DWC2=m && USB)
|
||||
help
|
||||
The Designware USB2.0 high-speed host controller
|
||||
integrated into many SoCs. Select this option if you want the
|
||||
|
|
@ -42,7 +42,7 @@ config USB_DWC2_PERIPHERAL
|
|||
|
||||
config USB_DWC2_DUAL_ROLE
|
||||
bool "Dual Role mode"
|
||||
depends on (USB=y || USB=USB_DWC2) && (USB_GADGET=y || USB_GADGET=USB_DWC2)
|
||||
depends on (USB=y && USB_GADGET=y) || (USB_DWC2=m && USB && USB_GADGET)
|
||||
help
|
||||
Select this option if you want the driver to work in a dual-role
|
||||
mode. In this mode both host and gadget features are enabled, and
|
||||
|
|
|
|||
|
|
@ -462,7 +462,7 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
|
|||
dwc2_enable_common_interrupts(hsotg);
|
||||
|
||||
/*
|
||||
* Do device or host intialization based on mode during PCD and
|
||||
* Do device or host initialization based on mode during PCD and
|
||||
* HCD initialization
|
||||
*/
|
||||
if (dwc2_is_host_mode(hsotg)) {
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ struct s3c_hsotg_req;
|
|||
* @halted: Set if the endpoint has been halted.
|
||||
* @periodic: Set if this is a periodic ep, such as Interrupt
|
||||
* @isochronous: Set if this is a isochronous ep
|
||||
* @sent_zlp: Set if we've sent a zero-length packet.
|
||||
* @send_zlp: Set if we need to send a zero-length packet.
|
||||
* @total_data: The total number of data bytes done.
|
||||
* @fifo_size: The size of the FIFO (for periodic IN endpoints)
|
||||
* @fifo_load: The amount of data loaded into the FIFO (periodic IN)
|
||||
|
|
@ -149,7 +149,7 @@ struct s3c_hsotg_ep {
|
|||
unsigned int halted:1;
|
||||
unsigned int periodic:1;
|
||||
unsigned int isochronous:1;
|
||||
unsigned int sent_zlp:1;
|
||||
unsigned int send_zlp:1;
|
||||
|
||||
char name[10];
|
||||
};
|
||||
|
|
@ -158,14 +158,12 @@ struct s3c_hsotg_ep {
|
|||
* struct s3c_hsotg_req - data transfer request
|
||||
* @req: The USB gadget request
|
||||
* @queue: The list of requests for the endpoint this is queued for.
|
||||
* @in_progress: Has already had size/packets written to core
|
||||
* @mapped: DMA buffer for this request has been mapped via dma_map_single().
|
||||
* @saved_req_buf: variable to save req.buf when bounce buffers are used.
|
||||
*/
|
||||
struct s3c_hsotg_req {
|
||||
struct usb_request req;
|
||||
struct list_head queue;
|
||||
unsigned char in_progress;
|
||||
unsigned char mapped;
|
||||
void *saved_req_buf;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
||||
|
|
@ -193,6 +191,22 @@ enum dwc2_lx_state {
|
|||
DWC2_L3, /* Off state */
|
||||
};
|
||||
|
||||
/*
|
||||
* Gadget periodic tx fifo sizes as used by legacy driver
|
||||
* EP0 is not included
|
||||
*/
|
||||
#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \
|
||||
768, 0, 0, 0, 0, 0, 0, 0}
|
||||
|
||||
/* Gadget ep0 states */
|
||||
enum dwc2_ep0_state {
|
||||
DWC2_EP0_SETUP,
|
||||
DWC2_EP0_DATA_IN,
|
||||
DWC2_EP0_DATA_OUT,
|
||||
DWC2_EP0_STATUS_IN,
|
||||
DWC2_EP0_STATUS_OUT,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dwc2_core_params - Parameters for configuring the core
|
||||
*
|
||||
|
|
@ -381,7 +395,7 @@ struct dwc2_core_params {
|
|||
* @power_optimized Are power optimizations enabled?
|
||||
* @num_dev_ep Number of device endpoints available
|
||||
* @num_dev_perio_in_ep Number of device periodic IN endpoints
|
||||
* avaialable
|
||||
* available
|
||||
* @dev_token_q_depth Device Mode IN Token Sequence Learning Queue
|
||||
* Depth
|
||||
* 0 to 30
|
||||
|
|
@ -434,6 +448,9 @@ struct dwc2_hw_params {
|
|||
u32 snpsid;
|
||||
};
|
||||
|
||||
/* Size of control and EP0 buffers */
|
||||
#define DWC2_CTRL_BUFF_SIZE 8
|
||||
|
||||
/**
|
||||
* struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
|
||||
* and periodic schedules
|
||||
|
|
@ -552,14 +569,20 @@ struct dwc2_hw_params {
|
|||
* @num_of_eps: Number of available EPs (excluding EP0)
|
||||
* @debug_root: Root directrory for debugfs.
|
||||
* @debug_file: Main status file for debugfs.
|
||||
* @debug_testmode: Testmode status file for debugfs.
|
||||
* @debug_fifo: FIFO status file for debugfs.
|
||||
* @ep0_reply: Request used for ep0 reply.
|
||||
* @ep0_buff: Buffer for EP0 reply data, if needed.
|
||||
* @ctrl_buff: Buffer for EP0 control requests.
|
||||
* @ctrl_req: Request for EP0 control packets.
|
||||
* @setup: NAK management for EP0 SETUP
|
||||
* @ep0_state: EP0 control transfers state
|
||||
* @test_mode: USB test mode requested by the host
|
||||
* @last_rst: Time of last reset
|
||||
* @eps: The endpoints being supplied to the gadget framework
|
||||
* @g_using_dma: Indicate if dma usage is enabled
|
||||
* @g_rx_fifo_sz: Contains rx fifo size value
|
||||
* @g_np_g_tx_fifo_sz: Contains Non-Periodic tx fifo size value
|
||||
* @g_tx_fifo_sz: Contains tx fifo size value per endpoints
|
||||
*/
|
||||
struct dwc2_hsotg {
|
||||
struct device *dev;
|
||||
|
|
@ -591,6 +614,7 @@ struct dwc2_hsotg {
|
|||
|
||||
struct dentry *debug_root;
|
||||
struct dentry *debug_file;
|
||||
struct dentry *debug_testmode;
|
||||
struct dentry *debug_fifo;
|
||||
|
||||
/* DWC OTG HW Release versions */
|
||||
|
|
@ -684,15 +708,21 @@ struct dwc2_hsotg {
|
|||
|
||||
struct usb_request *ep0_reply;
|
||||
struct usb_request *ctrl_req;
|
||||
u8 ep0_buff[8];
|
||||
u8 ctrl_buff[8];
|
||||
void *ep0_buff;
|
||||
void *ctrl_buff;
|
||||
enum dwc2_ep0_state ep0_state;
|
||||
u8 test_mode;
|
||||
|
||||
struct usb_gadget gadget;
|
||||
unsigned int enabled:1;
|
||||
unsigned int connected:1;
|
||||
unsigned int setup:1;
|
||||
unsigned long last_rst;
|
||||
struct s3c_hsotg_ep *eps;
|
||||
struct s3c_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
|
||||
struct s3c_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
|
||||
u32 g_using_dma;
|
||||
u32 g_rx_fifo_sz;
|
||||
u32 g_np_g_tx_fifo_sz;
|
||||
u32 g_tx_fifo_sz[MAX_EPS_CHANNELS];
|
||||
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
|
||||
};
|
||||
|
||||
|
|
@ -969,7 +999,8 @@ extern int s3c_hsotg_remove(struct dwc2_hsotg *hsotg);
|
|||
extern int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2);
|
||||
extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2);
|
||||
extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq);
|
||||
extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2);
|
||||
extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
|
||||
bool reset);
|
||||
extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
|
||||
extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
|
||||
#else
|
||||
|
|
@ -981,7 +1012,8 @@ static inline int s3c_hsotg_resume(struct dwc2_hsotg *dwc2)
|
|||
{ return 0; }
|
||||
static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
|
||||
{ return 0; }
|
||||
static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2) {}
|
||||
static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
|
||||
bool reset) {}
|
||||
static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
|
||||
static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -316,10 +316,12 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
|
|||
*/
|
||||
static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
if (hsotg->lx_state == DWC2_L2)
|
||||
if (hsotg->lx_state == DWC2_L2) {
|
||||
hsotg->flags.b.port_suspend_change = 1;
|
||||
else
|
||||
usb_hcd_resume_root_hub(hsotg->priv);
|
||||
} else {
|
||||
hsotg->flags.b.port_l1_change = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1371,7 +1373,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
|
|||
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
|
||||
dwc2_core_init(hsotg, false, -1);
|
||||
dwc2_enable_global_interrupts(hsotg);
|
||||
s3c_hsotg_core_init_disconnected(hsotg);
|
||||
s3c_hsotg_core_init_disconnected(hsotg, false);
|
||||
s3c_hsotg_core_connect(hsotg);
|
||||
} else {
|
||||
/* A-Device connector (Host Mode) */
|
||||
|
|
@ -1473,30 +1475,6 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
|
|||
}
|
||||
}
|
||||
|
||||
static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
u32 hprt0;
|
||||
|
||||
/* After clear the Stop PHY clock bit, we should wait for a moment
|
||||
* for PLL work stable with clock output.
|
||||
*/
|
||||
writel(0, hsotg->regs + PCGCTL);
|
||||
usleep_range(2000, 4000);
|
||||
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
hprt0 |= HPRT0_RES;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
hprt0 &= ~HPRT0_SUSP;
|
||||
/* according to USB2.0 Spec 7.1.7.7, the host must send the resume
|
||||
* signal for at least 20ms
|
||||
*/
|
||||
usleep_range(20000, 25000);
|
||||
|
||||
hprt0 &= ~HPRT0_RES;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
hsotg->lx_state = DWC2_L0;
|
||||
}
|
||||
|
||||
/* Handles hub class-specific requests */
|
||||
static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
||||
u16 wvalue, u16 windex, char *buf, u16 wlength)
|
||||
|
|
@ -1542,7 +1520,17 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
|||
case USB_PORT_FEAT_SUSPEND:
|
||||
dev_dbg(hsotg->dev,
|
||||
"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
|
||||
dwc2_port_resume(hsotg);
|
||||
writel(0, hsotg->regs + PCGCTL);
|
||||
usleep_range(20000, 40000);
|
||||
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
hprt0 |= HPRT0_RES;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
hprt0 &= ~HPRT0_SUSP;
|
||||
usleep_range(100000, 150000);
|
||||
|
||||
hprt0 &= ~HPRT0_RES;
|
||||
writel(hprt0, hsotg->regs + HPRT0);
|
||||
break;
|
||||
|
||||
case USB_PORT_FEAT_POWER:
|
||||
|
|
@ -1622,7 +1610,9 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
|||
hub_desc->bDescLength = 9;
|
||||
hub_desc->bDescriptorType = 0x29;
|
||||
hub_desc->bNbrPorts = 1;
|
||||
hub_desc->wHubCharacteristics = cpu_to_le16(0x08);
|
||||
hub_desc->wHubCharacteristics =
|
||||
cpu_to_le16(HUB_CHAR_COMMON_LPSM |
|
||||
HUB_CHAR_INDV_PORT_OCPM);
|
||||
hub_desc->bPwrOn2PwrGood = 1;
|
||||
hub_desc->bHubContrCurrent = 0;
|
||||
hub_desc->u.hs.DeviceRemovable[0] = 0;
|
||||
|
|
@ -2315,55 +2305,6 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
|
|||
usleep_range(1000, 3000);
|
||||
}
|
||||
|
||||
static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
|
||||
{
|
||||
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
|
||||
u32 hprt0;
|
||||
|
||||
if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
|
||||
(hsotg->op_state == OTG_STATE_A_HOST)))
|
||||
return 0;
|
||||
|
||||
/* TODO: We get into suspend from 'on' state, maybe we need to do
|
||||
* something if we get here from DWC2_L1(LPM sleep) state one day.
|
||||
*/
|
||||
if (hsotg->lx_state != DWC2_L0)
|
||||
return 0;
|
||||
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
if (hprt0 & HPRT0_CONNSTS) {
|
||||
dwc2_port_suspend(hsotg, 1);
|
||||
} else {
|
||||
u32 pcgctl = readl(hsotg->regs + PCGCTL);
|
||||
|
||||
pcgctl |= PCGCTL_STOPPCLK;
|
||||
writel(pcgctl, hsotg->regs + PCGCTL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dwc2_hcd_resume(struct usb_hcd *hcd)
|
||||
{
|
||||
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
|
||||
u32 hprt0;
|
||||
|
||||
if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
|
||||
(hsotg->op_state == OTG_STATE_A_HOST)))
|
||||
return 0;
|
||||
|
||||
if (hsotg->lx_state != DWC2_L2)
|
||||
return 0;
|
||||
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
if ((hprt0 & HPRT0_CONNSTS) && (hprt0 & HPRT0_SUSP))
|
||||
dwc2_port_resume(hsotg);
|
||||
else
|
||||
writel(0, hsotg->regs + PCGCTL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns the current frame number */
|
||||
static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
|
||||
{
|
||||
|
|
@ -2734,9 +2675,6 @@ static struct hc_driver dwc2_hc_driver = {
|
|||
.hub_status_data = _dwc2_hcd_hub_status_data,
|
||||
.hub_control = _dwc2_hcd_hub_control,
|
||||
.clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,
|
||||
|
||||
.bus_suspend = _dwc2_hcd_suspend,
|
||||
.bus_resume = _dwc2_hcd_resume,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -294,6 +294,7 @@
|
|||
#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26)
|
||||
#define GHWCFG4_NUM_IN_EPS_SHIFT 26
|
||||
#define GHWCFG4_DED_FIFO_EN (1 << 25)
|
||||
#define GHWCFG4_DED_FIFO_SHIFT 25
|
||||
#define GHWCFG4_SESSION_END_FILT_EN (1 << 24)
|
||||
#define GHWCFG4_B_VALID_FILT_EN (1 << 23)
|
||||
#define GHWCFG4_A_VALID_FILT_EN (1 << 22)
|
||||
|
|
@ -541,6 +542,7 @@
|
|||
|
||||
#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20))
|
||||
#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20))
|
||||
#define DXEPINT_SETUP_RCVD (1 << 15)
|
||||
#define DXEPINT_INEPNAKEFF (1 << 6)
|
||||
#define DXEPINT_BACK2BACKSETUP (1 << 6)
|
||||
#define DXEPINT_INTKNEPMIS (1 << 5)
|
||||
|
|
|
|||
|
|
@ -155,6 +155,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|||
struct dwc2_core_params defparams;
|
||||
struct dwc2_hsotg *hsotg;
|
||||
struct resource *res;
|
||||
struct phy *phy;
|
||||
struct usb_phy *uphy;
|
||||
int retval;
|
||||
int irq;
|
||||
|
||||
|
|
@ -212,6 +214,24 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|||
|
||||
hsotg->dr_mode = of_usb_get_dr_mode(dev->dev.of_node);
|
||||
|
||||
/*
|
||||
* Attempt to find a generic PHY, then look for an old style
|
||||
* USB PHY
|
||||
*/
|
||||
phy = devm_phy_get(&dev->dev, "usb2-phy");
|
||||
if (IS_ERR(phy)) {
|
||||
hsotg->phy = NULL;
|
||||
uphy = devm_usb_get_phy(&dev->dev, USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR(uphy))
|
||||
hsotg->uphy = NULL;
|
||||
else
|
||||
hsotg->uphy = uphy;
|
||||
} else {
|
||||
hsotg->phy = phy;
|
||||
phy_power_on(hsotg->phy);
|
||||
phy_init(hsotg->phy);
|
||||
}
|
||||
|
||||
spin_lock_init(&hsotg->lock);
|
||||
mutex_init(&hsotg->init_mutex);
|
||||
retval = dwc2_gadget_init(hsotg, irq);
|
||||
|
|
@ -231,8 +251,15 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
|
|||
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
if (dwc2_is_device_mode(dwc2))
|
||||
if (dwc2_is_device_mode(dwc2)) {
|
||||
ret = s3c_hsotg_suspend(dwc2);
|
||||
} else {
|
||||
if (dwc2->lx_state == DWC2_L0)
|
||||
return 0;
|
||||
phy_exit(dwc2->phy);
|
||||
phy_power_off(dwc2->phy);
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -241,8 +268,13 @@ static int __maybe_unused dwc2_resume(struct device *dev)
|
|||
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
if (dwc2_is_device_mode(dwc2))
|
||||
if (dwc2_is_device_mode(dwc2)) {
|
||||
ret = s3c_hsotg_resume(dwc2);
|
||||
} else {
|
||||
phy_power_on(dwc2->phy);
|
||||
phy_init(dwc2->phy);
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,12 +104,6 @@ config USB_DWC3_DEBUG
|
|||
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.
|
||||
|
||||
config DWC3_HOST_USB3_LPM_ENABLE
|
||||
bool "Enable USB3 LPM Capability"
|
||||
depends on USB_DWC3_HOST=y || USB_DWC3_DUAL_ROLE=y
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
CFLAGS_trace.o := -I$(src)
|
||||
|
||||
ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
|
||||
ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
|
||||
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3.o
|
||||
|
||||
|
|
|
|||
|
|
@ -345,7 +345,7 @@ static void dwc3_core_num_eps(struct dwc3 *dwc)
|
|||
dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
|
||||
dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
|
||||
|
||||
dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
|
||||
dwc3_trace(trace_dwc3_core, "found %d IN and %d OUT endpoints",
|
||||
dwc->num_in_eps, dwc->num_out_eps);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -431,7 +431,6 @@ struct dwc3_event_buffer {
|
|||
* @dwc: pointer to DWC controller
|
||||
* @saved_state: ep state saved during hibernation
|
||||
* @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
|
||||
* @resource_index: Resource transfer index
|
||||
|
|
@ -464,8 +463,6 @@ struct dwc3_ep {
|
|||
/* This last one is specific to EP0 */
|
||||
#define DWC3_EP0_DIR_IN (1 << 31)
|
||||
|
||||
unsigned current_trb;
|
||||
|
||||
u8 number;
|
||||
u8 type;
|
||||
u8 resource_index;
|
||||
|
|
@ -685,7 +682,6 @@ struct dwc3_scratchpad_array {
|
|||
* @is_utmi_l1_suspend: the core asserts output signal
|
||||
* 0 - utmi_sleep_n
|
||||
* 1 - utmi_l1_suspend_n
|
||||
* @is_selfpowered: true when we are selfpowered
|
||||
* @is_fpga: true when we are using the FPGA board
|
||||
* @needs_fifo_resize: not all users might want fifo resizing, flag it
|
||||
* @pullups_connected: true when Run/Stop bit is set
|
||||
|
|
@ -809,7 +805,6 @@ struct dwc3 {
|
|||
unsigned has_hibernation:1;
|
||||
unsigned has_lpm_erratum:1;
|
||||
unsigned is_utmi_l1_suspend:1;
|
||||
unsigned is_selfpowered:1;
|
||||
unsigned is_fpga:1;
|
||||
unsigned needs_fifo_resize:1;
|
||||
unsigned pullups_connected:1;
|
||||
|
|
|
|||
|
|
@ -22,9 +22,6 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/usb_phy_generic.h>
|
||||
|
||||
#include "platform_data.h"
|
||||
|
||||
/* FIXME define these in <linux/pci_ids.h> */
|
||||
|
|
@ -36,66 +33,41 @@
|
|||
#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30
|
||||
#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
|
||||
|
||||
struct dwc3_pci {
|
||||
struct device *dev;
|
||||
struct platform_device *dwc3;
|
||||
struct platform_device *usb2_phy;
|
||||
struct platform_device *usb3_phy;
|
||||
};
|
||||
|
||||
static int dwc3_pci_register_phys(struct dwc3_pci *glue)
|
||||
static int dwc3_pci_quirks(struct pci_dev *pdev)
|
||||
{
|
||||
struct usb_phy_generic_platform_data pdata;
|
||||
struct platform_device *pdev;
|
||||
int ret;
|
||||
if (pdev->vendor == PCI_VENDOR_ID_AMD &&
|
||||
pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
|
||||
struct dwc3_platform_data pdata;
|
||||
|
||||
memset(&pdata, 0x00, sizeof(pdata));
|
||||
memset(&pdata, 0, sizeof(pdata));
|
||||
|
||||
pdev = platform_device_alloc("usb_phy_generic", 0);
|
||||
if (!pdev)
|
||||
return -ENOMEM;
|
||||
pdata.has_lpm_erratum = true;
|
||||
pdata.lpm_nyet_threshold = 0xf;
|
||||
|
||||
glue->usb2_phy = pdev;
|
||||
pdata.type = USB_PHY_TYPE_USB2;
|
||||
pdata.gpio_reset = -1;
|
||||
pdata.u2exit_lfps_quirk = true;
|
||||
pdata.u2ss_inp3_quirk = true;
|
||||
pdata.req_p1p2p3_quirk = true;
|
||||
pdata.del_p1p2p3_quirk = true;
|
||||
pdata.del_phy_power_chg_quirk = true;
|
||||
pdata.lfps_filter_quirk = true;
|
||||
pdata.rx_detect_poll_quirk = true;
|
||||
|
||||
ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
|
||||
if (ret)
|
||||
goto err1;
|
||||
pdata.tx_de_emphasis_quirk = true;
|
||||
pdata.tx_de_emphasis = 1;
|
||||
|
||||
pdev = platform_device_alloc("usb_phy_generic", 1);
|
||||
if (!pdev) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
/*
|
||||
* FIXME these quirks should be removed when AMD NL
|
||||
* taps out
|
||||
*/
|
||||
pdata.disable_scramble_quirk = true;
|
||||
pdata.dis_u3_susphy_quirk = true;
|
||||
pdata.dis_u2_susphy_quirk = true;
|
||||
|
||||
return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
|
||||
sizeof(pdata));
|
||||
}
|
||||
|
||||
glue->usb3_phy = pdev;
|
||||
pdata.type = USB_PHY_TYPE_USB3;
|
||||
|
||||
ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata));
|
||||
if (ret)
|
||||
goto err2;
|
||||
|
||||
ret = platform_device_add(glue->usb2_phy);
|
||||
if (ret)
|
||||
goto err2;
|
||||
|
||||
ret = platform_device_add(glue->usb3_phy);
|
||||
if (ret)
|
||||
goto err3;
|
||||
|
||||
return 0;
|
||||
|
||||
err3:
|
||||
platform_device_del(glue->usb2_phy);
|
||||
|
||||
err2:
|
||||
platform_device_put(glue->usb3_phy);
|
||||
|
||||
err1:
|
||||
platform_device_put(glue->usb2_phy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_pci_probe(struct pci_dev *pci,
|
||||
|
|
@ -103,18 +75,8 @@ static int dwc3_pci_probe(struct pci_dev *pci,
|
|||
{
|
||||
struct resource res[2];
|
||||
struct platform_device *dwc3;
|
||||
struct dwc3_pci *glue;
|
||||
int ret;
|
||||
struct device *dev = &pci->dev;
|
||||
struct dwc3_platform_data dwc3_pdata;
|
||||
|
||||
memset(&dwc3_pdata, 0x00, sizeof(dwc3_pdata));
|
||||
|
||||
glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue)
|
||||
return -ENOMEM;
|
||||
|
||||
glue->dev = dev;
|
||||
|
||||
ret = pcim_enable_device(pci);
|
||||
if (ret) {
|
||||
|
|
@ -124,12 +86,6 @@ static int dwc3_pci_probe(struct pci_dev *pci,
|
|||
|
||||
pci_set_master(pci);
|
||||
|
||||
ret = dwc3_pci_register_phys(glue);
|
||||
if (ret) {
|
||||
dev_err(dev, "couldn't register PHYs\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
|
||||
if (!dwc3) {
|
||||
dev_err(dev, "couldn't allocate dwc3 device\n");
|
||||
|
|
@ -147,70 +103,34 @@ static int dwc3_pci_probe(struct pci_dev *pci,
|
|||
res[1].name = "dwc_usb3";
|
||||
res[1].flags = IORESOURCE_IRQ;
|
||||
|
||||
if (pci->vendor == PCI_VENDOR_ID_AMD &&
|
||||
pci->device == PCI_DEVICE_ID_AMD_NL_USB) {
|
||||
dwc3_pdata.has_lpm_erratum = true;
|
||||
dwc3_pdata.lpm_nyet_threshold = 0xf;
|
||||
|
||||
dwc3_pdata.u2exit_lfps_quirk = true;
|
||||
dwc3_pdata.u2ss_inp3_quirk = true;
|
||||
dwc3_pdata.req_p1p2p3_quirk = true;
|
||||
dwc3_pdata.del_p1p2p3_quirk = true;
|
||||
dwc3_pdata.del_phy_power_chg_quirk = true;
|
||||
dwc3_pdata.lfps_filter_quirk = true;
|
||||
dwc3_pdata.rx_detect_poll_quirk = true;
|
||||
|
||||
dwc3_pdata.tx_de_emphasis_quirk = true;
|
||||
dwc3_pdata.tx_de_emphasis = 1;
|
||||
|
||||
/*
|
||||
* FIXME these quirks should be removed when AMD NL
|
||||
* taps out
|
||||
*/
|
||||
dwc3_pdata.disable_scramble_quirk = true;
|
||||
dwc3_pdata.dis_u3_susphy_quirk = true;
|
||||
dwc3_pdata.dis_u2_susphy_quirk = true;
|
||||
}
|
||||
|
||||
ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
|
||||
if (ret) {
|
||||
dev_err(dev, "couldn't add resources to dwc3 device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pci, glue);
|
||||
|
||||
ret = platform_device_add_data(dwc3, &dwc3_pdata, sizeof(dwc3_pdata));
|
||||
pci_set_drvdata(pci, dwc3);
|
||||
ret = dwc3_pci_quirks(pci);
|
||||
if (ret)
|
||||
goto err3;
|
||||
goto err;
|
||||
|
||||
dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
|
||||
|
||||
dwc3->dev.dma_mask = dev->dma_mask;
|
||||
dwc3->dev.dma_parms = dev->dma_parms;
|
||||
dwc3->dev.parent = dev;
|
||||
glue->dwc3 = dwc3;
|
||||
|
||||
ret = platform_device_add(dwc3);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register dwc3 device\n");
|
||||
goto err3;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err3:
|
||||
err:
|
||||
platform_device_put(dwc3);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwc3_pci_remove(struct pci_dev *pci)
|
||||
{
|
||||
struct dwc3_pci *glue = pci_get_drvdata(pci);
|
||||
|
||||
platform_device_unregister(glue->dwc3);
|
||||
platform_device_unregister(glue->usb2_phy);
|
||||
platform_device_unregister(glue->usb3_phy);
|
||||
platform_device_unregister(pci_get_drvdata(pci));
|
||||
}
|
||||
|
||||
static const struct pci_device_id dwc3_pci_id_table[] = {
|
||||
|
|
@ -228,45 +148,11 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dwc3_pci_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci = to_pci_dev(dev);
|
||||
|
||||
pci_disable_device(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_pci_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci = to_pci_dev(dev);
|
||||
int ret;
|
||||
|
||||
ret = pci_enable_device(pci);
|
||||
if (ret) {
|
||||
dev_err(dev, "can't re-enable device --> %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pci_set_master(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
|
||||
};
|
||||
|
||||
static struct pci_driver dwc3_pci_driver = {
|
||||
.name = "dwc3-pci",
|
||||
.id_table = dwc3_pci_id_table,
|
||||
.probe = dwc3_pci_probe,
|
||||
.remove = dwc3_pci_remove,
|
||||
.driver = {
|
||||
.pm = &dwc3_pci_dev_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Felipe Balbi <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
|
|||
/*
|
||||
* LTM will be set once we know how to set this in HW.
|
||||
*/
|
||||
usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
|
||||
usb_status |= dwc->gadget.is_selfpowered;
|
||||
|
||||
if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
|
|
|
|||
|
|
@ -139,7 +139,8 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
|
|||
udelay(5);
|
||||
}
|
||||
|
||||
dev_vdbg(dwc->dev, "link state change request timed out\n");
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"link state change request timed out");
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
|
@ -219,7 +220,7 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
|
|||
|
||||
fifo_size |= (last_fifo_depth << 16);
|
||||
|
||||
dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
|
||||
dwc3_trace(trace_dwc3_gadget, "%s: Fifo Addr %04x Size %d",
|
||||
dep->name, last_fifo_depth, fifo_size & 0xffff);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
|
||||
|
|
@ -287,7 +288,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
|
|||
do {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
|
||||
if (!(reg & DWC3_DGCMD_CMDACT)) {
|
||||
dev_vdbg(dwc->dev, "Command Complete --> %d\n",
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"Command Complete --> %d",
|
||||
DWC3_DGCMD_STATUS(reg));
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -297,8 +299,11 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
|
|||
* interrupt context.
|
||||
*/
|
||||
timeout--;
|
||||
if (!timeout)
|
||||
if (!timeout) {
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"Command Timed Out");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
udelay(1);
|
||||
} while (1);
|
||||
}
|
||||
|
|
@ -320,7 +325,8 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
|||
do {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
|
||||
if (!(reg & DWC3_DEPCMD_CMDACT)) {
|
||||
dev_vdbg(dwc->dev, "Command Complete --> %d\n",
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"Command Complete --> %d",
|
||||
DWC3_DEPCMD_STATUS(reg));
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -330,8 +336,11 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
|||
* interrupt context.
|
||||
*/
|
||||
timeout--;
|
||||
if (!timeout)
|
||||
if (!timeout) {
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"Command Timed Out");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
udelay(1);
|
||||
} while (1);
|
||||
|
|
@ -352,9 +361,6 @@ static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
|
|||
if (dep->trb_pool)
|
||||
return 0;
|
||||
|
||||
if (dep->number == 0 || dep->number == 1)
|
||||
return 0;
|
||||
|
||||
dep->trb_pool = dma_alloc_coherent(dwc->dev,
|
||||
sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
|
||||
&dep->trb_pool_dma, GFP_KERNEL);
|
||||
|
|
@ -492,7 +498,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
|||
u32 reg;
|
||||
int ret;
|
||||
|
||||
dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
|
||||
dwc3_trace(trace_dwc3_gadget, "Enabling %s", dep->name);
|
||||
|
||||
if (!(dep->flags & DWC3_EP_ENABLED)) {
|
||||
ret = dwc3_gadget_start_config(dwc, dep);
|
||||
|
|
@ -729,10 +735,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
|||
struct dwc3_request *req, dma_addr_t dma,
|
||||
unsigned length, unsigned last, unsigned chain, unsigned node)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
struct dwc3_trb *trb;
|
||||
|
||||
dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
|
||||
dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s%s",
|
||||
dep->name, req, (unsigned long long) dma,
|
||||
length, last ? " last" : "",
|
||||
chain ? " chain" : "");
|
||||
|
|
@ -934,7 +939,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
|
|||
u32 cmd;
|
||||
|
||||
if (start_new && (dep->flags & DWC3_EP_BUSY)) {
|
||||
dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
|
||||
dwc3_trace(trace_dwc3_gadget, "%s: endpoint busy", dep->name);
|
||||
return -EBUSY;
|
||||
}
|
||||
dep->flags &= ~DWC3_EP_PENDING_REQUEST;
|
||||
|
|
@ -1005,8 +1010,9 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
|
|||
u32 uf;
|
||||
|
||||
if (list_empty(&dep->request_list)) {
|
||||
dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
|
||||
dep->name);
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"ISOC ep %s run out for requests",
|
||||
dep->name);
|
||||
dep->flags |= DWC3_EP_PENDING_REQUEST;
|
||||
return;
|
||||
}
|
||||
|
|
@ -1113,15 +1119,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
* handled.
|
||||
*/
|
||||
if (dep->stream_capable) {
|
||||
int ret;
|
||||
|
||||
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
|
||||
if (ret && ret != -EBUSY) {
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
|
||||
if (ret && ret != -EBUSY)
|
||||
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
|
||||
dep->name);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1152,8 +1153,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
|
|||
goto out;
|
||||
}
|
||||
|
||||
dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
|
||||
request, ep->name, request->length);
|
||||
trace_dwc3_ep_queue(req);
|
||||
|
||||
ret = __dwc3_gadget_ep_queue(dep, req);
|
||||
|
|
@ -1416,7 +1415,7 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
dwc->is_selfpowered = !!is_selfpowered;
|
||||
g->is_selfpowered = !!is_selfpowered;
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1468,7 +1467,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
|
|||
udelay(1);
|
||||
} while (1);
|
||||
|
||||
dev_vdbg(dwc->dev, "gadget %s data soft-%s\n",
|
||||
dwc3_trace(trace_dwc3_gadget, "gadget %s data soft-%s",
|
||||
dwc->gadget_driver
|
||||
? dwc->gadget_driver->function : "no-function",
|
||||
is_on ? "connect" : "disconnect");
|
||||
|
|
@ -1688,7 +1687,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
|||
|
||||
dep->endpoint.name = dep->name;
|
||||
|
||||
dev_vdbg(dwc->dev, "initializing %s\n", dep->name);
|
||||
dwc3_trace(trace_dwc3_gadget, "initializing %s", dep->name);
|
||||
|
||||
if (epnum == 0 || epnum == 1) {
|
||||
usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
|
||||
|
|
@ -1725,13 +1724,15 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
|
|||
|
||||
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
|
||||
if (ret < 0) {
|
||||
dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n");
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"failed to allocate OUT endpoints");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
|
||||
if (ret < 0) {
|
||||
dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n");
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"failed to allocate IN endpoints");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1977,7 +1978,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
|||
} else {
|
||||
int ret;
|
||||
|
||||
dev_vdbg(dwc->dev, "%s: reason %s\n",
|
||||
dwc3_trace(trace_dwc3_gadget, "%s: reason %s",
|
||||
dep->name, event->status &
|
||||
DEPEVT_STATUS_TRANSFER_ACTIVE
|
||||
? "Transfer Active"
|
||||
|
|
@ -2001,7 +2002,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
|||
|
||||
switch (event->status) {
|
||||
case DEPEVT_STREAMEVT_FOUND:
|
||||
dev_vdbg(dwc->dev, "Stream %d found and started\n",
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"Stream %d found and started",
|
||||
event->parameters);
|
||||
|
||||
break;
|
||||
|
|
@ -2015,7 +2017,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
|||
dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
|
||||
break;
|
||||
case DWC3_DEPEVT_EPCMDCMPLT:
|
||||
dev_vdbg(dwc->dev, "Endpoint Command Complete\n");
|
||||
dwc3_trace(trace_dwc3_gadget, "Endpoint Command Complete");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -2043,6 +2045,7 @@ static void dwc3_resume_gadget(struct dwc3 *dwc)
|
|||
if (dwc->gadget_driver && dwc->gadget_driver->resume) {
|
||||
spin_unlock(&dwc->lock);
|
||||
dwc->gadget_driver->resume(&dwc->gadget);
|
||||
spin_lock(&dwc->lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2079,7 +2082,7 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
|
|||
* We have discussed this with the IP Provider and it was
|
||||
* suggested to giveback all requests here, but give HW some
|
||||
* extra time to synchronize with the interconnect. We're using
|
||||
* an arbitraty 100us delay for that.
|
||||
* an arbitrary 100us delay for that.
|
||||
*
|
||||
* Note also that a similar handling was tested by Synopsys
|
||||
* (thanks a lot Paul) and nothing bad has come out of it.
|
||||
|
|
@ -2389,7 +2392,8 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
|
|||
(pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
|
||||
if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
|
||||
(next == DWC3_LINK_STATE_RESUME)) {
|
||||
dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n");
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"ignoring transition U3 -> Resume");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -2511,22 +2515,22 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
|
|||
dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_EOPF:
|
||||
dev_vdbg(dwc->dev, "End of Periodic Frame\n");
|
||||
dwc3_trace(trace_dwc3_gadget, "End of Periodic Frame");
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_SOF:
|
||||
dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
|
||||
dwc3_trace(trace_dwc3_gadget, "Start of Periodic Frame");
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
|
||||
dev_vdbg(dwc->dev, "Erratic Error\n");
|
||||
dwc3_trace(trace_dwc3_gadget, "Erratic Error");
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_CMD_CMPL:
|
||||
dev_vdbg(dwc->dev, "Command Complete\n");
|
||||
dwc3_trace(trace_dwc3_gadget, "Command Complete");
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_OVERFLOW:
|
||||
dev_vdbg(dwc->dev, "Overflow\n");
|
||||
dwc3_trace(trace_dwc3_gadget, "Overflow");
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
|
||||
dev_WARN(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,16 @@ DEFINE_EVENT(dwc3_log_msg, dwc3_writel,
|
|||
TP_ARGS(vaf)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dwc3_log_msg, dwc3_gadget,
|
||||
TP_PROTO(struct va_format *vaf),
|
||||
TP_ARGS(vaf)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dwc3_log_msg, dwc3_core,
|
||||
TP_PROTO(struct va_format *vaf),
|
||||
TP_ARGS(vaf)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dwc3_log_msg, dwc3_ep0,
|
||||
TP_PROTO(struct va_format *vaf),
|
||||
TP_ARGS(vaf)
|
||||
|
|
|
|||
|
|
@ -423,6 +423,17 @@ config USB_CONFIGFS_F_HID
|
|||
|
||||
For more information, see Documentation/usb/gadget_hid.txt.
|
||||
|
||||
config USB_CONFIGFS_F_UVC
|
||||
bool "USB Webcam function"
|
||||
depends on USB_CONFIGFS
|
||||
depends on VIDEO_DEV
|
||||
select VIDEOBUF2_VMALLOC
|
||||
select USB_F_UVC
|
||||
help
|
||||
The Webcam function acts as a composite USB Audio and Video Class
|
||||
device. It provides a userspace API to process UVC control requests
|
||||
and stream video data to the host.
|
||||
|
||||
source "drivers/usb/gadget/legacy/Kconfig"
|
||||
|
||||
endchoice
|
||||
|
|
|
|||
|
|
@ -1655,7 +1655,7 @@ unknown:
|
|||
* OS descriptors handling
|
||||
*/
|
||||
if (cdev->use_os_string && cdev->os_desc_config &&
|
||||
(ctrl->bRequest & USB_TYPE_VENDOR) &&
|
||||
(ctrl->bRequestType & USB_TYPE_VENDOR) &&
|
||||
ctrl->bRequest == cdev->b_vendor_code) {
|
||||
struct usb_request *req;
|
||||
struct usb_configuration *os_desc_cfg;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ usb_f_uac1-y := f_uac1.o u_uac1.o
|
|||
obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o
|
||||
usb_f_uac2-y := f_uac2.o
|
||||
obj-$(CONFIG_USB_F_UAC2) += usb_f_uac2.o
|
||||
usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o
|
||||
usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_configfs.o
|
||||
obj-$(CONFIG_USB_F_UVC) += usb_f_uvc.o
|
||||
usb_f_midi-y := f_midi.o
|
||||
obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/aio.h>
|
||||
#include <linux/mmu_context.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/eventfd.h>
|
||||
|
||||
#include "u_fs.h"
|
||||
#include "u_f.h"
|
||||
|
|
@ -153,6 +154,8 @@ struct ffs_io_data {
|
|||
|
||||
struct usb_ep *ep;
|
||||
struct usb_request *req;
|
||||
|
||||
struct ffs_data *ffs;
|
||||
};
|
||||
|
||||
struct ffs_desc_helper {
|
||||
|
|
@ -390,17 +393,20 @@ done_spin:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */
|
||||
static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
|
||||
size_t n)
|
||||
{
|
||||
/*
|
||||
* We are holding ffs->ev.waitq.lock and ffs->mutex and we need
|
||||
* to release them.
|
||||
* n cannot be bigger than ffs->ev.count, which cannot be bigger than
|
||||
* size of ffs->ev.types array (which is four) so that's how much space
|
||||
* we reserve.
|
||||
*/
|
||||
struct usb_functionfs_event events[n];
|
||||
struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)];
|
||||
const size_t size = n * sizeof *events;
|
||||
unsigned i = 0;
|
||||
|
||||
memset(events, 0, sizeof events);
|
||||
memset(events, 0, size);
|
||||
|
||||
do {
|
||||
events[i].type = ffs->ev.types[i];
|
||||
|
|
@ -410,19 +416,15 @@ static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
|
|||
}
|
||||
} while (++i < n);
|
||||
|
||||
if (n < ffs->ev.count) {
|
||||
ffs->ev.count -= n;
|
||||
ffs->ev.count -= n;
|
||||
if (ffs->ev.count)
|
||||
memmove(ffs->ev.types, ffs->ev.types + n,
|
||||
ffs->ev.count * sizeof *ffs->ev.types);
|
||||
} else {
|
||||
ffs->ev.count = 0;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&ffs->ev.waitq.lock);
|
||||
mutex_unlock(&ffs->mutex);
|
||||
|
||||
return unlikely(__copy_to_user(buf, events, sizeof events))
|
||||
? -EFAULT : sizeof events;
|
||||
return unlikely(__copy_to_user(buf, events, size)) ? -EFAULT : size;
|
||||
}
|
||||
|
||||
static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
|
||||
|
|
@ -606,6 +608,8 @@ static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait)
|
|||
}
|
||||
case FFS_CLOSING:
|
||||
break;
|
||||
case FFS_DEACTIVATED:
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&ffs->mutex);
|
||||
|
|
@ -673,6 +677,9 @@ static void ffs_user_copy_worker(struct work_struct *work)
|
|||
|
||||
aio_complete(io_data->kiocb, ret, ret);
|
||||
|
||||
if (io_data->ffs->ffs_eventfd && !io_data->kiocb->ki_eventfd)
|
||||
eventfd_signal(io_data->ffs->ffs_eventfd, 1);
|
||||
|
||||
usb_ep_free_request(io_data->ep, io_data->req);
|
||||
|
||||
io_data->kiocb->private = NULL;
|
||||
|
|
@ -826,6 +833,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
|||
io_data->buf = data;
|
||||
io_data->ep = ep->ep;
|
||||
io_data->req = req;
|
||||
io_data->ffs = epfile->ffs;
|
||||
|
||||
req->context = io_data;
|
||||
req->complete = ffs_epfile_async_io_complete;
|
||||
|
|
@ -1180,6 +1188,7 @@ struct ffs_sb_fill_data {
|
|||
struct ffs_file_perms perms;
|
||||
umode_t root_mode;
|
||||
const char *dev_name;
|
||||
bool no_disconnect;
|
||||
struct ffs_data *ffs_data;
|
||||
};
|
||||
|
||||
|
|
@ -1250,6 +1259,12 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
|
|||
|
||||
/* Interpret option */
|
||||
switch (eq - opts) {
|
||||
case 13:
|
||||
if (!memcmp(opts, "no_disconnect", 13))
|
||||
data->no_disconnect = !!value;
|
||||
else
|
||||
goto invalid;
|
||||
break;
|
||||
case 5:
|
||||
if (!memcmp(opts, "rmode", 5))
|
||||
data->root_mode = (value & 0555) | S_IFDIR;
|
||||
|
|
@ -1314,6 +1329,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
|
|||
.gid = GLOBAL_ROOT_GID,
|
||||
},
|
||||
.root_mode = S_IFDIR | 0500,
|
||||
.no_disconnect = false,
|
||||
};
|
||||
struct dentry *rv;
|
||||
int ret;
|
||||
|
|
@ -1330,6 +1346,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
|
|||
if (unlikely(!ffs))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ffs->file_perms = data.perms;
|
||||
ffs->no_disconnect = data.no_disconnect;
|
||||
|
||||
ffs->dev_name = kstrdup(dev_name, GFP_KERNEL);
|
||||
if (unlikely(!ffs->dev_name)) {
|
||||
|
|
@ -1361,6 +1378,7 @@ ffs_fs_kill_sb(struct super_block *sb)
|
|||
kill_litter_super(sb);
|
||||
if (sb->s_fs_info) {
|
||||
ffs_release_dev(sb->s_fs_info);
|
||||
ffs_data_closed(sb->s_fs_info);
|
||||
ffs_data_put(sb->s_fs_info);
|
||||
}
|
||||
}
|
||||
|
|
@ -1417,7 +1435,11 @@ static void ffs_data_opened(struct ffs_data *ffs)
|
|||
ENTER();
|
||||
|
||||
atomic_inc(&ffs->ref);
|
||||
atomic_inc(&ffs->opened);
|
||||
if (atomic_add_return(1, &ffs->opened) == 1 &&
|
||||
ffs->state == FFS_DEACTIVATED) {
|
||||
ffs->state = FFS_CLOSING;
|
||||
ffs_data_reset(ffs);
|
||||
}
|
||||
}
|
||||
|
||||
static void ffs_data_put(struct ffs_data *ffs)
|
||||
|
|
@ -1439,6 +1461,21 @@ static void ffs_data_closed(struct ffs_data *ffs)
|
|||
ENTER();
|
||||
|
||||
if (atomic_dec_and_test(&ffs->opened)) {
|
||||
if (ffs->no_disconnect) {
|
||||
ffs->state = FFS_DEACTIVATED;
|
||||
if (ffs->epfiles) {
|
||||
ffs_epfiles_destroy(ffs->epfiles,
|
||||
ffs->eps_count);
|
||||
ffs->epfiles = NULL;
|
||||
}
|
||||
if (ffs->setup_state == FFS_SETUP_PENDING)
|
||||
__ffs_ep0_stall(ffs);
|
||||
} else {
|
||||
ffs->state = FFS_CLOSING;
|
||||
ffs_data_reset(ffs);
|
||||
}
|
||||
}
|
||||
if (atomic_read(&ffs->opened) < 0) {
|
||||
ffs->state = FFS_CLOSING;
|
||||
ffs_data_reset(ffs);
|
||||
}
|
||||
|
|
@ -1480,6 +1517,9 @@ static void ffs_data_clear(struct ffs_data *ffs)
|
|||
if (ffs->epfiles)
|
||||
ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
|
||||
|
||||
if (ffs->ffs_eventfd)
|
||||
eventfd_ctx_put(ffs->ffs_eventfd);
|
||||
|
||||
kfree(ffs->raw_descs_data);
|
||||
kfree(ffs->raw_strings);
|
||||
kfree(ffs->stringtabs);
|
||||
|
|
@ -1581,10 +1621,10 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
|
|||
mutex_init(&epfile->mutex);
|
||||
init_waitqueue_head(&epfile->wait);
|
||||
if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
|
||||
sprintf(epfiles->name, "ep%02x", ffs->eps_addrmap[i]);
|
||||
sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
|
||||
else
|
||||
sprintf(epfiles->name, "ep%u", i);
|
||||
epfile->dentry = ffs_sb_create_file(ffs->sb, epfiles->name,
|
||||
sprintf(epfile->name, "ep%u", i);
|
||||
epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
|
||||
epfile,
|
||||
&ffs_epfile_operations);
|
||||
if (unlikely(!epfile->dentry)) {
|
||||
|
|
@ -1616,7 +1656,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
|
|||
kfree(epfiles);
|
||||
}
|
||||
|
||||
|
||||
static void ffs_func_eps_disable(struct ffs_function *func)
|
||||
{
|
||||
struct ffs_ep *ep = func->eps;
|
||||
|
|
@ -1629,10 +1668,12 @@ static void ffs_func_eps_disable(struct ffs_function *func)
|
|||
/* pending requests get nuked */
|
||||
if (likely(ep->ep))
|
||||
usb_ep_disable(ep->ep);
|
||||
epfile->ep = NULL;
|
||||
|
||||
++ep;
|
||||
++epfile;
|
||||
|
||||
if (epfile) {
|
||||
epfile->ep = NULL;
|
||||
++epfile;
|
||||
}
|
||||
} while (--count);
|
||||
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
|
||||
}
|
||||
|
|
@ -2138,7 +2179,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
|
|||
FUNCTIONFS_HAS_HS_DESC |
|
||||
FUNCTIONFS_HAS_SS_DESC |
|
||||
FUNCTIONFS_HAS_MS_OS_DESC |
|
||||
FUNCTIONFS_VIRTUAL_ADDR)) {
|
||||
FUNCTIONFS_VIRTUAL_ADDR |
|
||||
FUNCTIONFS_EVENTFD)) {
|
||||
ret = -ENOSYS;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -2149,6 +2191,20 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (flags & FUNCTIONFS_EVENTFD) {
|
||||
if (len < 4)
|
||||
goto error;
|
||||
ffs->ffs_eventfd =
|
||||
eventfd_ctx_fdget((int)get_unaligned_le32(data));
|
||||
if (IS_ERR(ffs->ffs_eventfd)) {
|
||||
ret = PTR_ERR(ffs->ffs_eventfd);
|
||||
ffs->ffs_eventfd = NULL;
|
||||
goto error;
|
||||
}
|
||||
data += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
/* Read fs_count, hs_count and ss_count (if present) */
|
||||
for (i = 0; i < 3; ++i) {
|
||||
if (!(flags & (1 << i))) {
|
||||
|
|
@ -2377,6 +2433,13 @@ static void __ffs_event_add(struct ffs_data *ffs,
|
|||
if (ffs->setup_state == FFS_SETUP_PENDING)
|
||||
ffs->setup_state = FFS_SETUP_CANCELLED;
|
||||
|
||||
/*
|
||||
* Logic of this function guarantees that there are at most four pending
|
||||
* evens on ffs->ev.types queue. This is important because the queue
|
||||
* has space for four elements only and __ffs_ep0_read_events function
|
||||
* depends on that limit as well. If more event types are added, those
|
||||
* limits have to be revisited or guaranteed to still hold.
|
||||
*/
|
||||
switch (type) {
|
||||
case FUNCTIONFS_RESUME:
|
||||
rem_type2 = FUNCTIONFS_SUSPEND;
|
||||
|
|
@ -2416,6 +2479,8 @@ static void __ffs_event_add(struct ffs_data *ffs,
|
|||
pr_vdebug("adding event %d\n", type);
|
||||
ffs->ev.types[ffs->ev.count++] = type;
|
||||
wake_up_locked(&ffs->ev.waitq);
|
||||
if (ffs->ffs_eventfd)
|
||||
eventfd_signal(ffs->ffs_eventfd, 1);
|
||||
}
|
||||
|
||||
static void ffs_event_add(struct ffs_data *ffs,
|
||||
|
|
@ -2888,6 +2953,13 @@ static int ffs_func_bind(struct usb_configuration *c,
|
|||
|
||||
/* Other USB function hooks *************************************************/
|
||||
|
||||
static void ffs_reset_work(struct work_struct *work)
|
||||
{
|
||||
struct ffs_data *ffs = container_of(work,
|
||||
struct ffs_data, reset_work);
|
||||
ffs_data_reset(ffs);
|
||||
}
|
||||
|
||||
static int ffs_func_set_alt(struct usb_function *f,
|
||||
unsigned interface, unsigned alt)
|
||||
{
|
||||
|
|
@ -2904,6 +2976,13 @@ static int ffs_func_set_alt(struct usb_function *f,
|
|||
if (ffs->func)
|
||||
ffs_func_eps_disable(ffs->func);
|
||||
|
||||
if (ffs->state == FFS_DEACTIVATED) {
|
||||
ffs->state = FFS_CLOSING;
|
||||
INIT_WORK(&ffs->reset_work, ffs_reset_work);
|
||||
schedule_work(&ffs->reset_work);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (ffs->state != FFS_ACTIVE)
|
||||
return -ENODEV;
|
||||
|
||||
|
|
|
|||
|
|
@ -759,7 +759,7 @@ static struct f_hid_opts_attribute f_hid_opts_##name = \
|
|||
|
||||
F_HID_OPT(subclass, 8, 255);
|
||||
F_HID_OPT(protocol, 8, 255);
|
||||
F_HID_OPT(report_length, 16, 65536);
|
||||
F_HID_OPT(report_length, 16, 65535);
|
||||
|
||||
static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1214,7 +1214,7 @@ static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->pattern);
|
||||
result = sprintf(page, "%u", opts->pattern);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -1258,7 +1258,7 @@ static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->isoc_interval);
|
||||
result = sprintf(page, "%u", opts->isoc_interval);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -1302,7 +1302,7 @@ static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->isoc_maxpacket);
|
||||
result = sprintf(page, "%u", opts->isoc_maxpacket);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -1346,7 +1346,7 @@ static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->isoc_mult);
|
||||
result = sprintf(page, "%u", opts->isoc_mult);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -1390,7 +1390,7 @@ static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->isoc_maxburst);
|
||||
result = sprintf(page, "%u", opts->isoc_maxburst);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -1434,7 +1434,7 @@ static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->bulk_buflen);
|
||||
result = sprintf(page, "%u", opts->bulk_buflen);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -1473,7 +1473,7 @@ static ssize_t f_ss_opts_int_interval_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->int_interval);
|
||||
result = sprintf(page, "%u", opts->int_interval);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -1517,7 +1517,7 @@ static ssize_t f_ss_opts_int_maxpacket_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->int_maxpacket);
|
||||
result = sprintf(page, "%u", opts->int_maxpacket);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -1561,7 +1561,7 @@ static ssize_t f_ss_opts_int_mult_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->int_mult);
|
||||
result = sprintf(page, "%u", opts->int_mult);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
@ -1605,7 +1605,7 @@ static ssize_t f_ss_opts_int_maxburst_show(struct f_ss_opts *opts, char *page)
|
|||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->int_maxburst);
|
||||
result = sprintf(page, "%u", opts->int_maxburst);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
|
|||
*/
|
||||
#define F_AUDIO_AC_INTERFACE 0
|
||||
#define F_AUDIO_AS_INTERFACE 1
|
||||
#define F_AUDIO_NUM_INTERFACES 2
|
||||
#define F_AUDIO_NUM_INTERFACES 1
|
||||
|
||||
/* B.3.1 Standard AC Interface Descriptor */
|
||||
static struct usb_interface_descriptor ac_interface_desc = {
|
||||
|
|
@ -42,14 +42,18 @@ static struct usb_interface_descriptor ac_interface_desc = {
|
|||
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
|
||||
};
|
||||
|
||||
DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
|
||||
/*
|
||||
* The number of AudioStreaming and MIDIStreaming interfaces
|
||||
* in the Audio Interface Collection
|
||||
*/
|
||||
DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
|
||||
|
||||
#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
|
||||
/* 1 input terminal, 1 output terminal and 1 feature unit */
|
||||
#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
|
||||
+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
|
||||
/* B.3.2 Class-Specific AC Interface Descriptor */
|
||||
static struct uac1_ac_header_descriptor_2 ac_header_desc = {
|
||||
static struct uac1_ac_header_descriptor_1 ac_header_desc = {
|
||||
.bLength = UAC_DT_AC_HEADER_LENGTH,
|
||||
.bDescriptorType = USB_DT_CS_INTERFACE,
|
||||
.bDescriptorSubtype = UAC_HEADER,
|
||||
|
|
@ -57,8 +61,8 @@ static struct uac1_ac_header_descriptor_2 ac_header_desc = {
|
|||
.wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
|
||||
.bInCollection = F_AUDIO_NUM_INTERFACES,
|
||||
.baInterfaceNr = {
|
||||
[0] = F_AUDIO_AC_INTERFACE,
|
||||
[1] = F_AUDIO_AS_INTERFACE,
|
||||
/* Interface number of the first AudioStream interface */
|
||||
[0] = 1,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -584,6 +588,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
|
||||
if (intf == 1) {
|
||||
if (alt == 1) {
|
||||
config_ep_by_speed(cdev->gadget, f, out_ep);
|
||||
usb_ep_enable(out_ep);
|
||||
out_ep->driver_data = audio;
|
||||
audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
|
||||
|
|
@ -669,7 +674,6 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
|
||||
audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
|
||||
audio->card.gadget = c->cdev->gadget;
|
||||
audio_opts->card = &audio->card;
|
||||
/* set up ASLA audio devices */
|
||||
if (!audio_opts->bound) {
|
||||
status = gaudio_setup(&audio->card);
|
||||
|
|
|
|||
|
|
@ -27,10 +27,11 @@
|
|||
#include <media/v4l2-dev.h>
|
||||
#include <media/v4l2-event.h>
|
||||
|
||||
#include "u_uvc.h"
|
||||
#include "uvc.h"
|
||||
#include "uvc_configfs.h"
|
||||
#include "uvc_v4l2.h"
|
||||
#include "uvc_video.h"
|
||||
#include "u_uvc.h"
|
||||
|
||||
unsigned int uvc_gadget_trace_param;
|
||||
|
||||
|
|
@ -509,6 +510,9 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
|||
break;
|
||||
}
|
||||
|
||||
if (!uvc_control_desc || !uvc_streaming_cls)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
/* Descriptors layout
|
||||
*
|
||||
* uvc_iad
|
||||
|
|
@ -605,7 +609,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
|
||||
INFO(cdev, "uvc_function_bind\n");
|
||||
|
||||
opts = to_f_uvc_opts(f->fi);
|
||||
opts = fi_to_f_uvc_opts(f->fi);
|
||||
/* Sanity check the streaming endpoint module parameters.
|
||||
*/
|
||||
opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
|
||||
|
|
@ -700,10 +704,27 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
|||
|
||||
/* Copy descriptors */
|
||||
f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
|
||||
if (gadget_is_dualspeed(cdev->gadget))
|
||||
if (IS_ERR(f->fs_descriptors)) {
|
||||
ret = PTR_ERR(f->fs_descriptors);
|
||||
f->fs_descriptors = NULL;
|
||||
goto error;
|
||||
}
|
||||
if (gadget_is_dualspeed(cdev->gadget)) {
|
||||
f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
|
||||
if (gadget_is_superspeed(c->cdev->gadget))
|
||||
if (IS_ERR(f->hs_descriptors)) {
|
||||
ret = PTR_ERR(f->hs_descriptors);
|
||||
f->hs_descriptors = NULL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
|
||||
if (IS_ERR(f->ss_descriptors)) {
|
||||
ret = PTR_ERR(f->ss_descriptors);
|
||||
f->ss_descriptors = NULL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Preallocate control endpoint request. */
|
||||
uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
|
||||
|
|
@ -766,27 +787,106 @@ error:
|
|||
|
||||
static void uvc_free_inst(struct usb_function_instance *f)
|
||||
{
|
||||
struct f_uvc_opts *opts = to_f_uvc_opts(f);
|
||||
struct f_uvc_opts *opts = fi_to_f_uvc_opts(f);
|
||||
|
||||
mutex_destroy(&opts->lock);
|
||||
kfree(opts);
|
||||
}
|
||||
|
||||
static struct usb_function_instance *uvc_alloc_inst(void)
|
||||
{
|
||||
struct f_uvc_opts *opts;
|
||||
struct uvc_camera_terminal_descriptor *cd;
|
||||
struct uvc_processing_unit_descriptor *pd;
|
||||
struct uvc_output_terminal_descriptor *od;
|
||||
struct uvc_color_matching_descriptor *md;
|
||||
struct uvc_descriptor_header **ctl_cls;
|
||||
|
||||
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
|
||||
if (!opts)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
opts->func_inst.free_func_inst = uvc_free_inst;
|
||||
mutex_init(&opts->lock);
|
||||
|
||||
cd = &opts->uvc_camera_terminal;
|
||||
cd->bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3);
|
||||
cd->bDescriptorType = USB_DT_CS_INTERFACE;
|
||||
cd->bDescriptorSubType = UVC_VC_INPUT_TERMINAL;
|
||||
cd->bTerminalID = 1;
|
||||
cd->wTerminalType = cpu_to_le16(0x0201);
|
||||
cd->bAssocTerminal = 0;
|
||||
cd->iTerminal = 0;
|
||||
cd->wObjectiveFocalLengthMin = cpu_to_le16(0);
|
||||
cd->wObjectiveFocalLengthMax = cpu_to_le16(0);
|
||||
cd->wOcularFocalLength = cpu_to_le16(0);
|
||||
cd->bControlSize = 3;
|
||||
cd->bmControls[0] = 2;
|
||||
cd->bmControls[1] = 0;
|
||||
cd->bmControls[2] = 0;
|
||||
|
||||
pd = &opts->uvc_processing;
|
||||
pd->bLength = UVC_DT_PROCESSING_UNIT_SIZE(2);
|
||||
pd->bDescriptorType = USB_DT_CS_INTERFACE;
|
||||
pd->bDescriptorSubType = UVC_VC_PROCESSING_UNIT;
|
||||
pd->bUnitID = 2;
|
||||
pd->bSourceID = 1;
|
||||
pd->wMaxMultiplier = cpu_to_le16(16*1024);
|
||||
pd->bControlSize = 2;
|
||||
pd->bmControls[0] = 1;
|
||||
pd->bmControls[1] = 0;
|
||||
pd->iProcessing = 0;
|
||||
|
||||
od = &opts->uvc_output_terminal;
|
||||
od->bLength = UVC_DT_OUTPUT_TERMINAL_SIZE;
|
||||
od->bDescriptorType = USB_DT_CS_INTERFACE;
|
||||
od->bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL;
|
||||
od->bTerminalID = 3;
|
||||
od->wTerminalType = cpu_to_le16(0x0101);
|
||||
od->bAssocTerminal = 0;
|
||||
od->bSourceID = 2;
|
||||
od->iTerminal = 0;
|
||||
|
||||
md = &opts->uvc_color_matching;
|
||||
md->bLength = UVC_DT_COLOR_MATCHING_SIZE;
|
||||
md->bDescriptorType = USB_DT_CS_INTERFACE;
|
||||
md->bDescriptorSubType = UVC_VS_COLORFORMAT;
|
||||
md->bColorPrimaries = 1;
|
||||
md->bTransferCharacteristics = 1;
|
||||
md->bMatrixCoefficients = 4;
|
||||
|
||||
/* Prepare fs control class descriptors for configfs-based gadgets */
|
||||
ctl_cls = opts->uvc_fs_control_cls;
|
||||
ctl_cls[0] = NULL; /* assigned elsewhere by configfs */
|
||||
ctl_cls[1] = (struct uvc_descriptor_header *)cd;
|
||||
ctl_cls[2] = (struct uvc_descriptor_header *)pd;
|
||||
ctl_cls[3] = (struct uvc_descriptor_header *)od;
|
||||
ctl_cls[4] = NULL; /* NULL-terminate */
|
||||
opts->fs_control =
|
||||
(const struct uvc_descriptor_header * const *)ctl_cls;
|
||||
|
||||
/* Prepare hs control class descriptors for configfs-based gadgets */
|
||||
ctl_cls = opts->uvc_ss_control_cls;
|
||||
ctl_cls[0] = NULL; /* assigned elsewhere by configfs */
|
||||
ctl_cls[1] = (struct uvc_descriptor_header *)cd;
|
||||
ctl_cls[2] = (struct uvc_descriptor_header *)pd;
|
||||
ctl_cls[3] = (struct uvc_descriptor_header *)od;
|
||||
ctl_cls[4] = NULL; /* NULL-terminate */
|
||||
opts->ss_control =
|
||||
(const struct uvc_descriptor_header * const *)ctl_cls;
|
||||
|
||||
opts->streaming_interval = 1;
|
||||
opts->streaming_maxpacket = 1024;
|
||||
|
||||
uvcg_attach_configfs(opts);
|
||||
return &opts->func_inst;
|
||||
}
|
||||
|
||||
static void uvc_free(struct usb_function *f)
|
||||
{
|
||||
struct uvc_device *uvc = to_uvc(f);
|
||||
|
||||
struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts,
|
||||
func_inst);
|
||||
--opts->refcnt;
|
||||
kfree(uvc);
|
||||
}
|
||||
|
||||
|
|
@ -812,19 +912,39 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
|
|||
{
|
||||
struct uvc_device *uvc;
|
||||
struct f_uvc_opts *opts;
|
||||
struct uvc_descriptor_header **strm_cls;
|
||||
|
||||
uvc = kzalloc(sizeof(*uvc), GFP_KERNEL);
|
||||
if (uvc == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
uvc->state = UVC_STATE_DISCONNECTED;
|
||||
opts = to_f_uvc_opts(fi);
|
||||
opts = fi_to_f_uvc_opts(fi);
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
if (opts->uvc_fs_streaming_cls) {
|
||||
strm_cls = opts->uvc_fs_streaming_cls;
|
||||
opts->fs_streaming =
|
||||
(const struct uvc_descriptor_header * const *)strm_cls;
|
||||
}
|
||||
if (opts->uvc_hs_streaming_cls) {
|
||||
strm_cls = opts->uvc_hs_streaming_cls;
|
||||
opts->hs_streaming =
|
||||
(const struct uvc_descriptor_header * const *)strm_cls;
|
||||
}
|
||||
if (opts->uvc_ss_streaming_cls) {
|
||||
strm_cls = opts->uvc_ss_streaming_cls;
|
||||
opts->ss_streaming =
|
||||
(const struct uvc_descriptor_header * const *)strm_cls;
|
||||
}
|
||||
|
||||
uvc->desc.fs_control = opts->fs_control;
|
||||
uvc->desc.ss_control = opts->ss_control;
|
||||
uvc->desc.fs_streaming = opts->fs_streaming;
|
||||
uvc->desc.hs_streaming = opts->hs_streaming;
|
||||
uvc->desc.ss_streaming = opts->ss_streaming;
|
||||
++opts->refcnt;
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
/* Register the function. */
|
||||
uvc->func.name = "uvc";
|
||||
|
|
|
|||
|
|
@ -729,9 +729,7 @@ static int get_ether_addr_str(u8 dev_addr[ETH_ALEN], char *str, int len)
|
|||
if (len < 18)
|
||||
return -EINVAL;
|
||||
|
||||
snprintf(str, len, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
dev_addr[0], dev_addr[1], dev_addr[2],
|
||||
dev_addr[3], dev_addr[4], dev_addr[5]);
|
||||
snprintf(str, len, "%pM", dev_addr);
|
||||
return 18;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/usb/composite.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#ifndef pr_vdebug
|
||||
|
|
@ -92,6 +93,26 @@ enum ffs_state {
|
|||
*/
|
||||
FFS_ACTIVE,
|
||||
|
||||
/*
|
||||
* Function is visible to host, but it's not functional. All
|
||||
* setup requests are stalled and transfers on another endpoints
|
||||
* are refused. All epfiles, except ep0, are deleted so there
|
||||
* is no way to perform any operations on them.
|
||||
*
|
||||
* This state is set after closing all functionfs files, when
|
||||
* mount parameter "no_disconnect=1" has been set. Function will
|
||||
* remain in deactivated state until filesystem is umounted or
|
||||
* ep0 is opened again. In the second case functionfs state will
|
||||
* be reset, and it will be ready for descriptors and strings
|
||||
* writing.
|
||||
*
|
||||
* This is useful only when functionfs is composed to gadget
|
||||
* with another function which can perform some critical
|
||||
* operations, and it's strongly desired to have this operations
|
||||
* completed, even after functionfs files closure.
|
||||
*/
|
||||
FFS_DEACTIVATED,
|
||||
|
||||
/*
|
||||
* All endpoints have been closed. This state is also set if
|
||||
* we encounter an unrecoverable error. The only
|
||||
|
|
@ -251,6 +272,10 @@ struct ffs_data {
|
|||
kgid_t gid;
|
||||
} file_perms;
|
||||
|
||||
struct eventfd_ctx *ffs_eventfd;
|
||||
bool no_disconnect;
|
||||
struct work_struct reset_work;
|
||||
|
||||
/*
|
||||
* The endpoint files, filled by ffs_epfiles_create(),
|
||||
* destroyed by ffs_epfiles_destroy().
|
||||
|
|
|
|||
|
|
@ -308,8 +308,7 @@ int gaudio_setup(struct gaudio *card)
|
|||
*/
|
||||
void gaudio_cleanup(struct gaudio *the_card)
|
||||
{
|
||||
if (the_card) {
|
||||
if (the_card)
|
||||
gaudio_close_snd_dev(the_card);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@ struct f_uac1_opts {
|
|||
unsigned fn_play_alloc:1;
|
||||
unsigned fn_cap_alloc:1;
|
||||
unsigned fn_cntl_alloc:1;
|
||||
struct gaudio *card;
|
||||
struct mutex lock;
|
||||
int refcnt;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@
|
|||
#define U_UVC_H
|
||||
|
||||
#include <linux/usb/composite.h>
|
||||
#include <linux/usb/video.h>
|
||||
|
||||
#define to_f_uvc_opts(f) container_of(f, struct f_uvc_opts, func_inst)
|
||||
#define fi_to_f_uvc_opts(f) container_of(f, struct f_uvc_opts, func_inst)
|
||||
|
||||
struct f_uvc_opts {
|
||||
struct usb_function_instance func_inst;
|
||||
|
|
@ -26,11 +27,60 @@ struct f_uvc_opts {
|
|||
unsigned int streaming_interval;
|
||||
unsigned int streaming_maxpacket;
|
||||
unsigned int streaming_maxburst;
|
||||
|
||||
/*
|
||||
* Control descriptors array pointers for full-/high-speed and
|
||||
* super-speed. They point by default to the uvc_fs_control_cls and
|
||||
* uvc_ss_control_cls arrays respectively. Legacy gadgets must
|
||||
* override them in their gadget bind callback.
|
||||
*/
|
||||
const struct uvc_descriptor_header * const *fs_control;
|
||||
const struct uvc_descriptor_header * const *ss_control;
|
||||
|
||||
/*
|
||||
* Streaming descriptors array pointers for full-speed, high-speed and
|
||||
* super-speed. They will point to the uvc_[fhs]s_streaming_cls arrays
|
||||
* for configfs-based gadgets. Legacy gadgets must initialize them in
|
||||
* their gadget bind callback.
|
||||
*/
|
||||
const struct uvc_descriptor_header * const *fs_streaming;
|
||||
const struct uvc_descriptor_header * const *hs_streaming;
|
||||
const struct uvc_descriptor_header * const *ss_streaming;
|
||||
|
||||
/* Default control descriptors for configfs-based gadgets. */
|
||||
struct uvc_camera_terminal_descriptor uvc_camera_terminal;
|
||||
struct uvc_processing_unit_descriptor uvc_processing;
|
||||
struct uvc_output_terminal_descriptor uvc_output_terminal;
|
||||
struct uvc_color_matching_descriptor uvc_color_matching;
|
||||
|
||||
/*
|
||||
* Control descriptors pointers arrays for full-/high-speed and
|
||||
* super-speed. The first element is a configurable control header
|
||||
* descriptor, the other elements point to the fixed default control
|
||||
* descriptors. Used by configfs only, must not be touched by legacy
|
||||
* gadgets.
|
||||
*/
|
||||
struct uvc_descriptor_header *uvc_fs_control_cls[5];
|
||||
struct uvc_descriptor_header *uvc_ss_control_cls[5];
|
||||
|
||||
/*
|
||||
* Streaming descriptors for full-speed, high-speed and super-speed.
|
||||
* Used by configfs only, must not be touched by legacy gadgets. The
|
||||
* arrays are allocated at runtime as the number of descriptors isn't
|
||||
* known in advance.
|
||||
*/
|
||||
struct uvc_descriptor_header **uvc_fs_streaming_cls;
|
||||
struct uvc_descriptor_header **uvc_hs_streaming_cls;
|
||||
struct uvc_descriptor_header **uvc_ss_streaming_cls;
|
||||
|
||||
/*
|
||||
* Read/write access to configfs attributes is handled by configfs.
|
||||
*
|
||||
* This lock protects the descriptors from concurrent access by
|
||||
* read/write and symlink creation/removal.
|
||||
*/
|
||||
struct mutex lock;
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
void uvc_set_trace_param(unsigned int trace);
|
||||
|
|
|
|||
2468
drivers/usb/gadget/function/uvc_configfs.c
Normal file
2468
drivers/usb/gadget/function/uvc_configfs.c
Normal file
File diff suppressed because it is too large
Load diff
22
drivers/usb/gadget/function/uvc_configfs.h
Normal file
22
drivers/usb/gadget/function/uvc_configfs.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* uvc_configfs.h
|
||||
*
|
||||
* Configfs support for the uvc function.
|
||||
*
|
||||
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#ifndef UVC_CONFIGFS_H
|
||||
#define UVC_CONFIGFS_H
|
||||
|
||||
struct f_uvc_opts;
|
||||
|
||||
int uvcg_attach_configfs(struct f_uvc_opts *opts);
|
||||
|
||||
#endif /* UVC_CONFIGFS_H */
|
||||
|
|
@ -176,7 +176,7 @@ static int proc_udc_show(struct seq_file *s, void *unused)
|
|||
udc->enabled
|
||||
? (udc->vbus ? "active" : "enabled")
|
||||
: "disabled",
|
||||
udc->selfpowered ? "self" : "VBUS",
|
||||
udc->gadget.is_selfpowered ? "self" : "VBUS",
|
||||
udc->suspended ? ", suspended" : "",
|
||||
udc->driver ? udc->driver->driver.name : "(none)");
|
||||
|
||||
|
|
@ -1000,7 +1000,7 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
udc->selfpowered = (is_on != 0);
|
||||
gadget->is_selfpowered = (is_on != 0);
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1149,7 +1149,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
|
|||
*/
|
||||
case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
|
||||
| USB_REQ_GET_STATUS:
|
||||
tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
|
||||
tmp = (udc->gadget.is_selfpowered << USB_DEVICE_SELF_POWERED);
|
||||
if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
|
||||
tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
|
||||
PACKET("get device status\n");
|
||||
|
|
@ -1653,7 +1653,7 @@ static int at91_start(struct usb_gadget *gadget,
|
|||
udc->driver = driver;
|
||||
udc->gadget.dev.of_node = udc->pdev->dev.of_node;
|
||||
udc->enabled = 1;
|
||||
udc->selfpowered = 1;
|
||||
udc->gadget.is_selfpowered = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,6 @@ struct at91_udc {
|
|||
unsigned req_pending:1;
|
||||
unsigned wait_for_addr_ack:1;
|
||||
unsigned wait_for_config_ack:1;
|
||||
unsigned selfpowered:1;
|
||||
unsigned active_suspend:1;
|
||||
u8 addr;
|
||||
struct at91_udc_data board;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
|
@ -315,6 +316,17 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc)
|
|||
}
|
||||
#endif
|
||||
|
||||
static inline u32 usba_int_enb_get(struct usba_udc *udc)
|
||||
{
|
||||
return udc->int_enb_cache;
|
||||
}
|
||||
|
||||
static inline void usba_int_enb_set(struct usba_udc *udc, u32 val)
|
||||
{
|
||||
usba_writel(udc, INT_ENB, val);
|
||||
udc->int_enb_cache = val;
|
||||
}
|
||||
|
||||
static int vbus_is_present(struct usba_udc *udc)
|
||||
{
|
||||
if (gpio_is_valid(udc->vbus_pin))
|
||||
|
|
@ -324,27 +336,22 @@ static int vbus_is_present(struct usba_udc *udc)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ARCH_AT91SAM9RL)
|
||||
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
|
||||
static void toggle_bias(int is_on)
|
||||
static void toggle_bias(struct usba_udc *udc, int is_on)
|
||||
{
|
||||
unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
|
||||
|
||||
if (is_on)
|
||||
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
|
||||
else
|
||||
at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
|
||||
if (udc->errata && udc->errata->toggle_bias)
|
||||
udc->errata->toggle_bias(udc, is_on);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void toggle_bias(int is_on)
|
||||
static void generate_bias_pulse(struct usba_udc *udc)
|
||||
{
|
||||
}
|
||||
if (!udc->bias_pulse_needed)
|
||||
return;
|
||||
|
||||
#endif /* CONFIG_ARCH_AT91SAM9RL */
|
||||
if (udc->errata && udc->errata->pulse_bias)
|
||||
udc->errata->pulse_bias(udc);
|
||||
|
||||
udc->bias_pulse_needed = false;
|
||||
}
|
||||
|
||||
static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
|
||||
{
|
||||
|
|
@ -601,16 +608,14 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
|||
if (ep->can_dma) {
|
||||
u32 ctrl;
|
||||
|
||||
usba_writel(udc, INT_ENB,
|
||||
(usba_readl(udc, INT_ENB)
|
||||
| USBA_BF(EPT_INT, 1 << ep->index)
|
||||
| USBA_BF(DMA_INT, 1 << ep->index)));
|
||||
usba_int_enb_set(udc, usba_int_enb_get(udc) |
|
||||
USBA_BF(EPT_INT, 1 << ep->index) |
|
||||
USBA_BF(DMA_INT, 1 << ep->index));
|
||||
ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
|
||||
usba_ep_writel(ep, CTL_ENB, ctrl);
|
||||
} else {
|
||||
usba_writel(udc, INT_ENB,
|
||||
(usba_readl(udc, INT_ENB)
|
||||
| USBA_BF(EPT_INT, 1 << ep->index)));
|
||||
usba_int_enb_set(udc, usba_int_enb_get(udc) |
|
||||
USBA_BF(EPT_INT, 1 << ep->index));
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
|
@ -618,7 +623,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
|||
DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
|
||||
(unsigned long)usba_ep_readl(ep, CFG));
|
||||
DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
|
||||
(unsigned long)usba_readl(udc, INT_ENB));
|
||||
(unsigned long)usba_int_enb_get(udc));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -654,9 +659,8 @@ static int usba_ep_disable(struct usb_ep *_ep)
|
|||
usba_dma_readl(ep, STATUS);
|
||||
}
|
||||
usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
|
||||
usba_writel(udc, INT_ENB,
|
||||
usba_readl(udc, INT_ENB)
|
||||
& ~USBA_BF(EPT_INT, 1 << ep->index));
|
||||
usba_int_enb_set(udc, usba_int_enb_get(udc) &
|
||||
~USBA_BF(EPT_INT, 1 << ep->index));
|
||||
|
||||
request_complete_list(ep, &req_list, -ESHUTDOWN);
|
||||
|
||||
|
|
@ -985,6 +989,7 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
|
|||
struct usba_udc *udc = to_usba_udc(gadget);
|
||||
unsigned long flags;
|
||||
|
||||
gadget->is_selfpowered = (is_selfpowered != 0);
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
if (is_selfpowered)
|
||||
udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
|
||||
|
|
@ -1619,18 +1624,21 @@ static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
|
|||
static irqreturn_t usba_udc_irq(int irq, void *devid)
|
||||
{
|
||||
struct usba_udc *udc = devid;
|
||||
u32 status;
|
||||
u32 status, int_enb;
|
||||
u32 dma_status;
|
||||
u32 ep_status;
|
||||
|
||||
spin_lock(&udc->lock);
|
||||
|
||||
status = usba_readl(udc, INT_STA);
|
||||
int_enb = usba_int_enb_get(udc);
|
||||
status = usba_readl(udc, INT_STA) & int_enb;
|
||||
DBG(DBG_INT, "irq, status=%#08x\n", status);
|
||||
|
||||
if (status & USBA_DET_SUSPEND) {
|
||||
toggle_bias(0);
|
||||
toggle_bias(udc, 0);
|
||||
usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
|
||||
usba_int_enb_set(udc, int_enb | USBA_WAKE_UP);
|
||||
udc->bias_pulse_needed = true;
|
||||
DBG(DBG_BUS, "Suspend detected\n");
|
||||
if (udc->gadget.speed != USB_SPEED_UNKNOWN
|
||||
&& udc->driver && udc->driver->suspend) {
|
||||
|
|
@ -1641,13 +1649,15 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
|
|||
}
|
||||
|
||||
if (status & USBA_WAKE_UP) {
|
||||
toggle_bias(1);
|
||||
toggle_bias(udc, 1);
|
||||
usba_writel(udc, INT_CLR, USBA_WAKE_UP);
|
||||
usba_int_enb_set(udc, int_enb & ~USBA_WAKE_UP);
|
||||
DBG(DBG_BUS, "Wake Up CPU detected\n");
|
||||
}
|
||||
|
||||
if (status & USBA_END_OF_RESUME) {
|
||||
usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
|
||||
generate_bias_pulse(udc);
|
||||
DBG(DBG_BUS, "Resume detected\n");
|
||||
if (udc->gadget.speed != USB_SPEED_UNKNOWN
|
||||
&& udc->driver && udc->driver->resume) {
|
||||
|
|
@ -1683,6 +1693,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
|
|||
struct usba_ep *ep0;
|
||||
|
||||
usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
|
||||
generate_bias_pulse(udc);
|
||||
reset_all_endpoints(udc);
|
||||
|
||||
if (udc->gadget.speed != USB_SPEED_UNKNOWN && udc->driver) {
|
||||
|
|
@ -1708,11 +1719,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
|
|||
| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
|
||||
usba_ep_writel(ep0, CTL_ENB,
|
||||
USBA_EPT_ENABLE | USBA_RX_SETUP);
|
||||
usba_writel(udc, INT_ENB,
|
||||
(usba_readl(udc, INT_ENB)
|
||||
| USBA_BF(EPT_INT, 1)
|
||||
| USBA_DET_SUSPEND
|
||||
| USBA_END_OF_RESUME));
|
||||
usba_int_enb_set(udc, int_enb | USBA_BF(EPT_INT, 1) |
|
||||
USBA_DET_SUSPEND | USBA_END_OF_RESUME);
|
||||
|
||||
/*
|
||||
* Unclear why we hit this irregularly, e.g. in usbtest,
|
||||
|
|
@ -1745,13 +1753,13 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
|
|||
vbus = vbus_is_present(udc);
|
||||
if (vbus != udc->vbus_prev) {
|
||||
if (vbus) {
|
||||
toggle_bias(1);
|
||||
toggle_bias(udc, 1);
|
||||
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
|
||||
usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
|
||||
usba_int_enb_set(udc, USBA_END_OF_RESET);
|
||||
} else {
|
||||
udc->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
reset_all_endpoints(udc);
|
||||
toggle_bias(0);
|
||||
toggle_bias(udc, 0);
|
||||
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
|
||||
if (udc->driver->disconnect) {
|
||||
spin_unlock(&udc->lock);
|
||||
|
|
@ -1797,9 +1805,9 @@ static int atmel_usba_start(struct usb_gadget *gadget,
|
|||
/* If Vbus is present, enable the controller and wait for reset */
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
if (vbus_is_present(udc) && udc->vbus_prev == 0) {
|
||||
toggle_bias(1);
|
||||
toggle_bias(udc, 1);
|
||||
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
|
||||
usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
|
||||
usba_int_enb_set(udc, USBA_END_OF_RESET);
|
||||
}
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
||||
|
|
@ -1820,7 +1828,7 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
|
|||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
|
||||
/* This will also disable the DP pullup */
|
||||
toggle_bias(0);
|
||||
toggle_bias(udc, 0);
|
||||
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
|
||||
|
||||
clk_disable_unprepare(udc->hclk);
|
||||
|
|
@ -1832,6 +1840,41 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static void at91sam9rl_toggle_bias(struct usba_udc *udc, int is_on)
|
||||
{
|
||||
unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
|
||||
|
||||
if (is_on)
|
||||
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
|
||||
else
|
||||
at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
|
||||
}
|
||||
|
||||
static void at91sam9g45_pulse_bias(struct usba_udc *udc)
|
||||
{
|
||||
unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
|
||||
|
||||
at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
|
||||
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
|
||||
}
|
||||
|
||||
static const struct usba_udc_errata at91sam9rl_errata = {
|
||||
.toggle_bias = at91sam9rl_toggle_bias,
|
||||
};
|
||||
|
||||
static const struct usba_udc_errata at91sam9g45_errata = {
|
||||
.pulse_bias = at91sam9g45_pulse_bias,
|
||||
};
|
||||
|
||||
static const struct of_device_id atmel_udc_dt_ids[] = {
|
||||
{ .compatible = "atmel,at91sam9rl-udc", .data = &at91sam9rl_errata },
|
||||
{ .compatible = "atmel,at91sam9g45-udc", .data = &at91sam9g45_errata },
|
||||
{ .compatible = "atmel,sama5d3-udc" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
|
||||
|
||||
static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
|
||||
struct usba_udc *udc)
|
||||
{
|
||||
|
|
@ -1839,10 +1882,17 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
|
|||
const char *name;
|
||||
enum of_gpio_flags flags;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
const struct of_device_id *match;
|
||||
struct device_node *pp;
|
||||
int i, ret;
|
||||
struct usba_ep *eps, *ep;
|
||||
|
||||
match = of_match_node(atmel_udc_dt_ids, np);
|
||||
if (!match)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
udc->errata = match->data;
|
||||
|
||||
udc->num_ep = 0;
|
||||
|
||||
udc->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
|
||||
|
|
@ -2033,7 +2083,7 @@ static int usba_udc_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n");
|
||||
return ret;
|
||||
}
|
||||
toggle_bias(0);
|
||||
|
||||
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
|
||||
clk_disable_unprepare(pclk);
|
||||
|
||||
|
|
@ -2042,6 +2092,8 @@ static int usba_udc_probe(struct platform_device *pdev)
|
|||
else
|
||||
udc->usba_ep = usba_udc_pdata(pdev, udc);
|
||||
|
||||
toggle_bias(udc, 0);
|
||||
|
||||
if (IS_ERR(udc->usba_ep))
|
||||
return PTR_ERR(udc->usba_ep);
|
||||
|
||||
|
|
@ -2101,15 +2153,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id atmel_udc_dt_ids[] = {
|
||||
{ .compatible = "atmel,at91sam9rl-udc" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver udc_driver = {
|
||||
.remove = __exit_p(usba_udc_remove),
|
||||
.driver = {
|
||||
|
|
|
|||
|
|
@ -304,6 +304,11 @@ struct usba_request {
|
|||
unsigned int mapped:1;
|
||||
};
|
||||
|
||||
struct usba_udc_errata {
|
||||
void (*toggle_bias)(struct usba_udc *udc, int is_on);
|
||||
void (*pulse_bias)(struct usba_udc *udc);
|
||||
};
|
||||
|
||||
struct usba_udc {
|
||||
/* Protect hw registers from concurrent modifications */
|
||||
spinlock_t lock;
|
||||
|
|
@ -314,6 +319,7 @@ struct usba_udc {
|
|||
struct usb_gadget gadget;
|
||||
struct usb_gadget_driver *driver;
|
||||
struct platform_device *pdev;
|
||||
const struct usba_udc_errata *errata;
|
||||
int irq;
|
||||
int vbus_pin;
|
||||
int vbus_pin_inverted;
|
||||
|
|
@ -321,12 +327,15 @@ struct usba_udc {
|
|||
struct clk *pclk;
|
||||
struct clk *hclk;
|
||||
struct usba_ep *usba_ep;
|
||||
bool bias_pulse_needed;
|
||||
|
||||
u16 devstatus;
|
||||
|
||||
u16 test_mode;
|
||||
int vbus_prev;
|
||||
|
||||
u32 int_enb_cache;
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_DEBUG_FS
|
||||
struct dentry *debugfs_root;
|
||||
struct dentry *debugfs_regs;
|
||||
|
|
|
|||
|
|
@ -521,7 +521,6 @@ static int bdc_remove(struct platform_device *pdev)
|
|||
static struct platform_driver bdc_driver = {
|
||||
.driver = {
|
||||
.name = BRCM_BDC_NAME,
|
||||
.owner = THIS_MODULE
|
||||
},
|
||||
.probe = bdc_probe,
|
||||
.remove = bdc_remove,
|
||||
|
|
|
|||
|
|
@ -718,7 +718,7 @@ static int ep_queue(struct bdc_ep *ep, struct bdc_req *req)
|
|||
struct bdc *bdc;
|
||||
int ret = 0;
|
||||
|
||||
if (!req || !ep || !ep->usb_ep.desc)
|
||||
if (!req || !ep->usb_ep.desc)
|
||||
return -EINVAL;
|
||||
|
||||
bdc = ep->bdc;
|
||||
|
|
@ -882,8 +882,8 @@ static int ep_set_halt(struct bdc_ep *ep, u32 value)
|
|||
|
||||
ret = bdc_ep_set_stall(bdc, ep->ep_num);
|
||||
if (ret)
|
||||
dev_err(bdc->dev, "failed to %s STALL on %s\n",
|
||||
value ? "set" : "clear", ep->name);
|
||||
dev_err(bdc->dev, "failed to set STALL on %s\n",
|
||||
ep->name);
|
||||
else
|
||||
ep->flags |= BDC_EP_STALL;
|
||||
} else {
|
||||
|
|
@ -891,8 +891,8 @@ static int ep_set_halt(struct bdc_ep *ep, u32 value)
|
|||
dev_dbg(bdc->dev, "Before Clear\n");
|
||||
ret = bdc_ep_clear_stall(bdc, ep->ep_num);
|
||||
if (ret)
|
||||
dev_err(bdc->dev, "failed to %s STALL on %s\n",
|
||||
value ? "set" : "clear", ep->name);
|
||||
dev_err(bdc->dev, "failed to clear STALL on %s\n",
|
||||
ep->name);
|
||||
else
|
||||
ep->flags &= ~BDC_EP_STALL;
|
||||
dev_dbg(bdc->dev, "After Clear\n");
|
||||
|
|
|
|||
|
|
@ -454,6 +454,7 @@ static int bdc_udc_set_selfpowered(struct usb_gadget *gadget,
|
|||
unsigned long flags;
|
||||
|
||||
dev_dbg(bdc->dev, "%s()\n", __func__);
|
||||
gadget->is_selfpowered = (is_self != 0);
|
||||
spin_lock_irqsave(&bdc->lock, flags);
|
||||
if (!is_self)
|
||||
bdc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
|
||||
|
|
|
|||
|
|
@ -802,6 +802,7 @@ static int dummy_set_selfpowered(struct usb_gadget *_gadget, int value)
|
|||
{
|
||||
struct dummy *dum;
|
||||
|
||||
_gadget->is_selfpowered = (value != 0);
|
||||
dum = gadget_to_dummy_hcd(_gadget)->dum;
|
||||
if (value)
|
||||
dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
|
||||
|
|
@ -1924,7 +1925,9 @@ ss_hub_descriptor(struct usb_hub_descriptor *desc)
|
|||
memset(desc, 0, sizeof *desc);
|
||||
desc->bDescriptorType = 0x2a;
|
||||
desc->bDescLength = 12;
|
||||
desc->wHubCharacteristics = cpu_to_le16(0x0001);
|
||||
desc->wHubCharacteristics = cpu_to_le16(
|
||||
HUB_CHAR_INDV_PORT_LPSM |
|
||||
HUB_CHAR_COMMON_OCPM);
|
||||
desc->bNbrPorts = 1;
|
||||
desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
|
||||
desc->u.ss.DeviceRemovable = 0xffff;
|
||||
|
|
@ -1935,7 +1938,9 @@ static inline void hub_descriptor(struct usb_hub_descriptor *desc)
|
|||
memset(desc, 0, sizeof *desc);
|
||||
desc->bDescriptorType = 0x29;
|
||||
desc->bDescLength = 9;
|
||||
desc->wHubCharacteristics = cpu_to_le16(0x0001);
|
||||
desc->wHubCharacteristics = cpu_to_le16(
|
||||
HUB_CHAR_INDV_PORT_LPSM |
|
||||
HUB_CHAR_COMMON_OCPM);
|
||||
desc->bNbrPorts = 1;
|
||||
desc->u.hs.DeviceRemovable[0] = 0xff;
|
||||
desc->u.hs.DeviceRemovable[1] = 0xff;
|
||||
|
|
|
|||
|
|
@ -2630,7 +2630,7 @@ static int qe_udc_remove(struct platform_device *ofdev)
|
|||
struct qe_udc *udc = platform_get_drvdata(ofdev);
|
||||
struct qe_ep *ep;
|
||||
unsigned int size;
|
||||
DECLARE_COMPLETION(done);
|
||||
DECLARE_COMPLETION_ONSTACK(done);
|
||||
|
||||
usb_del_gadget_udc(&udc->gadget);
|
||||
|
||||
|
|
|
|||
|
|
@ -1337,7 +1337,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
|
|||
|
||||
if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
|
||||
/* Get device status */
|
||||
tmp = 1 << USB_DEVICE_SELF_POWERED;
|
||||
tmp = udc->gadget.is_selfpowered;
|
||||
tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
|
||||
} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
|
||||
/* Get interface status */
|
||||
|
|
@ -1948,6 +1948,7 @@ static int fsl_udc_start(struct usb_gadget *g,
|
|||
/* hook up the driver */
|
||||
udc_controller->driver = driver;
|
||||
spin_unlock_irqrestore(&udc_controller->lock, flags);
|
||||
g->is_selfpowered = 1;
|
||||
|
||||
if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
|
||||
/* Suspend the controller until OTG enable it */
|
||||
|
|
@ -2529,7 +2530,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
|
|||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
DECLARE_COMPLETION(done);
|
||||
DECLARE_COMPLETION_ONSTACK(done);
|
||||
|
||||
if (!udc_controller)
|
||||
return -ENODEV;
|
||||
|
|
|
|||
|
|
@ -191,7 +191,6 @@ struct lpc32xx_udc {
|
|||
bool enabled;
|
||||
bool clocked;
|
||||
bool suspended;
|
||||
bool selfpowered;
|
||||
int ep0state;
|
||||
atomic_t enabled_ep_cnt;
|
||||
wait_queue_head_t ep_disable_wait_queue;
|
||||
|
|
@ -547,7 +546,7 @@ static int proc_udc_show(struct seq_file *s, void *unused)
|
|||
udc->vbus ? "present" : "off",
|
||||
udc->enabled ? (udc->vbus ? "active" : "enabled") :
|
||||
"disabled",
|
||||
udc->selfpowered ? "self" : "VBUS",
|
||||
udc->gadget.is_selfpowered ? "self" : "VBUS",
|
||||
udc->suspended ? ", suspended" : "",
|
||||
udc->driver ? udc->driver->driver.name : "(none)");
|
||||
|
||||
|
|
@ -2212,7 +2211,7 @@ static int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex)
|
|||
break; /* Not supported */
|
||||
|
||||
case USB_RECIP_DEVICE:
|
||||
ep0buff = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
|
||||
ep0buff = udc->gadget.is_selfpowered;
|
||||
if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP))
|
||||
ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP);
|
||||
break;
|
||||
|
|
@ -2498,10 +2497,7 @@ static int lpc32xx_wakeup(struct usb_gadget *gadget)
|
|||
|
||||
static int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on)
|
||||
{
|
||||
struct lpc32xx_udc *udc = to_udc(gadget);
|
||||
|
||||
/* Always self-powered */
|
||||
udc->selfpowered = (is_on != 0);
|
||||
gadget->is_selfpowered = (is_on != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2946,7 +2942,7 @@ static int lpc32xx_start(struct usb_gadget *gadget,
|
|||
udc->driver = driver;
|
||||
udc->gadget.dev.of_node = udc->dev->of_node;
|
||||
udc->enabled = 1;
|
||||
udc->selfpowered = 1;
|
||||
udc->gadget.is_selfpowered = 1;
|
||||
udc->vbus = 0;
|
||||
|
||||
/* Force VBUS process once to check for cable insertion */
|
||||
|
|
|
|||
|
|
@ -1378,9 +1378,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
|
|||
}
|
||||
}
|
||||
|
||||
/* pullup is always on */
|
||||
mv_udc_pullup(&udc->gadget, 1);
|
||||
|
||||
/* When boot with cable attached, there will be no vbus irq occurred */
|
||||
if (udc->qwork)
|
||||
queue_work(udc->qwork, &udc->vbus_work);
|
||||
|
|
|
|||
|
|
@ -1132,13 +1132,10 @@ net2272_wakeup(struct usb_gadget *_gadget)
|
|||
static int
|
||||
net2272_set_selfpowered(struct usb_gadget *_gadget, int value)
|
||||
{
|
||||
struct net2272 *dev;
|
||||
|
||||
if (!_gadget)
|
||||
return -ENODEV;
|
||||
dev = container_of(_gadget, struct net2272, gadget);
|
||||
|
||||
dev->is_selfpowered = value;
|
||||
_gadget->is_selfpowered = (value != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1844,7 +1841,7 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat)
|
|||
case USB_RECIP_DEVICE:
|
||||
if (u.r.wLength > 2)
|
||||
goto do_stall;
|
||||
if (dev->is_selfpowered)
|
||||
if (dev->gadget.is_selfpowered)
|
||||
status = (1 << USB_DEVICE_SELF_POWERED);
|
||||
|
||||
/* don't bother with a request object! */
|
||||
|
|
|
|||
|
|
@ -458,7 +458,6 @@ struct net2272 {
|
|||
struct usb_gadget_driver *driver;
|
||||
unsigned protocol_stall:1,
|
||||
softconnect:1,
|
||||
is_selfpowered:1,
|
||||
wakeup:1,
|
||||
dma_eot_polarity:1,
|
||||
dma_dack_polarity:1,
|
||||
|
|
|
|||
|
|
@ -12,11 +12,7 @@
|
|||
* the Mass Storage, Serial, and Ethernet/RNDIS gadget drivers
|
||||
* as well as Gadget Zero and Gadgetfs.
|
||||
*
|
||||
* DMA is enabled by default. Drivers using transfer queues might use
|
||||
* DMA chaining to remove IRQ latencies between transfers. (Except when
|
||||
* short OUT transfers happen.) Drivers can use the req->no_interrupt
|
||||
* hint to completely eliminate some IRQs, if a later IRQ is guaranteed
|
||||
* and DMA chaining is enabled.
|
||||
* DMA is enabled by default.
|
||||
*
|
||||
* MSI is enabled by default. The legacy IRQ is used if MSI couldn't
|
||||
* be enabled.
|
||||
|
|
@ -84,23 +80,6 @@ static const char *const ep_name[] = {
|
|||
"ep-e", "ep-f", "ep-g", "ep-h",
|
||||
};
|
||||
|
||||
/* use_dma -- general goodness, fewer interrupts, less cpu load (vs PIO)
|
||||
* use_dma_chaining -- dma descriptor queueing gives even more irq reduction
|
||||
*
|
||||
* The net2280 DMA engines are not tightly integrated with their FIFOs;
|
||||
* not all cases are (yet) handled well in this driver or the silicon.
|
||||
* Some gadget drivers work better with the dma support here than others.
|
||||
* These two parameters let you use PIO or more aggressive DMA.
|
||||
*/
|
||||
static bool use_dma = true;
|
||||
static bool use_dma_chaining;
|
||||
static bool use_msi = true;
|
||||
|
||||
/* "modprobe net2280 use_dma=n" etc */
|
||||
module_param(use_dma, bool, 0444);
|
||||
module_param(use_dma_chaining, bool, 0444);
|
||||
module_param(use_msi, bool, 0444);
|
||||
|
||||
/* mode 0 == ep-{a,b,c,d} 1K fifo each
|
||||
* mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable
|
||||
* mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable
|
||||
|
|
@ -120,11 +99,6 @@ static bool enable_suspend;
|
|||
/* "modprobe net2280 enable_suspend=1" etc */
|
||||
module_param(enable_suspend, bool, 0444);
|
||||
|
||||
/* force full-speed operation */
|
||||
static bool full_speed;
|
||||
module_param(full_speed, bool, 0444);
|
||||
MODULE_PARM_DESC(full_speed, "force full-speed mode -- for testing only!");
|
||||
|
||||
#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
|
||||
|
||||
static char *type_string(u8 bmAttributes)
|
||||
|
|
@ -202,15 +176,6 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
|||
/* set speed-dependent max packet; may kick in high bandwidth */
|
||||
set_max_speed(ep, max);
|
||||
|
||||
/* FIFO lines can't go to different packets. PIO is ok, so
|
||||
* use it instead of troublesome (non-bulk) multi-packet DMA.
|
||||
*/
|
||||
if (ep->dma && (max % 4) != 0 && use_dma_chaining) {
|
||||
ep_dbg(ep->dev, "%s, no dma for maxpacket %d\n",
|
||||
ep->ep.name, ep->ep.maxpacket);
|
||||
ep->dma = NULL;
|
||||
}
|
||||
|
||||
/* set type, direction, address; reset fifo counters */
|
||||
writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat);
|
||||
tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
|
||||
|
|
@ -478,7 +443,7 @@ static int net2280_disable(struct usb_ep *_ep)
|
|||
/* synch memory views with the device */
|
||||
(void)readl(&ep->cfg->ep_cfg);
|
||||
|
||||
if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4)
|
||||
if (!ep->dma && ep->num >= 1 && ep->num <= 4)
|
||||
ep->dma = &ep->dev->dma[ep->num - 1];
|
||||
|
||||
spin_unlock_irqrestore(&ep->dev->lock, flags);
|
||||
|
|
@ -610,9 +575,15 @@ static void out_flush(struct net2280_ep *ep)
|
|||
u32 __iomem *statp;
|
||||
u32 tmp;
|
||||
|
||||
ASSERT_OUT_NAKING(ep);
|
||||
|
||||
statp = &ep->regs->ep_stat;
|
||||
|
||||
tmp = readl(statp);
|
||||
if (tmp & BIT(NAK_OUT_PACKETS)) {
|
||||
ep_dbg(ep->dev, "%s %s %08x !NAK\n",
|
||||
ep->ep.name, __func__, tmp);
|
||||
writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
|
||||
}
|
||||
|
||||
writel(BIT(DATA_OUT_PING_TOKEN_INTERRUPT) |
|
||||
BIT(DATA_PACKET_RECEIVED_INTERRUPT),
|
||||
statp);
|
||||
|
|
@ -747,8 +718,7 @@ static void fill_dma_desc(struct net2280_ep *ep,
|
|||
req->valid = valid;
|
||||
if (valid)
|
||||
dmacount |= BIT(VALID_BIT);
|
||||
if (likely(!req->req.no_interrupt || !use_dma_chaining))
|
||||
dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE);
|
||||
dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE);
|
||||
|
||||
/* td->dmadesc = previously set by caller */
|
||||
td->dmaaddr = cpu_to_le32 (req->req.dma);
|
||||
|
|
@ -862,27 +832,11 @@ static void start_dma(struct net2280_ep *ep, struct net2280_request *req)
|
|||
req->td->dmadesc = cpu_to_le32 (ep->td_dma);
|
||||
fill_dma_desc(ep, req, 1);
|
||||
|
||||
if (!use_dma_chaining)
|
||||
req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN));
|
||||
req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN));
|
||||
|
||||
start_queue(ep, tmp, req->td_dma);
|
||||
}
|
||||
|
||||
static inline void resume_dma(struct net2280_ep *ep)
|
||||
{
|
||||
writel(readl(&ep->dma->dmactl) | BIT(DMA_ENABLE), &ep->dma->dmactl);
|
||||
|
||||
ep->dma_started = true;
|
||||
}
|
||||
|
||||
static inline void ep_stop_dma(struct net2280_ep *ep)
|
||||
{
|
||||
writel(readl(&ep->dma->dmactl) & ~BIT(DMA_ENABLE), &ep->dma->dmactl);
|
||||
spin_stop_dma(ep->dma);
|
||||
|
||||
ep->dma_started = false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
queue_dma(struct net2280_ep *ep, struct net2280_request *req, int valid)
|
||||
{
|
||||
|
|
@ -973,10 +927,8 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
ep_vdbg(dev, "%s queue req %p, len %d buf %p\n",
|
||||
_ep->name, _req, _req->length, _req->buf);
|
||||
#endif
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
|
||||
|
|
@ -984,24 +936,12 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
|||
_req->actual = 0;
|
||||
|
||||
/* kickstart this i/o queue? */
|
||||
if (list_empty(&ep->queue) && !ep->stopped) {
|
||||
/* DMA request while EP halted */
|
||||
if (ep->dma &&
|
||||
(readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)) &&
|
||||
(dev->quirks & PLX_SUPERSPEED)) {
|
||||
int valid = 1;
|
||||
if (ep->is_in) {
|
||||
int expect;
|
||||
expect = likely(req->req.zero ||
|
||||
((req->req.length %
|
||||
ep->ep.maxpacket) != 0));
|
||||
if (expect != ep->in_fifo_validate)
|
||||
valid = 0;
|
||||
}
|
||||
queue_dma(ep, req, valid);
|
||||
}
|
||||
if (list_empty(&ep->queue) && !ep->stopped &&
|
||||
!((dev->quirks & PLX_SUPERSPEED) && ep->dma &&
|
||||
(readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)))) {
|
||||
|
||||
/* use DMA if the endpoint supports it, else pio */
|
||||
else if (ep->dma)
|
||||
if (ep->dma)
|
||||
start_dma(ep, req);
|
||||
else {
|
||||
/* maybe there's no control data, just status ack */
|
||||
|
|
@ -1084,8 +1024,6 @@ dma_done(struct net2280_ep *ep, struct net2280_request *req, u32 dmacount,
|
|||
done(ep, req, status);
|
||||
}
|
||||
|
||||
static void restart_dma(struct net2280_ep *ep);
|
||||
|
||||
static void scan_dma_completions(struct net2280_ep *ep)
|
||||
{
|
||||
/* only look at descriptors that were "naturally" retired,
|
||||
|
|
@ -1117,9 +1055,8 @@ static void scan_dma_completions(struct net2280_ep *ep)
|
|||
dma_done(ep, req, tmp, 0);
|
||||
break;
|
||||
} else if (!ep->is_in &&
|
||||
(req->req.length % ep->ep.maxpacket) != 0) {
|
||||
if (ep->dev->quirks & PLX_SUPERSPEED)
|
||||
return dma_done(ep, req, tmp, 0);
|
||||
(req->req.length % ep->ep.maxpacket) &&
|
||||
!(ep->dev->quirks & PLX_SUPERSPEED)) {
|
||||
|
||||
tmp = readl(&ep->regs->ep_stat);
|
||||
/* AVOID TROUBLE HERE by not issuing short reads from
|
||||
|
|
@ -1150,67 +1087,15 @@ static void scan_dma_completions(struct net2280_ep *ep)
|
|||
static void restart_dma(struct net2280_ep *ep)
|
||||
{
|
||||
struct net2280_request *req;
|
||||
u32 dmactl = dmactl_default;
|
||||
|
||||
if (ep->stopped)
|
||||
return;
|
||||
req = list_entry(ep->queue.next, struct net2280_request, queue);
|
||||
|
||||
if (!use_dma_chaining) {
|
||||
start_dma(ep, req);
|
||||
return;
|
||||
}
|
||||
|
||||
/* the 2280 will be processing the queue unless queue hiccups after
|
||||
* the previous transfer:
|
||||
* IN: wanted automagic zlp, head doesn't (or vice versa)
|
||||
* DMA_FIFO_VALIDATE doesn't init from dma descriptors.
|
||||
* OUT: was "usb-short", we must restart.
|
||||
*/
|
||||
if (ep->is_in && !req->valid) {
|
||||
struct net2280_request *entry, *prev = NULL;
|
||||
int reqmode, done = 0;
|
||||
|
||||
ep_dbg(ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td);
|
||||
ep->in_fifo_validate = likely(req->req.zero ||
|
||||
(req->req.length % ep->ep.maxpacket) != 0);
|
||||
if (ep->in_fifo_validate)
|
||||
dmactl |= BIT(DMA_FIFO_VALIDATE);
|
||||
list_for_each_entry(entry, &ep->queue, queue) {
|
||||
__le32 dmacount;
|
||||
|
||||
if (entry == req)
|
||||
continue;
|
||||
dmacount = entry->td->dmacount;
|
||||
if (!done) {
|
||||
reqmode = likely(entry->req.zero ||
|
||||
(entry->req.length % ep->ep.maxpacket));
|
||||
if (reqmode == ep->in_fifo_validate) {
|
||||
entry->valid = 1;
|
||||
dmacount |= valid_bit;
|
||||
entry->td->dmacount = dmacount;
|
||||
prev = entry;
|
||||
continue;
|
||||
} else {
|
||||
/* force a hiccup */
|
||||
prev->td->dmacount |= dma_done_ie;
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* walk the rest of the queue so unlinks behave */
|
||||
entry->valid = 0;
|
||||
dmacount &= ~valid_bit;
|
||||
entry->td->dmacount = dmacount;
|
||||
prev = entry;
|
||||
}
|
||||
}
|
||||
|
||||
writel(0, &ep->dma->dmactl);
|
||||
start_queue(ep, dmactl, req->td_dma);
|
||||
start_dma(ep, req);
|
||||
}
|
||||
|
||||
static void abort_dma_228x(struct net2280_ep *ep)
|
||||
static void abort_dma(struct net2280_ep *ep)
|
||||
{
|
||||
/* abort the current transfer */
|
||||
if (likely(!list_empty(&ep->queue))) {
|
||||
|
|
@ -1222,19 +1107,6 @@ static void abort_dma_228x(struct net2280_ep *ep)
|
|||
scan_dma_completions(ep);
|
||||
}
|
||||
|
||||
static void abort_dma_338x(struct net2280_ep *ep)
|
||||
{
|
||||
writel(BIT(DMA_ABORT), &ep->dma->dmastat);
|
||||
spin_stop_dma(ep->dma);
|
||||
}
|
||||
|
||||
static void abort_dma(struct net2280_ep *ep)
|
||||
{
|
||||
if (ep->dev->quirks & PLX_LEGACY)
|
||||
return abort_dma_228x(ep);
|
||||
return abort_dma_338x(ep);
|
||||
}
|
||||
|
||||
/* dequeue ALL requests */
|
||||
static void nuke(struct net2280_ep *ep)
|
||||
{
|
||||
|
|
@ -1306,25 +1178,6 @@ static int net2280_dequeue(struct usb_ep *_ep, struct usb_request *_req)
|
|||
done(ep, req, -ECONNRESET);
|
||||
}
|
||||
req = NULL;
|
||||
|
||||
/* patch up hardware chaining data */
|
||||
} else if (ep->dma && use_dma_chaining) {
|
||||
if (req->queue.prev == ep->queue.next) {
|
||||
writel(le32_to_cpu(req->td->dmadesc),
|
||||
&ep->dma->dmadesc);
|
||||
if (req->td->dmacount & dma_done_ie)
|
||||
writel(readl(&ep->dma->dmacount) |
|
||||
le32_to_cpu(dma_done_ie),
|
||||
&ep->dma->dmacount);
|
||||
} else {
|
||||
struct net2280_request *prev;
|
||||
|
||||
prev = list_entry(req->queue.prev,
|
||||
struct net2280_request, queue);
|
||||
prev->td->dmadesc = req->td->dmadesc;
|
||||
if (req->td->dmacount & dma_done_ie)
|
||||
prev->td->dmacount |= dma_done_ie;
|
||||
}
|
||||
}
|
||||
|
||||
if (req)
|
||||
|
|
@ -1512,10 +1365,10 @@ static int net2280_set_selfpowered(struct usb_gadget *_gadget, int value)
|
|||
tmp = readl(&dev->usb->usbctl);
|
||||
if (value) {
|
||||
tmp |= BIT(SELF_POWERED_STATUS);
|
||||
dev->selfpowered = 1;
|
||||
_gadget->is_selfpowered = 1;
|
||||
} else {
|
||||
tmp &= ~BIT(SELF_POWERED_STATUS);
|
||||
dev->selfpowered = 0;
|
||||
_gadget->is_selfpowered = 0;
|
||||
}
|
||||
writel(tmp, &dev->usb->usbctl);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
|
@ -1604,14 +1457,11 @@ static ssize_t registers_show(struct device *_dev,
|
|||
|
||||
/* Main Control Registers */
|
||||
t = scnprintf(next, size, "%s version " DRIVER_VERSION
|
||||
", chiprev %04x, dma %s\n\n"
|
||||
", chiprev %04x\n\n"
|
||||
"devinit %03x fifoctl %08x gadget '%s'\n"
|
||||
"pci irqenb0 %02x irqenb1 %08x "
|
||||
"irqstat0 %04x irqstat1 %08x\n",
|
||||
driver_name, dev->chiprev,
|
||||
use_dma
|
||||
? (use_dma_chaining ? "chaining" : "enabled")
|
||||
: "disabled",
|
||||
readl(&dev->regs->devinit),
|
||||
readl(&dev->regs->fifoctl),
|
||||
s,
|
||||
|
|
@ -1913,76 +1763,73 @@ static void defect7374_disable_data_eps(struct net2280 *dev)
|
|||
static void defect7374_enable_data_eps_zero(struct net2280 *dev)
|
||||
{
|
||||
u32 tmp = 0, tmp_reg;
|
||||
u32 fsmvalue, scratch;
|
||||
u32 scratch;
|
||||
int i;
|
||||
unsigned char ep_sel;
|
||||
|
||||
scratch = get_idx_reg(dev->regs, SCRATCH);
|
||||
fsmvalue = scratch & (0xf << DEFECT7374_FSM_FIELD);
|
||||
|
||||
WARN_ON((scratch & (0xf << DEFECT7374_FSM_FIELD))
|
||||
== DEFECT7374_FSM_SS_CONTROL_READ);
|
||||
|
||||
scratch &= ~(0xf << DEFECT7374_FSM_FIELD);
|
||||
|
||||
/*See if firmware needs to set up for workaround*/
|
||||
if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) {
|
||||
ep_warn(dev, "Operate Defect 7374 workaround soft this time");
|
||||
ep_warn(dev, "It will operate on cold-reboot and SS connect");
|
||||
ep_warn(dev, "Operate Defect 7374 workaround soft this time");
|
||||
ep_warn(dev, "It will operate on cold-reboot and SS connect");
|
||||
|
||||
/*GPEPs:*/
|
||||
tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) |
|
||||
(2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) |
|
||||
((dev->enhanced_mode) ?
|
||||
BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) |
|
||||
BIT(IN_ENDPOINT_ENABLE));
|
||||
/*GPEPs:*/
|
||||
tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) |
|
||||
(2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) |
|
||||
((dev->enhanced_mode) ?
|
||||
BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) |
|
||||
BIT(IN_ENDPOINT_ENABLE));
|
||||
|
||||
for (i = 1; i < 5; i++)
|
||||
writel(tmp, &dev->ep[i].cfg->ep_cfg);
|
||||
for (i = 1; i < 5; i++)
|
||||
writel(tmp, &dev->ep[i].cfg->ep_cfg);
|
||||
|
||||
/* CSRIN, PCIIN, STATIN, RCIN*/
|
||||
tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_ENABLE));
|
||||
writel(tmp, &dev->dep[1].dep_cfg);
|
||||
writel(tmp, &dev->dep[3].dep_cfg);
|
||||
writel(tmp, &dev->dep[4].dep_cfg);
|
||||
writel(tmp, &dev->dep[5].dep_cfg);
|
||||
/* CSRIN, PCIIN, STATIN, RCIN*/
|
||||
tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_ENABLE));
|
||||
writel(tmp, &dev->dep[1].dep_cfg);
|
||||
writel(tmp, &dev->dep[3].dep_cfg);
|
||||
writel(tmp, &dev->dep[4].dep_cfg);
|
||||
writel(tmp, &dev->dep[5].dep_cfg);
|
||||
|
||||
/*Implemented for development and debug.
|
||||
* Can be refined/tuned later.*/
|
||||
for (ep_sel = 0; ep_sel <= 21; ep_sel++) {
|
||||
/* Select an endpoint for subsequent operations: */
|
||||
tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
|
||||
writel(((tmp_reg & ~0x1f) | ep_sel),
|
||||
&dev->plregs->pl_ep_ctrl);
|
||||
/*Implemented for development and debug.
|
||||
* Can be refined/tuned later.*/
|
||||
for (ep_sel = 0; ep_sel <= 21; ep_sel++) {
|
||||
/* Select an endpoint for subsequent operations: */
|
||||
tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
|
||||
writel(((tmp_reg & ~0x1f) | ep_sel),
|
||||
&dev->plregs->pl_ep_ctrl);
|
||||
|
||||
if (ep_sel == 1) {
|
||||
tmp =
|
||||
(readl(&dev->plregs->pl_ep_ctrl) |
|
||||
BIT(CLEAR_ACK_ERROR_CODE) | 0);
|
||||
writel(tmp, &dev->plregs->pl_ep_ctrl);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ep_sel == 0 || (ep_sel > 9 && ep_sel < 14) ||
|
||||
ep_sel == 18 || ep_sel == 20)
|
||||
continue;
|
||||
|
||||
tmp = (readl(&dev->plregs->pl_ep_cfg_4) |
|
||||
BIT(NON_CTRL_IN_TOLERATE_BAD_DIR) | 0);
|
||||
writel(tmp, &dev->plregs->pl_ep_cfg_4);
|
||||
|
||||
tmp = readl(&dev->plregs->pl_ep_ctrl) &
|
||||
~BIT(EP_INITIALIZED);
|
||||
if (ep_sel == 1) {
|
||||
tmp =
|
||||
(readl(&dev->plregs->pl_ep_ctrl) |
|
||||
BIT(CLEAR_ACK_ERROR_CODE) | 0);
|
||||
writel(tmp, &dev->plregs->pl_ep_ctrl);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Set FSM to focus on the first Control Read:
|
||||
* - Tip: Connection speed is known upon the first
|
||||
* setup request.*/
|
||||
scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
|
||||
set_idx_reg(dev->regs, SCRATCH, scratch);
|
||||
if (ep_sel == 0 || (ep_sel > 9 && ep_sel < 14) ||
|
||||
ep_sel == 18 || ep_sel == 20)
|
||||
continue;
|
||||
|
||||
tmp = (readl(&dev->plregs->pl_ep_cfg_4) |
|
||||
BIT(NON_CTRL_IN_TOLERATE_BAD_DIR) | 0);
|
||||
writel(tmp, &dev->plregs->pl_ep_cfg_4);
|
||||
|
||||
tmp = readl(&dev->plregs->pl_ep_ctrl) &
|
||||
~BIT(EP_INITIALIZED);
|
||||
writel(tmp, &dev->plregs->pl_ep_ctrl);
|
||||
|
||||
} else{
|
||||
ep_warn(dev, "Defect 7374 workaround soft will NOT operate");
|
||||
ep_warn(dev, "It will operate on cold-reboot and SS connect");
|
||||
}
|
||||
|
||||
/* Set FSM to focus on the first Control Read:
|
||||
* - Tip: Connection speed is known upon the first
|
||||
* setup request.*/
|
||||
scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
|
||||
set_idx_reg(dev->regs, SCRATCH, scratch);
|
||||
|
||||
}
|
||||
|
||||
/* keeping it simple:
|
||||
|
|
@ -2033,21 +1880,13 @@ static void usb_reset_228x(struct net2280 *dev)
|
|||
static void usb_reset_338x(struct net2280 *dev)
|
||||
{
|
||||
u32 tmp;
|
||||
u32 fsmvalue;
|
||||
|
||||
dev->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
(void)readl(&dev->usb->usbctl);
|
||||
|
||||
net2280_led_init(dev);
|
||||
|
||||
fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
|
||||
(0xf << DEFECT7374_FSM_FIELD);
|
||||
|
||||
/* See if firmware needs to set up for workaround: */
|
||||
if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) {
|
||||
ep_info(dev, "%s: Defect 7374 FsmValue 0x%08x\n", __func__,
|
||||
fsmvalue);
|
||||
} else {
|
||||
if (dev->bug7734_patched) {
|
||||
/* disable automatic responses, and irqs */
|
||||
writel(0, &dev->usb->stdrsp);
|
||||
writel(0, &dev->regs->pciirqenb0);
|
||||
|
|
@ -2064,7 +1903,7 @@ static void usb_reset_338x(struct net2280 *dev)
|
|||
|
||||
writel(~0, &dev->regs->irqstat0), writel(~0, &dev->regs->irqstat1);
|
||||
|
||||
if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) {
|
||||
if (dev->bug7734_patched) {
|
||||
/* reset, and enable pci */
|
||||
tmp = readl(&dev->regs->devinit) |
|
||||
BIT(PCI_ENABLE) |
|
||||
|
|
@ -2093,10 +1932,6 @@ static void usb_reset(struct net2280 *dev)
|
|||
static void usb_reinit_228x(struct net2280 *dev)
|
||||
{
|
||||
u32 tmp;
|
||||
int init_dma;
|
||||
|
||||
/* use_dma changes are ignored till next device re-init */
|
||||
init_dma = use_dma;
|
||||
|
||||
/* basic endpoint init */
|
||||
for (tmp = 0; tmp < 7; tmp++) {
|
||||
|
|
@ -2108,8 +1943,7 @@ static void usb_reinit_228x(struct net2280 *dev)
|
|||
|
||||
if (tmp > 0 && tmp <= 4) {
|
||||
ep->fifo_size = 1024;
|
||||
if (init_dma)
|
||||
ep->dma = &dev->dma[tmp - 1];
|
||||
ep->dma = &dev->dma[tmp - 1];
|
||||
} else
|
||||
ep->fifo_size = 64;
|
||||
ep->regs = &dev->epregs[tmp];
|
||||
|
|
@ -2133,17 +1967,12 @@ static void usb_reinit_228x(struct net2280 *dev)
|
|||
|
||||
static void usb_reinit_338x(struct net2280 *dev)
|
||||
{
|
||||
int init_dma;
|
||||
int i;
|
||||
u32 tmp, val;
|
||||
u32 fsmvalue;
|
||||
static const u32 ne[9] = { 0, 1, 2, 3, 4, 1, 2, 3, 4 };
|
||||
static const u32 ep_reg_addr[9] = { 0x00, 0xC0, 0x00, 0xC0, 0x00,
|
||||
0x00, 0xC0, 0x00, 0xC0 };
|
||||
|
||||
/* use_dma changes are ignored till next device re-init */
|
||||
init_dma = use_dma;
|
||||
|
||||
/* basic endpoint init */
|
||||
for (i = 0; i < dev->n_ep; i++) {
|
||||
struct net2280_ep *ep = &dev->ep[i];
|
||||
|
|
@ -2152,7 +1981,7 @@ static void usb_reinit_338x(struct net2280 *dev)
|
|||
ep->dev = dev;
|
||||
ep->num = i;
|
||||
|
||||
if (i > 0 && i <= 4 && init_dma)
|
||||
if (i > 0 && i <= 4)
|
||||
ep->dma = &dev->dma[i - 1];
|
||||
|
||||
if (dev->enhanced_mode) {
|
||||
|
|
@ -2177,14 +2006,7 @@ static void usb_reinit_338x(struct net2280 *dev)
|
|||
dev->ep[0].stopped = 0;
|
||||
|
||||
/* Link layer set up */
|
||||
fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
|
||||
(0xf << DEFECT7374_FSM_FIELD);
|
||||
|
||||
/* See if driver needs to set up for workaround: */
|
||||
if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ)
|
||||
ep_info(dev, "%s: Defect 7374 FsmValue %08x\n",
|
||||
__func__, fsmvalue);
|
||||
else {
|
||||
if (dev->bug7734_patched) {
|
||||
tmp = readl(&dev->usb_ext->usbctl2) &
|
||||
~(BIT(U1_ENABLE) | BIT(U2_ENABLE) | BIT(LTM_ENABLE));
|
||||
writel(tmp, &dev->usb_ext->usbctl2);
|
||||
|
|
@ -2291,15 +2113,8 @@ static void ep0_start_228x(struct net2280 *dev)
|
|||
|
||||
static void ep0_start_338x(struct net2280 *dev)
|
||||
{
|
||||
u32 fsmvalue;
|
||||
|
||||
fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
|
||||
(0xf << DEFECT7374_FSM_FIELD);
|
||||
|
||||
if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ)
|
||||
ep_info(dev, "%s: Defect 7374 FsmValue %08x\n", __func__,
|
||||
fsmvalue);
|
||||
else
|
||||
if (dev->bug7734_patched)
|
||||
writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE) |
|
||||
BIT(SET_EP_HIDE_STATUS_PHASE),
|
||||
&dev->epregs[0].ep_rsp);
|
||||
|
|
@ -2382,16 +2197,12 @@ static int net2280_start(struct usb_gadget *_gadget,
|
|||
if (retval)
|
||||
goto err_func;
|
||||
|
||||
/* Enable force-full-speed testing mode, if desired */
|
||||
if (full_speed && (dev->quirks & PLX_LEGACY))
|
||||
writel(BIT(FORCE_FULL_SPEED_MODE), &dev->usb->xcvrdiag);
|
||||
|
||||
/* ... then enable host detection and ep0; and we're ready
|
||||
/* enable host detection and ep0; and we're ready
|
||||
* for set_configuration as well as eventual disconnect.
|
||||
*/
|
||||
net2280_led_active(dev, 1);
|
||||
|
||||
if (dev->quirks & PLX_SUPERSPEED)
|
||||
if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
|
||||
defect7374_enable_data_eps_zero(dev);
|
||||
|
||||
ep0_start(dev);
|
||||
|
|
@ -2444,10 +2255,6 @@ static int net2280_stop(struct usb_gadget *_gadget)
|
|||
|
||||
net2280_led_active(dev, 0);
|
||||
|
||||
/* Disable full-speed test mode */
|
||||
if (dev->quirks & PLX_LEGACY)
|
||||
writel(0, &dev->usb->xcvrdiag);
|
||||
|
||||
device_remove_file(&dev->pdev->dev, &dev_attr_function);
|
||||
device_remove_file(&dev->pdev->dev, &dev_attr_queues);
|
||||
|
||||
|
|
@ -2478,10 +2285,10 @@ static void handle_ep_small(struct net2280_ep *ep)
|
|||
/* ack all, and handle what we care about */
|
||||
t = readl(&ep->regs->ep_stat);
|
||||
ep->irqs++;
|
||||
#if 0
|
||||
|
||||
ep_vdbg(ep->dev, "%s ack ep_stat %08x, req %p\n",
|
||||
ep->ep.name, t, req ? &req->req : 0);
|
||||
#endif
|
||||
ep->ep.name, t, req ? &req->req : NULL);
|
||||
|
||||
if (!ep->is_in || (ep->dev->quirks & PLX_2280))
|
||||
writel(t & ~BIT(NAK_OUT_PACKETS), &ep->regs->ep_stat);
|
||||
else
|
||||
|
|
@ -2717,6 +2524,7 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r)
|
|||
* run after the next USB connection.
|
||||
*/
|
||||
scratch |= DEFECT7374_FSM_NON_SS_CONTROL_READ;
|
||||
dev->bug7734_patched = 1;
|
||||
goto restore_data_eps;
|
||||
}
|
||||
|
||||
|
|
@ -2730,6 +2538,7 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r)
|
|||
if ((state >= (ACK_GOOD_NORMAL << STATE)) &&
|
||||
(state <= (ACK_GOOD_MORE_ACKS_TO_COME << STATE))) {
|
||||
scratch |= DEFECT7374_FSM_SS_CONTROL_READ;
|
||||
dev->bug7734_patched = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -2766,80 +2575,19 @@ restore_data_eps:
|
|||
return;
|
||||
}
|
||||
|
||||
static void ep_stall(struct net2280_ep *ep, int stall)
|
||||
static void ep_clear_seqnum(struct net2280_ep *ep)
|
||||
{
|
||||
struct net2280 *dev = ep->dev;
|
||||
u32 val;
|
||||
static const u32 ep_pl[9] = { 0, 3, 4, 7, 8, 2, 5, 6, 9 };
|
||||
|
||||
if (stall) {
|
||||
writel(BIT(SET_ENDPOINT_HALT) |
|
||||
/* BIT(SET_NAK_PACKETS) | */
|
||||
BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE),
|
||||
&ep->regs->ep_rsp);
|
||||
ep->is_halt = 1;
|
||||
} else {
|
||||
if (dev->gadget.speed == USB_SPEED_SUPER) {
|
||||
/*
|
||||
* Workaround for SS SeqNum not cleared via
|
||||
* Endpoint Halt (Clear) bit. select endpoint
|
||||
*/
|
||||
val = readl(&dev->plregs->pl_ep_ctrl);
|
||||
val = (val & ~0x1f) | ep_pl[ep->num];
|
||||
writel(val, &dev->plregs->pl_ep_ctrl);
|
||||
val = readl(&dev->plregs->pl_ep_ctrl) & ~0x1f;
|
||||
val |= ep_pl[ep->num];
|
||||
writel(val, &dev->plregs->pl_ep_ctrl);
|
||||
val |= BIT(SEQUENCE_NUMBER_RESET);
|
||||
writel(val, &dev->plregs->pl_ep_ctrl);
|
||||
|
||||
val |= BIT(SEQUENCE_NUMBER_RESET);
|
||||
writel(val, &dev->plregs->pl_ep_ctrl);
|
||||
}
|
||||
val = readl(&ep->regs->ep_rsp);
|
||||
val |= BIT(CLEAR_ENDPOINT_HALT) |
|
||||
BIT(CLEAR_ENDPOINT_TOGGLE);
|
||||
writel(val,
|
||||
/* | BIT(CLEAR_NAK_PACKETS),*/
|
||||
&ep->regs->ep_rsp);
|
||||
ep->is_halt = 0;
|
||||
val = readl(&ep->regs->ep_rsp);
|
||||
}
|
||||
}
|
||||
|
||||
static void ep_stdrsp(struct net2280_ep *ep, int value, int wedged)
|
||||
{
|
||||
/* set/clear, then synch memory views with the device */
|
||||
if (value) {
|
||||
ep->stopped = 1;
|
||||
if (ep->num == 0)
|
||||
ep->dev->protocol_stall = 1;
|
||||
else {
|
||||
if (ep->dma)
|
||||
ep_stop_dma(ep);
|
||||
ep_stall(ep, true);
|
||||
}
|
||||
|
||||
if (wedged)
|
||||
ep->wedged = 1;
|
||||
} else {
|
||||
ep->stopped = 0;
|
||||
ep->wedged = 0;
|
||||
|
||||
ep_stall(ep, false);
|
||||
|
||||
/* Flush the queue */
|
||||
if (!list_empty(&ep->queue)) {
|
||||
struct net2280_request *req =
|
||||
list_entry(ep->queue.next, struct net2280_request,
|
||||
queue);
|
||||
if (ep->dma)
|
||||
resume_dma(ep);
|
||||
else {
|
||||
if (ep->is_in)
|
||||
write_fifo(ep, &req->req);
|
||||
else {
|
||||
if (read_fifo(ep, req))
|
||||
done(ep, req, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void handle_stat0_irqs_superspeed(struct net2280 *dev,
|
||||
|
|
@ -2863,7 +2611,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
|
|||
switch (r.bRequestType) {
|
||||
case (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE):
|
||||
status = dev->wakeup_enable ? 0x02 : 0x00;
|
||||
if (dev->selfpowered)
|
||||
if (dev->gadget.is_selfpowered)
|
||||
status |= BIT(0);
|
||||
status |= (dev->u1_enable << 2 | dev->u2_enable << 3 |
|
||||
dev->ltm_enable << 4);
|
||||
|
|
@ -2940,7 +2688,12 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
|
|||
if (w_value != USB_ENDPOINT_HALT)
|
||||
goto do_stall3;
|
||||
ep_vdbg(dev, "%s clear halt\n", e->ep.name);
|
||||
ep_stall(e, false);
|
||||
/*
|
||||
* Workaround for SS SeqNum not cleared via
|
||||
* Endpoint Halt (Clear) bit. select endpoint
|
||||
*/
|
||||
ep_clear_seqnum(e);
|
||||
clear_halt(e);
|
||||
if (!list_empty(&e->queue) && e->td_dma)
|
||||
restart_dma(e);
|
||||
allow_status(ep);
|
||||
|
|
@ -2998,7 +2751,14 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
|
|||
e = get_ep_by_addr(dev, w_index);
|
||||
if (!e || (w_value != USB_ENDPOINT_HALT))
|
||||
goto do_stall3;
|
||||
ep_stdrsp(e, true, false);
|
||||
ep->stopped = 1;
|
||||
if (ep->num == 0)
|
||||
ep->dev->protocol_stall = 1;
|
||||
else {
|
||||
if (ep->dma)
|
||||
abort_dma(ep);
|
||||
set_halt(ep);
|
||||
}
|
||||
allow_status_338x(ep);
|
||||
break;
|
||||
|
||||
|
|
@ -3026,7 +2786,7 @@ do_stall3:
|
|||
r.bRequestType, r.bRequest, tmp);
|
||||
dev->protocol_stall = 1;
|
||||
/* TD 9.9 Halt Endpoint test. TD 9.22 Set feature test */
|
||||
ep_stall(ep, true);
|
||||
set_halt(ep);
|
||||
}
|
||||
|
||||
next_endpoints3:
|
||||
|
|
@ -3091,9 +2851,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
|
|||
}
|
||||
ep->stopped = 0;
|
||||
dev->protocol_stall = 0;
|
||||
if (dev->quirks & PLX_SUPERSPEED)
|
||||
ep->is_halt = 0;
|
||||
else{
|
||||
if (!(dev->quirks & PLX_SUPERSPEED)) {
|
||||
if (ep->dev->quirks & PLX_2280)
|
||||
tmp = BIT(FIFO_OVERFLOW) |
|
||||
BIT(FIFO_UNDERFLOW);
|
||||
|
|
@ -3120,7 +2878,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
|
|||
cpu_to_le32s(&u.raw[0]);
|
||||
cpu_to_le32s(&u.raw[1]);
|
||||
|
||||
if (dev->quirks & PLX_SUPERSPEED)
|
||||
if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
|
||||
defect7374_workaround(dev, u.r);
|
||||
|
||||
tmp = 0;
|
||||
|
|
@ -3423,17 +3181,12 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* chaining should stop on abort, short OUT from fifo,
|
||||
* or (stat0 codepath) short OUT transfer.
|
||||
*/
|
||||
if (!use_dma_chaining) {
|
||||
if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) {
|
||||
ep_dbg(ep->dev, "%s no xact done? %08x\n",
|
||||
ep->ep.name, tmp);
|
||||
continue;
|
||||
}
|
||||
stop_dma(ep->dma);
|
||||
if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) {
|
||||
ep_dbg(ep->dev, "%s no xact done? %08x\n",
|
||||
ep->ep.name, tmp);
|
||||
continue;
|
||||
}
|
||||
stop_dma(ep->dma);
|
||||
|
||||
/* OUT transfers terminate when the data from the
|
||||
* host is in our memory. Process whatever's done.
|
||||
|
|
@ -3448,30 +3201,9 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat)
|
|||
scan_dma_completions(ep);
|
||||
|
||||
/* disable dma on inactive queues; else maybe restart */
|
||||
if (list_empty(&ep->queue)) {
|
||||
if (use_dma_chaining)
|
||||
stop_dma(ep->dma);
|
||||
} else {
|
||||
if (!list_empty(&ep->queue)) {
|
||||
tmp = readl(&dma->dmactl);
|
||||
if (!use_dma_chaining || (tmp & BIT(DMA_ENABLE)) == 0)
|
||||
restart_dma(ep);
|
||||
else if (ep->is_in && use_dma_chaining) {
|
||||
struct net2280_request *req;
|
||||
__le32 dmacount;
|
||||
|
||||
/* the descriptor at the head of the chain
|
||||
* may still have VALID_BIT clear; that's
|
||||
* used to trigger changing DMA_FIFO_VALIDATE
|
||||
* (affects automagic zlp writes).
|
||||
*/
|
||||
req = list_entry(ep->queue.next,
|
||||
struct net2280_request, queue);
|
||||
dmacount = req->td->dmacount;
|
||||
dmacount &= cpu_to_le32(BIT(VALID_BIT) |
|
||||
DMA_BYTE_COUNT_MASK);
|
||||
if (dmacount && (dmacount & valid_bit) == 0)
|
||||
restart_dma(ep);
|
||||
}
|
||||
restart_dma(ep);
|
||||
}
|
||||
ep->irqs++;
|
||||
}
|
||||
|
|
@ -3556,7 +3288,7 @@ static void net2280_remove(struct pci_dev *pdev)
|
|||
}
|
||||
if (dev->got_irq)
|
||||
free_irq(pdev->irq, dev);
|
||||
if (use_msi && dev->quirks & PLX_SUPERSPEED)
|
||||
if (dev->quirks & PLX_SUPERSPEED)
|
||||
pci_disable_msi(pdev);
|
||||
if (dev->regs)
|
||||
iounmap(dev->regs);
|
||||
|
|
@ -3581,9 +3313,6 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
void __iomem *base = NULL;
|
||||
int retval, i;
|
||||
|
||||
if (!use_dma)
|
||||
use_dma_chaining = 0;
|
||||
|
||||
/* alloc, and start init */
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (dev == NULL) {
|
||||
|
|
@ -3663,9 +3392,12 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
|
||||
(0xf << DEFECT7374_FSM_FIELD);
|
||||
/* See if firmware needs to set up for workaround: */
|
||||
if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ)
|
||||
if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) {
|
||||
dev->bug7734_patched = 1;
|
||||
writel(0, &dev->usb->usbctl);
|
||||
} else{
|
||||
} else
|
||||
dev->bug7734_patched = 0;
|
||||
} else {
|
||||
dev->enhanced_mode = 0;
|
||||
dev->n_ep = 7;
|
||||
/* put into initial config, link up all endpoints */
|
||||
|
|
@ -3682,7 +3414,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
goto done;
|
||||
}
|
||||
|
||||
if (use_msi && (dev->quirks & PLX_SUPERSPEED))
|
||||
if (dev->quirks & PLX_SUPERSPEED)
|
||||
if (pci_enable_msi(pdev))
|
||||
ep_err(dev, "Failed to enable MSI mode\n");
|
||||
|
||||
|
|
@ -3741,9 +3473,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
ep_info(dev, "%s\n", driver_desc);
|
||||
ep_info(dev, "irq %d, pci mem %p, chip rev %04x\n",
|
||||
pdev->irq, base, dev->chiprev);
|
||||
ep_info(dev, "version: " DRIVER_VERSION "; dma %s %s\n",
|
||||
use_dma ? (use_dma_chaining ? "chaining" : "enabled")
|
||||
: "disabled",
|
||||
ep_info(dev, "version: " DRIVER_VERSION "; %s\n",
|
||||
dev->enhanced_mode ? "enhanced mode" : "legacy mode");
|
||||
retval = device_create_file(&pdev->dev, &dev_attr_registers);
|
||||
if (retval)
|
||||
|
|
@ -3776,9 +3506,6 @@ static void net2280_shutdown(struct pci_dev *pdev)
|
|||
/* disable the pullup so the host will think we're gone */
|
||||
writel(0, &dev->usb->usbctl);
|
||||
|
||||
/* Disable full-speed test mode */
|
||||
if (dev->quirks & PLX_LEGACY)
|
||||
writel(0, &dev->usb->xcvrdiag);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,6 @@ struct net2280_ep {
|
|||
dma_addr_t td_dma; /* of dummy */
|
||||
struct net2280 *dev;
|
||||
unsigned long irqs;
|
||||
unsigned is_halt:1, dma_started:1;
|
||||
|
||||
/* analogous to a host-side qh */
|
||||
struct list_head queue;
|
||||
|
|
@ -126,7 +125,7 @@ static inline void allow_status(struct net2280_ep *ep)
|
|||
ep->stopped = 1;
|
||||
}
|
||||
|
||||
static void allow_status_338x(struct net2280_ep *ep)
|
||||
static inline void allow_status_338x(struct net2280_ep *ep)
|
||||
{
|
||||
/*
|
||||
* Control Status Phase Handshake was set by the chip when the setup
|
||||
|
|
@ -165,8 +164,8 @@ struct net2280 {
|
|||
u2_enable:1,
|
||||
ltm_enable:1,
|
||||
wakeup_enable:1,
|
||||
selfpowered:1,
|
||||
addressed_state:1;
|
||||
addressed_state:1,
|
||||
bug7734_patched:1;
|
||||
u16 chiprev;
|
||||
int enhanced_mode;
|
||||
int n_ep;
|
||||
|
|
@ -356,23 +355,6 @@ static inline void start_out_naking(struct net2280_ep *ep)
|
|||
readl(&ep->regs->ep_rsp);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static inline void assert_out_naking(struct net2280_ep *ep, const char *where)
|
||||
{
|
||||
u32 tmp = readl(&ep->regs->ep_stat);
|
||||
|
||||
if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) {
|
||||
ep_dbg(ep->dev, "%s %s %08x !NAK\n",
|
||||
ep->ep.name, where, tmp);
|
||||
writel(BIT(SET_NAK_OUT_PACKETS),
|
||||
&ep->regs->ep_rsp);
|
||||
}
|
||||
}
|
||||
#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__)
|
||||
#else
|
||||
#define ASSERT_OUT_NAKING(ep) do {} while (0)
|
||||
#endif
|
||||
|
||||
static inline void stop_out_naking(struct net2280_ep *ep)
|
||||
{
|
||||
u32 tmp;
|
||||
|
|
|
|||
|
|
@ -1171,6 +1171,7 @@ omap_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
|
|||
unsigned long flags;
|
||||
u16 syscon1;
|
||||
|
||||
gadget->is_selfpowered = (is_selfpowered != 0);
|
||||
udc = container_of(gadget, struct omap_udc, gadget);
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
syscon1 = omap_readw(UDC_SYSCON1);
|
||||
|
|
|
|||
|
|
@ -1161,6 +1161,7 @@ static int pch_udc_pcd_selfpowered(struct usb_gadget *gadget, int value)
|
|||
|
||||
if (!gadget)
|
||||
return -EINVAL;
|
||||
gadget->is_selfpowered = (value != 0);
|
||||
dev = container_of(gadget, struct pch_udc_dev, gadget);
|
||||
if (value)
|
||||
pch_udc_set_selfpowered(dev);
|
||||
|
|
|
|||
|
|
@ -1272,7 +1272,6 @@ static int pxa25x_udc_start(struct usb_gadget *g,
|
|||
goto bind_fail;
|
||||
}
|
||||
|
||||
pullup(dev);
|
||||
dump_state(dev);
|
||||
return 0;
|
||||
bind_fail:
|
||||
|
|
@ -1339,7 +1338,6 @@ static int pxa25x_udc_stop(struct usb_gadget*g)
|
|||
|
||||
local_irq_disable();
|
||||
dev->pullup = 0;
|
||||
pullup(dev);
|
||||
stop_activity(dev, NULL);
|
||||
local_irq_enable();
|
||||
|
||||
|
|
|
|||
|
|
@ -1809,7 +1809,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
|
|||
|
||||
/* first hook up the driver ... */
|
||||
udc->driver = driver;
|
||||
dplus_pullup(udc, 1);
|
||||
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver)) {
|
||||
retval = otg_set_peripheral(udc->transceiver->otg,
|
||||
|
|
@ -1862,7 +1861,6 @@ static int pxa27x_udc_stop(struct usb_gadget *g)
|
|||
|
||||
stop_activity(udc, NULL);
|
||||
udc_disable(udc);
|
||||
dplus_pullup(udc, 0);
|
||||
|
||||
udc->driver = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -1803,6 +1803,7 @@ static int r8a66597_set_selfpowered(struct usb_gadget *gadget, int is_self)
|
|||
{
|
||||
struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
|
||||
|
||||
gadget->is_selfpowered = (is_self != 0);
|
||||
if (is_self)
|
||||
r8a66597->device_status |= 1 << USB_DEVICE_SELF_POWERED;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -238,14 +238,6 @@ static inline void s3c2410_udc_set_ep0_de_out(void __iomem *base)
|
|||
S3C2410_UDC_EP0_CSR_REG);
|
||||
}
|
||||
|
||||
static inline void s3c2410_udc_set_ep0_sse_out(void __iomem *base)
|
||||
{
|
||||
udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
|
||||
udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY
|
||||
| S3C2410_UDC_EP0_CSR_SSE),
|
||||
S3C2410_UDC_EP0_CSR_REG);
|
||||
}
|
||||
|
||||
static inline void s3c2410_udc_set_ep0_de_in(void __iomem *base)
|
||||
{
|
||||
udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
|
||||
|
|
@ -291,18 +283,6 @@ static void s3c2410_udc_nuke(struct s3c2410_udc *udc,
|
|||
}
|
||||
}
|
||||
|
||||
static inline void s3c2410_udc_clear_ep_state(struct s3c2410_udc *dev)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
/* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
|
||||
* fifos, and pending transactions mustn't be continued in any case.
|
||||
*/
|
||||
|
||||
for (i = 1; i < S3C2410_ENDPOINTS; i++)
|
||||
s3c2410_udc_nuke(dev, &dev->ep[i], -ECONNABORTED);
|
||||
}
|
||||
|
||||
static inline int s3c2410_udc_fifo_count_out(void)
|
||||
{
|
||||
int tmp;
|
||||
|
|
@ -1454,6 +1434,7 @@ static int s3c2410_udc_set_selfpowered(struct usb_gadget *gadget, int value)
|
|||
|
||||
dprintk(DEBUG_NORMAL, "%s()\n", __func__);
|
||||
|
||||
gadget->is_selfpowered = (value != 0);
|
||||
if (value)
|
||||
udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -564,6 +564,7 @@ static USB_UDC_ATTR(is_a_peripheral);
|
|||
static USB_UDC_ATTR(b_hnp_enable);
|
||||
static USB_UDC_ATTR(a_hnp_support);
|
||||
static USB_UDC_ATTR(a_alt_hnp_support);
|
||||
static USB_UDC_ATTR(is_selfpowered);
|
||||
|
||||
static struct attribute *usb_udc_attrs[] = {
|
||||
&dev_attr_srp.attr,
|
||||
|
|
@ -577,6 +578,7 @@ static struct attribute *usb_udc_attrs[] = {
|
|||
&dev_attr_b_hnp_enable.attr,
|
||||
&dev_attr_a_hnp_support.attr,
|
||||
&dev_attr_a_alt_hnp_support.attr,
|
||||
&dev_attr_is_selfpowered.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ config USB_EHCI_TEGRA
|
|||
|
||||
config USB_EHCI_HCD_PPC_OF
|
||||
bool "EHCI support for PPC USB controller on OF platform bus"
|
||||
depends on PPC_OF
|
||||
depends on PPC
|
||||
default y
|
||||
---help---
|
||||
Enables support for the USB controller present on the PowerPC
|
||||
|
|
@ -331,20 +331,6 @@ config USB_ISP116X_HCD
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called isp116x-hcd.
|
||||
|
||||
config USB_ISP1760_HCD
|
||||
tristate "ISP 1760 HCD support"
|
||||
---help---
|
||||
The ISP1760 chip is a USB 2.0 host controller.
|
||||
|
||||
This driver does not support isochronous transfers or OTG.
|
||||
This USB controller is usually attached to a non-DMA-Master
|
||||
capable bus. NXP's eval kit brings this chip on PCI card
|
||||
where the chip itself is behind a PLB to simulate such
|
||||
a bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called isp1760.
|
||||
|
||||
config USB_ISP1362_HCD
|
||||
tristate "ISP1362 HCD support"
|
||||
---help---
|
||||
|
|
@ -494,7 +480,7 @@ config USB_OHCI_ATH79
|
|||
|
||||
config USB_OHCI_HCD_PPC_OF_BE
|
||||
bool "OHCI support for OF platform bus (big endian)"
|
||||
depends on PPC_OF
|
||||
depends on PPC
|
||||
select USB_OHCI_BIG_ENDIAN_DESC
|
||||
select USB_OHCI_BIG_ENDIAN_MMIO
|
||||
---help---
|
||||
|
|
@ -503,7 +489,7 @@ config USB_OHCI_HCD_PPC_OF_BE
|
|||
|
||||
config USB_OHCI_HCD_PPC_OF_LE
|
||||
bool "OHCI support for OF platform bus (little endian)"
|
||||
depends on PPC_OF
|
||||
depends on PPC
|
||||
select USB_OHCI_LITTLE_ENDIAN
|
||||
---help---
|
||||
Enables support for little-endian USB controllers present on the
|
||||
|
|
@ -511,7 +497,7 @@ config USB_OHCI_HCD_PPC_OF_LE
|
|||
|
||||
config USB_OHCI_HCD_PPC_OF
|
||||
bool
|
||||
depends on PPC_OF
|
||||
depends on PPC
|
||||
default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE
|
||||
|
||||
config USB_OHCI_HCD_PCI
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@
|
|||
# tell define_trace.h where to find the xhci trace header
|
||||
CFLAGS_xhci-trace.o := -I$(src)
|
||||
|
||||
isp1760-y := isp1760-hcd.o isp1760-if.o
|
||||
|
||||
fhci-y := fhci-hcd.o fhci-hub.o fhci-q.o
|
||||
fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
|
||||
|
||||
|
|
@ -69,7 +67,6 @@ obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
|
|||
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
|
||||
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
|
||||
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
|
||||
obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
|
||||
obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
|
||||
obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
|
||||
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
|
||||
|
|
|
|||
|
|
@ -27,44 +27,66 @@
|
|||
#define DRIVER_DESC "EHCI Atmel driver"
|
||||
|
||||
static const char hcd_name[] = "ehci-atmel";
|
||||
static struct hc_driver __read_mostly ehci_atmel_hc_driver;
|
||||
|
||||
/* interface and function clocks */
|
||||
static struct clk *iclk, *fclk, *uclk;
|
||||
static int clocked;
|
||||
#define hcd_to_atmel_ehci_priv(h) \
|
||||
((struct atmel_ehci_priv *)hcd_to_ehci(h)->priv)
|
||||
|
||||
struct atmel_ehci_priv {
|
||||
struct clk *iclk;
|
||||
struct clk *fclk;
|
||||
struct clk *uclk;
|
||||
bool clocked;
|
||||
};
|
||||
|
||||
static struct hc_driver __read_mostly ehci_atmel_hc_driver;
|
||||
|
||||
static const struct ehci_driver_overrides ehci_atmel_drv_overrides __initconst = {
|
||||
.extra_priv_size = sizeof(struct atmel_ehci_priv),
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void atmel_start_clock(void)
|
||||
static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
|
||||
{
|
||||
if (atmel_ehci->clocked)
|
||||
return;
|
||||
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
|
||||
clk_set_rate(uclk, 48000000);
|
||||
clk_prepare_enable(uclk);
|
||||
clk_set_rate(atmel_ehci->uclk, 48000000);
|
||||
clk_prepare_enable(atmel_ehci->uclk);
|
||||
}
|
||||
clk_prepare_enable(iclk);
|
||||
clk_prepare_enable(fclk);
|
||||
clocked = 1;
|
||||
clk_prepare_enable(atmel_ehci->iclk);
|
||||
clk_prepare_enable(atmel_ehci->fclk);
|
||||
atmel_ehci->clocked = true;
|
||||
}
|
||||
|
||||
static void atmel_stop_clock(void)
|
||||
static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
|
||||
{
|
||||
clk_disable_unprepare(fclk);
|
||||
clk_disable_unprepare(iclk);
|
||||
if (!atmel_ehci->clocked)
|
||||
return;
|
||||
clk_disable_unprepare(atmel_ehci->fclk);
|
||||
clk_disable_unprepare(atmel_ehci->iclk);
|
||||
if (IS_ENABLED(CONFIG_COMMON_CLK))
|
||||
clk_disable_unprepare(uclk);
|
||||
clocked = 0;
|
||||
clk_disable_unprepare(atmel_ehci->uclk);
|
||||
atmel_ehci->clocked = false;
|
||||
}
|
||||
|
||||
static void atmel_start_ehci(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
|
||||
|
||||
dev_dbg(&pdev->dev, "start\n");
|
||||
atmel_start_clock();
|
||||
atmel_start_clock(atmel_ehci);
|
||||
}
|
||||
|
||||
static void atmel_stop_ehci(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
|
||||
|
||||
dev_dbg(&pdev->dev, "stop\n");
|
||||
atmel_stop_clock();
|
||||
atmel_stop_clock(atmel_ehci);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
|
@ -75,6 +97,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
|
|||
const struct hc_driver *driver = &ehci_atmel_hc_driver;
|
||||
struct resource *res;
|
||||
struct ehci_hcd *ehci;
|
||||
struct atmel_ehci_priv *atmel_ehci;
|
||||
int irq;
|
||||
int retval;
|
||||
|
||||
|
|
@ -105,6 +128,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
|
|||
retval = -ENOMEM;
|
||||
goto fail_create_hcd;
|
||||
}
|
||||
atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
|
|
@ -116,23 +140,23 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
|
|||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = resource_size(res);
|
||||
|
||||
iclk = devm_clk_get(&pdev->dev, "ehci_clk");
|
||||
if (IS_ERR(iclk)) {
|
||||
atmel_ehci->iclk = devm_clk_get(&pdev->dev, "ehci_clk");
|
||||
if (IS_ERR(atmel_ehci->iclk)) {
|
||||
dev_err(&pdev->dev, "Error getting interface clock\n");
|
||||
retval = -ENOENT;
|
||||
goto fail_request_resource;
|
||||
}
|
||||
fclk = devm_clk_get(&pdev->dev, "uhpck");
|
||||
if (IS_ERR(fclk)) {
|
||||
atmel_ehci->fclk = devm_clk_get(&pdev->dev, "uhpck");
|
||||
if (IS_ERR(atmel_ehci->fclk)) {
|
||||
dev_err(&pdev->dev, "Error getting function clock\n");
|
||||
retval = -ENOENT;
|
||||
goto fail_request_resource;
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
|
||||
uclk = devm_clk_get(&pdev->dev, "usb_clk");
|
||||
if (IS_ERR(uclk)) {
|
||||
atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
|
||||
if (IS_ERR(atmel_ehci->uclk)) {
|
||||
dev_err(&pdev->dev, "failed to get uclk\n");
|
||||
retval = PTR_ERR(uclk);
|
||||
retval = PTR_ERR(atmel_ehci->uclk);
|
||||
goto fail_request_resource;
|
||||
}
|
||||
}
|
||||
|
|
@ -169,11 +193,35 @@ static int ehci_atmel_drv_remove(struct platform_device *pdev)
|
|||
usb_put_hcd(hcd);
|
||||
|
||||
atmel_stop_ehci(pdev);
|
||||
fclk = iclk = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ehci_atmel_drv_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
|
||||
int ret;
|
||||
|
||||
ret = ehci_suspend(hcd, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
atmel_stop_clock(atmel_ehci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ehci_atmel_drv_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
|
||||
|
||||
atmel_start_clock(atmel_ehci);
|
||||
return ehci_resume(hcd, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id atmel_ehci_dt_ids[] = {
|
||||
{ .compatible = "atmel,at91sam9g45-ehci" },
|
||||
|
|
@ -183,12 +231,16 @@ static const struct of_device_id atmel_ehci_dt_ids[] = {
|
|||
MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ehci_atmel_pm_ops, ehci_atmel_drv_suspend,
|
||||
ehci_atmel_drv_resume);
|
||||
|
||||
static struct platform_driver ehci_atmel_driver = {
|
||||
.probe = ehci_atmel_drv_probe,
|
||||
.remove = ehci_atmel_drv_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "atmel-ehci",
|
||||
.pm = &ehci_atmel_pm_ops,
|
||||
.of_match_table = of_match_ptr(atmel_ehci_dt_ids),
|
||||
},
|
||||
};
|
||||
|
|
@ -199,7 +251,7 @@ static int __init ehci_atmel_init(void)
|
|||
return -ENODEV;
|
||||
|
||||
pr_info("%s: " DRIVER_DESC "\n", hcd_name);
|
||||
ehci_init_driver(&ehci_atmel_hc_driver, NULL);
|
||||
ehci_init_driver(&ehci_atmel_hc_driver, &ehci_atmel_drv_overrides);
|
||||
return platform_driver_register(&ehci_atmel_driver);
|
||||
}
|
||||
module_init(ehci_atmel_init);
|
||||
|
|
|
|||
|
|
@ -709,7 +709,6 @@ static struct platform_driver ehci_fsl_driver = {
|
|||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "fsl-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = EHCI_FSL_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -187,7 +187,6 @@ static struct platform_driver ehci_grlib_driver = {
|
|||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "grlib-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ehci_hcd_grlib_of_match,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1110,7 +1110,7 @@ int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup)
|
|||
EXPORT_SYMBOL_GPL(ehci_suspend);
|
||||
|
||||
/* Returns 0 if power was preserved, 1 if power was lost */
|
||||
int ehci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||
int ehci_resume(struct usb_hcd *hcd, bool force_reset)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
|
|
@ -1124,12 +1124,12 @@ int ehci_resume(struct usb_hcd *hcd, bool hibernated)
|
|||
return 0; /* Controller is dead */
|
||||
|
||||
/*
|
||||
* If CF is still set and we aren't resuming from hibernation
|
||||
* If CF is still set and reset isn't forced
|
||||
* then we maintained suspend power.
|
||||
* Just undo the effect of ehci_suspend().
|
||||
*/
|
||||
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
|
||||
!hibernated) {
|
||||
!force_reset) {
|
||||
int mask = INTR_MASK;
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
|
|
|
|||
|
|
@ -700,15 +700,15 @@ ehci_hub_descriptor (
|
|||
memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
|
||||
memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
|
||||
|
||||
temp = 0x0008; /* per-port overcurrent reporting */
|
||||
temp = HUB_CHAR_INDV_PORT_OCPM; /* per-port overcurrent reporting */
|
||||
if (HCS_PPC (ehci->hcs_params))
|
||||
temp |= 0x0001; /* per-port power control */
|
||||
temp |= HUB_CHAR_INDV_PORT_LPSM; /* per-port power control */
|
||||
else
|
||||
temp |= 0x0002; /* no power switching */
|
||||
temp |= HUB_CHAR_NO_LPSM; /* no power switching */
|
||||
#if 0
|
||||
// re-enable when we support USB_PORT_FEAT_INDICATOR below.
|
||||
if (HCS_INDICATOR (ehci->hcs_params))
|
||||
temp |= 0x0080; /* per-port indicators (LEDs) */
|
||||
temp |= HUB_CHAR_PORTIND; /* per-port indicators (LEDs) */
|
||||
#endif
|
||||
desc->wHubCharacteristics = cpu_to_le16(temp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,24 @@ static inline bool is_intel_quark_x1000(struct pci_dev *pdev)
|
|||
pdev->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the list of PCI IDs for the devices that have EHCI USB class and
|
||||
* specific drivers for that. One of the example is a ChipIdea device installed
|
||||
* on some Intel MID platforms.
|
||||
*/
|
||||
static const struct pci_device_id bypass_pci_id_table[] = {
|
||||
/* ChipIdea on Intel MID platform */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811), },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829), },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe006), },
|
||||
{}
|
||||
};
|
||||
|
||||
static inline bool is_bypassed_id(struct pci_dev *pdev)
|
||||
{
|
||||
return !!pci_match_id(bypass_pci_id_table, pdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* 0x84 is the offset of in/out threshold register,
|
||||
* and it is the same offset as the register of 'hostpc'.
|
||||
|
|
@ -352,6 +370,13 @@ static const struct ehci_driver_overrides pci_overrides __initconst = {
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int ehci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
if (is_bypassed_id(pdev))
|
||||
return -ENODEV;
|
||||
return usb_hcd_pci_probe(pdev, id);
|
||||
}
|
||||
|
||||
/* PCI driver selection metadata; PCI hotplugging uses this */
|
||||
static const struct pci_device_id pci_ids [] = { {
|
||||
/* handle any USB 2.0 EHCI controller */
|
||||
|
|
@ -370,7 +395,7 @@ static struct pci_driver ehci_pci_driver = {
|
|||
.name = (char *) hcd_name,
|
||||
.id_table = pci_ids,
|
||||
|
||||
.probe = usb_hcd_pci_probe,
|
||||
.probe = ehci_pci_probe,
|
||||
.remove = usb_hcd_pci_remove,
|
||||
.shutdown = usb_hcd_pci_shutdown,
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,8 @@
|
|||
struct ehci_platform_priv {
|
||||
struct clk *clks[EHCI_MAX_CLKS];
|
||||
struct reset_control *rst;
|
||||
struct phy *phy;
|
||||
struct phy **phys;
|
||||
int num_phys;
|
||||
};
|
||||
|
||||
static const char hcd_name[] = "ehci-platform";
|
||||
|
|
@ -78,7 +79,7 @@ static int ehci_platform_power_on(struct platform_device *dev)
|
|||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||
struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
|
||||
int clk, ret;
|
||||
int clk, ret, phy_num;
|
||||
|
||||
for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
|
||||
ret = clk_prepare_enable(priv->clks[clk]);
|
||||
|
|
@ -86,20 +87,28 @@ static int ehci_platform_power_on(struct platform_device *dev)
|
|||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
if (priv->phy) {
|
||||
ret = phy_init(priv->phy);
|
||||
if (ret)
|
||||
goto err_disable_clks;
|
||||
|
||||
ret = phy_power_on(priv->phy);
|
||||
if (ret)
|
||||
goto err_exit_phy;
|
||||
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
|
||||
if (priv->phys[phy_num]) {
|
||||
ret = phy_init(priv->phys[phy_num]);
|
||||
if (ret)
|
||||
goto err_exit_phy;
|
||||
ret = phy_power_on(priv->phys[phy_num]);
|
||||
if (ret) {
|
||||
phy_exit(priv->phys[phy_num]);
|
||||
goto err_exit_phy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_exit_phy:
|
||||
phy_exit(priv->phy);
|
||||
while (--phy_num >= 0) {
|
||||
if (priv->phys[phy_num]) {
|
||||
phy_power_off(priv->phys[phy_num]);
|
||||
phy_exit(priv->phys[phy_num]);
|
||||
}
|
||||
}
|
||||
err_disable_clks:
|
||||
while (--clk >= 0)
|
||||
clk_disable_unprepare(priv->clks[clk]);
|
||||
|
|
@ -111,11 +120,13 @@ static void ehci_platform_power_off(struct platform_device *dev)
|
|||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||
struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
|
||||
int clk;
|
||||
int clk, phy_num;
|
||||
|
||||
if (priv->phy) {
|
||||
phy_power_off(priv->phy);
|
||||
phy_exit(priv->phy);
|
||||
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
|
||||
if (priv->phys[phy_num]) {
|
||||
phy_power_off(priv->phys[phy_num]);
|
||||
phy_exit(priv->phys[phy_num]);
|
||||
}
|
||||
}
|
||||
|
||||
for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
|
||||
|
|
@ -143,7 +154,8 @@ static int ehci_platform_probe(struct platform_device *dev)
|
|||
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
|
||||
struct ehci_platform_priv *priv;
|
||||
struct ehci_hcd *ehci;
|
||||
int err, irq, clk = 0;
|
||||
const char *phy_name;
|
||||
int err, irq, phy_num, clk = 0;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
|
@ -155,7 +167,8 @@ static int ehci_platform_probe(struct platform_device *dev)
|
|||
if (!pdata)
|
||||
pdata = &ehci_platform_defaults;
|
||||
|
||||
err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
|
||||
err = dma_coerce_mask_and_coherent(&dev->dev,
|
||||
pdata->dma_mask_64 ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -185,12 +198,42 @@ static int ehci_platform_probe(struct platform_device *dev)
|
|||
if (of_property_read_bool(dev->dev.of_node, "big-endian"))
|
||||
ehci->big_endian_mmio = ehci->big_endian_desc = 1;
|
||||
|
||||
priv->phy = devm_phy_get(&dev->dev, "usb");
|
||||
if (IS_ERR(priv->phy)) {
|
||||
err = PTR_ERR(priv->phy);
|
||||
if (err == -EPROBE_DEFER)
|
||||
goto err_put_hcd;
|
||||
priv->phy = NULL;
|
||||
if (of_property_read_bool(dev->dev.of_node,
|
||||
"needs-reset-on-resume"))
|
||||
pdata->reset_on_resume = 1;
|
||||
|
||||
priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
|
||||
"phys", "#phy-cells");
|
||||
priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1;
|
||||
|
||||
priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
|
||||
sizeof(struct phy *), GFP_KERNEL);
|
||||
if (!priv->phys)
|
||||
return -ENOMEM;
|
||||
|
||||
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
|
||||
err = of_property_read_string_index(
|
||||
dev->dev.of_node,
|
||||
"phy-names", phy_num,
|
||||
&phy_name);
|
||||
|
||||
if (err < 0) {
|
||||
if (priv->num_phys > 1) {
|
||||
dev_err(&dev->dev, "phy-names not provided");
|
||||
goto err_put_hcd;
|
||||
} else
|
||||
phy_name = "usb";
|
||||
}
|
||||
|
||||
priv->phys[phy_num] = devm_phy_get(&dev->dev,
|
||||
phy_name);
|
||||
if (IS_ERR(priv->phys[phy_num])) {
|
||||
err = PTR_ERR(priv->phys[phy_num]);
|
||||
if ((priv->num_phys > 1) ||
|
||||
(err == -EPROBE_DEFER))
|
||||
goto err_put_hcd;
|
||||
priv->phys[phy_num] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
|
||||
|
|
@ -340,7 +383,7 @@ static int ehci_platform_resume(struct device *dev)
|
|||
return err;
|
||||
}
|
||||
|
||||
ehci_resume(hcd, false);
|
||||
ehci_resume(hcd, pdata->reset_on_resume);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
|
@ -349,6 +392,7 @@ static const struct of_device_id vt8500_ehci_ids[] = {
|
|||
{ .compatible = "via,vt8500-ehci", },
|
||||
{ .compatible = "wm,prizm-ehci", },
|
||||
{ .compatible = "generic-ehci", },
|
||||
{ .compatible = "cavium,octeon-6335-ehci", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
|
||||
|
|
|
|||
|
|
@ -325,6 +325,5 @@ static struct platform_driver ehci_hcd_msp_driver = {
|
|||
.remove = ehci_hcd_msp_drv_remove,
|
||||
.driver = {
|
||||
.name = "pmcmsp-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -234,7 +234,6 @@ static struct platform_driver ehci_hcd_ppc_of_driver = {
|
|||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "ppc-of-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ehci_hcd_ppc_of_match,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -178,7 +178,6 @@ static struct platform_driver ehci_hcd_sead3_driver = {
|
|||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "sead3-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = SEAD3_EHCI_PMOPS,
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -189,7 +189,6 @@ static struct platform_driver ehci_hcd_sh_driver = {
|
|||
.shutdown = ehci_hcd_sh_shutdown,
|
||||
.driver = {
|
||||
.name = "sh_ehci",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -210,7 +210,6 @@ static struct platform_driver ehci_hcd_tilegx_driver = {
|
|||
.shutdown = ehci_hcd_tilegx_drv_shutdown,
|
||||
.driver = {
|
||||
.name = "tilegx-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -236,7 +236,6 @@ static struct platform_driver ehci_hcd_xilinx_of_driver = {
|
|||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "xilinx-of-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ehci_hcd_xilinx_of_match,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -871,7 +871,7 @@ extern int ehci_handshake(struct ehci_hcd *ehci, void __iomem *ptr,
|
|||
|
||||
#ifdef CONFIG_PM
|
||||
extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);
|
||||
extern int ehci_resume(struct usb_hcd *hcd, bool hibernated);
|
||||
extern int ehci_resume(struct usb_hcd *hcd, bool force_reset);
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
extern int ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ static u8 root_hub_des[] = {
|
|||
0x09, /* blength */
|
||||
0x29, /* bDescriptorType;hub-descriptor */
|
||||
0x01, /* bNbrPorts */
|
||||
0x00, /* wHubCharacteristics */
|
||||
0x00,
|
||||
HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_NO_OCPM, /* wHubCharacteristics */
|
||||
0x00, /* per-port power, no overcurrent */
|
||||
0x01, /* bPwrOn2pwrGood;2ms */
|
||||
0x00, /* bHubContrCurrent;0mA */
|
||||
0x00, /* DeviceRemoveable */
|
||||
|
|
@ -208,7 +208,6 @@ int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
{
|
||||
struct fhci_hcd *fhci = hcd_to_fhci(hcd);
|
||||
int retval = 0;
|
||||
int len = 0;
|
||||
struct usb_hub_status *hub_status;
|
||||
struct usb_port_status *port_status;
|
||||
unsigned long flags;
|
||||
|
|
@ -272,8 +271,6 @@ int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
break;
|
||||
case GetHubDescriptor:
|
||||
memcpy(buf, root_hub_des, sizeof(root_hub_des));
|
||||
buf[3] = 0x11; /* per-port power, no ovrcrnt */
|
||||
len = (buf[0] < wLength) ? buf[0] : wLength;
|
||||
break;
|
||||
case GetHubStatus:
|
||||
hub_status = (struct usb_hub_status *)buf;
|
||||
|
|
@ -281,7 +278,6 @@ int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
cpu_to_le16(fhci->vroot_hub->hub.wHubStatus);
|
||||
hub_status->wHubChange =
|
||||
cpu_to_le16(fhci->vroot_hub->hub.wHubChange);
|
||||
len = 4;
|
||||
break;
|
||||
case GetPortStatus:
|
||||
port_status = (struct usb_port_status *)buf;
|
||||
|
|
@ -289,7 +285,6 @@ int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
cpu_to_le16(fhci->vroot_hub->port.wPortStatus);
|
||||
port_status->wPortChange =
|
||||
cpu_to_le16(fhci->vroot_hub->port.wPortChange);
|
||||
len = 4;
|
||||
break;
|
||||
case SetHubFeature:
|
||||
switch (wValue) {
|
||||
|
|
|
|||
|
|
@ -1521,8 +1521,8 @@ fotg210_hub_descriptor(
|
|||
memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
|
||||
memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
|
||||
|
||||
temp = 0x0008; /* per-port overcurrent reporting */
|
||||
temp |= 0x0002; /* no power switching */
|
||||
temp = HUB_CHAR_INDV_PORT_OCPM; /* per-port overcurrent reporting */
|
||||
temp |= HUB_CHAR_NO_LPSM; /* no power switching */
|
||||
desc->wHubCharacteristics = cpu_to_le16(temp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1479,8 +1479,8 @@ fusbh200_hub_descriptor (
|
|||
memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
|
||||
memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
|
||||
|
||||
temp = 0x0008; /* per-port overcurrent reporting */
|
||||
temp |= 0x0002; /* no power switching */
|
||||
temp = HUB_CHAR_INDV_PORT_OCPM; /* per-port overcurrent reporting */
|
||||
temp |= HUB_CHAR_NO_LPSM; /* no power switching */
|
||||
desc->wHubCharacteristics = cpu_to_le16(temp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1482,9 +1482,8 @@ static int get_hub_descriptor(struct usb_hcd *hcd,
|
|||
desc->bDescLength = 9;
|
||||
desc->bPwrOn2PwrGood = 0;
|
||||
desc->wHubCharacteristics = (__force __u16) cpu_to_le16(
|
||||
0x0002 | /* No power switching */
|
||||
0x0010 | /* No over current protection */
|
||||
0);
|
||||
HUB_CHAR_NO_LPSM | /* No power switching */
|
||||
HUB_CHAR_NO_OCPM); /* No over current protection */
|
||||
|
||||
desc->u.hs.DeviceRemovable[0] = 1 << 1;
|
||||
desc->u.hs.DeviceRemovable[1] = ~0;
|
||||
|
|
|
|||
|
|
@ -948,7 +948,10 @@ static void isp116x_hub_descriptor(struct isp116x *isp116x,
|
|||
desc->bHubContrCurrent = 0;
|
||||
desc->bNbrPorts = (u8) (reg & 0x3);
|
||||
/* Power switching, device type, overcurrent. */
|
||||
desc->wHubCharacteristics = cpu_to_le16((u16) ((reg >> 8) & 0x1f));
|
||||
desc->wHubCharacteristics = cpu_to_le16((u16) ((reg >> 8) &
|
||||
(HUB_CHAR_LPSM |
|
||||
HUB_CHAR_COMPOUND |
|
||||
HUB_CHAR_OCPM)));
|
||||
desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff);
|
||||
/* ports removable, and legacy PortPwrCtrlMask */
|
||||
desc->u.hs.DeviceRemovable[0] = 0;
|
||||
|
|
|
|||
|
|
@ -1543,8 +1543,12 @@ static void isp1362_hub_descriptor(struct isp1362_hcd *isp1362_hcd,
|
|||
desc->bHubContrCurrent = 0;
|
||||
desc->bNbrPorts = reg & 0x3;
|
||||
/* Power switching, device type, overcurrent. */
|
||||
desc->wHubCharacteristics = cpu_to_le16((reg >> 8) & 0x1f);
|
||||
DBG(0, "%s: hubcharacteristics = %02x\n", __func__, cpu_to_le16((reg >> 8) & 0x1f));
|
||||
desc->wHubCharacteristics = cpu_to_le16((reg >> 8) &
|
||||
(HUB_CHAR_LPSM |
|
||||
HUB_CHAR_COMPOUND |
|
||||
HUB_CHAR_OCPM));
|
||||
DBG(0, "%s: hubcharacteristics = %02x\n", __func__,
|
||||
desc->wHubCharacteristics);
|
||||
desc->bPwrOn2PwrGood = (reg >> 24) & 0xff;
|
||||
/* ports removable, and legacy PortPwrCtrlMask */
|
||||
desc->u.hs.DeviceRemovable[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1;
|
||||
|
|
|
|||
|
|
@ -1,208 +0,0 @@
|
|||
#ifndef _ISP1760_HCD_H_
|
||||
#define _ISP1760_HCD_H_
|
||||
|
||||
/* exports for if */
|
||||
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
|
||||
int irq, unsigned long irqflags,
|
||||
int rst_gpio,
|
||||
struct device *dev, const char *busname,
|
||||
unsigned int devflags);
|
||||
int init_kmem_once(void);
|
||||
void deinit_kmem_cache(void);
|
||||
|
||||
/* EHCI capability registers */
|
||||
#define HC_CAPLENGTH 0x00
|
||||
#define HC_HCSPARAMS 0x04
|
||||
#define HC_HCCPARAMS 0x08
|
||||
|
||||
/* EHCI operational registers */
|
||||
#define HC_USBCMD 0x20
|
||||
#define HC_USBSTS 0x24
|
||||
#define HC_FRINDEX 0x2c
|
||||
#define HC_CONFIGFLAG 0x60
|
||||
#define HC_PORTSC1 0x64
|
||||
#define HC_ISO_PTD_DONEMAP_REG 0x130
|
||||
#define HC_ISO_PTD_SKIPMAP_REG 0x134
|
||||
#define HC_ISO_PTD_LASTPTD_REG 0x138
|
||||
#define HC_INT_PTD_DONEMAP_REG 0x140
|
||||
#define HC_INT_PTD_SKIPMAP_REG 0x144
|
||||
#define HC_INT_PTD_LASTPTD_REG 0x148
|
||||
#define HC_ATL_PTD_DONEMAP_REG 0x150
|
||||
#define HC_ATL_PTD_SKIPMAP_REG 0x154
|
||||
#define HC_ATL_PTD_LASTPTD_REG 0x158
|
||||
|
||||
/* Configuration Register */
|
||||
#define HC_HW_MODE_CTRL 0x300
|
||||
#define ALL_ATX_RESET (1 << 31)
|
||||
#define HW_ANA_DIGI_OC (1 << 15)
|
||||
#define HW_DATA_BUS_32BIT (1 << 8)
|
||||
#define HW_DACK_POL_HIGH (1 << 6)
|
||||
#define HW_DREQ_POL_HIGH (1 << 5)
|
||||
#define HW_INTR_HIGH_ACT (1 << 2)
|
||||
#define HW_INTR_EDGE_TRIG (1 << 1)
|
||||
#define HW_GLOBAL_INTR_EN (1 << 0)
|
||||
|
||||
#define HC_CHIP_ID_REG 0x304
|
||||
#define HC_SCRATCH_REG 0x308
|
||||
|
||||
#define HC_RESET_REG 0x30c
|
||||
#define SW_RESET_RESET_HC (1 << 1)
|
||||
#define SW_RESET_RESET_ALL (1 << 0)
|
||||
|
||||
#define HC_BUFFER_STATUS_REG 0x334
|
||||
#define ISO_BUF_FILL (1 << 2)
|
||||
#define INT_BUF_FILL (1 << 1)
|
||||
#define ATL_BUF_FILL (1 << 0)
|
||||
|
||||
#define HC_MEMORY_REG 0x33c
|
||||
#define ISP_BANK(x) ((x) << 16)
|
||||
|
||||
#define HC_PORT1_CTRL 0x374
|
||||
#define PORT1_POWER (3 << 3)
|
||||
#define PORT1_INIT1 (1 << 7)
|
||||
#define PORT1_INIT2 (1 << 23)
|
||||
#define HW_OTG_CTRL_SET 0x374
|
||||
#define HW_OTG_CTRL_CLR 0x376
|
||||
|
||||
/* Interrupt Register */
|
||||
#define HC_INTERRUPT_REG 0x310
|
||||
|
||||
#define HC_INTERRUPT_ENABLE 0x314
|
||||
#define HC_ISO_INT (1 << 9)
|
||||
#define HC_ATL_INT (1 << 8)
|
||||
#define HC_INTL_INT (1 << 7)
|
||||
#define HC_EOT_INT (1 << 3)
|
||||
#define HC_SOT_INT (1 << 1)
|
||||
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
|
||||
|
||||
#define HC_ISO_IRQ_MASK_OR_REG 0x318
|
||||
#define HC_INT_IRQ_MASK_OR_REG 0x31C
|
||||
#define HC_ATL_IRQ_MASK_OR_REG 0x320
|
||||
#define HC_ISO_IRQ_MASK_AND_REG 0x324
|
||||
#define HC_INT_IRQ_MASK_AND_REG 0x328
|
||||
#define HC_ATL_IRQ_MASK_AND_REG 0x32C
|
||||
|
||||
/* urb state*/
|
||||
#define DELETE_URB (0x0008)
|
||||
#define NO_TRANSFER_ACTIVE (0xffffffff)
|
||||
|
||||
/* Philips Proprietary Transfer Descriptor (PTD) */
|
||||
typedef __u32 __bitwise __dw;
|
||||
struct ptd {
|
||||
__dw dw0;
|
||||
__dw dw1;
|
||||
__dw dw2;
|
||||
__dw dw3;
|
||||
__dw dw4;
|
||||
__dw dw5;
|
||||
__dw dw6;
|
||||
__dw dw7;
|
||||
};
|
||||
#define PTD_OFFSET 0x0400
|
||||
#define ISO_PTD_OFFSET 0x0400
|
||||
#define INT_PTD_OFFSET 0x0800
|
||||
#define ATL_PTD_OFFSET 0x0c00
|
||||
#define PAYLOAD_OFFSET 0x1000
|
||||
|
||||
struct slotinfo {
|
||||
struct isp1760_qh *qh;
|
||||
struct isp1760_qtd *qtd;
|
||||
unsigned long timestamp;
|
||||
};
|
||||
|
||||
|
||||
typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
|
||||
struct isp1760_qtd *qtd);
|
||||
|
||||
/*
|
||||
* Device flags that can vary from board to board. All of these
|
||||
* indicate the most "atypical" case, so that a devflags of 0 is
|
||||
* a sane default configuration.
|
||||
*/
|
||||
#define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */
|
||||
#define ISP1760_FLAG_OTG_EN 0x00000004 /* Port 1 supports OTG */
|
||||
#define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */
|
||||
#define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */
|
||||
#define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */
|
||||
#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
|
||||
#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
|
||||
#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
|
||||
#define ISP1760_FLAG_RESET_ACTIVE_HIGH 0x80000000 /* RESET GPIO active high */
|
||||
|
||||
/* chip memory management */
|
||||
struct memory_chunk {
|
||||
unsigned int start;
|
||||
unsigned int size;
|
||||
unsigned int free;
|
||||
};
|
||||
|
||||
/*
|
||||
* 60kb divided in:
|
||||
* - 32 blocks @ 256 bytes
|
||||
* - 20 blocks @ 1024 bytes
|
||||
* - 4 blocks @ 8192 bytes
|
||||
*/
|
||||
|
||||
#define BLOCK_1_NUM 32
|
||||
#define BLOCK_2_NUM 20
|
||||
#define BLOCK_3_NUM 4
|
||||
|
||||
#define BLOCK_1_SIZE 256
|
||||
#define BLOCK_2_SIZE 1024
|
||||
#define BLOCK_3_SIZE 8192
|
||||
#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
|
||||
#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE
|
||||
#define PAYLOAD_AREA_SIZE 0xf000
|
||||
|
||||
/* ATL */
|
||||
/* DW0 */
|
||||
#define DW0_VALID_BIT 1
|
||||
#define FROM_DW0_VALID(x) ((x) & 0x01)
|
||||
#define TO_DW0_LENGTH(x) (((u32) x) << 3)
|
||||
#define TO_DW0_MAXPACKET(x) (((u32) x) << 18)
|
||||
#define TO_DW0_MULTI(x) (((u32) x) << 29)
|
||||
#define TO_DW0_ENDPOINT(x) (((u32) x) << 31)
|
||||
/* DW1 */
|
||||
#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3)
|
||||
#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10)
|
||||
#define DW1_TRANS_BULK ((u32) 2 << 12)
|
||||
#define DW1_TRANS_INT ((u32) 3 << 12)
|
||||
#define DW1_TRANS_SPLIT ((u32) 1 << 14)
|
||||
#define DW1_SE_USB_LOSPEED ((u32) 2 << 16)
|
||||
#define TO_DW1_PORT_NUM(x) (((u32) x) << 18)
|
||||
#define TO_DW1_HUB_NUM(x) (((u32) x) << 25)
|
||||
/* DW2 */
|
||||
#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8)
|
||||
#define TO_DW2_RL(x) ((x) << 25)
|
||||
#define FROM_DW2_RL(x) (((x) >> 25) & 0xf)
|
||||
/* DW3 */
|
||||
#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff)
|
||||
#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff)
|
||||
#define TO_DW3_NAKCOUNT(x) ((x) << 19)
|
||||
#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf)
|
||||
#define TO_DW3_CERR(x) ((x) << 23)
|
||||
#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3)
|
||||
#define TO_DW3_DATA_TOGGLE(x) ((x) << 25)
|
||||
#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1)
|
||||
#define TO_DW3_PING(x) ((x) << 26)
|
||||
#define FROM_DW3_PING(x) (((x) >> 26) & 0x1)
|
||||
#define DW3_ERROR_BIT (1 << 28)
|
||||
#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)
|
||||
#define INT_EXACT (1 << 0)
|
||||
|
||||
#define SETUP_PID (2)
|
||||
#define IN_PID (1)
|
||||
#define OUT_PID (0)
|
||||
|
||||
/* Errata 1 */
|
||||
#define RL_COUNTER (0)
|
||||
#define NAK_COUNTER (0)
|
||||
#define ERR_COUNTER (2)
|
||||
|
||||
#endif /* _ISP1760_HCD_H_ */
|
||||
|
|
@ -1,477 +0,0 @@
|
|||
/*
|
||||
* Glue code for the ISP1760 driver and bus
|
||||
* Currently there is support for
|
||||
* - OpenFirmware
|
||||
* - PCI
|
||||
* - PDEV (generic platform device centralized driver model)
|
||||
*
|
||||
* (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/isp1760.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
|
||||
#include "isp1760-hcd.h"
|
||||
|
||||
#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#include <linux/pci.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
|
||||
struct isp1760 {
|
||||
struct usb_hcd *hcd;
|
||||
int rst_gpio;
|
||||
};
|
||||
|
||||
static int of_isp1760_probe(struct platform_device *dev)
|
||||
{
|
||||
struct isp1760 *drvdata;
|
||||
struct device_node *dp = dev->dev.of_node;
|
||||
struct resource *res;
|
||||
struct resource memory;
|
||||
int virq;
|
||||
resource_size_t res_len;
|
||||
int ret;
|
||||
unsigned int devflags = 0;
|
||||
enum of_gpio_flags gpio_flags;
|
||||
u32 bus_width = 0;
|
||||
|
||||
drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
|
||||
if (!drvdata)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_address_to_resource(dp, 0, &memory);
|
||||
if (ret) {
|
||||
ret = -ENXIO;
|
||||
goto free_data;
|
||||
}
|
||||
|
||||
res_len = resource_size(&memory);
|
||||
|
||||
res = request_mem_region(memory.start, res_len, dev_name(&dev->dev));
|
||||
if (!res) {
|
||||
ret = -EBUSY;
|
||||
goto free_data;
|
||||
}
|
||||
|
||||
virq = irq_of_parse_and_map(dp, 0);
|
||||
if (!virq) {
|
||||
ret = -ENODEV;
|
||||
goto release_reg;
|
||||
}
|
||||
|
||||
if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
|
||||
devflags |= ISP1760_FLAG_ISP1761;
|
||||
|
||||
/* Some systems wire up only 16 of the 32 data lines */
|
||||
of_property_read_u32(dp, "bus-width", &bus_width);
|
||||
if (bus_width == 16)
|
||||
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
|
||||
|
||||
if (of_get_property(dp, "port1-otg", NULL) != NULL)
|
||||
devflags |= ISP1760_FLAG_OTG_EN;
|
||||
|
||||
if (of_get_property(dp, "analog-oc", NULL) != NULL)
|
||||
devflags |= ISP1760_FLAG_ANALOG_OC;
|
||||
|
||||
if (of_get_property(dp, "dack-polarity", NULL) != NULL)
|
||||
devflags |= ISP1760_FLAG_DACK_POL_HIGH;
|
||||
|
||||
if (of_get_property(dp, "dreq-polarity", NULL) != NULL)
|
||||
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
|
||||
|
||||
drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags);
|
||||
if (gpio_is_valid(drvdata->rst_gpio)) {
|
||||
ret = gpio_request(drvdata->rst_gpio, dev_name(&dev->dev));
|
||||
if (!ret) {
|
||||
if (!(gpio_flags & OF_GPIO_ACTIVE_LOW)) {
|
||||
devflags |= ISP1760_FLAG_RESET_ACTIVE_HIGH;
|
||||
gpio_direction_output(drvdata->rst_gpio, 0);
|
||||
} else {
|
||||
gpio_direction_output(drvdata->rst_gpio, 1);
|
||||
}
|
||||
} else {
|
||||
drvdata->rst_gpio = ret;
|
||||
}
|
||||
}
|
||||
|
||||
drvdata->hcd = isp1760_register(memory.start, res_len, virq,
|
||||
IRQF_SHARED, drvdata->rst_gpio,
|
||||
&dev->dev, dev_name(&dev->dev),
|
||||
devflags);
|
||||
if (IS_ERR(drvdata->hcd)) {
|
||||
ret = PTR_ERR(drvdata->hcd);
|
||||
goto free_gpio;
|
||||
}
|
||||
|
||||
platform_set_drvdata(dev, drvdata);
|
||||
return ret;
|
||||
|
||||
free_gpio:
|
||||
if (gpio_is_valid(drvdata->rst_gpio))
|
||||
gpio_free(drvdata->rst_gpio);
|
||||
release_reg:
|
||||
release_mem_region(memory.start, res_len);
|
||||
free_data:
|
||||
kfree(drvdata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int of_isp1760_remove(struct platform_device *dev)
|
||||
{
|
||||
struct isp1760 *drvdata = platform_get_drvdata(dev);
|
||||
|
||||
usb_remove_hcd(drvdata->hcd);
|
||||
iounmap(drvdata->hcd->regs);
|
||||
release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len);
|
||||
usb_put_hcd(drvdata->hcd);
|
||||
|
||||
if (gpio_is_valid(drvdata->rst_gpio))
|
||||
gpio_free(drvdata->rst_gpio);
|
||||
|
||||
kfree(drvdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_isp1760_match[] = {
|
||||
{
|
||||
.compatible = "nxp,usb-isp1760",
|
||||
},
|
||||
{
|
||||
.compatible = "nxp,usb-isp1761",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_isp1760_match);
|
||||
|
||||
static struct platform_driver isp1760_of_driver = {
|
||||
.driver = {
|
||||
.name = "nxp-isp1760",
|
||||
.of_match_table = of_isp1760_match,
|
||||
},
|
||||
.probe = of_isp1760_probe,
|
||||
.remove = of_isp1760_remove,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
static int isp1761_pci_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
u8 latency, limit;
|
||||
__u32 reg_data;
|
||||
int retry_count;
|
||||
struct usb_hcd *hcd;
|
||||
unsigned int devflags = 0;
|
||||
int ret_status = 0;
|
||||
|
||||
resource_size_t pci_mem_phy0;
|
||||
resource_size_t memlength;
|
||||
|
||||
u8 __iomem *chip_addr;
|
||||
u8 __iomem *iobase;
|
||||
resource_size_t nxp_pci_io_base;
|
||||
resource_size_t iolength;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
if (pci_enable_device(dev) < 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (!dev->irq)
|
||||
return -ENODEV;
|
||||
|
||||
/* Grab the PLX PCI mem maped port start address we need */
|
||||
nxp_pci_io_base = pci_resource_start(dev, 0);
|
||||
iolength = pci_resource_len(dev, 0);
|
||||
|
||||
if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) {
|
||||
printk(KERN_ERR "request region #1\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
iobase = ioremap_nocache(nxp_pci_io_base, iolength);
|
||||
if (!iobase) {
|
||||
printk(KERN_ERR "ioremap #1\n");
|
||||
ret_status = -ENOMEM;
|
||||
goto cleanup1;
|
||||
}
|
||||
/* Grab the PLX PCI shared memory of the ISP 1761 we need */
|
||||
pci_mem_phy0 = pci_resource_start(dev, 3);
|
||||
memlength = pci_resource_len(dev, 3);
|
||||
if (memlength < 0xffff) {
|
||||
printk(KERN_ERR "memory length for this resource is wrong\n");
|
||||
ret_status = -ENOMEM;
|
||||
goto cleanup2;
|
||||
}
|
||||
|
||||
if (!request_mem_region(pci_mem_phy0, memlength, "ISP-PCI")) {
|
||||
printk(KERN_ERR "host controller already in use\n");
|
||||
ret_status = -EBUSY;
|
||||
goto cleanup2;
|
||||
}
|
||||
|
||||
/* map available memory */
|
||||
chip_addr = ioremap_nocache(pci_mem_phy0,memlength);
|
||||
if (!chip_addr) {
|
||||
printk(KERN_ERR "Error ioremap failed\n");
|
||||
ret_status = -ENOMEM;
|
||||
goto cleanup3;
|
||||
}
|
||||
|
||||
/* bad pci latencies can contribute to overruns */
|
||||
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
|
||||
if (latency) {
|
||||
pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
|
||||
if (limit && limit < latency)
|
||||
pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
|
||||
}
|
||||
|
||||
/* Try to check whether we can access Scratch Register of
|
||||
* Host Controller or not. The initial PCI access is retried until
|
||||
* local init for the PCI bridge is completed
|
||||
*/
|
||||
retry_count = 20;
|
||||
reg_data = 0;
|
||||
while ((reg_data != 0xFACE) && retry_count) {
|
||||
/*by default host is in 16bit mode, so
|
||||
* io operations at this stage must be 16 bit
|
||||
* */
|
||||
writel(0xface, chip_addr + HC_SCRATCH_REG);
|
||||
udelay(100);
|
||||
reg_data = readl(chip_addr + HC_SCRATCH_REG) & 0x0000ffff;
|
||||
retry_count--;
|
||||
}
|
||||
|
||||
iounmap(chip_addr);
|
||||
|
||||
/* Host Controller presence is detected by writing to scratch register
|
||||
* and reading back and checking the contents are same or not
|
||||
*/
|
||||
if (reg_data != 0xFACE) {
|
||||
dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
|
||||
ret_status = -ENOMEM;
|
||||
goto cleanup3;
|
||||
}
|
||||
|
||||
pci_set_master(dev);
|
||||
|
||||
/* configure PLX PCI chip to pass interrupts */
|
||||
#define PLX_INT_CSR_REG 0x68
|
||||
reg_data = readl(iobase + PLX_INT_CSR_REG);
|
||||
reg_data |= 0x900;
|
||||
writel(reg_data, iobase + PLX_INT_CSR_REG);
|
||||
|
||||
dev->dev.dma_mask = NULL;
|
||||
hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq,
|
||||
IRQF_SHARED, -ENOENT, &dev->dev, dev_name(&dev->dev),
|
||||
devflags);
|
||||
if (IS_ERR(hcd)) {
|
||||
ret_status = -ENODEV;
|
||||
goto cleanup3;
|
||||
}
|
||||
|
||||
/* done with PLX IO access */
|
||||
iounmap(iobase);
|
||||
release_mem_region(nxp_pci_io_base, iolength);
|
||||
|
||||
pci_set_drvdata(dev, hcd);
|
||||
return 0;
|
||||
|
||||
cleanup3:
|
||||
release_mem_region(pci_mem_phy0, memlength);
|
||||
cleanup2:
|
||||
iounmap(iobase);
|
||||
cleanup1:
|
||||
release_mem_region(nxp_pci_io_base, iolength);
|
||||
return ret_status;
|
||||
}
|
||||
|
||||
static void isp1761_pci_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
hcd = pci_get_drvdata(dev);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
pci_disable_device(dev);
|
||||
}
|
||||
|
||||
static void isp1761_pci_shutdown(struct pci_dev *dev)
|
||||
{
|
||||
printk(KERN_ERR "ips1761_pci_shutdown\n");
|
||||
}
|
||||
|
||||
static const struct pci_device_id isp1760_plx [] = {
|
||||
{
|
||||
.class = PCI_CLASS_BRIDGE_OTHER << 8,
|
||||
.class_mask = ~0,
|
||||
.vendor = PCI_VENDOR_ID_PLX,
|
||||
.device = 0x5406,
|
||||
.subvendor = PCI_VENDOR_ID_PLX,
|
||||
.subdevice = 0x9054,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, isp1760_plx);
|
||||
|
||||
static struct pci_driver isp1761_pci_driver = {
|
||||
.name = "isp1760",
|
||||
.id_table = isp1760_plx,
|
||||
.probe = isp1761_pci_probe,
|
||||
.remove = isp1761_pci_remove,
|
||||
.shutdown = isp1761_pci_shutdown,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int isp1760_plat_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct usb_hcd *hcd;
|
||||
struct resource *mem_res;
|
||||
struct resource *irq_res;
|
||||
resource_size_t mem_size;
|
||||
struct isp1760_platform_data *priv = dev_get_platdata(&pdev->dev);
|
||||
unsigned int devflags = 0;
|
||||
unsigned long irqflags = IRQF_SHARED;
|
||||
|
||||
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mem_res) {
|
||||
pr_warning("isp1760: Memory resource not available\n");
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
mem_size = resource_size(mem_res);
|
||||
if (!request_mem_region(mem_res->start, mem_size, "isp1760")) {
|
||||
pr_warning("isp1760: Cannot reserve the memory resource\n");
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!irq_res) {
|
||||
pr_warning("isp1760: IRQ resource not available\n");
|
||||
ret = -ENODEV;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
irqflags |= irq_res->flags & IRQF_TRIGGER_MASK;
|
||||
|
||||
if (priv) {
|
||||
if (priv->is_isp1761)
|
||||
devflags |= ISP1760_FLAG_ISP1761;
|
||||
if (priv->bus_width_16)
|
||||
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
|
||||
if (priv->port1_otg)
|
||||
devflags |= ISP1760_FLAG_OTG_EN;
|
||||
if (priv->analog_oc)
|
||||
devflags |= ISP1760_FLAG_ANALOG_OC;
|
||||
if (priv->dack_polarity_high)
|
||||
devflags |= ISP1760_FLAG_DACK_POL_HIGH;
|
||||
if (priv->dreq_polarity_high)
|
||||
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
|
||||
}
|
||||
|
||||
hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
|
||||
irqflags, -ENOENT,
|
||||
&pdev->dev, dev_name(&pdev->dev), devflags);
|
||||
|
||||
platform_set_drvdata(pdev, hcd);
|
||||
|
||||
if (IS_ERR(hcd)) {
|
||||
pr_warning("isp1760: Failed to register the HCD device\n");
|
||||
ret = -ENODEV;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pr_info("ISP1760 USB device initialised\n");
|
||||
return ret;
|
||||
|
||||
cleanup:
|
||||
release_mem_region(mem_res->start, mem_size);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int isp1760_plat_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *mem_res;
|
||||
resource_size_t mem_size;
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
mem_size = resource_size(mem_res);
|
||||
release_mem_region(mem_res->start, mem_size);
|
||||
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver isp1760_plat_driver = {
|
||||
.probe = isp1760_plat_probe,
|
||||
.remove = isp1760_plat_remove,
|
||||
.driver = {
|
||||
.name = "isp1760",
|
||||
},
|
||||
};
|
||||
|
||||
static int __init isp1760_init(void)
|
||||
{
|
||||
int ret, any_ret = -ENODEV;
|
||||
|
||||
init_kmem_once();
|
||||
|
||||
ret = platform_driver_register(&isp1760_plat_driver);
|
||||
if (!ret)
|
||||
any_ret = 0;
|
||||
#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
|
||||
ret = platform_driver_register(&isp1760_of_driver);
|
||||
if (!ret)
|
||||
any_ret = 0;
|
||||
#endif
|
||||
#ifdef CONFIG_PCI
|
||||
ret = pci_register_driver(&isp1761_pci_driver);
|
||||
if (!ret)
|
||||
any_ret = 0;
|
||||
#endif
|
||||
|
||||
if (any_ret)
|
||||
deinit_kmem_cache();
|
||||
return any_ret;
|
||||
}
|
||||
module_init(isp1760_init);
|
||||
|
||||
static void __exit isp1760_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&isp1760_plat_driver);
|
||||
#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
|
||||
platform_driver_unregister(&isp1760_of_driver);
|
||||
#endif
|
||||
#ifdef CONFIG_PCI
|
||||
pci_unregister_driver(&isp1761_pci_driver);
|
||||
#endif
|
||||
deinit_kmem_cache();
|
||||
}
|
||||
module_exit(isp1760_exit);
|
||||
|
|
@ -55,6 +55,7 @@
|
|||
* single thread (max3421_spi_thread).
|
||||
*/
|
||||
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/usb.h>
|
||||
|
|
@ -1291,7 +1292,7 @@ max3421_handle_irqs(struct usb_hcd *hcd)
|
|||
char sbuf[16 * 16], *dp, *end;
|
||||
int i;
|
||||
|
||||
if (jiffies - last_time > 5*HZ) {
|
||||
if (time_after(jiffies, last_time + 5*HZ)) {
|
||||
dp = sbuf;
|
||||
end = sbuf + sizeof(sbuf);
|
||||
*dp = '\0';
|
||||
|
|
@ -1660,7 +1661,8 @@ hub_descriptor(struct usb_hub_descriptor *desc)
|
|||
*/
|
||||
desc->bDescriptorType = 0x29; /* hub descriptor */
|
||||
desc->bDescLength = 9;
|
||||
desc->wHubCharacteristics = cpu_to_le16(0x0001);
|
||||
desc->wHubCharacteristics = cpu_to_le16(HUB_CHAR_INDV_PORT_LPSM |
|
||||
HUB_CHAR_COMMON_OCPM);
|
||||
desc->bNbrPorts = 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,17 @@
|
|||
for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++)
|
||||
|
||||
/* interface, function and usb clocks; sometimes also an AHB clock */
|
||||
static struct clk *iclk, *fclk, *uclk, *hclk;
|
||||
#define hcd_to_ohci_at91_priv(h) \
|
||||
((struct ohci_at91_priv *)hcd_to_ohci(h)->priv)
|
||||
|
||||
struct ohci_at91_priv {
|
||||
struct clk *iclk;
|
||||
struct clk *fclk;
|
||||
struct clk *uclk;
|
||||
struct clk *hclk;
|
||||
bool clocked;
|
||||
bool wakeup; /* Saved wake-up state for resume */
|
||||
};
|
||||
/* interface and function clocks; sometimes also an AHB clock */
|
||||
|
||||
#define DRIVER_DESC "OHCI Atmel driver"
|
||||
|
|
@ -41,45 +51,53 @@ static struct clk *iclk, *fclk, *uclk, *hclk;
|
|||
static const char hcd_name[] = "ohci-atmel";
|
||||
|
||||
static struct hc_driver __read_mostly ohci_at91_hc_driver;
|
||||
static int clocked;
|
||||
|
||||
static const struct ohci_driver_overrides ohci_at91_drv_overrides __initconst = {
|
||||
.extra_priv_size = sizeof(struct ohci_at91_priv),
|
||||
};
|
||||
|
||||
extern int usb_disabled(void);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void at91_start_clock(void)
|
||||
static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
|
||||
{
|
||||
if (ohci_at91->clocked)
|
||||
return;
|
||||
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
|
||||
clk_set_rate(uclk, 48000000);
|
||||
clk_prepare_enable(uclk);
|
||||
clk_set_rate(ohci_at91->uclk, 48000000);
|
||||
clk_prepare_enable(ohci_at91->uclk);
|
||||
}
|
||||
clk_prepare_enable(hclk);
|
||||
clk_prepare_enable(iclk);
|
||||
clk_prepare_enable(fclk);
|
||||
clocked = 1;
|
||||
clk_prepare_enable(ohci_at91->hclk);
|
||||
clk_prepare_enable(ohci_at91->iclk);
|
||||
clk_prepare_enable(ohci_at91->fclk);
|
||||
ohci_at91->clocked = true;
|
||||
}
|
||||
|
||||
static void at91_stop_clock(void)
|
||||
static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
|
||||
{
|
||||
clk_disable_unprepare(fclk);
|
||||
clk_disable_unprepare(iclk);
|
||||
clk_disable_unprepare(hclk);
|
||||
if (!ohci_at91->clocked)
|
||||
return;
|
||||
clk_disable_unprepare(ohci_at91->fclk);
|
||||
clk_disable_unprepare(ohci_at91->iclk);
|
||||
clk_disable_unprepare(ohci_at91->hclk);
|
||||
if (IS_ENABLED(CONFIG_COMMON_CLK))
|
||||
clk_disable_unprepare(uclk);
|
||||
clocked = 0;
|
||||
clk_disable_unprepare(ohci_at91->uclk);
|
||||
ohci_at91->clocked = false;
|
||||
}
|
||||
|
||||
static void at91_start_hc(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct ohci_regs __iomem *regs = hcd->regs;
|
||||
struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
|
||||
|
||||
dev_dbg(&pdev->dev, "start\n");
|
||||
|
||||
/*
|
||||
* Start the USB clocks.
|
||||
*/
|
||||
at91_start_clock();
|
||||
at91_start_clock(ohci_at91);
|
||||
|
||||
/*
|
||||
* The USB host controller must remain in reset.
|
||||
|
|
@ -91,6 +109,7 @@ static void at91_stop_hc(struct platform_device *pdev)
|
|||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct ohci_regs __iomem *regs = hcd->regs;
|
||||
struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
|
||||
|
||||
dev_dbg(&pdev->dev, "stop\n");
|
||||
|
||||
|
|
@ -102,7 +121,7 @@ static void at91_stop_hc(struct platform_device *pdev)
|
|||
/*
|
||||
* Stop the USB clocks.
|
||||
*/
|
||||
at91_stop_clock();
|
||||
at91_stop_clock(ohci_at91);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -128,7 +147,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
|
|||
struct at91_usbh_data *board;
|
||||
struct ohci_hcd *ohci;
|
||||
int retval;
|
||||
struct usb_hcd *hcd = NULL;
|
||||
struct usb_hcd *hcd;
|
||||
struct ohci_at91_priv *ohci_at91;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
|
|
@ -142,6 +162,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
|
|||
hcd = usb_create_hcd(driver, dev, "at91");
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
ohci_at91 = hcd_to_ohci_at91_priv(hcd);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
hcd->regs = devm_ioremap_resource(dev, res);
|
||||
|
|
@ -152,29 +173,29 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
|
|||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = resource_size(res);
|
||||
|
||||
iclk = devm_clk_get(dev, "ohci_clk");
|
||||
if (IS_ERR(iclk)) {
|
||||
ohci_at91->iclk = devm_clk_get(dev, "ohci_clk");
|
||||
if (IS_ERR(ohci_at91->iclk)) {
|
||||
dev_err(dev, "failed to get ohci_clk\n");
|
||||
retval = PTR_ERR(iclk);
|
||||
retval = PTR_ERR(ohci_at91->iclk);
|
||||
goto err;
|
||||
}
|
||||
fclk = devm_clk_get(dev, "uhpck");
|
||||
if (IS_ERR(fclk)) {
|
||||
ohci_at91->fclk = devm_clk_get(dev, "uhpck");
|
||||
if (IS_ERR(ohci_at91->fclk)) {
|
||||
dev_err(dev, "failed to get uhpck\n");
|
||||
retval = PTR_ERR(fclk);
|
||||
retval = PTR_ERR(ohci_at91->fclk);
|
||||
goto err;
|
||||
}
|
||||
hclk = devm_clk_get(dev, "hclk");
|
||||
if (IS_ERR(hclk)) {
|
||||
ohci_at91->hclk = devm_clk_get(dev, "hclk");
|
||||
if (IS_ERR(ohci_at91->hclk)) {
|
||||
dev_err(dev, "failed to get hclk\n");
|
||||
retval = PTR_ERR(hclk);
|
||||
retval = PTR_ERR(ohci_at91->hclk);
|
||||
goto err;
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
|
||||
uclk = devm_clk_get(dev, "usb_clk");
|
||||
if (IS_ERR(uclk)) {
|
||||
ohci_at91->uclk = devm_clk_get(dev, "usb_clk");
|
||||
if (IS_ERR(ohci_at91->uclk)) {
|
||||
dev_err(dev, "failed to get uclk\n");
|
||||
retval = PTR_ERR(uclk);
|
||||
retval = PTR_ERR(ohci_at91->uclk);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
|
@ -347,11 +368,13 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
*/
|
||||
|
||||
desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM);
|
||||
desc->wHubCharacteristics |= cpu_to_le16(0x0001);
|
||||
desc->wHubCharacteristics |=
|
||||
cpu_to_le16(HUB_CHAR_INDV_PORT_LPSM);
|
||||
|
||||
if (pdata->overcurrent_supported) {
|
||||
desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM);
|
||||
desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001);
|
||||
desc->wHubCharacteristics |=
|
||||
cpu_to_le16(HUB_CHAR_INDV_PORT_OCPM);
|
||||
}
|
||||
|
||||
dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n",
|
||||
|
|
@ -593,19 +616,27 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
|
|||
#ifdef CONFIG_PM
|
||||
|
||||
static int
|
||||
ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
|
||||
ohci_hcd_at91_drv_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
bool do_wakeup = device_may_wakeup(&pdev->dev);
|
||||
struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
|
||||
int ret;
|
||||
|
||||
if (do_wakeup)
|
||||
/*
|
||||
* Disable wakeup if we are going to sleep with slow clock mode
|
||||
* enabled.
|
||||
*/
|
||||
ohci_at91->wakeup = device_may_wakeup(dev)
|
||||
&& !at91_suspend_entering_slow_clock();
|
||||
|
||||
if (ohci_at91->wakeup)
|
||||
enable_irq_wake(hcd->irq);
|
||||
|
||||
ret = ohci_suspend(hcd, do_wakeup);
|
||||
ret = ohci_suspend(hcd, ohci_at91->wakeup);
|
||||
if (ret) {
|
||||
disable_irq_wake(hcd->irq);
|
||||
if (ohci_at91->wakeup)
|
||||
disable_irq_wake(hcd->irq);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
|
|
@ -615,7 +646,7 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
|
|||
*
|
||||
* REVISIT: some boards will be able to turn VBUS off...
|
||||
*/
|
||||
if (at91_suspend_entering_slow_clock()) {
|
||||
if (!ohci_at91->wakeup) {
|
||||
ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
|
||||
ohci->hc_control &= OHCI_CTRL_RWC;
|
||||
ohci_writel(ohci, ohci->hc_control, &ohci->regs->control);
|
||||
|
|
@ -623,38 +654,37 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
|
|||
|
||||
/* flush the writes */
|
||||
(void) ohci_readl (ohci, &ohci->regs->control);
|
||||
at91_stop_clock();
|
||||
at91_stop_clock(ohci_at91);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
|
||||
static int ohci_hcd_at91_drv_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
|
||||
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
if (ohci_at91->wakeup)
|
||||
disable_irq_wake(hcd->irq);
|
||||
|
||||
if (!clocked)
|
||||
at91_start_clock();
|
||||
at91_start_clock(ohci_at91);
|
||||
|
||||
ohci_resume(hcd, false);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ohci_hcd_at91_drv_suspend NULL
|
||||
#define ohci_hcd_at91_drv_resume NULL
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ohci_hcd_at91_pm_ops, ohci_hcd_at91_drv_suspend,
|
||||
ohci_hcd_at91_drv_resume);
|
||||
|
||||
static struct platform_driver ohci_hcd_at91_driver = {
|
||||
.probe = ohci_hcd_at91_drv_probe,
|
||||
.remove = ohci_hcd_at91_drv_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.suspend = ohci_hcd_at91_drv_suspend,
|
||||
.resume = ohci_hcd_at91_drv_resume,
|
||||
.driver = {
|
||||
.name = "at91_ohci",
|
||||
.pm = &ohci_hcd_at91_pm_ops,
|
||||
.of_match_table = of_match_ptr(at91_ohci_dt_ids),
|
||||
},
|
||||
};
|
||||
|
|
@ -665,7 +695,7 @@ static int __init ohci_at91_init(void)
|
|||
return -ENODEV;
|
||||
|
||||
pr_info("%s: " DRIVER_DESC "\n", hcd_name);
|
||||
ohci_init_driver(&ohci_at91_hc_driver, NULL);
|
||||
ohci_init_driver(&ohci_at91_hc_driver, &ohci_at91_drv_overrides);
|
||||
|
||||
/*
|
||||
* The Atmel HW has some unusual quirks, which require Atmel-specific
|
||||
|
|
|
|||
|
|
@ -431,7 +431,6 @@ static struct platform_driver ohci_hcd_da8xx_driver = {
|
|||
.resume = ohci_da8xx_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "ohci",
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -544,15 +544,15 @@ ohci_hub_descriptor (
|
|||
temp = 1 + (ohci->num_ports / 8);
|
||||
desc->bDescLength = 7 + 2 * temp;
|
||||
|
||||
temp = 0;
|
||||
temp = HUB_CHAR_COMMON_LPSM | HUB_CHAR_COMMON_OCPM;
|
||||
if (rh & RH_A_NPS) /* no power switching? */
|
||||
temp |= 0x0002;
|
||||
temp |= HUB_CHAR_NO_LPSM;
|
||||
if (rh & RH_A_PSM) /* per-port power switching? */
|
||||
temp |= 0x0001;
|
||||
temp |= HUB_CHAR_INDV_PORT_LPSM;
|
||||
if (rh & RH_A_NOCP) /* no overcurrent reporting? */
|
||||
temp |= 0x0010;
|
||||
temp |= HUB_CHAR_NO_OCPM;
|
||||
else if (rh & RH_A_OCPM) /* per-port overcurrent reporting? */
|
||||
temp |= 0x0008;
|
||||
temp |= HUB_CHAR_INDV_PORT_OCPM;
|
||||
desc->wHubCharacteristics = cpu_to_le16(temp);
|
||||
|
||||
/* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
|
||||
|
|
|
|||
|
|
@ -239,7 +239,6 @@ static struct platform_driver ohci_hcd_jz4740_driver = {
|
|||
.remove = jz4740_ohci_remove,
|
||||
.driver = {
|
||||
.name = "jz4740-ohci",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@
|
|||
struct ohci_platform_priv {
|
||||
struct clk *clks[OHCI_MAX_CLKS];
|
||||
struct reset_control *rst;
|
||||
struct phy *phy;
|
||||
struct phy **phys;
|
||||
int num_phys;
|
||||
};
|
||||
|
||||
static const char hcd_name[] = "ohci-platform";
|
||||
|
|
@ -47,7 +48,7 @@ static int ohci_platform_power_on(struct platform_device *dev)
|
|||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||
struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
|
||||
int clk, ret;
|
||||
int clk, ret, phy_num;
|
||||
|
||||
for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) {
|
||||
ret = clk_prepare_enable(priv->clks[clk]);
|
||||
|
|
@ -55,20 +56,28 @@ static int ohci_platform_power_on(struct platform_device *dev)
|
|||
goto err_disable_clks;
|
||||
}
|
||||
|
||||
if (priv->phy) {
|
||||
ret = phy_init(priv->phy);
|
||||
if (ret)
|
||||
goto err_disable_clks;
|
||||
|
||||
ret = phy_power_on(priv->phy);
|
||||
if (ret)
|
||||
goto err_exit_phy;
|
||||
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
|
||||
if (priv->phys[phy_num]) {
|
||||
ret = phy_init(priv->phys[phy_num]);
|
||||
if (ret)
|
||||
goto err_exit_phy;
|
||||
ret = phy_power_on(priv->phys[phy_num]);
|
||||
if (ret) {
|
||||
phy_exit(priv->phys[phy_num]);
|
||||
goto err_exit_phy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_exit_phy:
|
||||
phy_exit(priv->phy);
|
||||
while (--phy_num >= 0) {
|
||||
if (priv->phys[phy_num]) {
|
||||
phy_power_off(priv->phys[phy_num]);
|
||||
phy_exit(priv->phys[phy_num]);
|
||||
}
|
||||
}
|
||||
err_disable_clks:
|
||||
while (--clk >= 0)
|
||||
clk_disable_unprepare(priv->clks[clk]);
|
||||
|
|
@ -80,11 +89,13 @@ static void ohci_platform_power_off(struct platform_device *dev)
|
|||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||
struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
|
||||
int clk;
|
||||
int clk, phy_num;
|
||||
|
||||
if (priv->phy) {
|
||||
phy_power_off(priv->phy);
|
||||
phy_exit(priv->phy);
|
||||
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
|
||||
if (priv->phys[phy_num]) {
|
||||
phy_power_off(priv->phys[phy_num]);
|
||||
phy_exit(priv->phys[phy_num]);
|
||||
}
|
||||
}
|
||||
|
||||
for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
|
||||
|
|
@ -112,7 +123,8 @@ static int ohci_platform_probe(struct platform_device *dev)
|
|||
struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
|
||||
struct ohci_platform_priv *priv;
|
||||
struct ohci_hcd *ohci;
|
||||
int err, irq, clk = 0;
|
||||
const char *phy_name;
|
||||
int err, irq, phy_num, clk = 0;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
|
@ -160,12 +172,38 @@ static int ohci_platform_probe(struct platform_device *dev)
|
|||
of_property_read_u32(dev->dev.of_node, "num-ports",
|
||||
&ohci->num_ports);
|
||||
|
||||
priv->phy = devm_phy_get(&dev->dev, "usb");
|
||||
if (IS_ERR(priv->phy)) {
|
||||
err = PTR_ERR(priv->phy);
|
||||
if (err == -EPROBE_DEFER)
|
||||
goto err_put_hcd;
|
||||
priv->phy = NULL;
|
||||
priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
|
||||
"phys", "#phy-cells");
|
||||
priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1;
|
||||
|
||||
priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
|
||||
sizeof(struct phy *), GFP_KERNEL);
|
||||
if (!priv->phys)
|
||||
return -ENOMEM;
|
||||
|
||||
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
|
||||
err = of_property_read_string_index(
|
||||
dev->dev.of_node,
|
||||
"phy-names", phy_num,
|
||||
&phy_name);
|
||||
|
||||
if (err < 0) {
|
||||
if (priv->num_phys > 1) {
|
||||
dev_err(&dev->dev, "phy-names not provided");
|
||||
goto err_put_hcd;
|
||||
} else
|
||||
phy_name = "usb";
|
||||
}
|
||||
|
||||
priv->phys[phy_num] = devm_phy_get(&dev->dev,
|
||||
phy_name);
|
||||
if (IS_ERR(priv->phys[phy_num])) {
|
||||
err = PTR_ERR(priv->phys[phy_num]);
|
||||
if ((priv->num_phys > 1) ||
|
||||
(err == -EPROBE_DEFER))
|
||||
goto err_put_hcd;
|
||||
priv->phys[phy_num] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {
|
||||
|
|
@ -328,6 +366,7 @@ static int ohci_platform_resume(struct device *dev)
|
|||
|
||||
static const struct of_device_id ohci_platform_ids[] = {
|
||||
{ .compatible = "generic-ohci", },
|
||||
{ .compatible = "cavium,octeon-6335-ohci", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ohci_platform_ids);
|
||||
|
|
|
|||
|
|
@ -229,7 +229,6 @@ static struct platform_driver ohci_hcd_ppc_of_driver = {
|
|||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "ppc-of-ohci",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ohci_hcd_ppc_of_match,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -249,14 +249,14 @@ static int ohci_s3c2410_hub_control(
|
|||
*/
|
||||
|
||||
desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM);
|
||||
desc->wHubCharacteristics |= cpu_to_le16(0x0001);
|
||||
desc->wHubCharacteristics |= cpu_to_le16(
|
||||
HUB_CHAR_INDV_PORT_LPSM);
|
||||
|
||||
if (info->enable_oc) {
|
||||
desc->wHubCharacteristics &= ~cpu_to_le16(
|
||||
HUB_CHAR_OCPM);
|
||||
desc->wHubCharacteristics |= cpu_to_le16(
|
||||
0x0008 |
|
||||
0x0001);
|
||||
HUB_CHAR_INDV_PORT_OCPM);
|
||||
}
|
||||
|
||||
dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n",
|
||||
|
|
|
|||
|
|
@ -265,7 +265,6 @@ static struct platform_driver ohci_hcd_sm501_driver = {
|
|||
.suspend = ohci_sm501_suspend,
|
||||
.resume = ohci_sm501_resume,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "sm501-usb",
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -199,7 +199,6 @@ static struct platform_driver ohci_hcd_tilegx_driver = {
|
|||
.shutdown = ohci_hcd_tilegx_drv_shutdown,
|
||||
.driver = {
|
||||
.name = "tilegx-ohci",
|
||||
.owner = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -368,6 +368,5 @@ static struct platform_driver ohci_hcd_tmio_driver = {
|
|||
.resume = ohci_hcd_tmio_drv_resume,
|
||||
.driver = {
|
||||
.name = "tmio-ohci",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue