mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-15 17:43:59 +00:00
Merge 3.5-rc7 into usb-next
This resolves the merge issue with the drivers/usb/host/ehci-omap.c file. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
commit
b903bd69e3
18
Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
Normal file
18
Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
Normal file
@ -0,0 +1,18 @@
|
||||
* Freescale i.MX ci13xxx usb controllers
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "fsl,imx27-usb"
|
||||
- reg: Should contain registers location and length
|
||||
- interrupts: Should contain controller interrupt
|
||||
|
||||
Optional properties:
|
||||
- fsl,usbphy: phandler of usb phy that connects to the only one port
|
||||
- vbus-supply: regulator for vbus
|
||||
|
||||
Examples:
|
||||
usb@02184000 { /* USB OTG */
|
||||
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
|
||||
reg = <0x02184000 0x200>;
|
||||
interrupts = <0 43 0x04>;
|
||||
fsl,usbphy = <&usbphy1>;
|
||||
};
|
13
Documentation/devicetree/bindings/usb/mxs-phy.txt
Normal file
13
Documentation/devicetree/bindings/usb/mxs-phy.txt
Normal file
@ -0,0 +1,13 @@
|
||||
* Freescale MXS USB Phy Device
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "fsl,imx23-usbphy"
|
||||
- reg: Should contain registers location and length
|
||||
- interrupts: Should contain phy interrupt
|
||||
|
||||
Example:
|
||||
usbphy1: usbphy@020c9000 {
|
||||
compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
|
||||
reg = <0x020c9000 0x1000>;
|
||||
interrupts = <0 44 0x04>;
|
||||
};
|
226
Documentation/usb/mass-storage.txt
Normal file
226
Documentation/usb/mass-storage.txt
Normal file
@ -0,0 +1,226 @@
|
||||
* Overview
|
||||
|
||||
Mass Storage Gadget (or MSG) acts as a USB Mass Storage device,
|
||||
appearing to the host as a disk or a CD-ROM drive. It supports
|
||||
multiple logical units (LUNs). Backing storage for each LUN is
|
||||
provided by a regular file or a block device, access can be limited
|
||||
to read-only, and gadget can indicate that it is removable and/or
|
||||
CD-ROM (the latter implies read-only access).
|
||||
|
||||
Its requirements are modest; only a bulk-in and a bulk-out endpoint
|
||||
are needed. The memory requirement amounts to two 16K buffers.
|
||||
Support is included for full-speed, high-speed and SuperSpeed
|
||||
operation.
|
||||
|
||||
Note that the driver is slightly non-portable in that it assumes
|
||||
a single memory/DMA buffer will be useable for bulk-in and bulk-out
|
||||
endpoints. With most device controllers this is not an issue, but
|
||||
there may be some with hardware restrictions that prevent a buffer
|
||||
from being used by more than one endpoint.
|
||||
|
||||
This document describes how to use the gadget from user space, its
|
||||
relation to mass storage function (or MSF) and different gadgets
|
||||
using it, and how it differs from File Storage Gadget (or FSG). It
|
||||
will talk only briefly about how to use MSF within composite
|
||||
gadgets.
|
||||
|
||||
* Module parameters
|
||||
|
||||
The mass storage gadget accepts the following mass storage specific
|
||||
module parameters:
|
||||
|
||||
- file=filename[,filename...]
|
||||
|
||||
This parameter lists paths to files or block devices used for
|
||||
backing storage for each logical unit. There may be at most
|
||||
FSG_MAX_LUNS (8) LUNs set. If more files are specified, they will
|
||||
be silently ignored. See also “luns” parameter.
|
||||
|
||||
*BEWARE* that if a file is used as a backing storage, it may not
|
||||
be modified by any other process. This is because the host
|
||||
assumes the data does not change without its knowledge. It may be
|
||||
read, but (if the logical unit is writable) due to buffering on
|
||||
the host side, the contents are not well defined.
|
||||
|
||||
The size of the logical unit will be rounded down to a full
|
||||
logical block. The logical block size is 2048 bytes for LUNs
|
||||
simulating CD-ROM, block size of the device if the backing file is
|
||||
a block device, or 512 bytes otherwise.
|
||||
|
||||
- removable=b[,b...]
|
||||
|
||||
This parameter specifies whether each logical unit should be
|
||||
removable. “b” here is either “y”, “Y” or “1” for true or “n”,
|
||||
“N” or “0” for false.
|
||||
|
||||
If this option is set for a logical unit, gadget will accept an
|
||||
“eject” SCSI request (Start/Stop Unit). When it is sent, the
|
||||
backing file will be closed to simulate ejection and the logical
|
||||
unit will not be mountable by the host until a new backing file is
|
||||
specified by userspace on the device (see “sysfs entries”
|
||||
section).
|
||||
|
||||
If a logical unit is not removable (the default), a backing file
|
||||
must be specified for it with the “file” parameter as the module
|
||||
is loaded. The same applies if the module is built in, no
|
||||
exceptions.
|
||||
|
||||
The default value of the flag is false, *HOWEVER* it used to be
|
||||
true. This has been changed to better match File Storage Gadget
|
||||
and because it seems like a saner default after all. Thus to
|
||||
maintain compatibility with older kernels, it's best to specify
|
||||
the default values. Also, if one relied on old default, explicit
|
||||
“n” needs to be specified now.
|
||||
|
||||
Note that “removable” means the logical unit's media can be
|
||||
ejected or removed (as is true for a CD-ROM drive or a card
|
||||
reader). It does *not* mean that the entire gadget can be
|
||||
unplugged from the host; the proper term for that is
|
||||
“hot-unpluggable”.
|
||||
|
||||
- cdrom=b[,b...]
|
||||
|
||||
This parameter specifies whether each logical unit should simulate
|
||||
CD-ROM. The default is false.
|
||||
|
||||
- ro=b[,b...]
|
||||
|
||||
This parameter specifies whether each logical unit should be
|
||||
reported as read only. This will prevent host from modifying the
|
||||
backing files.
|
||||
|
||||
Note that if this flag for given logical unit is false but the
|
||||
backing file could not be opened in read/write mode, the gadget
|
||||
will fall back to read only mode anyway.
|
||||
|
||||
The default value for non-CD-ROM logical units is false; for
|
||||
logical units simulating CD-ROM it is forced to true.
|
||||
|
||||
- nofua=b[,b...]
|
||||
|
||||
This parameter specifies whether FUA flag should be ignored in SCSI
|
||||
Write10 and Write12 commands sent to given logical units.
|
||||
|
||||
MS Windows mounts removable storage in “Removal optimised mode” by
|
||||
default. All the writes to the media are synchronous, which is
|
||||
achieved by setting the FUA (Force Unit Access) bit in SCSI
|
||||
Write(10,12) commands. This forces each write to wait until the
|
||||
data has actually been written out and prevents I/O requests
|
||||
aggregation in block layer dramatically decreasing performance.
|
||||
|
||||
Note that this may mean that if the device is powered from USB and
|
||||
the user unplugs the device without unmounting it first (which at
|
||||
least some Windows users do), the data may be lost.
|
||||
|
||||
The default value is false.
|
||||
|
||||
- luns=N
|
||||
|
||||
This parameter specifies number of logical units the gadget will
|
||||
have. It is limited by FSG_MAX_LUNS (8) and higher value will be
|
||||
capped.
|
||||
|
||||
If this parameter is provided, and the number of files specified
|
||||
in “file” argument is greater then the value of “luns”, all excess
|
||||
files will be ignored.
|
||||
|
||||
If this parameter is not present, the number of logical units will
|
||||
be deduced from the number of files specified in the “file”
|
||||
parameter. If the file parameter is missing as well, one is
|
||||
assumed.
|
||||
|
||||
- stall=b
|
||||
|
||||
Specifies whether the gadget is allowed to halt bulk endpoints.
|
||||
The default is determined according to the type of USB device
|
||||
controller, but usually true.
|
||||
|
||||
In addition to the above, the gadget also accepts the following
|
||||
parameters defined by the composite framework (they are common to
|
||||
all composite gadgets so just a quick listing):
|
||||
|
||||
- idVendor -- USB Vendor ID (16 bit integer)
|
||||
- idProduct -- USB Product ID (16 bit integer)
|
||||
- bcdDevice -- USB Device version (BCD) (16 bit integer)
|
||||
- iManufacturer -- USB Manufacturer string (string)
|
||||
- iProduct -- USB Product string (string)
|
||||
- iSerialNumber -- SerialNumber string (sting)
|
||||
|
||||
* sysfs entries
|
||||
|
||||
For each logical unit, the gadget creates a directory in the sysfs
|
||||
hierarchy. Inside of it the following three files are created:
|
||||
|
||||
- file
|
||||
|
||||
When read it returns the path to the backing file for the given
|
||||
logical unit. If there is no backing file (possible only if the
|
||||
logical unit is removable), the content is empty.
|
||||
|
||||
When written into, it changes the backing file for given logical
|
||||
unit. This change can be performed even if given logical unit is
|
||||
not specified as removable (but that may look strange to the
|
||||
host). It may fail, however, if host disallowed medium removal
|
||||
with the Prevent-Allow Medium Removal SCSI command.
|
||||
|
||||
- ro
|
||||
|
||||
Reflects the state of ro flag for the given logical unit. It can
|
||||
be read any time, and written to when there is no backing file
|
||||
open for given logical unit.
|
||||
|
||||
- nofua
|
||||
|
||||
Reflects the state of nofua flag for given logical unit. It can
|
||||
be read and written.
|
||||
|
||||
Other then those, as usual, the values of module parameters can be
|
||||
read from /sys/module/g_mass_storage/parameters/* files.
|
||||
|
||||
* Other gadgets using mass storage function
|
||||
|
||||
The Mass Storage Gadget uses the Mass Storage Function to handle
|
||||
mass storage protocol. As a composite function, MSF may be used by
|
||||
other gadgets as well (eg. g_multi and acm_ms).
|
||||
|
||||
All of the information in previous sections are valid for other
|
||||
gadgets using MSF, except that support for mass storage related
|
||||
module parameters may be missing, or the parameters may have
|
||||
a prefix. To figure out whether any of this is true one needs to
|
||||
consult the gadget's documentation or its source code.
|
||||
|
||||
For examples of how to include mass storage function in gadgets, one
|
||||
may take a look at mass_storage.c, acm_ms.c and multi.c (sorted by
|
||||
complexity).
|
||||
|
||||
* Relation to file storage gadget
|
||||
|
||||
The Mass Storage Function and thus the Mass Storage Gadget has been
|
||||
based on the File Storage Gadget. The difference between the two is
|
||||
that MSG is a composite gadget (ie. uses the composite framework)
|
||||
while file storage gadget is a traditional gadget. From userspace
|
||||
point of view this distinction does not really matter, but from
|
||||
kernel hacker's point of view, this means that (i) MSG does not
|
||||
duplicate code needed for handling basic USB protocol commands and
|
||||
(ii) MSF can be used in any other composite gadget.
|
||||
|
||||
Because of that, File Storage Gadget has been deprecated and
|
||||
scheduled to be removed in Linux 3.8. All users need to transition
|
||||
to the Mass Storage Gadget by that time. The two gadgets behave
|
||||
mostly the same from the outside except:
|
||||
|
||||
1. In FSG the “removable” and “cdrom” module parameters set the flag
|
||||
for all logical units whereas in MSG they accept a list of y/n
|
||||
values for each logical unit. If one uses only a single logical
|
||||
unit this does not matter, but if there are more, the y/n value
|
||||
needs to be repeated for each logical unit.
|
||||
|
||||
2. FSG's “serial”, “vendor”, “product” and “release” module
|
||||
parameters are handled in MSG by the composite layer's parameters
|
||||
named respectively: “iSerialnumber”, “idVendor”, “idProduct” and
|
||||
“bcdDevice”.
|
||||
|
||||
3. MSG does not support FSG's test mode, thus “transport”,
|
||||
“protocol” and “buflen” FSG's module parameters are not
|
||||
supported. MSG always uses SCSI protocol with bulk only
|
||||
transport mode and 16 KiB buffers.
|
@ -3391,15 +3391,15 @@ static struct omap_clk omap3xxx_clks[] = {
|
||||
CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
|
||||
CLK(NULL, "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
|
||||
CLK("usbhs_omap", "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
|
||||
CLK("usbhs_omap", "utmi_p1_gfclk", &dummy_ck, CK_3XXX),
|
||||
CLK("usbhs_omap", "utmi_p2_gfclk", &dummy_ck, CK_3XXX),
|
||||
CLK("usbhs_omap", "xclk60mhsp1_ck", &dummy_ck, CK_3XXX),
|
||||
CLK("usbhs_omap", "xclk60mhsp2_ck", &dummy_ck, CK_3XXX),
|
||||
CLK("usbhs_omap", "usb_host_hs_utmi_p1_clk", &dummy_ck, CK_3XXX),
|
||||
CLK("usbhs_omap", "usb_host_hs_utmi_p2_clk", &dummy_ck, CK_3XXX),
|
||||
CLK(NULL, "utmi_p1_gfclk", &dummy_ck, CK_3XXX),
|
||||
CLK(NULL, "utmi_p2_gfclk", &dummy_ck, CK_3XXX),
|
||||
CLK(NULL, "xclk60mhsp1_ck", &dummy_ck, CK_3XXX),
|
||||
CLK(NULL, "xclk60mhsp2_ck", &dummy_ck, CK_3XXX),
|
||||
CLK(NULL, "usb_host_hs_utmi_p1_clk", &dummy_ck, CK_3XXX),
|
||||
CLK(NULL, "usb_host_hs_utmi_p2_clk", &dummy_ck, CK_3XXX),
|
||||
CLK("usbhs_omap", "usb_tll_hs_usb_ch0_clk", &dummy_ck, CK_3XXX),
|
||||
CLK("usbhs_omap", "usb_tll_hs_usb_ch1_clk", &dummy_ck, CK_3XXX),
|
||||
CLK("usbhs_omap", "init_60m_fclk", &dummy_ck, CK_3XXX),
|
||||
CLK(NULL, "init_60m_fclk", &dummy_ck, CK_3XXX),
|
||||
CLK(NULL, "usim_fck", &usim_fck, CK_3430ES2PLUS | CK_36XX),
|
||||
CLK(NULL, "gpt1_fck", &gpt1_fck, CK_3XXX),
|
||||
CLK(NULL, "wkup_32k_fck", &wkup_32k_fck, CK_3XXX),
|
||||
|
@ -2517,7 +2517,7 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev)
|
||||
dev_err(di->dev, "%s mask and set failed\n", __func__);
|
||||
|
||||
usb_unregister_notifier(di->usb_phy, &di->nb);
|
||||
usb_put_transceiver(di->usb_phy);
|
||||
usb_put_phy(di->usb_phy);
|
||||
|
||||
/* Delete the work queue */
|
||||
destroy_workqueue(di->charger_wq);
|
||||
@ -2688,8 +2688,8 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev)
|
||||
goto free_ac;
|
||||
}
|
||||
|
||||
di->usb_phy = usb_get_transceiver();
|
||||
if (!di->usb_phy) {
|
||||
di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR_OR_NULL(di->usb_phy)) {
|
||||
dev_err(di->dev, "failed to get usb transceiver\n");
|
||||
ret = -EINVAL;
|
||||
goto free_usb;
|
||||
@ -2747,7 +2747,7 @@ free_irq:
|
||||
free_irq(irq, di);
|
||||
}
|
||||
put_usb_phy:
|
||||
usb_put_transceiver(di->usb_phy);
|
||||
usb_put_phy(di->usb_phy);
|
||||
free_usb:
|
||||
power_supply_unregister(&di->usb_chg.psy);
|
||||
free_ac:
|
||||
|
@ -415,8 +415,8 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
|
||||
if (!isp)
|
||||
return -ENOMEM;
|
||||
|
||||
isp->phy = usb_get_transceiver();
|
||||
if (!isp->phy)
|
||||
isp->phy = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR_OR_NULL(isp->phy))
|
||||
goto fail0;
|
||||
|
||||
isp->dev = &pdev->dev;
|
||||
@ -475,7 +475,7 @@ fail2:
|
||||
power_supply_unregister(&isp->psy);
|
||||
fail1:
|
||||
isp1704_charger_set_power(isp, 0);
|
||||
usb_put_transceiver(isp->phy);
|
||||
usb_put_phy(isp->phy);
|
||||
fail0:
|
||||
kfree(isp);
|
||||
|
||||
@ -490,7 +490,7 @@ static int __devexit isp1704_charger_remove(struct platform_device *pdev)
|
||||
|
||||
usb_unregister_notifier(isp->phy, &isp->nb);
|
||||
power_supply_unregister(&isp->psy);
|
||||
usb_put_transceiver(isp->phy);
|
||||
usb_put_phy(isp->phy);
|
||||
isp1704_charger_set_power(isp, 0);
|
||||
kfree(isp);
|
||||
|
||||
|
@ -321,12 +321,12 @@ static int pda_power_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
transceiver = usb_get_transceiver();
|
||||
if (transceiver && !pdata->is_usb_online) {
|
||||
pdata->is_usb_online = otg_is_usb_online;
|
||||
}
|
||||
if (transceiver && !pdata->is_ac_online) {
|
||||
pdata->is_ac_online = otg_is_ac_online;
|
||||
transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (!IS_ERR_OR_NULL(transceiver)) {
|
||||
if (!pdata->is_usb_online)
|
||||
pdata->is_usb_online = otg_is_usb_online;
|
||||
if (!pdata->is_ac_online)
|
||||
pdata->is_ac_online = otg_is_ac_online;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -373,7 +373,7 @@ static int pda_power_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
if (transceiver && pdata->use_otg_notifier) {
|
||||
if (!IS_ERR_OR_NULL(transceiver) && pdata->use_otg_notifier) {
|
||||
otg_nb.notifier_call = otg_handle_notification;
|
||||
ret = usb_register_notifier(transceiver, &otg_nb);
|
||||
if (ret) {
|
||||
@ -408,8 +408,8 @@ usb_supply_failed:
|
||||
if (pdata->is_ac_online && ac_irq)
|
||||
free_irq(ac_irq->start, &pda_psy_ac);
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
if (transceiver)
|
||||
usb_put_transceiver(transceiver);
|
||||
if (!IS_ERR_OR_NULL(transceiver))
|
||||
usb_put_phy(transceiver);
|
||||
#endif
|
||||
ac_irq_failed:
|
||||
if (pdata->is_ac_online)
|
||||
@ -443,8 +443,8 @@ static int pda_power_remove(struct platform_device *pdev)
|
||||
if (pdata->is_ac_online)
|
||||
power_supply_unregister(&pda_psy_ac);
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
if (transceiver)
|
||||
usb_put_transceiver(transceiver);
|
||||
if (!IS_ERR_OR_NULL(transceiver))
|
||||
usb_put_phy(transceiver);
|
||||
#endif
|
||||
if (ac_draw) {
|
||||
regulator_put(ac_draw);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
@ -479,8 +480,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
|
||||
|
||||
INIT_WORK(&bci->work, twl4030_bci_usb_work);
|
||||
|
||||
bci->transceiver = usb_get_transceiver();
|
||||
if (bci->transceiver != NULL) {
|
||||
bci->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (!IS_ERR_OR_NULL(bci->transceiver)) {
|
||||
bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
|
||||
usb_register_notifier(bci->transceiver, &bci->usb_nb);
|
||||
}
|
||||
@ -507,9 +508,9 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
fail_unmask_interrupts:
|
||||
if (bci->transceiver != NULL) {
|
||||
if (!IS_ERR_OR_NULL(bci->transceiver)) {
|
||||
usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
|
||||
usb_put_transceiver(bci->transceiver);
|
||||
usb_put_phy(bci->transceiver);
|
||||
}
|
||||
free_irq(bci->irq_bci, bci);
|
||||
fail_bci_irq:
|
||||
@ -538,9 +539,9 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
|
||||
twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
|
||||
TWL4030_INTERRUPTS_BCIIMR2A);
|
||||
|
||||
if (bci->transceiver != NULL) {
|
||||
if (!IS_ERR_OR_NULL(bci->transceiver)) {
|
||||
usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
|
||||
usb_put_transceiver(bci->transceiver);
|
||||
usb_put_phy(bci->transceiver);
|
||||
}
|
||||
free_irq(bci->irq_bci, bci);
|
||||
free_irq(bci->irq_chg, bci);
|
||||
|
@ -20,6 +20,7 @@ config USB_CHIPIDEA_UDC
|
||||
|
||||
config USB_CHIPIDEA_HOST
|
||||
bool "ChipIdea host controller"
|
||||
select USB_EHCI_ROOT_HUB_TT
|
||||
help
|
||||
Say Y here to enable host controller functionality of the
|
||||
ChipIdea driver.
|
||||
|
@ -5,10 +5,15 @@ ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o
|
||||
ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST) += host.o
|
||||
ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o
|
||||
|
||||
# Glue/Bridge layers go here
|
||||
|
||||
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_msm.o
|
||||
|
||||
# PCI doesn't provide stubs, need to check
|
||||
ifneq ($(CONFIG_PCI),)
|
||||
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_pci.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_ARCH_MSM),)
|
||||
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_msm.o
|
||||
ifneq ($(CONFIG_OF_DEVICE),)
|
||||
obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o
|
||||
endif
|
||||
|
@ -36,7 +36,7 @@
|
||||
* @name: string description of the endpoint
|
||||
* @qh: queue head for this endpoint
|
||||
* @wedge: is the endpoint wedged
|
||||
* @udc: pointer to the controller
|
||||
* @ci: pointer to the controller
|
||||
* @lock: pointer to controller's spinlock
|
||||
* @td_pool: pointer to controller's TD pool
|
||||
*/
|
||||
@ -54,7 +54,7 @@ struct ci13xxx_ep {
|
||||
int wedge;
|
||||
|
||||
/* global resources */
|
||||
struct ci13xxx *udc;
|
||||
struct ci13xxx *ci;
|
||||
spinlock_t *lock;
|
||||
struct dma_pool *td_pool;
|
||||
};
|
||||
@ -125,7 +125,7 @@ struct hw_bank {
|
||||
* @remote_wakeup: host-enabled remote wakeup
|
||||
* @suspended: suspended by host
|
||||
* @test_mode: the selected test mode
|
||||
* @udc_driver: platform specific information supplied by parent device
|
||||
* @platdata: platform specific information supplied by parent device
|
||||
* @vbus_active: is VBUS active
|
||||
* @transceiver: pointer to USB PHY, if any
|
||||
* @hcd: pointer to usb_hcd for ehci host driver
|
||||
@ -158,8 +158,10 @@ struct ci13xxx {
|
||||
u8 suspended;
|
||||
u8 test_mode;
|
||||
|
||||
struct ci13xxx_udc_driver *udc_driver;
|
||||
struct ci13xxx_platform_data *platdata;
|
||||
int vbus_active;
|
||||
/* FIXME: some day, we'll not use global phy */
|
||||
bool global_phy;
|
||||
struct usb_phy *transceiver;
|
||||
struct usb_hcd *hcd;
|
||||
};
|
||||
@ -250,9 +252,9 @@ static inline int ffs_nr(u32 x)
|
||||
*
|
||||
* This function returns register contents
|
||||
*/
|
||||
static inline u32 hw_read(struct ci13xxx *udc, enum ci13xxx_regs reg, u32 mask)
|
||||
static inline u32 hw_read(struct ci13xxx *ci, enum ci13xxx_regs reg, u32 mask)
|
||||
{
|
||||
return ioread32(udc->hw_bank.regmap[reg]) & mask;
|
||||
return ioread32(ci->hw_bank.regmap[reg]) & mask;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -261,14 +263,14 @@ static inline u32 hw_read(struct ci13xxx *udc, enum ci13xxx_regs reg, u32 mask)
|
||||
* @mask: bitfield mask
|
||||
* @data: new value
|
||||
*/
|
||||
static inline void hw_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
|
||||
static inline void hw_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
|
||||
u32 mask, u32 data)
|
||||
{
|
||||
if (~mask)
|
||||
data = (ioread32(udc->hw_bank.regmap[reg]) & ~mask)
|
||||
data = (ioread32(ci->hw_bank.regmap[reg]) & ~mask)
|
||||
| (data & mask);
|
||||
|
||||
iowrite32(data, udc->hw_bank.regmap[reg]);
|
||||
iowrite32(data, ci->hw_bank.regmap[reg]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -278,12 +280,12 @@ static inline void hw_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
|
||||
*
|
||||
* This function returns register contents
|
||||
*/
|
||||
static inline u32 hw_test_and_clear(struct ci13xxx *udc, enum ci13xxx_regs reg,
|
||||
static inline u32 hw_test_and_clear(struct ci13xxx *ci, enum ci13xxx_regs reg,
|
||||
u32 mask)
|
||||
{
|
||||
u32 val = ioread32(udc->hw_bank.regmap[reg]) & mask;
|
||||
u32 val = ioread32(ci->hw_bank.regmap[reg]) & mask;
|
||||
|
||||
iowrite32(val, udc->hw_bank.regmap[reg]);
|
||||
iowrite32(val, ci->hw_bank.regmap[reg]);
|
||||
return val;
|
||||
}
|
||||
|
||||
@ -295,12 +297,12 @@ static inline u32 hw_test_and_clear(struct ci13xxx *udc, enum ci13xxx_regs reg,
|
||||
*
|
||||
* This function returns register contents
|
||||
*/
|
||||
static inline u32 hw_test_and_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
|
||||
static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
|
||||
u32 mask, u32 data)
|
||||
{
|
||||
u32 val = hw_read(udc, reg, ~0);
|
||||
u32 val = hw_read(ci, reg, ~0);
|
||||
|
||||
hw_write(udc, reg, mask, data);
|
||||
hw_write(ci, reg, mask, data);
|
||||
return (val & mask) >> ffs_nr(mask);
|
||||
}
|
||||
|
||||
|
198
drivers/usb/chipidea/ci13xxx_imx.c
Normal file
198
drivers/usb/chipidea/ci13xxx_imx.c
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||
* Copyright (C) 2012 Marek Vasut <marex@denx.de>
|
||||
* on behalf of DENX Software Engineering GmbH
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/usb/chipidea.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include "ci.h"
|
||||
|
||||
#define pdev_to_phy(pdev) \
|
||||
((struct usb_phy *)platform_get_drvdata(pdev))
|
||||
|
||||
struct ci13xxx_imx_data {
|
||||
struct device_node *phy_np;
|
||||
struct usb_phy *phy;
|
||||
struct platform_device *ci_pdev;
|
||||
struct clk *clk;
|
||||
struct regulator *reg_vbus;
|
||||
};
|
||||
|
||||
static struct ci13xxx_platform_data ci13xxx_imx_platdata __devinitdata = {
|
||||
.name = "ci13xxx_imx",
|
||||
.flags = CI13XXX_REQUIRE_TRANSCEIVER |
|
||||
CI13XXX_PULLUP_ON_VBUS |
|
||||
CI13XXX_DISABLE_STREAMING,
|
||||
.capoffset = DEF_CAPOFFSET,
|
||||
};
|
||||
|
||||
static int __devinit ci13xxx_imx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ci13xxx_imx_data *data;
|
||||
struct platform_device *plat_ci, *phy_pdev;
|
||||
struct device_node *phy_np;
|
||||
struct resource *res;
|
||||
struct regulator *reg_vbus;
|
||||
int ret;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
dev_err(&pdev->dev, "Failed to allocate CI13xxx-IMX data!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Can't get device resources!\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
data->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(data->clk)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to get clock, err=%ld\n", PTR_ERR(data->clk));
|
||||
return PTR_ERR(data->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(data->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to prepare or enable clock, err=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
phy_np = of_parse_phandle(pdev->dev.of_node, "fsl,usbphy", 0);
|
||||
if (phy_np) {
|
||||
data->phy_np = phy_np;
|
||||
phy_pdev = of_find_device_by_node(phy_np);
|
||||
if (phy_pdev) {
|
||||
struct usb_phy *phy;
|
||||
phy = pdev_to_phy(phy_pdev);
|
||||
if (phy &&
|
||||
try_module_get(phy_pdev->dev.driver->owner)) {
|
||||
usb_phy_init(phy);
|
||||
data->phy = phy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we only support host now, so enable vbus here */
|
||||
reg_vbus = devm_regulator_get(&pdev->dev, "vbus");
|
||||
if (!IS_ERR(reg_vbus)) {
|
||||
ret = regulator_enable(reg_vbus);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to enable vbus regulator, err=%d\n",
|
||||
ret);
|
||||
goto put_np;
|
||||
}
|
||||
data->reg_vbus = reg_vbus;
|
||||
} else {
|
||||
reg_vbus = NULL;
|
||||
}
|
||||
|
||||
ci13xxx_imx_platdata.phy = data->phy;
|
||||
|
||||
if (!pdev->dev.dma_mask) {
|
||||
pdev->dev.dma_mask = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
|
||||
if (!pdev->dev.dma_mask) {
|
||||
ret = -ENOMEM;
|
||||
dev_err(&pdev->dev, "Failed to alloc dma_mask!\n");
|
||||
goto err;
|
||||
}
|
||||
*pdev->dev.dma_mask = DMA_BIT_MASK(32);
|
||||
dma_set_coherent_mask(&pdev->dev, *pdev->dev.dma_mask);
|
||||
}
|
||||
plat_ci = ci13xxx_add_device(&pdev->dev,
|
||||
pdev->resource, pdev->num_resources,
|
||||
&ci13xxx_imx_platdata);
|
||||
if (IS_ERR(plat_ci)) {
|
||||
ret = PTR_ERR(plat_ci);
|
||||
dev_err(&pdev->dev,
|
||||
"Can't register ci_hdrc platform device, err=%d\n",
|
||||
ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
data->ci_pdev = plat_ci;
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
pm_runtime_no_callbacks(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (reg_vbus)
|
||||
regulator_disable(reg_vbus);
|
||||
put_np:
|
||||
if (phy_np)
|
||||
of_node_put(phy_np);
|
||||
clk_disable_unprepare(data->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit ci13xxx_imx_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ci13xxx_imx_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
ci13xxx_remove_device(data->ci_pdev);
|
||||
|
||||
if (data->reg_vbus)
|
||||
regulator_disable(data->reg_vbus);
|
||||
|
||||
if (data->phy) {
|
||||
usb_phy_shutdown(data->phy);
|
||||
module_put(data->phy->dev->driver->owner);
|
||||
}
|
||||
|
||||
of_node_put(data->phy_np);
|
||||
|
||||
clk_disable_unprepare(data->clk);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ci13xxx_imx_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx27-usb", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ci13xxx_imx_dt_ids);
|
||||
|
||||
static struct platform_driver ci13xxx_imx_driver = {
|
||||
.probe = ci13xxx_imx_probe,
|
||||
.remove = __devexit_p(ci13xxx_imx_remove),
|
||||
.driver = {
|
||||
.name = "imx_usb",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ci13xxx_imx_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(ci13xxx_imx_driver);
|
||||
|
||||
MODULE_ALIAS("platform:imx-usb");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("CI13xxx i.MX USB binding");
|
||||
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
|
||||
MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
|
@ -15,11 +15,11 @@
|
||||
|
||||
#include "ci.h"
|
||||
|
||||
#define MSM_USB_BASE (udc->hw_bank.abs)
|
||||
#define MSM_USB_BASE (ci->hw_bank.abs)
|
||||
|
||||
static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
|
||||
static void ci13xxx_msm_notify_event(struct ci13xxx *ci, unsigned event)
|
||||
{
|
||||
struct device *dev = udc->gadget.dev.parent;
|
||||
struct device *dev = ci->gadget.dev.parent;
|
||||
int val;
|
||||
|
||||
switch (event) {
|
||||
@ -34,18 +34,18 @@ static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
|
||||
* Put the transceiver in non-driving mode. Otherwise host
|
||||
* may not detect soft-disconnection.
|
||||
*/
|
||||
val = usb_phy_io_read(udc->transceiver, ULPI_FUNC_CTRL);
|
||||
val = usb_phy_io_read(ci->transceiver, ULPI_FUNC_CTRL);
|
||||
val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
|
||||
val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
|
||||
usb_phy_io_write(udc->transceiver, val, ULPI_FUNC_CTRL);
|
||||
usb_phy_io_write(ci->transceiver, val, ULPI_FUNC_CTRL);
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dev, "unknown ci13xxx_udc event\n");
|
||||
dev_dbg(dev, "unknown ci13xxx event\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
|
||||
static struct ci13xxx_platform_data ci13xxx_msm_platdata = {
|
||||
.name = "ci13xxx_msm",
|
||||
.flags = CI13XXX_REGS_SHARED |
|
||||
CI13XXX_REQUIRE_TRANSCEIVER |
|
||||
@ -55,56 +55,45 @@ static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
|
||||
.notify_event = ci13xxx_msm_notify_event,
|
||||
};
|
||||
|
||||
static int ci13xxx_msm_probe(struct platform_device *pdev)
|
||||
static int __devinit ci13xxx_msm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_device *plat_ci;
|
||||
int ret;
|
||||
|
||||
dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
|
||||
|
||||
plat_ci = platform_device_alloc("ci_hdrc", -1);
|
||||
if (!plat_ci) {
|
||||
dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n");
|
||||
return -ENOMEM;
|
||||
plat_ci = ci13xxx_add_device(&pdev->dev,
|
||||
pdev->resource, pdev->num_resources,
|
||||
&ci13xxx_msm_platdata);
|
||||
if (IS_ERR(plat_ci)) {
|
||||
dev_err(&pdev->dev, "ci13xxx_add_device failed!\n");
|
||||
return PTR_ERR(plat_ci);
|
||||
}
|
||||
|
||||
ret = platform_device_add_resources(plat_ci, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "can't add resources to platform device\n");
|
||||
goto put_platform;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(plat_ci, &ci13xxx_msm_udc_driver,
|
||||
sizeof(ci13xxx_msm_udc_driver));
|
||||
if (ret)
|
||||
goto put_platform;
|
||||
|
||||
ret = platform_device_add(plat_ci);
|
||||
if (ret)
|
||||
goto put_platform;
|
||||
platform_set_drvdata(pdev, plat_ci);
|
||||
|
||||
pm_runtime_no_callbacks(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
put_platform:
|
||||
platform_device_put(plat_ci);
|
||||
static int __devexit ci13xxx_msm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_device *plat_ci = platform_get_drvdata(pdev);
|
||||
|
||||
return ret;
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
ci13xxx_remove_device(plat_ci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ci13xxx_msm_driver = {
|
||||
.probe = ci13xxx_msm_probe,
|
||||
.remove = __devexit_p(ci13xxx_msm_remove),
|
||||
.driver = { .name = "msm_hsusb", },
|
||||
};
|
||||
|
||||
module_platform_driver(ci13xxx_msm_driver);
|
||||
|
||||
MODULE_ALIAS("platform:msm_hsusb");
|
||||
|
||||
static int __init ci13xxx_msm_init(void)
|
||||
{
|
||||
return platform_driver_register(&ci13xxx_msm_driver);
|
||||
}
|
||||
module_init(ci13xxx_msm_init);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -23,17 +23,17 @@
|
||||
/******************************************************************************
|
||||
* PCI block
|
||||
*****************************************************************************/
|
||||
struct ci13xxx_udc_driver pci_driver = {
|
||||
struct ci13xxx_platform_data pci_platdata = {
|
||||
.name = UDC_DRIVER_NAME,
|
||||
.capoffset = DEF_CAPOFFSET,
|
||||
};
|
||||
|
||||
struct ci13xxx_udc_driver langwell_pci_driver = {
|
||||
struct ci13xxx_platform_data langwell_pci_platdata = {
|
||||
.name = UDC_DRIVER_NAME,
|
||||
.capoffset = 0,
|
||||
};
|
||||
|
||||
struct ci13xxx_udc_driver penwell_pci_driver = {
|
||||
struct ci13xxx_platform_data penwell_pci_platdata = {
|
||||
.name = UDC_DRIVER_NAME,
|
||||
.capoffset = 0,
|
||||
.power_budget = 200,
|
||||
@ -51,12 +51,12 @@ struct ci13xxx_udc_driver penwell_pci_driver = {
|
||||
static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct ci13xxx_udc_driver *driver = (void *)id->driver_data;
|
||||
struct ci13xxx_platform_data *platdata = (void *)id->driver_data;
|
||||
struct platform_device *plat_ci;
|
||||
struct resource res[3];
|
||||
int retval = 0, nres = 2;
|
||||
|
||||
if (!driver) {
|
||||
if (!platdata) {
|
||||
dev_err(&pdev->dev, "device doesn't provide driver data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -75,13 +75,6 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
|
||||
pci_set_master(pdev);
|
||||
pci_try_set_mwi(pdev);
|
||||
|
||||
plat_ci = platform_device_alloc("ci_hdrc", -1);
|
||||
if (!plat_ci) {
|
||||
dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n");
|
||||
retval = -ENOMEM;
|
||||
goto disable_device;
|
||||
}
|
||||
|
||||
memset(res, 0, sizeof(res));
|
||||
res[0].start = pci_resource_start(pdev, 0);
|
||||
res[0].end = pci_resource_end(pdev, 0);
|
||||
@ -89,32 +82,17 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
|
||||
res[1].start = pdev->irq;
|
||||
res[1].flags = IORESOURCE_IRQ;
|
||||
|
||||
retval = platform_device_add_resources(plat_ci, res, nres);
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev, "can't add resources to platform device\n");
|
||||
goto put_platform;
|
||||
plat_ci = ci13xxx_add_device(&pdev->dev, res, nres, platdata);
|
||||
if (IS_ERR(plat_ci)) {
|
||||
dev_err(&pdev->dev, "ci13xxx_add_device failed!\n");
|
||||
retval = PTR_ERR(plat_ci);
|
||||
goto disable_device;
|
||||
}
|
||||
|
||||
retval = platform_device_add_data(plat_ci, driver, sizeof(*driver));
|
||||
if (retval)
|
||||
goto put_platform;
|
||||
|
||||
dma_set_coherent_mask(&plat_ci->dev, pdev->dev.coherent_dma_mask);
|
||||
plat_ci->dev.dma_mask = pdev->dev.dma_mask;
|
||||
plat_ci->dev.dma_parms = pdev->dev.dma_parms;
|
||||
plat_ci->dev.parent = &pdev->dev;
|
||||
|
||||
pci_set_drvdata(pdev, plat_ci);
|
||||
|
||||
retval = platform_device_add(plat_ci);
|
||||
if (retval)
|
||||
goto put_platform;
|
||||
|
||||
return 0;
|
||||
|
||||
put_platform:
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
platform_device_put(plat_ci);
|
||||
disable_device:
|
||||
pci_disable_device(pdev);
|
||||
done:
|
||||
@ -133,7 +111,7 @@ static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct platform_device *plat_ci = pci_get_drvdata(pdev);
|
||||
|
||||
platform_device_unregister(plat_ci);
|
||||
ci13xxx_remove_device(plat_ci);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
@ -147,19 +125,19 @@ static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
|
||||
static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
|
||||
{
|
||||
PCI_DEVICE(0x153F, 0x1004),
|
||||
.driver_data = (kernel_ulong_t)&pci_driver,
|
||||
.driver_data = (kernel_ulong_t)&pci_platdata,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(0x153F, 0x1006),
|
||||
.driver_data = (kernel_ulong_t)&pci_driver,
|
||||
.driver_data = (kernel_ulong_t)&pci_platdata,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811),
|
||||
.driver_data = (kernel_ulong_t)&langwell_pci_driver,
|
||||
.driver_data = (kernel_ulong_t)&langwell_pci_platdata,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829),
|
||||
.driver_data = (kernel_ulong_t)&penwell_pci_driver,
|
||||
.driver_data = (kernel_ulong_t)&penwell_pci_platdata,
|
||||
},
|
||||
{ 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
|
||||
};
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
@ -179,7 +180,7 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
|
||||
ci->hw_bank.abs = base;
|
||||
|
||||
ci->hw_bank.cap = ci->hw_bank.abs;
|
||||
ci->hw_bank.cap += ci->udc_driver->capoffset;
|
||||
ci->hw_bank.cap += ci->platdata->capoffset;
|
||||
ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap);
|
||||
|
||||
hw_alloc_regmap(ci, false);
|
||||
@ -227,11 +228,11 @@ int hw_device_reset(struct ci13xxx *ci, u32 mode)
|
||||
udelay(10); /* not RTOS friendly */
|
||||
|
||||
|
||||
if (ci->udc_driver->notify_event)
|
||||
ci->udc_driver->notify_event(ci,
|
||||
if (ci->platdata->notify_event)
|
||||
ci->platdata->notify_event(ci,
|
||||
CI13XXX_CONTROLLER_RESET_EVENT);
|
||||
|
||||
if (ci->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
|
||||
if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING)
|
||||
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
|
||||
|
||||
/* USBMODE should be configured step by step */
|
||||
@ -332,6 +333,59 @@ static irqreturn_t ci_irq(int irq, void *data)
|
||||
return ci->role == CI_ROLE_END ? ret : ci_role(ci)->irq(ci);
|
||||
}
|
||||
|
||||
static DEFINE_IDA(ci_ida);
|
||||
|
||||
struct platform_device *ci13xxx_add_device(struct device *dev,
|
||||
struct resource *res, int nres,
|
||||
struct ci13xxx_platform_data *platdata)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
int id, ret;
|
||||
|
||||
id = ida_simple_get(&ci_ida, 0, 0, GFP_KERNEL);
|
||||
if (id < 0)
|
||||
return ERR_PTR(id);
|
||||
|
||||
pdev = platform_device_alloc("ci_hdrc", id);
|
||||
if (!pdev) {
|
||||
ret = -ENOMEM;
|
||||
goto put_id;
|
||||
}
|
||||
|
||||
pdev->dev.parent = dev;
|
||||
pdev->dev.dma_mask = dev->dma_mask;
|
||||
pdev->dev.dma_parms = dev->dma_parms;
|
||||
dma_set_coherent_mask(&pdev->dev, dev->coherent_dma_mask);
|
||||
|
||||
ret = platform_device_add_resources(pdev, res, nres);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = platform_device_add_data(pdev, platdata, sizeof(*platdata));
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return pdev;
|
||||
|
||||
err:
|
||||
platform_device_put(pdev);
|
||||
put_id:
|
||||
ida_simple_remove(&ci_ida, id);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ci13xxx_add_device);
|
||||
|
||||
void ci13xxx_remove_device(struct platform_device *pdev)
|
||||
{
|
||||
platform_device_unregister(pdev);
|
||||
ida_simple_remove(&ci_ida, pdev->id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ci13xxx_remove_device);
|
||||
|
||||
static int __devinit ci_hdrc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -364,7 +418,11 @@ static int __devinit ci_hdrc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
ci->dev = dev;
|
||||
ci->udc_driver = dev->platform_data;
|
||||
ci->platdata = dev->platform_data;
|
||||
if (ci->platdata->phy)
|
||||
ci->transceiver = ci->platdata->phy;
|
||||
else
|
||||
ci->global_phy = true;
|
||||
|
||||
ret = hw_device_init(ci, base);
|
||||
if (ret < 0) {
|
||||
@ -419,7 +477,7 @@ static int __devinit ci_hdrc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, ci);
|
||||
ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->udc_driver->name,
|
||||
ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->platdata->name,
|
||||
ci);
|
||||
if (ret)
|
||||
goto stop;
|
||||
|
@ -68,15 +68,15 @@ void dbg_interrupt(u32 intmask)
|
||||
*
|
||||
* This function returns number of registers read
|
||||
*/
|
||||
static size_t hw_register_read(struct ci13xxx *udc, u32 *buf, size_t size)
|
||||
static size_t hw_register_read(struct ci13xxx *ci, u32 *buf, size_t size)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (size > udc->hw_bank.size)
|
||||
size = udc->hw_bank.size;
|
||||
if (size > ci->hw_bank.size)
|
||||
size = ci->hw_bank.size;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
buf[i] = hw_read(udc, i * sizeof(u32), ~0);
|
||||
buf[i] = hw_read(ci, i * sizeof(u32), ~0);
|
||||
|
||||
return size;
|
||||
}
|
||||
@ -88,18 +88,18 @@ static size_t hw_register_read(struct ci13xxx *udc, u32 *buf, size_t size)
|
||||
*
|
||||
* This function returns an error code
|
||||
*/
|
||||
static int hw_register_write(struct ci13xxx *udc, u16 addr, u32 data)
|
||||
static int hw_register_write(struct ci13xxx *ci, u16 addr, u32 data)
|
||||
{
|
||||
/* align */
|
||||
addr /= sizeof(u32);
|
||||
|
||||
if (addr >= udc->hw_bank.size)
|
||||
if (addr >= ci->hw_bank.size)
|
||||
return -EINVAL;
|
||||
|
||||
/* align */
|
||||
addr *= sizeof(u32);
|
||||
|
||||
hw_write(udc, addr, ~0, data);
|
||||
hw_write(ci, addr, ~0, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -110,13 +110,13 @@ static int hw_register_write(struct ci13xxx *udc, u16 addr, u32 data)
|
||||
*
|
||||
* This function returns an error code
|
||||
*/
|
||||
static int hw_intr_clear(struct ci13xxx *udc, int n)
|
||||
static int hw_intr_clear(struct ci13xxx *ci, int n)
|
||||
{
|
||||
if (n >= REG_BITS)
|
||||
return -EINVAL;
|
||||
|
||||
hw_write(udc, OP_USBINTR, BIT(n), 0);
|
||||
hw_write(udc, OP_USBSTS, BIT(n), BIT(n));
|
||||
hw_write(ci, OP_USBINTR, BIT(n), 0);
|
||||
hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -127,15 +127,15 @@ static int hw_intr_clear(struct ci13xxx *udc, int n)
|
||||
*
|
||||
* This function returns an error code
|
||||
*/
|
||||
static int hw_intr_force(struct ci13xxx *udc, int n)
|
||||
static int hw_intr_force(struct ci13xxx *ci, int n)
|
||||
{
|
||||
if (n >= REG_BITS)
|
||||
return -EINVAL;
|
||||
|
||||
hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
|
||||
hw_write(udc, OP_USBINTR, BIT(n), BIT(n));
|
||||
hw_write(udc, OP_USBSTS, BIT(n), BIT(n));
|
||||
hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, 0);
|
||||
hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
|
||||
hw_write(ci, OP_USBINTR, BIT(n), BIT(n));
|
||||
hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
|
||||
hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -147,12 +147,12 @@ static int hw_intr_force(struct ci13xxx *udc, int n)
|
||||
static ssize_t show_device(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct usb_gadget *gadget = &udc->gadget;
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct usb_gadget *gadget = &ci->gadget;
|
||||
int n = 0;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(udc->dev, "[%s] EINVAL\n", __func__);
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -188,8 +188,8 @@ static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
|
||||
static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct usb_gadget_driver *driver = udc->driver;
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct usb_gadget_driver *driver = ci->driver;
|
||||
int n = 0;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
@ -412,22 +412,22 @@ static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
|
||||
static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
unsigned long flags;
|
||||
u32 intr;
|
||||
unsigned i, j, n = 0;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(udc->dev, "[%s] EINVAL\n", __func__);
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
|
||||
/*n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||
"status = %08x\n", hw_read_intr_status(udc));
|
||||
"status = %08x\n", hw_read_intr_status(ci));
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||
"enable = %08x\n", hw_read_intr_enable(udc));*/
|
||||
"enable = %08x\n", hw_read_intr_enable(ci));*/
|
||||
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
|
||||
isr_statistics.test);
|
||||
@ -471,7 +471,7 @@ static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
return n;
|
||||
}
|
||||
@ -485,31 +485,31 @@ static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
unsigned long flags;
|
||||
unsigned en, bit;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(udc->dev, "EINVAL\n");
|
||||
dev_err(ci->dev, "EINVAL\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
|
||||
dev_err(udc->dev, "<1|0> <bit>: enable|disable interrupt\n");
|
||||
dev_err(ci->dev, "<1|0> <bit>: enable|disable interrupt\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
if (en) {
|
||||
if (hw_intr_force(udc, bit))
|
||||
if (hw_intr_force(ci, bit))
|
||||
dev_err(dev, "invalid bit number\n");
|
||||
else
|
||||
isr_statistics.test++;
|
||||
} else {
|
||||
if (hw_intr_clear(udc, bit))
|
||||
if (hw_intr_clear(ci, bit))
|
||||
dev_err(dev, "invalid bit number\n");
|
||||
}
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
done:
|
||||
return count;
|
||||
@ -524,18 +524,18 @@ static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
|
||||
static ssize_t show_port_test(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
unsigned long flags;
|
||||
unsigned mode;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(udc->dev, "EINVAL\n");
|
||||
dev_err(ci->dev, "EINVAL\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
mode = hw_port_test_get(udc);
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
mode = hw_port_test_get(ci);
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
|
||||
}
|
||||
@ -549,24 +549,24 @@ static ssize_t store_port_test(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
unsigned long flags;
|
||||
unsigned mode;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(udc->dev, "[%s] EINVAL\n", __func__);
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "%u", &mode) != 1) {
|
||||
dev_err(udc->dev, "<mode>: set port test mode");
|
||||
dev_err(ci->dev, "<mode>: set port test mode");
|
||||
goto done;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
if (hw_port_test_set(udc, mode))
|
||||
dev_err(udc->dev, "invalid mode\n");
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
if (hw_port_test_set(ci, mode))
|
||||
dev_err(ci->dev, "invalid mode\n");
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
done:
|
||||
return count;
|
||||
@ -582,20 +582,20 @@ static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
|
||||
static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
unsigned long flags;
|
||||
unsigned i, j, n = 0;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(udc->dev, "[%s] EINVAL\n", __func__);
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
for (i = 0; i < udc->hw_ep_max/2; i++) {
|
||||
struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
for (i = 0; i < ci->hw_ep_max/2; i++) {
|
||||
struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i];
|
||||
struct ci13xxx_ep *mEpTx =
|
||||
&udc->ci13xxx_ep[i + udc->hw_ep_max/2];
|
||||
&ci->ci13xxx_ep[i + ci->hw_ep_max/2];
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||
"EP=%02i: RX=%08X TX=%08X\n",
|
||||
i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
|
||||
@ -606,7 +606,7 @@ static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
|
||||
*((u32 *)mEpTx->qh.ptr + j));
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
return n;
|
||||
}
|
||||
@ -621,25 +621,25 @@ static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
|
||||
static ssize_t show_registers(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
unsigned long flags;
|
||||
u32 *dump;
|
||||
unsigned i, k, n = 0;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(udc->dev, "[%s] EINVAL\n", __func__);
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
|
||||
if (!dump) {
|
||||
dev_err(udc->dev, "%s: out of memory\n", __func__);
|
||||
dev_err(ci->dev, "%s: out of memory\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
k = hw_register_read(udc, dump, DUMP_ENTRIES);
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
k = hw_register_read(ci, dump, DUMP_ENTRIES);
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
for (i = 0; i < k; i++) {
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||
@ -660,24 +660,24 @@ static ssize_t store_registers(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
unsigned long addr, data, flags;
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(udc->dev, "[%s] EINVAL\n", __func__);
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (sscanf(buf, "%li %li", &addr, &data) != 2) {
|
||||
dev_err(udc->dev,
|
||||
dev_err(ci->dev,
|
||||
"<addr> <data>: write data to register address\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
if (hw_register_write(udc, addr, data))
|
||||
dev_err(udc->dev, "invalid address range\n");
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
if (hw_register_write(ci, addr, data))
|
||||
dev_err(ci->dev, "invalid address range\n");
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
done:
|
||||
return count;
|
||||
@ -693,34 +693,34 @@ static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
|
||||
static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
|
||||
unsigned long flags;
|
||||
struct list_head *ptr = NULL;
|
||||
struct ci13xxx_req *req = NULL;
|
||||
unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
|
||||
|
||||
if (attr == NULL || buf == NULL) {
|
||||
dev_err(udc->dev, "[%s] EINVAL\n", __func__);
|
||||
dev_err(ci->dev, "[%s] EINVAL\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
for (i = 0; i < udc->hw_ep_max; i++)
|
||||
list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue)
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
for (i = 0; i < ci->hw_ep_max; i++)
|
||||
list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue)
|
||||
{
|
||||
req = list_entry(ptr, struct ci13xxx_req, queue);
|
||||
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||
"EP=%02i: TD=%08X %s\n",
|
||||
i % udc->hw_ep_max/2, (u32)req->dma,
|
||||
((i < udc->hw_ep_max/2) ? "RX" : "TX"));
|
||||
i % ci->hw_ep_max/2, (u32)req->dma,
|
||||
((i < ci->hw_ep_max/2) ? "RX" : "TX"));
|
||||
|
||||
for (j = 0; j < qSize; j++)
|
||||
n += scnprintf(buf + n, PAGE_SIZE - n,
|
||||
" %04X: %08X\n", j,
|
||||
*((u32 *)req->ptr + j));
|
||||
}
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
@ -116,7 +116,8 @@ static int host_start(struct ci13xxx *ci)
|
||||
hcd->regs = ci->hw_bank.abs;
|
||||
hcd->has_tt = 1;
|
||||
|
||||
hcd->power_budget = ci->udc_driver->power_budget;
|
||||
hcd->power_budget = ci->platdata->power_budget;
|
||||
hcd->phy = ci->transceiver;
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = ci->hw_bank.cap;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -996,7 +996,7 @@ static int acm_probe(struct usb_interface *intf,
|
||||
case USB_CDC_CALL_MANAGEMENT_TYPE:
|
||||
call_management_function = buffer[3];
|
||||
call_interface_num = buffer[4];
|
||||
if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
|
||||
if ((quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
|
||||
dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
|
||||
break;
|
||||
default:
|
||||
|
@ -32,8 +32,6 @@
|
||||
#define DRIVER_AUTHOR "Oliver Neukum"
|
||||
#define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
|
||||
|
||||
#define HUAWEI_VENDOR_ID 0x12D1
|
||||
|
||||
static const struct usb_device_id wdm_ids[] = {
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
@ -41,29 +39,6 @@ static const struct usb_device_id wdm_ids[] = {
|
||||
.bInterfaceClass = USB_CLASS_COMM,
|
||||
.bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Huawei E392, E398 and possibly other Qualcomm based modems
|
||||
* embed the Qualcomm QMI protocol inside CDC on CDC ECM like
|
||||
* control interfaces. Userspace access to this is required
|
||||
* to configure the accompanying data interface
|
||||
*/
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = HUAWEI_VENDOR_ID,
|
||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
||||
.bInterfaceSubClass = 1,
|
||||
.bInterfaceProtocol = 9, /* NOTE: CDC ECM control interface! */
|
||||
},
|
||||
{
|
||||
/* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = HUAWEI_VENDOR_ID,
|
||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
||||
.bInterfaceSubClass = 1,
|
||||
.bInterfaceProtocol = 57, /* NOTE: CDC ECM control interface! */
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/user_namespace.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/moduleparam.h>
|
||||
@ -55,6 +56,7 @@
|
||||
|
||||
#define USB_MAXBUS 64
|
||||
#define USB_DEVICE_MAX USB_MAXBUS * 128
|
||||
#define USB_SG_SIZE 16384 /* split-size for large txs */
|
||||
|
||||
/* Mutual exclusion for removal, open, and release */
|
||||
DEFINE_MUTEX(usbfs_mutex);
|
||||
@ -285,9 +287,16 @@ static struct async *alloc_async(unsigned int numisoframes)
|
||||
|
||||
static void free_async(struct async *as)
|
||||
{
|
||||
int i;
|
||||
|
||||
put_pid(as->pid);
|
||||
if (as->cred)
|
||||
put_cred(as->cred);
|
||||
for (i = 0; i < as->urb->num_sgs; i++) {
|
||||
if (sg_page(&as->urb->sg[i]))
|
||||
kfree(sg_virt(&as->urb->sg[i]));
|
||||
}
|
||||
kfree(as->urb->sg);
|
||||
kfree(as->urb->transfer_buffer);
|
||||
kfree(as->urb->setup_packet);
|
||||
usb_free_urb(as->urb);
|
||||
@ -388,6 +397,53 @@ static void snoop_urb(struct usb_device *udev,
|
||||
}
|
||||
}
|
||||
|
||||
static void snoop_urb_data(struct urb *urb, unsigned len)
|
||||
{
|
||||
int i, size;
|
||||
|
||||
if (!usbfs_snoop)
|
||||
return;
|
||||
|
||||
if (urb->num_sgs == 0) {
|
||||
print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
|
||||
urb->transfer_buffer, len, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < urb->num_sgs && len; i++) {
|
||||
size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
|
||||
print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
|
||||
sg_virt(&urb->sg[i]), size, 1);
|
||||
len -= size;
|
||||
}
|
||||
}
|
||||
|
||||
static int copy_urb_data_to_user(u8 __user *userbuffer, struct urb *urb)
|
||||
{
|
||||
unsigned i, len, size;
|
||||
|
||||
if (urb->number_of_packets > 0) /* Isochronous */
|
||||
len = urb->transfer_buffer_length;
|
||||
else /* Non-Isoc */
|
||||
len = urb->actual_length;
|
||||
|
||||
if (urb->num_sgs == 0) {
|
||||
if (copy_to_user(userbuffer, urb->transfer_buffer, len))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < urb->num_sgs && len; i++) {
|
||||
size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
|
||||
if (copy_to_user(userbuffer, sg_virt(&urb->sg[i]), size))
|
||||
return -EFAULT;
|
||||
userbuffer += size;
|
||||
len -= size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define AS_CONTINUATION 1
|
||||
#define AS_UNLINK 2
|
||||
|
||||
@ -454,9 +510,10 @@ static void async_completed(struct urb *urb)
|
||||
}
|
||||
snoop(&urb->dev->dev, "urb complete\n");
|
||||
snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
|
||||
as->status, COMPLETE,
|
||||
((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_OUT) ?
|
||||
NULL : urb->transfer_buffer, urb->actual_length);
|
||||
as->status, COMPLETE, NULL, 0);
|
||||
if ((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_IN)
|
||||
snoop_urb_data(urb, urb->actual_length);
|
||||
|
||||
if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
|
||||
as->status != -ENOENT)
|
||||
cancel_bulk_urbs(ps, as->bulk_addr);
|
||||
@ -1114,8 +1171,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
|
||||
struct async *as = NULL;
|
||||
struct usb_ctrlrequest *dr = NULL;
|
||||
unsigned int u, totlen, isofrmlen;
|
||||
int ret, ifnum = -1;
|
||||
int is_in;
|
||||
int i, ret, is_in, num_sgs = 0, ifnum = -1;
|
||||
void *buf;
|
||||
|
||||
if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP |
|
||||
USBDEVFS_URB_SHORT_NOT_OK |
|
||||
@ -1199,6 +1256,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
|
||||
goto interrupt_urb;
|
||||
}
|
||||
uurb->number_of_packets = 0;
|
||||
num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE);
|
||||
if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize)
|
||||
num_sgs = 0;
|
||||
break;
|
||||
|
||||
case USBDEVFS_URB_TYPE_INTERRUPT:
|
||||
@ -1255,26 +1315,67 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length;
|
||||
|
||||
u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length +
|
||||
num_sgs * sizeof(struct scatterlist);
|
||||
ret = usbfs_increase_memory_usage(u);
|
||||
if (ret)
|
||||
goto error;
|
||||
as->mem_usage = u;
|
||||
|
||||
if (uurb->buffer_length > 0) {
|
||||
if (num_sgs) {
|
||||
as->urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist),
|
||||
GFP_KERNEL);
|
||||
if (!as->urb->sg) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
as->urb->num_sgs = num_sgs;
|
||||
sg_init_table(as->urb->sg, as->urb->num_sgs);
|
||||
|
||||
totlen = uurb->buffer_length;
|
||||
for (i = 0; i < as->urb->num_sgs; i++) {
|
||||
u = (totlen > USB_SG_SIZE) ? USB_SG_SIZE : totlen;
|
||||
buf = kmalloc(u, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
sg_set_buf(&as->urb->sg[i], buf, u);
|
||||
|
||||
if (!is_in) {
|
||||
if (copy_from_user(buf, uurb->buffer, u)) {
|
||||
ret = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
totlen -= u;
|
||||
}
|
||||
} else if (uurb->buffer_length > 0) {
|
||||
as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
|
||||
GFP_KERNEL);
|
||||
if (!as->urb->transfer_buffer) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
/* Isochronous input data may end up being discontiguous
|
||||
* if some of the packets are short. Clear the buffer so
|
||||
* that the gaps don't leak kernel data to userspace.
|
||||
*/
|
||||
if (is_in && uurb->type == USBDEVFS_URB_TYPE_ISO)
|
||||
|
||||
if (!is_in) {
|
||||
if (copy_from_user(as->urb->transfer_buffer,
|
||||
uurb->buffer,
|
||||
uurb->buffer_length)) {
|
||||
ret = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
} else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
|
||||
/*
|
||||
* Isochronous input data may end up being
|
||||
* discontiguous if some of the packets are short.
|
||||
* Clear the buffer so that the gaps don't leak
|
||||
* kernel data to userspace.
|
||||
*/
|
||||
memset(as->urb->transfer_buffer, 0,
|
||||
uurb->buffer_length);
|
||||
}
|
||||
}
|
||||
as->urb->dev = ps->dev;
|
||||
as->urb->pipe = (uurb->type << 30) |
|
||||
@ -1328,17 +1429,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
|
||||
as->pid = get_pid(task_pid(current));
|
||||
as->cred = get_current_cred();
|
||||
security_task_getsecid(current, &as->secid);
|
||||
if (!is_in && uurb->buffer_length > 0) {
|
||||
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
|
||||
uurb->buffer_length)) {
|
||||
ret = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
|
||||
as->urb->transfer_buffer_length, 0, SUBMIT,
|
||||
is_in ? NULL : as->urb->transfer_buffer,
|
||||
uurb->buffer_length);
|
||||
NULL, 0);
|
||||
if (!is_in)
|
||||
snoop_urb_data(as->urb, as->urb->transfer_buffer_length);
|
||||
|
||||
async_newpending(as);
|
||||
|
||||
if (usb_endpoint_xfer_bulk(&ep->desc)) {
|
||||
@ -1433,11 +1529,7 @@ static int processcompl(struct async *as, void __user * __user *arg)
|
||||
unsigned int i;
|
||||
|
||||
if (as->userbuffer && urb->actual_length) {
|
||||
if (urb->number_of_packets > 0) /* Isochronous */
|
||||
i = urb->transfer_buffer_length;
|
||||
else /* Non-Isoc */
|
||||
i = urb->actual_length;
|
||||
if (copy_to_user(as->userbuffer, urb->transfer_buffer, i))
|
||||
if (copy_urb_data_to_user(as->userbuffer, urb))
|
||||
goto err_out;
|
||||
}
|
||||
if (put_user(as->status, &userurb->status))
|
||||
@ -1604,10 +1696,10 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
|
||||
void __user *addr = as->userurb;
|
||||
unsigned int i;
|
||||
|
||||
if (as->userbuffer && urb->actual_length)
|
||||
if (copy_to_user(as->userbuffer, urb->transfer_buffer,
|
||||
urb->actual_length))
|
||||
if (as->userbuffer && urb->actual_length) {
|
||||
if (copy_urb_data_to_user(as->userbuffer, urb))
|
||||
return -EFAULT;
|
||||
}
|
||||
if (put_user(as->status, &userurb->status))
|
||||
return -EFAULT;
|
||||
if (put_user(urb->actual_length, &userurb->actual_length))
|
||||
@ -1820,6 +1912,22 @@ static int proc_release_port(struct dev_state *ps, void __user *arg)
|
||||
return usb_hub_release_port(ps->dev, portnum, ps);
|
||||
}
|
||||
|
||||
static int proc_get_capabilities(struct dev_state *ps, void __user *arg)
|
||||
{
|
||||
__u32 caps;
|
||||
|
||||
caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM;
|
||||
if (!ps->dev->bus->no_stop_on_short)
|
||||
caps |= USBDEVFS_CAP_BULK_CONTINUATION;
|
||||
if (ps->dev->bus->sg_tablesize)
|
||||
caps |= USBDEVFS_CAP_BULK_SCATTER_GATHER;
|
||||
|
||||
if (put_user(caps, (__u32 __user *)arg))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: All requests here that have interface numbers as parameters
|
||||
* are assuming that somehow the configuration has been prevented from
|
||||
@ -1990,6 +2098,9 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
|
||||
snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__);
|
||||
ret = proc_release_port(ps, p);
|
||||
break;
|
||||
case USBDEVFS_GET_CAPABILITIES:
|
||||
ret = proc_get_capabilities(ps, p);
|
||||
break;
|
||||
}
|
||||
usb_unlock_device(dev);
|
||||
if (ret >= 0)
|
||||
|
@ -367,6 +367,7 @@ static int usb_probe_interface(struct device *dev)
|
||||
return error;
|
||||
|
||||
err:
|
||||
usb_set_intfdata(intf, NULL);
|
||||
intf->needs_remote_wakeup = 0;
|
||||
intf->condition = USB_INTERFACE_UNBOUND;
|
||||
usb_cancel_queued_reset(intf);
|
||||
@ -622,14 +623,15 @@ int usb_match_one_id(struct usb_interface *interface,
|
||||
if (!usb_match_device(dev, id))
|
||||
return 0;
|
||||
|
||||
/* The interface class, subclass, and protocol should never be
|
||||
/* The interface class, subclass, protocol and number should never be
|
||||
* checked for a match if the device class is Vendor Specific,
|
||||
* unless the match record specifies the Vendor ID. */
|
||||
if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
|
||||
!(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
|
||||
(id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_SUBCLASS |
|
||||
USB_DEVICE_ID_MATCH_INT_PROTOCOL)))
|
||||
USB_DEVICE_ID_MATCH_INT_PROTOCOL |
|
||||
USB_DEVICE_ID_MATCH_INT_NUMBER)))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
|
||||
@ -644,6 +646,10 @@ int usb_match_one_id(struct usb_interface *interface,
|
||||
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
|
||||
(id->bInterfaceNumber != intf->desc.bInterfaceNumber))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_match_one_id);
|
||||
|
@ -92,7 +92,7 @@ static int init_usb_class(void)
|
||||
}
|
||||
|
||||
kref_init(&usb_class->kref);
|
||||
usb_class->class = class_create(THIS_MODULE, "usb");
|
||||
usb_class->class = class_create(THIS_MODULE, "usbmisc");
|
||||
if (IS_ERR(usb_class->class)) {
|
||||
result = IS_ERR(usb_class->class);
|
||||
printk(KERN_ERR "class_create failed for usb devices\n");
|
||||
|
@ -1398,7 +1398,15 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
||||
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
|
||||
if (hcd->self.uses_dma) {
|
||||
if (urb->num_sgs) {
|
||||
int n = dma_map_sg(
|
||||
int n;
|
||||
|
||||
/* We don't support sg for isoc transfers ! */
|
||||
if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
n = dma_map_sg(
|
||||
hcd->self.controller,
|
||||
urb->sg,
|
||||
urb->num_sgs,
|
||||
|
@ -81,7 +81,7 @@ struct usb_hub {
|
||||
u8 indicator[USB_MAXCHILDREN];
|
||||
struct delayed_work leds;
|
||||
struct delayed_work init_work;
|
||||
void **port_owners;
|
||||
struct dev_state **port_owners;
|
||||
};
|
||||
|
||||
static inline int hub_is_superspeed(struct usb_device *hdev)
|
||||
@ -1271,7 +1271,8 @@ static int hub_configure(struct usb_hub *hub,
|
||||
|
||||
hdev->children = kzalloc(hdev->maxchild *
|
||||
sizeof(struct usb_device *), GFP_KERNEL);
|
||||
hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
|
||||
hub->port_owners = kzalloc(hdev->maxchild * sizeof(struct dev_state *),
|
||||
GFP_KERNEL);
|
||||
if (!hdev->children || !hub->port_owners) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
@ -1649,7 +1650,7 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
|
||||
* to one of these "claimed" ports, the program will "own" the device.
|
||||
*/
|
||||
static int find_port_owner(struct usb_device *hdev, unsigned port1,
|
||||
void ***ppowner)
|
||||
struct dev_state ***ppowner)
|
||||
{
|
||||
if (hdev->state == USB_STATE_NOTATTACHED)
|
||||
return -ENODEV;
|
||||
@ -1664,10 +1665,11 @@ static int find_port_owner(struct usb_device *hdev, unsigned port1,
|
||||
}
|
||||
|
||||
/* In the following three functions, the caller must hold hdev's lock */
|
||||
int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, void *owner)
|
||||
int usb_hub_claim_port(struct usb_device *hdev, unsigned port1,
|
||||
struct dev_state *owner)
|
||||
{
|
||||
int rc;
|
||||
void **powner;
|
||||
struct dev_state **powner;
|
||||
|
||||
rc = find_port_owner(hdev, port1, &powner);
|
||||
if (rc)
|
||||
@ -1678,10 +1680,11 @@ int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, void *owner)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner)
|
||||
int usb_hub_release_port(struct usb_device *hdev, unsigned port1,
|
||||
struct dev_state *owner)
|
||||
{
|
||||
int rc;
|
||||
void **powner;
|
||||
struct dev_state **powner;
|
||||
|
||||
rc = find_port_owner(hdev, port1, &powner);
|
||||
if (rc)
|
||||
@ -1692,10 +1695,10 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner)
|
||||
return rc;
|
||||
}
|
||||
|
||||
void usb_hub_release_all_ports(struct usb_device *hdev, void *owner)
|
||||
void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner)
|
||||
{
|
||||
int n;
|
||||
void **powner;
|
||||
struct dev_state **powner;
|
||||
|
||||
n = find_port_owner(hdev, 1, &powner);
|
||||
if (n == 0) {
|
||||
|
@ -1559,7 +1559,7 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
|
||||
if (add_uevent_var(env,
|
||||
"MODALIAS=usb:"
|
||||
"v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
|
||||
"v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02Xin%02X",
|
||||
le16_to_cpu(usb_dev->descriptor.idVendor),
|
||||
le16_to_cpu(usb_dev->descriptor.idProduct),
|
||||
le16_to_cpu(usb_dev->descriptor.bcdDevice),
|
||||
@ -1568,7 +1568,8 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
usb_dev->descriptor.bDeviceProtocol,
|
||||
alt->desc.bInterfaceClass,
|
||||
alt->desc.bInterfaceSubClass,
|
||||
alt->desc.bInterfaceProtocol))
|
||||
alt->desc.bInterfaceProtocol,
|
||||
alt->desc.bInterfaceNumber))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
|
@ -840,7 +840,7 @@ static ssize_t show_modalias(struct device *dev,
|
||||
alt = intf->cur_altsetting;
|
||||
|
||||
return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
|
||||
"ic%02Xisc%02Xip%02X\n",
|
||||
"ic%02Xisc%02Xip%02Xin%02X\n",
|
||||
le16_to_cpu(udev->descriptor.idVendor),
|
||||
le16_to_cpu(udev->descriptor.idProduct),
|
||||
le16_to_cpu(udev->descriptor.bcdDevice),
|
||||
@ -849,7 +849,8 @@ static ssize_t show_modalias(struct device *dev,
|
||||
udev->descriptor.bDeviceProtocol,
|
||||
alt->desc.bInterfaceClass,
|
||||
alt->desc.bInterfaceSubClass,
|
||||
alt->desc.bInterfaceProtocol);
|
||||
alt->desc.bInterfaceProtocol,
|
||||
alt->desc.bInterfaceNumber);
|
||||
}
|
||||
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include <linux/pm.h>
|
||||
|
||||
struct dev_state;
|
||||
|
||||
/* Functions local to drivers/usb/core/ */
|
||||
|
||||
extern int usb_create_sysfs_dev_files(struct usb_device *dev);
|
||||
@ -41,10 +43,11 @@ extern void usb_forced_unbind_intf(struct usb_interface *intf);
|
||||
extern void usb_rebind_intf(struct usb_interface *intf);
|
||||
|
||||
extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port,
|
||||
void *owner);
|
||||
struct dev_state *owner);
|
||||
extern int usb_hub_release_port(struct usb_device *hdev, unsigned port,
|
||||
void *owner);
|
||||
extern void usb_hub_release_all_ports(struct usb_device *hdev, void *owner);
|
||||
struct dev_state *owner);
|
||||
extern void usb_hub_release_all_ports(struct usb_device *hdev,
|
||||
struct dev_state *owner);
|
||||
extern bool usb_device_is_owned(struct usb_device *udev);
|
||||
|
||||
extern int usb_hub_init(void);
|
||||
|
@ -148,6 +148,8 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc)
|
||||
reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
/* After PHYs are stable we can take Core out of reset state */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
reg &= ~DWC3_GCTL_CORESOFTRESET;
|
||||
@ -255,7 +257,7 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
|
||||
*
|
||||
* Returns 0 on success otherwise negative errno.
|
||||
*/
|
||||
static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
|
||||
static int dwc3_event_buffers_setup(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int n;
|
||||
@ -266,6 +268,8 @@ static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
|
||||
evt->buf, (unsigned long long) evt->dma,
|
||||
evt->length);
|
||||
|
||||
evt->lpos = 0;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
|
||||
lower_32_bits(evt->dma));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
|
||||
@ -285,6 +289,9 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
|
||||
|
||||
for (n = 0; n < dwc->num_event_buffers; n++) {
|
||||
evt = dwc->ev_buffs[n];
|
||||
|
||||
evt->lpos = 0;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
|
||||
@ -328,8 +335,6 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
|
||||
}
|
||||
dwc->revision = reg;
|
||||
|
||||
dwc3_core_soft_reset(dwc);
|
||||
|
||||
/* issue device SoftReset too */
|
||||
timeout = jiffies + msecs_to_jiffies(500);
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
|
||||
@ -347,6 +352,8 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
|
||||
cpu_relax();
|
||||
} while (true);
|
||||
|
||||
dwc3_core_soft_reset(dwc);
|
||||
|
||||
dwc3_cache_hwparams(dwc);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
|
@ -67,6 +67,7 @@
|
||||
#define DWC3_DEVICE_EVENT_CONNECT_DONE 2
|
||||
#define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE 3
|
||||
#define DWC3_DEVICE_EVENT_WAKEUP 4
|
||||
#define DWC3_DEVICE_EVENT_HIBER_REQ 5
|
||||
#define DWC3_DEVICE_EVENT_EOPF 6
|
||||
#define DWC3_DEVICE_EVENT_SOF 7
|
||||
#define DWC3_DEVICE_EVENT_ERRATIC_ERROR 9
|
||||
@ -171,28 +172,36 @@
|
||||
#define DWC3_GCTL_PRTCAP_DEVICE 2
|
||||
#define DWC3_GCTL_PRTCAP_OTG 3
|
||||
|
||||
#define DWC3_GCTL_CORESOFTRESET (1 << 11)
|
||||
#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4)
|
||||
#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
|
||||
#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
|
||||
#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
|
||||
#define DWC3_GCTL_CORESOFTRESET (1 << 11)
|
||||
#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4)
|
||||
#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
|
||||
#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
|
||||
#define DWC3_GCTL_GBLHIBERNATIONEN (1 << 1)
|
||||
#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
|
||||
|
||||
/* Global USB2 PHY Configuration Register */
|
||||
#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
|
||||
#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
|
||||
#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
|
||||
#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
|
||||
|
||||
/* Global USB3 PIPE Control Register */
|
||||
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
|
||||
#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
|
||||
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
|
||||
#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
|
||||
|
||||
/* Global TX Fifo Size Register */
|
||||
#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
|
||||
#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
|
||||
#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
|
||||
#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
|
||||
|
||||
/* Global HWPARAMS1 Register */
|
||||
#define DWC3_GHWPARAMS1_EN_PWROPT(n) (((n) & (3 << 24)) >> 24)
|
||||
#define DWC3_GHWPARAMS1_EN_PWROPT_NO 0
|
||||
#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
|
||||
#define DWC3_GHWPARAMS1_EN_PWROPT_HIB 2
|
||||
#define DWC3_GHWPARAMS1_PWROPT(n) ((n) << 24)
|
||||
#define DWC3_GHWPARAMS1_PWROPT_MASK DWC3_GHWPARAMS1_PWROPT(3)
|
||||
|
||||
/* Global HWPARAMS4 Register */
|
||||
#define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n) (((n) & (0x0f << 13)) >> 13)
|
||||
#define DWC3_MAX_HIBER_SCRATCHBUFS 15
|
||||
|
||||
/* Device Configuration Register */
|
||||
#define DWC3_DCFG_LPM_CAP (1 << 22)
|
||||
@ -206,24 +215,32 @@
|
||||
#define DWC3_DCFG_LOWSPEED (2 << 0)
|
||||
#define DWC3_DCFG_FULLSPEED1 (3 << 0)
|
||||
|
||||
#define DWC3_DCFG_LPM_CAP (1 << 22)
|
||||
|
||||
/* Device Control Register */
|
||||
#define DWC3_DCTL_RUN_STOP (1 << 31)
|
||||
#define DWC3_DCTL_CSFTRST (1 << 30)
|
||||
#define DWC3_DCTL_LSFTRST (1 << 29)
|
||||
|
||||
#define DWC3_DCTL_HIRD_THRES_MASK (0x1f << 24)
|
||||
#define DWC3_DCTL_HIRD_THRES(n) (((n) & DWC3_DCTL_HIRD_THRES_MASK) >> 24)
|
||||
#define DWC3_DCTL_HIRD_THRES(n) ((n) << 24)
|
||||
|
||||
#define DWC3_DCTL_APPL1RES (1 << 23)
|
||||
|
||||
#define DWC3_DCTL_TRGTULST_MASK (0x0f << 17)
|
||||
#define DWC3_DCTL_TRGTULST(n) ((n) << 17)
|
||||
/* These apply for core versions 1.87a and earlier */
|
||||
#define DWC3_DCTL_TRGTULST_MASK (0x0f << 17)
|
||||
#define DWC3_DCTL_TRGTULST(n) ((n) << 17)
|
||||
#define DWC3_DCTL_TRGTULST_U2 (DWC3_DCTL_TRGTULST(2))
|
||||
#define DWC3_DCTL_TRGTULST_U3 (DWC3_DCTL_TRGTULST(3))
|
||||
#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4))
|
||||
#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5))
|
||||
#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6))
|
||||
|
||||
#define DWC3_DCTL_TRGTULST_U2 (DWC3_DCTL_TRGTULST(2))
|
||||
#define DWC3_DCTL_TRGTULST_U3 (DWC3_DCTL_TRGTULST(3))
|
||||
#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4))
|
||||
#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5))
|
||||
#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6))
|
||||
/* These apply for core versions 1.94a and later */
|
||||
#define DWC3_DCTL_KEEP_CONNECT (1 << 19)
|
||||
#define DWC3_DCTL_L1_HIBER_EN (1 << 18)
|
||||
#define DWC3_DCTL_CRS (1 << 17)
|
||||
#define DWC3_DCTL_CSS (1 << 16)
|
||||
|
||||
#define DWC3_DCTL_INITU2ENA (1 << 12)
|
||||
#define DWC3_DCTL_ACCEPTU2ENA (1 << 11)
|
||||
@ -249,6 +266,7 @@
|
||||
#define DWC3_DEVTEN_ERRTICERREN (1 << 9)
|
||||
#define DWC3_DEVTEN_SOFEN (1 << 7)
|
||||
#define DWC3_DEVTEN_EOPFEN (1 << 6)
|
||||
#define DWC3_DEVTEN_HIBERNATIONREQEVTEN (1 << 5)
|
||||
#define DWC3_DEVTEN_WKUPEVTEN (1 << 4)
|
||||
#define DWC3_DEVTEN_ULSTCNGEN (1 << 3)
|
||||
#define DWC3_DEVTEN_CONNECTDONEEN (1 << 2)
|
||||
@ -256,7 +274,15 @@
|
||||
#define DWC3_DEVTEN_DISCONNEVTEN (1 << 0)
|
||||
|
||||
/* Device Status Register */
|
||||
#define DWC3_DSTS_DCNRD (1 << 29)
|
||||
|
||||
/* This applies for core versions 1.87a and earlier */
|
||||
#define DWC3_DSTS_PWRUPREQ (1 << 24)
|
||||
|
||||
/* These apply for core versions 1.94a and later */
|
||||
#define DWC3_DSTS_RSS (1 << 25)
|
||||
#define DWC3_DSTS_SSS (1 << 24)
|
||||
|
||||
#define DWC3_DSTS_COREIDLE (1 << 23)
|
||||
#define DWC3_DSTS_DEVCTRLHLT (1 << 22)
|
||||
|
||||
@ -265,7 +291,7 @@
|
||||
|
||||
#define DWC3_DSTS_RXFIFOEMPTY (1 << 17)
|
||||
|
||||
#define DWC3_DSTS_SOFFN_MASK (0x3ff << 3)
|
||||
#define DWC3_DSTS_SOFFN_MASK (0x3fff << 3)
|
||||
#define DWC3_DSTS_SOFFN(n) (((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
|
||||
|
||||
#define DWC3_DSTS_CONNECTSPD (7 << 0)
|
||||
@ -280,6 +306,11 @@
|
||||
#define DWC3_DGCMD_SET_LMP 0x01
|
||||
#define DWC3_DGCMD_SET_PERIODIC_PAR 0x02
|
||||
#define DWC3_DGCMD_XMIT_FUNCTION 0x03
|
||||
|
||||
/* These apply for core versions 1.94a and later */
|
||||
#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO 0x04
|
||||
#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI 0x05
|
||||
|
||||
#define DWC3_DGCMD_SELECTED_FIFO_FLUSH 0x09
|
||||
#define DWC3_DGCMD_ALL_FIFO_FLUSH 0x0a
|
||||
#define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c
|
||||
@ -287,6 +318,15 @@
|
||||
|
||||
#define DWC3_DGCMD_STATUS(n) (((n) >> 15) & 1)
|
||||
#define DWC3_DGCMD_CMDACT (1 << 10)
|
||||
#define DWC3_DGCMD_CMDIOC (1 << 8)
|
||||
|
||||
/* Device Generic Command Parameter Register */
|
||||
#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT (1 << 0)
|
||||
#define DWC3_DGCMDPAR_FIFO_NUM(n) ((n) << 0)
|
||||
#define DWC3_DGCMDPAR_RX_FIFO (0 << 5)
|
||||
#define DWC3_DGCMDPAR_TX_FIFO (1 << 5)
|
||||
#define DWC3_DGCMDPAR_LOOPBACK_DIS (0 << 0)
|
||||
#define DWC3_DGCMDPAR_LOOPBACK_ENA (1 << 0)
|
||||
|
||||
/* Device Endpoint Command Register */
|
||||
#define DWC3_DEPCMD_PARAM_SHIFT 16
|
||||
@ -303,7 +343,10 @@
|
||||
#define DWC3_DEPCMD_STARTTRANSFER (0x06 << 0)
|
||||
#define DWC3_DEPCMD_CLEARSTALL (0x05 << 0)
|
||||
#define DWC3_DEPCMD_SETSTALL (0x04 << 0)
|
||||
/* This applies for core versions 1.90a and earlier */
|
||||
#define DWC3_DEPCMD_GETSEQNUMBER (0x03 << 0)
|
||||
/* This applies for core versions 1.94a and later */
|
||||
#define DWC3_DEPCMD_GETEPSTATE (0x03 << 0)
|
||||
#define DWC3_DEPCMD_SETTRANSFRESOURCE (0x02 << 0)
|
||||
#define DWC3_DEPCMD_SETEPCONFIG (0x01 << 0)
|
||||
|
||||
@ -361,7 +404,8 @@ struct dwc3_event_buffer {
|
||||
* @current_trb: index of current used trb
|
||||
* @number: endpoint number (1 - 15)
|
||||
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
|
||||
* @res_trans_idx: Resource transfer index
|
||||
* @resource_index: Resource transfer index
|
||||
* @current_uf: Current uf received through last event parameter
|
||||
* @interval: the intervall on which the ISOC transfer is started
|
||||
* @name: a human readable name e.g. ep1out-bulk
|
||||
* @direction: true for TX, false for RX
|
||||
@ -385,6 +429,7 @@ struct dwc3_ep {
|
||||
#define DWC3_EP_WEDGE (1 << 2)
|
||||
#define DWC3_EP_BUSY (1 << 4)
|
||||
#define DWC3_EP_PENDING_REQUEST (1 << 5)
|
||||
#define DWC3_EP_MISSED_ISOC (1 << 6)
|
||||
|
||||
/* This last one is specific to EP0 */
|
||||
#define DWC3_EP0_DIR_IN (1 << 31)
|
||||
@ -393,7 +438,8 @@ struct dwc3_ep {
|
||||
|
||||
u8 number;
|
||||
u8 type;
|
||||
u8 res_trans_idx;
|
||||
u8 resource_index;
|
||||
u16 current_uf;
|
||||
u32 interval;
|
||||
|
||||
char name[20];
|
||||
@ -437,6 +483,8 @@ enum dwc3_link_state {
|
||||
DWC3_LINK_STATE_HRESET = 0x09,
|
||||
DWC3_LINK_STATE_CMPLY = 0x0a,
|
||||
DWC3_LINK_STATE_LPBK = 0x0b,
|
||||
DWC3_LINK_STATE_RESET = 0x0e,
|
||||
DWC3_LINK_STATE_RESUME = 0x0f,
|
||||
DWC3_LINK_STATE_MASK = 0x0f,
|
||||
};
|
||||
|
||||
@ -450,11 +498,12 @@ enum dwc3_device_state {
|
||||
#define DWC3_TRB_SIZE_MASK (0x00ffffff)
|
||||
#define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK)
|
||||
#define DWC3_TRB_SIZE_PCM1(n) (((n) & 0x03) << 24)
|
||||
#define DWC3_TRB_SIZE_TRBSTS(n) (((n) & (0x0f << 28) >> 28))
|
||||
#define DWC3_TRB_SIZE_TRBSTS(n) (((n) & (0x0f << 28)) >> 28)
|
||||
|
||||
#define DWC3_TRBSTS_OK 0
|
||||
#define DWC3_TRBSTS_MISSED_ISOC 1
|
||||
#define DWC3_TRBSTS_SETUP_PENDING 2
|
||||
#define DWC3_TRB_STS_XFER_IN_PROG 4
|
||||
|
||||
/* TRB Control */
|
||||
#define DWC3_TRB_CTRL_HWO (1 << 0)
|
||||
@ -543,6 +592,14 @@ struct dwc3_request {
|
||||
unsigned queued:1;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct dwc3_scratchpad_array - hibernation scratchpad array
|
||||
* (format defined by hw)
|
||||
*/
|
||||
struct dwc3_scratchpad_array {
|
||||
__le64 dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dwc3 - representation of our controller
|
||||
* @ctrl_req: usb control request which is used for ep0
|
||||
@ -624,8 +681,10 @@ struct dwc3 {
|
||||
#define DWC3_REVISION_180A 0x5533180a
|
||||
#define DWC3_REVISION_183A 0x5533183a
|
||||
#define DWC3_REVISION_185A 0x5533185a
|
||||
#define DWC3_REVISION_187A 0x5533187a
|
||||
#define DWC3_REVISION_188A 0x5533188a
|
||||
#define DWC3_REVISION_190A 0x5533190a
|
||||
#define DWC3_REVISION_194A 0x5533194a
|
||||
#define DWC3_REVISION_200A 0x5533200a
|
||||
#define DWC3_REVISION_202A 0x5533202a
|
||||
#define DWC3_REVISION_210A 0x5533210a
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/dwc3-exynos.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "core.h"
|
||||
|
@ -54,7 +54,9 @@
|
||||
#include "gadget.h"
|
||||
#include "io.h"
|
||||
|
||||
static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum);
|
||||
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
|
||||
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
struct dwc3_ep *dep, struct dwc3_request *req);
|
||||
|
||||
static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
|
||||
{
|
||||
@ -111,7 +113,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
|
||||
}
|
||||
|
||||
dep->flags |= DWC3_EP_BUSY;
|
||||
dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
|
||||
dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
|
||||
dep->number);
|
||||
|
||||
dwc->ep0_next_event = DWC3_EP0_COMPLETE;
|
||||
@ -150,16 +152,15 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = dwc3_ep0_start_trans(dwc, direction,
|
||||
req->request.dma, req->request.length,
|
||||
DWC3_TRBCTL_CONTROL_DATA);
|
||||
__dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req);
|
||||
|
||||
dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
|
||||
DWC3_EP0_DIR_IN);
|
||||
} else if (dwc->delayed_status) {
|
||||
dwc->delayed_status = false;
|
||||
|
||||
if (dwc->ep0state == EP0_STATUS_PHASE)
|
||||
dwc3_ep0_do_control_status(dwc, 1);
|
||||
__dwc3_ep0_do_control_status(dwc, dwc->eps[1]);
|
||||
else
|
||||
dev_dbg(dwc->dev, "too early for delayed status\n");
|
||||
}
|
||||
@ -224,6 +225,16 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
|
||||
dwc3_ep0_out_start(dwc);
|
||||
}
|
||||
|
||||
int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
|
||||
{
|
||||
struct dwc3_ep *dep = to_dwc3_ep(ep);
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dwc3_ep0_out_start(struct dwc3 *dwc)
|
||||
{
|
||||
int ret;
|
||||
@ -463,6 +474,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
u32 cfg;
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
||||
dwc->start_config_issued = false;
|
||||
cfg = le16_to_cpu(ctrl->wValue);
|
||||
@ -477,6 +489,14 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
||||
/* if the cfg matches and the cfg is non zero */
|
||||
if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
|
||||
dwc->dev_state = DWC3_CONFIGURED_STATE;
|
||||
/*
|
||||
* Enable transition to U1/U2 state when
|
||||
* nothing is pending from application.
|
||||
*/
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
|
||||
dwc->resize_fifos = true;
|
||||
dev_dbg(dwc->dev, "resize fifos flag SET\n");
|
||||
}
|
||||
@ -514,8 +534,8 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
|
||||
|
||||
dwc->u1sel = timing.u1sel;
|
||||
dwc->u1pel = timing.u1pel;
|
||||
dwc->u2sel = timing.u2sel;
|
||||
dwc->u2pel = timing.u2pel;
|
||||
dwc->u2sel = le16_to_cpu(timing.u2sel);
|
||||
dwc->u2pel = le16_to_cpu(timing.u2pel);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
if (reg & DWC3_DCTL_INITU2ENA)
|
||||
@ -640,11 +660,11 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
|
||||
int ret;
|
||||
int ret = -EINVAL;
|
||||
u32 len;
|
||||
|
||||
if (!dwc->gadget_driver)
|
||||
goto err;
|
||||
goto out;
|
||||
|
||||
len = le16_to_cpu(ctrl->wLength);
|
||||
if (!len) {
|
||||
@ -665,11 +685,9 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
|
||||
if (ret == USB_GADGET_DELAYED_STATUS)
|
||||
dwc->delayed_status = true;
|
||||
|
||||
if (ret >= 0)
|
||||
return;
|
||||
|
||||
err:
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
out:
|
||||
if (ret < 0)
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
}
|
||||
|
||||
static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
||||
@ -723,7 +741,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_ep0_complete_req(struct dwc3 *dwc,
|
||||
static void dwc3_ep0_complete_status(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
struct dwc3_request *r;
|
||||
@ -745,6 +763,7 @@ static void dwc3_ep0_complete_req(struct dwc3 *dwc,
|
||||
dev_dbg(dwc->dev, "Invalid Test #%d\n",
|
||||
dwc->test_mode_nr);
|
||||
dwc3_ep0_stall_and_restart(dwc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -758,7 +777,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
|
||||
struct dwc3_ep *dep = dwc->eps[event->endpoint_number];
|
||||
|
||||
dep->flags &= ~DWC3_EP_BUSY;
|
||||
dep->res_trans_idx = 0;
|
||||
dep->resource_index = 0;
|
||||
dwc->setup_packet_pending = false;
|
||||
|
||||
switch (dwc->ep0state) {
|
||||
@ -774,7 +793,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
|
||||
|
||||
case EP0_STATUS_PHASE:
|
||||
dev_vdbg(dwc->dev, "Status Phase\n");
|
||||
dwc3_ep0_complete_req(dwc, event);
|
||||
dwc3_ep0_complete_status(dwc, event);
|
||||
break;
|
||||
default:
|
||||
WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state);
|
||||
@ -787,12 +806,63 @@ static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
|
||||
dwc3_ep0_out_start(dwc);
|
||||
}
|
||||
|
||||
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
{
|
||||
int ret;
|
||||
|
||||
req->direction = !!dep->number;
|
||||
|
||||
if (req->request.length == 0) {
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number,
|
||||
dwc->ctrl_req_addr, 0,
|
||||
DWC3_TRBCTL_CONTROL_DATA);
|
||||
} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
|
||||
&& (dep->number == 0)) {
|
||||
u32 transfer_size;
|
||||
|
||||
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
|
||||
dep->number);
|
||||
if (ret) {
|
||||
dev_dbg(dwc->dev, "failed to map request\n");
|
||||
return;
|
||||
}
|
||||
|
||||
WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE);
|
||||
|
||||
transfer_size = roundup(req->request.length,
|
||||
(u32) dep->endpoint.maxpacket);
|
||||
|
||||
dwc->ep0_bounced = true;
|
||||
|
||||
/*
|
||||
* REVISIT in case request length is bigger than
|
||||
* DWC3_EP0_BOUNCE_SIZE we will need two chained
|
||||
* TRBs to handle the transfer.
|
||||
*/
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number,
|
||||
dwc->ep0_bounce_addr, transfer_size,
|
||||
DWC3_TRBCTL_CONTROL_DATA);
|
||||
} else {
|
||||
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
|
||||
dep->number);
|
||||
if (ret) {
|
||||
dev_dbg(dwc->dev, "failed to map request\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma,
|
||||
req->request.length, DWC3_TRBCTL_CONTROL_DATA);
|
||||
}
|
||||
|
||||
WARN_ON(ret < 0);
|
||||
}
|
||||
|
||||
static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
struct dwc3_request *req;
|
||||
int ret;
|
||||
|
||||
dep = dwc->eps[0];
|
||||
|
||||
@ -806,47 +876,9 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
}
|
||||
|
||||
req = next_request(&dep->request_list);
|
||||
req->direction = !!event->endpoint_number;
|
||||
dep = dwc->eps[event->endpoint_number];
|
||||
|
||||
if (req->request.length == 0) {
|
||||
ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
|
||||
dwc->ctrl_req_addr, 0,
|
||||
DWC3_TRBCTL_CONTROL_DATA);
|
||||
} else if ((req->request.length % dep->endpoint.maxpacket)
|
||||
&& (event->endpoint_number == 0)) {
|
||||
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
|
||||
event->endpoint_number);
|
||||
if (ret) {
|
||||
dev_dbg(dwc->dev, "failed to map request\n");
|
||||
return;
|
||||
}
|
||||
|
||||
WARN_ON(req->request.length > dep->endpoint.maxpacket);
|
||||
|
||||
dwc->ep0_bounced = true;
|
||||
|
||||
/*
|
||||
* REVISIT in case request length is bigger than EP0
|
||||
* wMaxPacketSize, we will need two chained TRBs to handle
|
||||
* the transfer.
|
||||
*/
|
||||
ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
|
||||
dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
|
||||
DWC3_TRBCTL_CONTROL_DATA);
|
||||
} else {
|
||||
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
|
||||
event->endpoint_number);
|
||||
if (ret) {
|
||||
dev_dbg(dwc->dev, "failed to map request\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
|
||||
req->request.dma, req->request.length,
|
||||
DWC3_TRBCTL_CONTROL_DATA);
|
||||
}
|
||||
|
||||
WARN_ON(ret < 0);
|
||||
__dwc3_ep0_do_control_data(dwc, dep, req);
|
||||
}
|
||||
|
||||
static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
|
||||
@ -861,10 +893,8 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
|
||||
dwc->ctrl_req_addr, 0, type);
|
||||
}
|
||||
|
||||
static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
|
||||
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
{
|
||||
struct dwc3_ep *dep = dwc->eps[epnum];
|
||||
|
||||
if (dwc->resize_fifos) {
|
||||
dev_dbg(dwc->dev, "starting to resize fifos\n");
|
||||
dwc3_gadget_resize_tx_fifos(dwc);
|
||||
@ -874,13 +904,21 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
|
||||
WARN_ON(dwc3_ep0_start_control_status(dep));
|
||||
}
|
||||
|
||||
static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
struct dwc3_ep *dep = dwc->eps[event->endpoint_number];
|
||||
|
||||
__dwc3_ep0_do_control_status(dwc, dep);
|
||||
}
|
||||
|
||||
static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
dwc->setup_packet_pending = true;
|
||||
|
||||
/*
|
||||
* This part is very tricky: If we has just handled
|
||||
* This part is very tricky: If we have just handled
|
||||
* XferNotReady(Setup) and we're now expecting a
|
||||
* XferComplete but, instead, we receive another
|
||||
* XferNotReady(Setup), we should STALL and restart
|
||||
@ -974,7 +1012,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
|
||||
return;
|
||||
}
|
||||
|
||||
dwc3_ep0_do_control_status(dwc, event->endpoint_number);
|
||||
dwc3_ep0_do_control_status(dwc, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,23 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
|
||||
int retries = 10000;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Wait until device controller is ready. Only applies to 1.94a and
|
||||
* later RTL.
|
||||
*/
|
||||
if (dwc->revision >= DWC3_REVISION_194A) {
|
||||
while (--retries) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
|
||||
if (reg & DWC3_DSTS_DCNRD)
|
||||
udelay(5);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (retries <= 0)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
|
||||
|
||||
@ -107,7 +124,15 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
|
||||
reg |= DWC3_DCTL_ULSTCHNGREQ(state);
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
|
||||
/*
|
||||
* The following code is racy when called from dwc3_gadget_wakeup,
|
||||
* and is not needed, at least on newer versions
|
||||
*/
|
||||
if (dwc->revision >= DWC3_REVISION_194A)
|
||||
return 0;
|
||||
|
||||
/* wait for a change in DSTS */
|
||||
retries = 10000;
|
||||
while (--retries) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
|
||||
|
||||
@ -265,8 +290,8 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
|
||||
return "Clear Stall";
|
||||
case DWC3_DEPCMD_SETSTALL:
|
||||
return "Set Stall";
|
||||
case DWC3_DEPCMD_GETSEQNUMBER:
|
||||
return "Get Data Sequence Number";
|
||||
case DWC3_DEPCMD_GETEPSTATE:
|
||||
return "Get Endpoint State";
|
||||
case DWC3_DEPCMD_SETTRANSFRESOURCE:
|
||||
return "Set Endpoint Transfer Resource";
|
||||
case DWC3_DEPCMD_SETEPCONFIG:
|
||||
@ -414,7 +439,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
|
||||
params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
|
||||
| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc))
|
||||
| DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst);
|
||||
| DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst - 1);
|
||||
|
||||
params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
|
||||
| DWC3_DEPCFG_XFER_NOT_READY_EN;
|
||||
@ -530,9 +555,37 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
{
|
||||
struct dwc3_request *req;
|
||||
|
||||
if (!list_empty(&dep->req_queued))
|
||||
if (!list_empty(&dep->req_queued)) {
|
||||
dwc3_stop_active_transfer(dwc, dep->number);
|
||||
|
||||
/*
|
||||
* NOTICE: We are violating what the Databook says about the
|
||||
* EndTransfer command. Ideally we would _always_ wait for the
|
||||
* EndTransfer Command Completion IRQ, but that's causing too
|
||||
* much trouble synchronizing between us and gadget driver.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Note also that a similar handling was tested by Synopsys
|
||||
* (thanks a lot Paul) and nothing bad has come out of it.
|
||||
* In short, what we're doing is:
|
||||
*
|
||||
* - Issue EndTransfer WITH CMDIOC bit set
|
||||
* - Wait 100us
|
||||
* - giveback all requests to gadget driver
|
||||
*/
|
||||
udelay(100);
|
||||
|
||||
while (!list_empty(&dep->req_queued)) {
|
||||
req = next_request(&dep->req_queued);
|
||||
|
||||
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
|
||||
}
|
||||
}
|
||||
|
||||
while (!list_empty(&dep->request_list)) {
|
||||
req = next_request(&dep->request_list);
|
||||
|
||||
@ -741,8 +794,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
|
||||
|
||||
/* IOC every DWC3_TRB_NUM / 4 so we can refill */
|
||||
if (!(cur_slot % (DWC3_TRB_NUM / 4)))
|
||||
if (!req->request.no_interrupt)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_IOC;
|
||||
break;
|
||||
|
||||
@ -958,14 +1010,42 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
|
||||
dep->flags |= DWC3_EP_BUSY;
|
||||
|
||||
if (start_new) {
|
||||
dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
|
||||
dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
|
||||
dep->number);
|
||||
WARN_ON_ONCE(!dep->res_trans_idx);
|
||||
WARN_ON_ONCE(!dep->resource_index);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
|
||||
struct dwc3_ep *dep, u32 cur_uf)
|
||||
{
|
||||
u32 uf;
|
||||
|
||||
if (list_empty(&dep->request_list)) {
|
||||
dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
|
||||
dep->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 4 micro frames in the future */
|
||||
uf = cur_uf + dep->interval * 4;
|
||||
|
||||
__dwc3_gadget_kick_transfer(dep, uf, 1);
|
||||
}
|
||||
|
||||
static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
|
||||
struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
|
||||
{
|
||||
u32 cur_uf, mask;
|
||||
|
||||
mask = ~(dep->interval - 1);
|
||||
cur_uf = event->parameters & mask;
|
||||
|
||||
__dwc3_gadget_start_isoc(dwc, dep, cur_uf);
|
||||
}
|
||||
|
||||
static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
@ -995,11 +1075,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
|
||||
list_add_tail(&req->list, &dep->request_list);
|
||||
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && (dep->flags & DWC3_EP_BUSY))
|
||||
dep->flags |= DWC3_EP_PENDING_REQUEST;
|
||||
|
||||
/*
|
||||
* There are two special cases:
|
||||
* There are a few special cases:
|
||||
*
|
||||
* 1. XferNotReady with empty list of requests. We need to kick the
|
||||
* transfer here in that situation, otherwise we will be NAKing
|
||||
@ -1008,31 +1085,46 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
* able to receive the data until the next request is queued.
|
||||
* The following code is handling exactly that.
|
||||
*
|
||||
* 2. XferInProgress on Isoc EP with an active transfer. We need to
|
||||
* kick the transfer here after queuing a request, otherwise the
|
||||
* core may not see the modified TRB(s).
|
||||
*/
|
||||
if (dep->flags & DWC3_EP_PENDING_REQUEST) {
|
||||
int ret;
|
||||
int start_trans = 1;
|
||||
u8 trans_idx = dep->res_trans_idx;
|
||||
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
|
||||
(dep->flags & DWC3_EP_BUSY)) {
|
||||
start_trans = 0;
|
||||
WARN_ON_ONCE(!trans_idx);
|
||||
} else {
|
||||
trans_idx = 0;
|
||||
}
|
||||
|
||||
ret = __dwc3_gadget_kick_transfer(dep, trans_idx, start_trans);
|
||||
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
|
||||
if (ret && ret != -EBUSY) {
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
|
||||
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
|
||||
dep->name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* 2. XferInProgress on Isoc EP with an active transfer. We need to
|
||||
* kick the transfer here after queuing a request, otherwise the
|
||||
* core may not see the modified TRB(s).
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
|
||||
(dep->flags & DWC3_EP_BUSY)) {
|
||||
WARN_ON_ONCE(!dep->resource_index);
|
||||
ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index,
|
||||
false);
|
||||
if (ret && ret != -EBUSY) {
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
|
||||
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
|
||||
dep->name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 3. Missed ISOC Handling. We need to start isoc transfer on the saved
|
||||
* uframe number.
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
|
||||
(dep->flags & DWC3_EP_MISSED_ISOC)) {
|
||||
__dwc3_gadget_start_isoc(dwc, dep, dep->current_uf);
|
||||
dep->flags &= ~DWC3_EP_MISSED_ISOC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1118,15 +1210,6 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
|
||||
memset(¶ms, 0x00, sizeof(params));
|
||||
|
||||
if (value) {
|
||||
if (dep->number == 0 || dep->number == 1) {
|
||||
/*
|
||||
* Whenever EP0 is stalled, we will restart
|
||||
* the state machine, thus moving back to
|
||||
* Setup Phase
|
||||
*/
|
||||
dwc->ep0state = EP0_SETUP_PHASE;
|
||||
}
|
||||
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
|
||||
DWC3_DEPCMD_SETSTALL, ¶ms);
|
||||
if (ret)
|
||||
@ -1186,7 +1269,10 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
|
||||
dep->flags |= DWC3_EP_WEDGE;
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return dwc3_gadget_ep_set_halt(ep, 1);
|
||||
if (dep->number == 0 || dep->number == 1)
|
||||
return dwc3_gadget_ep0_set_halt(ep, 1);
|
||||
else
|
||||
return dwc3_gadget_ep_set_halt(ep, 1);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@ -1204,7 +1290,7 @@ static const struct usb_ep_ops dwc3_gadget_ep0_ops = {
|
||||
.free_request = dwc3_gadget_ep_free_request,
|
||||
.queue = dwc3_gadget_ep0_queue,
|
||||
.dequeue = dwc3_gadget_ep_dequeue,
|
||||
.set_halt = dwc3_gadget_ep_set_halt,
|
||||
.set_halt = dwc3_gadget_ep0_set_halt,
|
||||
.set_wedge = dwc3_gadget_ep_set_wedge,
|
||||
};
|
||||
|
||||
@ -1280,9 +1366,13 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* write zeroes to Link Change Request */
|
||||
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
/* Recent versions do this automatically */
|
||||
if (dwc->revision < DWC3_REVISION_194A) {
|
||||
/* write zeroes to Link Change Request */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
}
|
||||
|
||||
/* poll until Link State changes to ON */
|
||||
timeout = jiffies + msecs_to_jiffies(100);
|
||||
@ -1319,16 +1409,21 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
|
||||
static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
|
||||
{
|
||||
u32 reg;
|
||||
u32 timeout = 500;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
if (is_on) {
|
||||
reg &= ~DWC3_DCTL_TRGTULST_MASK;
|
||||
reg |= (DWC3_DCTL_RUN_STOP
|
||||
| DWC3_DCTL_TRGTULST_RX_DET);
|
||||
if (dwc->revision <= DWC3_REVISION_187A) {
|
||||
reg &= ~DWC3_DCTL_TRGTULST_MASK;
|
||||
reg |= DWC3_DCTL_TRGTULST_RX_DET;
|
||||
}
|
||||
|
||||
if (dwc->revision >= DWC3_REVISION_194A)
|
||||
reg &= ~DWC3_DCTL_KEEP_CONNECT;
|
||||
reg |= DWC3_DCTL_RUN_STOP;
|
||||
} else {
|
||||
reg &= ~DWC3_DCTL_RUN_STOP;
|
||||
}
|
||||
@ -1346,7 +1441,7 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
|
||||
}
|
||||
timeout--;
|
||||
if (!timeout)
|
||||
break;
|
||||
return -ETIMEDOUT;
|
||||
udelay(1);
|
||||
} while (1);
|
||||
|
||||
@ -1354,20 +1449,23 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
|
||||
dwc->gadget_driver
|
||||
? dwc->gadget_driver->function : "no-function",
|
||||
is_on ? "connect" : "disconnect");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
|
||||
{
|
||||
struct dwc3 *dwc = gadget_to_dwc(g);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
is_on = !!is_on;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
dwc3_gadget_run_stop(dwc, is_on);
|
||||
ret = dwc3_gadget_run_stop(dwc, is_on);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dwc3_gadget_start(struct usb_gadget *g,
|
||||
@ -1468,6 +1566,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct usb_gadget_ops dwc3_gadget_ops = {
|
||||
.get_frame = dwc3_gadget_get_frame,
|
||||
.wakeup = dwc3_gadget_wakeup,
|
||||
@ -1558,6 +1657,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
struct dwc3_trb *trb;
|
||||
unsigned int count;
|
||||
unsigned int s_pkt = 0;
|
||||
unsigned int trb_status;
|
||||
|
||||
do {
|
||||
req = next_request(&dep->req_queued);
|
||||
@ -1583,9 +1683,18 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
|
||||
if (dep->direction) {
|
||||
if (count) {
|
||||
dev_err(dwc->dev, "incomplete IN transfer %s\n",
|
||||
dep->name);
|
||||
status = -ECONNRESET;
|
||||
trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size);
|
||||
if (trb_status == DWC3_TRBSTS_MISSED_ISOC) {
|
||||
dev_dbg(dwc->dev, "incomplete IN transfer %s\n",
|
||||
dep->name);
|
||||
dep->current_uf = event->parameters &
|
||||
~(dep->interval - 1);
|
||||
dep->flags |= DWC3_EP_MISSED_ISOC;
|
||||
} else {
|
||||
dev_err(dwc->dev, "incomplete IN transfer %s\n",
|
||||
dep->name);
|
||||
status = -ECONNRESET;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (count && (event->status & DEPEVT_STATUS_SHORT))
|
||||
@ -1604,7 +1713,8 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
if (s_pkt)
|
||||
break;
|
||||
if ((event->status & DEPEVT_STATUS_LST) &&
|
||||
(trb->ctrl & DWC3_TRB_CTRL_LST))
|
||||
(trb->ctrl & (DWC3_TRB_CTRL_LST |
|
||||
DWC3_TRB_CTRL_HWO)))
|
||||
break;
|
||||
if ((event->status & DEPEVT_STATUS_IOC) &&
|
||||
(trb->ctrl & DWC3_TRB_CTRL_IOC))
|
||||
@ -1657,65 +1767,6 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
|
||||
struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
|
||||
{
|
||||
u32 uf, mask;
|
||||
|
||||
if (list_empty(&dep->request_list)) {
|
||||
dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
|
||||
dep->name);
|
||||
return;
|
||||
}
|
||||
|
||||
mask = ~(dep->interval - 1);
|
||||
uf = event->parameters & mask;
|
||||
/* 4 micro frames in the future */
|
||||
uf += dep->interval * 4;
|
||||
|
||||
__dwc3_gadget_kick_transfer(dep, uf, 1);
|
||||
}
|
||||
|
||||
static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
struct dwc3_event_depevt mod_ev = *event;
|
||||
|
||||
/*
|
||||
* We were asked to remove one request. It is possible that this
|
||||
* request and a few others were started together and have the same
|
||||
* transfer index. Since we stopped the complete endpoint we don't
|
||||
* know how many requests were already completed (and not yet)
|
||||
* reported and how could be done (later). We purge them all until
|
||||
* the end of the list.
|
||||
*/
|
||||
mod_ev.status = DEPEVT_STATUS_LST;
|
||||
dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
|
||||
dep->flags &= ~DWC3_EP_BUSY;
|
||||
/* pending requests are ignored and are queued on XferNotReady */
|
||||
}
|
||||
|
||||
static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
u32 param = event->parameters;
|
||||
u32 cmd_type = (param >> 8) & ((1 << 5) - 1);
|
||||
|
||||
switch (cmd_type) {
|
||||
case DWC3_DEPCMD_ENDTRANSFER:
|
||||
dwc3_process_ep_cmd_complete(dep, event);
|
||||
break;
|
||||
case DWC3_DEPCMD_STARTTRANSFER:
|
||||
dep->res_trans_idx = param & 0x7f;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "%s() unknown /unexpected type: %d\n",
|
||||
__func__, cmd_type);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
@ -1724,6 +1775,9 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
||||
|
||||
dep = dwc->eps[epnum];
|
||||
|
||||
if (!(dep->flags & DWC3_EP_ENABLED))
|
||||
return;
|
||||
|
||||
dev_vdbg(dwc->dev, "%s: %s\n", dep->name,
|
||||
dwc3_ep_event_string(event->endpoint_event));
|
||||
|
||||
@ -1734,7 +1788,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
||||
|
||||
switch (event->endpoint_event) {
|
||||
case DWC3_DEPEVT_XFERCOMPLETE:
|
||||
dep->res_trans_idx = 0;
|
||||
dep->resource_index = 0;
|
||||
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
|
||||
@ -1797,7 +1851,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
||||
dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
|
||||
break;
|
||||
case DWC3_DEPEVT_EPCMDCMPLT:
|
||||
dwc3_ep_cmd_compl(dep, event);
|
||||
dev_vdbg(dwc->dev, "Endpoint Command Complete\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1820,16 +1874,16 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
|
||||
|
||||
dep = dwc->eps[epnum];
|
||||
|
||||
WARN_ON(!dep->res_trans_idx);
|
||||
if (dep->res_trans_idx) {
|
||||
cmd = DWC3_DEPCMD_ENDTRANSFER;
|
||||
cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
|
||||
cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx);
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms);
|
||||
WARN_ON_ONCE(ret);
|
||||
dep->res_trans_idx = 0;
|
||||
}
|
||||
if (!dep->resource_index)
|
||||
return;
|
||||
|
||||
cmd = DWC3_DEPCMD_ENDTRANSFER;
|
||||
cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
|
||||
cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms);
|
||||
WARN_ON_ONCE(ret);
|
||||
dep->resource_index = 0;
|
||||
}
|
||||
|
||||
static void dwc3_stop_active_transfers(struct dwc3 *dwc)
|
||||
@ -1872,11 +1926,9 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
|
||||
|
||||
static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
|
||||
{
|
||||
int reg;
|
||||
|
||||
dev_vdbg(dwc->dev, "%s\n", __func__);
|
||||
#if 0
|
||||
XXX
|
||||
U1/U2 is powersave optimization. Skip it for now. Anyway we need to
|
||||
enable it before we can disable it.
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg &= ~DWC3_DCTL_INITU1ENA;
|
||||
@ -1884,9 +1936,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
|
||||
|
||||
reg &= ~DWC3_DCTL_INITU2ENA;
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
#endif
|
||||
|
||||
dwc3_stop_active_transfers(dwc);
|
||||
dwc3_disconnect_gadget(dwc);
|
||||
dwc->start_config_issued = false;
|
||||
|
||||
@ -1894,30 +1944,30 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
|
||||
dwc->setup_packet_pending = false;
|
||||
}
|
||||
|
||||
static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
|
||||
static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
|
||||
if (on)
|
||||
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
else
|
||||
if (suspend)
|
||||
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
else
|
||||
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
|
||||
}
|
||||
|
||||
static void dwc3_gadget_usb2_phy_power(struct dwc3 *dwc, int on)
|
||||
static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
|
||||
if (on)
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
else
|
||||
if (suspend)
|
||||
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
else
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
}
|
||||
@ -1962,16 +2012,18 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
|
||||
/* after reset -> Default State */
|
||||
dwc->dev_state = DWC3_DEFAULT_STATE;
|
||||
|
||||
/* Enable PHYs */
|
||||
dwc3_gadget_usb2_phy_power(dwc, true);
|
||||
dwc3_gadget_usb3_phy_power(dwc, true);
|
||||
/* Recent versions support automatic phy suspend and don't need this */
|
||||
if (dwc->revision < DWC3_REVISION_194A) {
|
||||
/* Resume PHYs */
|
||||
dwc3_gadget_usb2_phy_suspend(dwc, false);
|
||||
dwc3_gadget_usb3_phy_suspend(dwc, false);
|
||||
}
|
||||
|
||||
if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
|
||||
dwc3_disconnect_gadget(dwc);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
|
||||
reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA);
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
dwc->test_mode = false;
|
||||
|
||||
@ -2010,16 +2062,16 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
}
|
||||
|
||||
static void dwc3_gadget_disable_phy(struct dwc3 *dwc, u8 speed)
|
||||
static void dwc3_gadget_phy_suspend(struct dwc3 *dwc, u8 speed)
|
||||
{
|
||||
switch (speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
dwc3_gadget_usb2_phy_power(dwc, false);
|
||||
dwc3_gadget_usb2_phy_suspend(dwc, true);
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
case USB_SPEED_FULL:
|
||||
case USB_SPEED_LOW:
|
||||
dwc3_gadget_usb3_phy_power(dwc, false);
|
||||
dwc3_gadget_usb3_phy_suspend(dwc, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2082,8 +2134,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Disable unneded PHY */
|
||||
dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
|
||||
/* Recent versions support automatic phy suspend and don't need this */
|
||||
if (dwc->revision < DWC3_REVISION_194A) {
|
||||
/* Suspend unneeded PHY */
|
||||
dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed);
|
||||
}
|
||||
|
||||
dep = dwc->eps[0];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
|
||||
@ -2373,10 +2428,6 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
|
||||
reg |= DWC3_DCFG_LPM_CAP;
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg |= DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA;
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
|
||||
/* Enable all but Start and End of Frame IRQs */
|
||||
reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
|
||||
DWC3_DEVTEN_EVNTOVERFLOWEN |
|
||||
@ -2389,6 +2440,24 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
|
||||
DWC3_DEVTEN_DISCONNEVTEN);
|
||||
dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
|
||||
|
||||
/* Enable USB2 LPM and automatic phy suspend only on recent versions */
|
||||
if (dwc->revision >= DWC3_REVISION_194A) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
|
||||
reg |= DWC3_DCFG_LPM_CAP;
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
|
||||
|
||||
/* TODO: This should be configurable */
|
||||
reg |= DWC3_DCTL_HIRD_THRES(28);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
|
||||
dwc3_gadget_usb2_phy_suspend(dwc, false);
|
||||
dwc3_gadget_usb3_phy_suspend(dwc, false);
|
||||
}
|
||||
|
||||
ret = device_register(&dwc->gadget.dev);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to register gadget device\n");
|
||||
|
@ -66,7 +66,12 @@ struct dwc3;
|
||||
#define DWC3_DEPCFG_FIFO_NUMBER(n) ((n) << 17)
|
||||
#define DWC3_DEPCFG_BURST_SIZE(n) ((n) << 22)
|
||||
#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26)
|
||||
/* This applies for core versions earlier than 1.94a */
|
||||
#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31)
|
||||
/* These apply for core versions 1.94a and later */
|
||||
#define DWC3_DEPCFG_ACTION_INIT (0 << 30)
|
||||
#define DWC3_DEPCFG_ACTION_RESTORE (1 << 30)
|
||||
#define DWC3_DEPCFG_ACTION_MODIFY (2 << 30)
|
||||
|
||||
/* DEPXFERCFG parameter 0 */
|
||||
#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff)
|
||||
@ -106,6 +111,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
|
||||
void dwc3_ep0_interrupt(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event);
|
||||
void dwc3_ep0_out_start(struct dwc3 *dwc);
|
||||
int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
|
||||
int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
|
||||
gfp_t gfp_flags);
|
||||
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
|
||||
|
@ -334,7 +334,7 @@ static int dbgp_control_msg(unsigned devnum, int requesttype,
|
||||
int ret;
|
||||
|
||||
read = (requesttype & USB_DIR_IN) != 0;
|
||||
if (size > (read ? DBGP_MAX_PACKET:0))
|
||||
if (size > (read ? DBGP_MAX_PACKET : 0))
|
||||
return -1;
|
||||
|
||||
/* Compute the control message */
|
||||
|
@ -321,6 +321,15 @@ config USB_MV_UDC
|
||||
USB2.0 OTG controller, which can be configured as high speed or
|
||||
full speed USB peripheral.
|
||||
|
||||
config USB_MV_U3D
|
||||
tristate "MARVELL PXA2128 USB 3.0 controller"
|
||||
depends on CPU_MMP3
|
||||
select USB_GADGET_DUALSPEED
|
||||
select USB_GADGET_SUPERSPEED
|
||||
help
|
||||
MARVELL PXA2128 Processor series include a super speed USB3.0 device
|
||||
controller, which support super speed USB peripheral.
|
||||
|
||||
#
|
||||
# Controllers available in both integrated and discrete versions
|
||||
#
|
||||
|
@ -29,6 +29,7 @@ obj-$(CONFIG_USB_EG20T) += pch_udc.o
|
||||
obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
|
||||
mv_udc-y := mv_udc_core.o
|
||||
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
|
||||
obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
|
||||
|
||||
#
|
||||
# USB gadget drivers
|
||||
|
@ -235,6 +235,7 @@ static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
|
||||
static struct usb_composite_driver acm_ms_driver = {
|
||||
.name = "g_acm_ms",
|
||||
.dev = &device_desc,
|
||||
.max_speed = USB_SPEED_SUPER,
|
||||
.strings = dev_strings,
|
||||
.unbind = __exit_p(acm_ms_unbind),
|
||||
};
|
||||
|
@ -1634,6 +1634,7 @@ static int at91_start(struct usb_gadget *gadget,
|
||||
udc = container_of(gadget, struct at91_udc, gadget);
|
||||
udc->driver = driver;
|
||||
udc->gadget.dev.driver = &driver->driver;
|
||||
udc->gadget.dev.of_node = udc->pdev->dev.of_node;
|
||||
dev_set_drvdata(&udc->gadget.dev, &driver->driver);
|
||||
udc->enabled = 1;
|
||||
udc->selfpowered = 1;
|
||||
|
@ -117,6 +117,7 @@ int config_ep_by_speed(struct usb_gadget *g,
|
||||
struct usb_function *f,
|
||||
struct usb_ep *_ep)
|
||||
{
|
||||
struct usb_composite_dev *cdev = get_gadget_data(g);
|
||||
struct usb_endpoint_descriptor *chosen_desc = NULL;
|
||||
struct usb_descriptor_header **speed_desc = NULL;
|
||||
|
||||
@ -180,10 +181,12 @@ ep_found:
|
||||
_ep->mult = comp_desc->bmAttributes & 0x3;
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
_ep->maxburst = comp_desc->bMaxBurst;
|
||||
_ep->maxburst = comp_desc->bMaxBurst + 1;
|
||||
break;
|
||||
default:
|
||||
/* Do nothing for control endpoints */
|
||||
if (comp_desc->bMaxBurst != 0)
|
||||
ERROR(cdev, "ep0 bMaxBurst must be 0\n");
|
||||
_ep->maxburst = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/hid.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/usb/composite.h>
|
||||
@ -1671,6 +1672,12 @@ static int __must_check ffs_do_desc(char *data, unsigned len,
|
||||
}
|
||||
break;
|
||||
|
||||
case HID_DT_HID:
|
||||
pr_vdebug("hid descriptor\n");
|
||||
if (length != sizeof(struct hid_descriptor))
|
||||
goto inv_length;
|
||||
break;
|
||||
|
||||
case USB_DT_OTG:
|
||||
if (length != sizeof(struct usb_otg_descriptor))
|
||||
goto inv_length;
|
||||
|
@ -26,6 +26,12 @@ static struct class *hidg_class;
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* HID gadget struct */
|
||||
|
||||
struct f_hidg_req_list {
|
||||
struct usb_request *req;
|
||||
unsigned int pos;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct f_hidg {
|
||||
/* configuration */
|
||||
unsigned char bInterfaceSubClass;
|
||||
@ -35,10 +41,10 @@ struct f_hidg {
|
||||
unsigned short report_length;
|
||||
|
||||
/* recv report */
|
||||
char *set_report_buff;
|
||||
unsigned short set_report_length;
|
||||
struct list_head completed_out_req;
|
||||
spinlock_t spinlock;
|
||||
wait_queue_head_t read_queue;
|
||||
unsigned int qlen;
|
||||
|
||||
/* send report */
|
||||
struct mutex lock;
|
||||
@ -49,7 +55,9 @@ struct f_hidg {
|
||||
int minor;
|
||||
struct cdev cdev;
|
||||
struct usb_function func;
|
||||
|
||||
struct usb_ep *in_ep;
|
||||
struct usb_ep *out_ep;
|
||||
};
|
||||
|
||||
static inline struct f_hidg *func_to_hidg(struct usb_function *f)
|
||||
@ -65,7 +73,7 @@ static struct usb_interface_descriptor hidg_interface_desc = {
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
/* .bInterfaceNumber = DYNAMIC */
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 1,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_HID,
|
||||
/* .bInterfaceSubClass = DYNAMIC */
|
||||
/* .bInterfaceProtocol = DYNAMIC */
|
||||
@ -96,10 +104,23 @@ static struct usb_endpoint_descriptor hidg_hs_in_ep_desc = {
|
||||
*/
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hidg_hs_out_ep_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
/*.wMaxPacketSize = DYNAMIC */
|
||||
.bInterval = 4, /* FIXME: Add this field in the
|
||||
* HID gadget configuration?
|
||||
* (struct hidg_func_descriptor)
|
||||
*/
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *hidg_hs_descriptors[] = {
|
||||
(struct usb_descriptor_header *)&hidg_interface_desc,
|
||||
(struct usb_descriptor_header *)&hidg_desc,
|
||||
(struct usb_descriptor_header *)&hidg_hs_in_ep_desc,
|
||||
(struct usb_descriptor_header *)&hidg_hs_out_ep_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -117,10 +138,23 @@ static struct usb_endpoint_descriptor hidg_fs_in_ep_desc = {
|
||||
*/
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor hidg_fs_out_ep_desc = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
/*.wMaxPacketSize = DYNAMIC */
|
||||
.bInterval = 10, /* FIXME: Add this field in the
|
||||
* HID gadget configuration?
|
||||
* (struct hidg_func_descriptor)
|
||||
*/
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *hidg_fs_descriptors[] = {
|
||||
(struct usb_descriptor_header *)&hidg_interface_desc,
|
||||
(struct usb_descriptor_header *)&hidg_desc,
|
||||
(struct usb_descriptor_header *)&hidg_fs_in_ep_desc,
|
||||
(struct usb_descriptor_header *)&hidg_fs_out_ep_desc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -130,9 +164,11 @@ static struct usb_descriptor_header *hidg_fs_descriptors[] = {
|
||||
static ssize_t f_hidg_read(struct file *file, char __user *buffer,
|
||||
size_t count, loff_t *ptr)
|
||||
{
|
||||
struct f_hidg *hidg = file->private_data;
|
||||
char *tmp_buff = NULL;
|
||||
unsigned long flags;
|
||||
struct f_hidg *hidg = file->private_data;
|
||||
struct f_hidg_req_list *list;
|
||||
struct usb_request *req;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
@ -142,8 +178,9 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
|
||||
|
||||
spin_lock_irqsave(&hidg->spinlock, flags);
|
||||
|
||||
#define READ_COND (hidg->set_report_buff != NULL)
|
||||
#define READ_COND (!list_empty(&hidg->completed_out_req))
|
||||
|
||||
/* wait for at least one buffer to complete */
|
||||
while (!READ_COND) {
|
||||
spin_unlock_irqrestore(&hidg->spinlock, flags);
|
||||
if (file->f_flags & O_NONBLOCK)
|
||||
@ -155,19 +192,34 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
|
||||
spin_lock_irqsave(&hidg->spinlock, flags);
|
||||
}
|
||||
|
||||
|
||||
count = min_t(unsigned, count, hidg->set_report_length);
|
||||
tmp_buff = hidg->set_report_buff;
|
||||
hidg->set_report_buff = NULL;
|
||||
|
||||
/* pick the first one */
|
||||
list = list_first_entry(&hidg->completed_out_req,
|
||||
struct f_hidg_req_list, list);
|
||||
req = list->req;
|
||||
count = min_t(unsigned int, count, req->actual - list->pos);
|
||||
spin_unlock_irqrestore(&hidg->spinlock, flags);
|
||||
|
||||
if (tmp_buff != NULL) {
|
||||
/* copy to user outside spinlock */
|
||||
count -= copy_to_user(buffer, tmp_buff, count);
|
||||
kfree(tmp_buff);
|
||||
} else
|
||||
count = -ENOMEM;
|
||||
/* copy to user outside spinlock */
|
||||
count -= copy_to_user(buffer, req->buf + list->pos, count);
|
||||
list->pos += count;
|
||||
|
||||
/*
|
||||
* if this request is completely handled and transfered to
|
||||
* userspace, remove its entry from the list and requeue it
|
||||
* again. Otherwise, we will revisit it again upon the next
|
||||
* call, taking into account its current read position.
|
||||
*/
|
||||
if (list->pos == req->actual) {
|
||||
spin_lock_irqsave(&hidg->spinlock, flags);
|
||||
list_del(&list->list);
|
||||
kfree(list);
|
||||
spin_unlock_irqrestore(&hidg->spinlock, flags);
|
||||
|
||||
req->length = hidg->report_length;
|
||||
ret = usb_ep_queue(hidg->out_ep, req, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -282,28 +334,37 @@ static int f_hidg_open(struct inode *inode, struct file *fd)
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* usb_function */
|
||||
|
||||
static struct usb_request *hidg_alloc_ep_req(struct usb_ep *ep, unsigned length)
|
||||
{
|
||||
struct usb_request *req;
|
||||
|
||||
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
|
||||
if (req) {
|
||||
req->length = length;
|
||||
req->buf = kmalloc(length, GFP_ATOMIC);
|
||||
if (!req->buf) {
|
||||
usb_ep_free_request(ep, req);
|
||||
req = NULL;
|
||||
}
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct f_hidg *hidg = (struct f_hidg *)req->context;
|
||||
struct f_hidg *hidg = (struct f_hidg *) req->context;
|
||||
struct f_hidg_req_list *req_list;
|
||||
unsigned long flags;
|
||||
|
||||
if (req->status != 0 || req->buf == NULL || req->actual == 0) {
|
||||
ERROR(hidg->func.config->cdev, "%s FAILED\n", __func__);
|
||||
req_list = kzalloc(sizeof(*req_list), GFP_ATOMIC);
|
||||
if (!req_list)
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock(&hidg->spinlock);
|
||||
req_list->req = req;
|
||||
|
||||
hidg->set_report_buff = krealloc(hidg->set_report_buff,
|
||||
req->actual, GFP_ATOMIC);
|
||||
|
||||
if (hidg->set_report_buff == NULL) {
|
||||
spin_unlock(&hidg->spinlock);
|
||||
return;
|
||||
}
|
||||
hidg->set_report_length = req->actual;
|
||||
memcpy(hidg->set_report_buff, req->buf, req->actual);
|
||||
|
||||
spin_unlock(&hidg->spinlock);
|
||||
spin_lock_irqsave(&hidg->spinlock, flags);
|
||||
list_add_tail(&req_list->list, &hidg->completed_out_req);
|
||||
spin_unlock_irqrestore(&hidg->spinlock, flags);
|
||||
|
||||
wake_up(&hidg->read_queue);
|
||||
}
|
||||
@ -344,9 +405,7 @@ static int hidg_setup(struct usb_function *f,
|
||||
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
|
||||
| HID_REQ_SET_REPORT):
|
||||
VDBG(cdev, "set_report | wLenght=%d\n", ctrl->wLength);
|
||||
req->context = hidg;
|
||||
req->complete = hidg_set_report_complete;
|
||||
goto respond;
|
||||
goto stall;
|
||||
break;
|
||||
|
||||
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
|
||||
@ -403,16 +462,25 @@ respond:
|
||||
static void hidg_disable(struct usb_function *f)
|
||||
{
|
||||
struct f_hidg *hidg = func_to_hidg(f);
|
||||
struct f_hidg_req_list *list, *next;
|
||||
|
||||
usb_ep_disable(hidg->in_ep);
|
||||
hidg->in_ep->driver_data = NULL;
|
||||
|
||||
usb_ep_disable(hidg->out_ep);
|
||||
hidg->out_ep->driver_data = NULL;
|
||||
|
||||
list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
|
||||
list_del(&list->list);
|
||||
kfree(list);
|
||||
}
|
||||
}
|
||||
|
||||
static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
{
|
||||
struct usb_composite_dev *cdev = f->config->cdev;
|
||||
struct f_hidg *hidg = func_to_hidg(f);
|
||||
int status = 0;
|
||||
int i, status = 0;
|
||||
|
||||
VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
|
||||
|
||||
@ -429,11 +497,55 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
}
|
||||
status = usb_ep_enable(hidg->in_ep);
|
||||
if (status < 0) {
|
||||
ERROR(cdev, "Enable endpoint FAILED!\n");
|
||||
ERROR(cdev, "Enable IN endpoint FAILED!\n");
|
||||
goto fail;
|
||||
}
|
||||
hidg->in_ep->driver_data = hidg;
|
||||
}
|
||||
|
||||
|
||||
if (hidg->out_ep != NULL) {
|
||||
/* restart endpoint */
|
||||
if (hidg->out_ep->driver_data != NULL)
|
||||
usb_ep_disable(hidg->out_ep);
|
||||
|
||||
status = config_ep_by_speed(f->config->cdev->gadget, f,
|
||||
hidg->out_ep);
|
||||
if (status) {
|
||||
ERROR(cdev, "config_ep_by_speed FAILED!\n");
|
||||
goto fail;
|
||||
}
|
||||
status = usb_ep_enable(hidg->out_ep);
|
||||
if (status < 0) {
|
||||
ERROR(cdev, "Enable IN endpoint FAILED!\n");
|
||||
goto fail;
|
||||
}
|
||||
hidg->out_ep->driver_data = hidg;
|
||||
|
||||
/*
|
||||
* allocate a bunch of read buffers and queue them all at once.
|
||||
*/
|
||||
for (i = 0; i < hidg->qlen && status == 0; i++) {
|
||||
struct usb_request *req =
|
||||
hidg_alloc_ep_req(hidg->out_ep,
|
||||
hidg->report_length);
|
||||
if (req) {
|
||||
req->complete = hidg_set_report_complete;
|
||||
req->context = hidg;
|
||||
status = usb_ep_queue(hidg->out_ep, req,
|
||||
GFP_ATOMIC);
|
||||
if (status)
|
||||
ERROR(cdev, "%s queue req --> %d\n",
|
||||
hidg->out_ep->name, status);
|
||||
} else {
|
||||
usb_ep_disable(hidg->out_ep);
|
||||
hidg->out_ep->driver_data = NULL;
|
||||
status = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
return status;
|
||||
}
|
||||
@ -470,13 +582,18 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
ep->driver_data = c->cdev; /* claim */
|
||||
hidg->in_ep = ep;
|
||||
|
||||
ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_out_ep_desc);
|
||||
if (!ep)
|
||||
goto fail;
|
||||
ep->driver_data = c->cdev; /* claim */
|
||||
hidg->out_ep = ep;
|
||||
|
||||
/* preallocate request and buffer */
|
||||
status = -ENOMEM;
|
||||
hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL);
|
||||
if (!hidg->req)
|
||||
goto fail;
|
||||
|
||||
|
||||
hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL);
|
||||
if (!hidg->req->buf)
|
||||
goto fail;
|
||||
@ -486,12 +603,12 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
|
||||
hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
|
||||
hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
|
||||
hidg_hs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
|
||||
hidg_fs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
|
||||
hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT;
|
||||
hidg_desc.desc[0].wDescriptorLength =
|
||||
cpu_to_le16(hidg->report_desc_length);
|
||||
|
||||
hidg->set_report_buff = NULL;
|
||||
|
||||
/* copy descriptors */
|
||||
f->descriptors = usb_copy_descriptors(hidg_fs_descriptors);
|
||||
if (!f->descriptors)
|
||||
@ -500,6 +617,8 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (gadget_is_dualspeed(c->cdev->gadget)) {
|
||||
hidg_hs_in_ep_desc.bEndpointAddress =
|
||||
hidg_fs_in_ep_desc.bEndpointAddress;
|
||||
hidg_hs_out_ep_desc.bEndpointAddress =
|
||||
hidg_fs_out_ep_desc.bEndpointAddress;
|
||||
f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
|
||||
if (!f->hs_descriptors)
|
||||
goto fail;
|
||||
@ -509,6 +628,7 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
spin_lock_init(&hidg->spinlock);
|
||||
init_waitqueue_head(&hidg->write_queue);
|
||||
init_waitqueue_head(&hidg->read_queue);
|
||||
INIT_LIST_HEAD(&hidg->completed_out_req);
|
||||
|
||||
/* create char device */
|
||||
cdev_init(&hidg->cdev, &f_hidg_fops);
|
||||
@ -553,7 +673,6 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
usb_free_descriptors(f->descriptors);
|
||||
|
||||
kfree(hidg->report_desc);
|
||||
kfree(hidg->set_report_buff);
|
||||
kfree(hidg);
|
||||
}
|
||||
|
||||
@ -624,6 +743,9 @@ int __init hidg_bind_config(struct usb_configuration *c,
|
||||
hidg->func.disable = hidg_disable;
|
||||
hidg->func.setup = hidg_setup;
|
||||
|
||||
/* this could me made configurable at some point */
|
||||
hidg->qlen = 4;
|
||||
|
||||
status = usb_add_function(c, &hidg->func);
|
||||
if (status)
|
||||
kfree(hidg);
|
||||
|
@ -44,12 +44,12 @@
|
||||
* function for a USB device, it also illustrates a technique of
|
||||
* double-buffering for increased throughput.
|
||||
*
|
||||
* Function supports multiple logical units (LUNs). Backing storage
|
||||
* for each LUN is provided by a regular file or a block device.
|
||||
* Access for each LUN can be limited to read-only. Moreover, the
|
||||
* function can indicate that LUN is removable and/or CD-ROM. (The
|
||||
* later implies read-only access.)
|
||||
*
|
||||
* For more information about MSF and in particular its module
|
||||
* parameters and sysfs interface read the
|
||||
* <Documentation/usb/mass-storage.txt> file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MSF is configured by specifying a fsg_config structure. It has the
|
||||
* following fields:
|
||||
*
|
||||
@ -75,25 +75,6 @@
|
||||
* ->nofua Flag specifying that FUA flag in SCSI WRITE(10,12)
|
||||
* commands for this LUN shall be ignored.
|
||||
*
|
||||
* lun_name_format A printf-like format for names of the LUN
|
||||
* devices. This determines how the
|
||||
* directory in sysfs will be named.
|
||||
* Unless you are using several MSFs in
|
||||
* a single gadget (as opposed to single
|
||||
* MSF in many configurations) you may
|
||||
* leave it as NULL (in which case
|
||||
* "lun%d" will be used). In the format
|
||||
* you can use "%d" to index LUNs for
|
||||
* MSF's with more than one LUN. (Beware
|
||||
* that there is only one integer given
|
||||
* as an argument for the format and
|
||||
* specifying invalid format may cause
|
||||
* unspecified behaviour.)
|
||||
* thread_name Name of the kernel thread process used by the
|
||||
* MSF. You can safely set it to NULL
|
||||
* (in which case default "file-storage"
|
||||
* will be used).
|
||||
*
|
||||
* vendor_name
|
||||
* product_name
|
||||
* release Information used as a reply to INQUIRY
|
||||
@ -114,62 +95,6 @@
|
||||
* data track and no audio tracks; hence there need be only one
|
||||
* backing file per LUN.
|
||||
*
|
||||
*
|
||||
* MSF includes support for module parameters. If gadget using it
|
||||
* decides to use it, the following module parameters will be
|
||||
* available:
|
||||
*
|
||||
* file=filename[,filename...]
|
||||
* Names of the files or block devices used for
|
||||
* backing storage.
|
||||
* ro=b[,b...] Default false, boolean for read-only access.
|
||||
* removable=b[,b...]
|
||||
* Default true, boolean for removable media.
|
||||
* cdrom=b[,b...] Default false, boolean for whether to emulate
|
||||
* a CD-ROM drive.
|
||||
* nofua=b[,b...] Default false, booleans for ignore FUA flag
|
||||
* in SCSI WRITE(10,12) commands
|
||||
* luns=N Default N = number of filenames, number of
|
||||
* LUNs to support.
|
||||
* stall Default determined according to the type of
|
||||
* USB device controller (usually true),
|
||||
* boolean to permit the driver to halt
|
||||
* bulk endpoints.
|
||||
*
|
||||
* The module parameters may be prefixed with some string. You need
|
||||
* to consult gadget's documentation or source to verify whether it is
|
||||
* using those module parameters and if it does what are the prefixes
|
||||
* (look for FSG_MODULE_PARAMETERS() macro usage, what's inside it is
|
||||
* the prefix).
|
||||
*
|
||||
*
|
||||
* Requirements are modest; only a bulk-in and a bulk-out endpoint are
|
||||
* needed. The memory requirement amounts to two 16K buffers, size
|
||||
* configurable by a parameter. Support is included for both
|
||||
* full-speed and high-speed operation.
|
||||
*
|
||||
* Note that the driver is slightly non-portable in that it assumes a
|
||||
* single memory/DMA buffer will be useable for bulk-in, bulk-out, and
|
||||
* interrupt-in endpoints. With most device controllers this isn't an
|
||||
* issue, but there may be some with hardware restrictions that prevent
|
||||
* a buffer from being used by more than one endpoint.
|
||||
*
|
||||
*
|
||||
* The pathnames of the backing files and the ro settings are
|
||||
* available in the attribute files "file" and "ro" in the lun<n> (or
|
||||
* to be more precise in a directory which name comes from
|
||||
* "lun_name_format" option!) subdirectory of the gadget's sysfs
|
||||
* directory. If the "removable" option is set, writing to these
|
||||
* files will simulate ejecting/loading the medium (writing an empty
|
||||
* line means eject) and adjusting a write-enable tab. Changes to the
|
||||
* ro setting are not allowed when the medium is loaded or if CD-ROM
|
||||
* emulation is being used.
|
||||
*
|
||||
* When a LUN receive an "eject" SCSI request (Start/Stop Unit),
|
||||
* if the LUN is removable, the backing file is released to simulate
|
||||
* ejection.
|
||||
*
|
||||
*
|
||||
* This function is heavily based on "File-backed Storage Gadget" by
|
||||
* Alan Stern which in turn is heavily based on "Gadget Zero" by David
|
||||
* Brownell. The driver's SCSI command interface was based on the
|
||||
@ -211,7 +136,7 @@
|
||||
* In normal operation the main thread is started during the gadget's
|
||||
* fsg_bind() callback and stopped during fsg_unbind(). But it can
|
||||
* also exit when it receives a signal, and there's no point leaving
|
||||
* the gadget running when the thread is dead. At of this moment, MSF
|
||||
* the gadget running when the thread is dead. As of this moment, MSF
|
||||
* provides no way to deregister the gadget when thread dies -- maybe
|
||||
* a callback functions is needed.
|
||||
*
|
||||
@ -417,9 +342,6 @@ struct fsg_config {
|
||||
char nofua;
|
||||
} luns[FSG_MAX_LUNS];
|
||||
|
||||
const char *lun_name_format;
|
||||
const char *thread_name;
|
||||
|
||||
/* Callback functions. */
|
||||
const struct fsg_operations *ops;
|
||||
/* Gadget's private data. */
|
||||
@ -2687,11 +2609,15 @@ static int fsg_main_thread(void *common_)
|
||||
|
||||
/*************************** DEVICE ATTRIBUTES ***************************/
|
||||
|
||||
/* Write permission is checked per LUN in store_*() functions. */
|
||||
static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
|
||||
static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua);
|
||||
static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
|
||||
|
||||
static struct device_attribute dev_attr_ro_cdrom =
|
||||
__ATTR(ro, 0444, fsg_show_ro, NULL);
|
||||
static struct device_attribute dev_attr_file_nonremovable =
|
||||
__ATTR(file, 0444, fsg_show_file, NULL);
|
||||
|
||||
|
||||
/****************************** FSG COMMON ******************************/
|
||||
|
||||
@ -2792,11 +2718,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
||||
curlun->dev.parent = &gadget->dev;
|
||||
/* curlun->dev.driver = &fsg_driver.driver; XXX */
|
||||
dev_set_drvdata(&curlun->dev, &common->filesem);
|
||||
dev_set_name(&curlun->dev,
|
||||
cfg->lun_name_format
|
||||
? cfg->lun_name_format
|
||||
: "lun%d",
|
||||
i);
|
||||
dev_set_name(&curlun->dev, "lun%d", i);
|
||||
|
||||
rc = device_register(&curlun->dev);
|
||||
if (rc) {
|
||||
@ -2806,10 +2728,16 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
||||
goto error_release;
|
||||
}
|
||||
|
||||
rc = device_create_file(&curlun->dev, &dev_attr_ro);
|
||||
rc = device_create_file(&curlun->dev,
|
||||
curlun->cdrom
|
||||
? &dev_attr_ro_cdrom
|
||||
: &dev_attr_ro);
|
||||
if (rc)
|
||||
goto error_luns;
|
||||
rc = device_create_file(&curlun->dev, &dev_attr_file);
|
||||
rc = device_create_file(&curlun->dev,
|
||||
curlun->removable
|
||||
? &dev_attr_file
|
||||
: &dev_attr_file_nonremovable);
|
||||
if (rc)
|
||||
goto error_luns;
|
||||
rc = device_create_file(&curlun->dev, &dev_attr_nofua);
|
||||
@ -2878,8 +2806,7 @@ buffhds_first_it:
|
||||
|
||||
/* Tell the thread to start working */
|
||||
common->thread_task =
|
||||
kthread_create(fsg_main_thread, common,
|
||||
cfg->thread_name ?: "file-storage");
|
||||
kthread_create(fsg_main_thread, common, "file-storage");
|
||||
if (IS_ERR(common->thread_task)) {
|
||||
rc = PTR_ERR(common->thread_task);
|
||||
goto error_release;
|
||||
@ -2945,8 +2872,14 @@ static void fsg_common_release(struct kref *ref)
|
||||
/* In error recovery common->nluns may be zero. */
|
||||
for (; i; --i, ++lun) {
|
||||
device_remove_file(&lun->dev, &dev_attr_nofua);
|
||||
device_remove_file(&lun->dev, &dev_attr_ro);
|
||||
device_remove_file(&lun->dev, &dev_attr_file);
|
||||
device_remove_file(&lun->dev,
|
||||
lun->cdrom
|
||||
? &dev_attr_ro_cdrom
|
||||
: &dev_attr_ro);
|
||||
device_remove_file(&lun->dev,
|
||||
lun->removable
|
||||
? &dev_attr_file
|
||||
: &dev_attr_file_nonremovable);
|
||||
fsg_lun_close(lun);
|
||||
device_unregister(&lun->dev);
|
||||
}
|
||||
@ -3167,8 +3100,7 @@ fsg_config_from_params(struct fsg_config *cfg,
|
||||
for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) {
|
||||
lun->ro = !!params->ro[i];
|
||||
lun->cdrom = !!params->cdrom[i];
|
||||
lun->removable = /* Removable by default */
|
||||
params->removable_count <= i || params->removable[i];
|
||||
lun->removable = !!params->removable[i];
|
||||
lun->filename =
|
||||
params->file_count > i && params->file[i][0]
|
||||
? params->file[i]
|
||||
@ -3176,8 +3108,6 @@ fsg_config_from_params(struct fsg_config *cfg,
|
||||
}
|
||||
|
||||
/* Let MSF use defaults */
|
||||
cfg->lun_name_format = 0;
|
||||
cfg->thread_name = 0;
|
||||
cfg->vendor_name = 0;
|
||||
cfg->product_name = 0;
|
||||
cfg->release = 0xffff;
|
||||
@ -3203,4 +3133,3 @@ fsg_common_from_params(struct fsg_common *common,
|
||||
fsg_config_from_params(&cfg, params);
|
||||
return fsg_common_init(common, cdev, &cfg);
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,25 @@
|
||||
|
||||
unsigned int uvc_gadget_trace_param;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* module parameters specific to the Video streaming endpoint */
|
||||
static unsigned streaming_interval = 1;
|
||||
module_param(streaming_interval, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(streaming_interval, "1 - 16");
|
||||
|
||||
static unsigned streaming_maxpacket = 1024;
|
||||
module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(streaming_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
|
||||
|
||||
static unsigned streaming_mult;
|
||||
module_param(streaming_mult, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(streaming_mult, "0 - 2 (hs/ss only)");
|
||||
|
||||
static unsigned streaming_maxburst;
|
||||
module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Function descriptors
|
||||
*/
|
||||
@ -59,6 +78,8 @@ static struct usb_gadget_strings *uvc_function_strings[] = {
|
||||
#define UVC_INTF_VIDEO_CONTROL 0
|
||||
#define UVC_INTF_VIDEO_STREAMING 1
|
||||
|
||||
#define STATUS_BYTECOUNT 16 /* 16 bytes status */
|
||||
|
||||
static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
|
||||
.bLength = sizeof(uvc_iad),
|
||||
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
||||
@ -82,12 +103,12 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = {
|
||||
.iInterface = 0,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor uvc_control_ep __initdata = {
|
||||
static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(16),
|
||||
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.bInterval = 8,
|
||||
};
|
||||
|
||||
@ -95,7 +116,7 @@ static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = {
|
||||
.bLength = UVC_DT_CONTROL_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_CS_ENDPOINT,
|
||||
.bDescriptorSubType = UVC_EP_INTERRUPT,
|
||||
.wMaxTransferSize = cpu_to_le16(16),
|
||||
.wMaxTransferSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
};
|
||||
|
||||
static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = {
|
||||
@ -122,7 +143,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = {
|
||||
.iInterface = 0,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor uvc_streaming_ep = {
|
||||
static struct usb_endpoint_descriptor uvc_fs_streaming_ep = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
@ -131,15 +152,72 @@ static struct usb_endpoint_descriptor uvc_streaming_ep = {
|
||||
.bInterval = 1,
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor uvc_hs_streaming_ep = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
.bInterval = 1,
|
||||
};
|
||||
|
||||
/* super speed support */
|
||||
static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
.bInterval = 8,
|
||||
};
|
||||
|
||||
static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = {
|
||||
.bLength = sizeof uvc_ss_control_comp,
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
|
||||
/* the following 3 values can be tweaked if necessary */
|
||||
/* .bMaxBurst = 0, */
|
||||
/* .bmAttributes = 0, */
|
||||
.wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT),
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
|
||||
.bEndpointAddress = USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
.bInterval = 4,
|
||||
};
|
||||
|
||||
static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = {
|
||||
.bLength = sizeof uvc_ss_streaming_comp,
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
|
||||
/* the following 3 values can be tweaked if necessary */
|
||||
.bMaxBurst = 0,
|
||||
.bmAttributes = 0,
|
||||
.wBytesPerInterval = cpu_to_le16(1024),
|
||||
};
|
||||
|
||||
static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
|
||||
(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
|
||||
(struct usb_descriptor_header *) &uvc_streaming_ep,
|
||||
(struct usb_descriptor_header *) &uvc_fs_streaming_ep,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct usb_descriptor_header * const uvc_hs_streaming[] = {
|
||||
(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
|
||||
(struct usb_descriptor_header *) &uvc_streaming_ep,
|
||||
(struct usb_descriptor_header *) &uvc_hs_streaming_ep,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct usb_descriptor_header * const uvc_ss_streaming[] = {
|
||||
(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
|
||||
(struct usb_descriptor_header *) &uvc_ss_streaming_ep,
|
||||
(struct usb_descriptor_header *) &uvc_ss_streaming_comp,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -215,6 +293,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
|
||||
struct uvc_device *uvc = to_uvc(f);
|
||||
struct v4l2_event v4l2_event;
|
||||
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
|
||||
int ret;
|
||||
|
||||
INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
|
||||
|
||||
@ -262,7 +341,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
|
||||
return 0;
|
||||
|
||||
if (uvc->video.ep) {
|
||||
uvc->video.ep->desc = &uvc_streaming_ep;
|
||||
ret = config_ep_by_speed(f->config->cdev->gadget,
|
||||
&(uvc->func), uvc->video.ep);
|
||||
if (ret)
|
||||
return ret;
|
||||
usb_ep_enable(uvc->video.ep);
|
||||
}
|
||||
|
||||
@ -368,9 +450,11 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
||||
{
|
||||
struct uvc_input_header_descriptor *uvc_streaming_header;
|
||||
struct uvc_header_descriptor *uvc_control_header;
|
||||
const struct uvc_descriptor_header * const *uvc_control_desc;
|
||||
const struct uvc_descriptor_header * const *uvc_streaming_cls;
|
||||
const struct usb_descriptor_header * const *uvc_streaming_std;
|
||||
const struct usb_descriptor_header * const *src;
|
||||
static struct usb_endpoint_descriptor *uvc_control_ep;
|
||||
struct usb_descriptor_header **dst;
|
||||
struct usb_descriptor_header **hdr;
|
||||
unsigned int control_size;
|
||||
@ -379,10 +463,29 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
||||
unsigned int bytes;
|
||||
void *mem;
|
||||
|
||||
uvc_streaming_cls = (speed == USB_SPEED_FULL)
|
||||
? uvc->desc.fs_streaming : uvc->desc.hs_streaming;
|
||||
uvc_streaming_std = (speed == USB_SPEED_FULL)
|
||||
? uvc_fs_streaming : uvc_hs_streaming;
|
||||
switch (speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
uvc_control_desc = uvc->desc.ss_control;
|
||||
uvc_streaming_cls = uvc->desc.ss_streaming;
|
||||
uvc_streaming_std = uvc_ss_streaming;
|
||||
uvc_control_ep = &uvc_ss_control_ep;
|
||||
break;
|
||||
|
||||
case USB_SPEED_HIGH:
|
||||
uvc_control_desc = uvc->desc.fs_control;
|
||||
uvc_streaming_cls = uvc->desc.hs_streaming;
|
||||
uvc_streaming_std = uvc_hs_streaming;
|
||||
uvc_control_ep = &uvc_fs_control_ep;
|
||||
break;
|
||||
|
||||
case USB_SPEED_FULL:
|
||||
default:
|
||||
uvc_control_desc = uvc->desc.fs_control;
|
||||
uvc_streaming_cls = uvc->desc.fs_streaming;
|
||||
uvc_streaming_std = uvc_fs_streaming;
|
||||
uvc_control_ep = &uvc_fs_control_ep;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Descriptors layout
|
||||
*
|
||||
@ -400,16 +503,24 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
||||
control_size = 0;
|
||||
streaming_size = 0;
|
||||
bytes = uvc_iad.bLength + uvc_control_intf.bLength
|
||||
+ uvc_control_ep.bLength + uvc_control_cs_ep.bLength
|
||||
+ uvc_control_ep->bLength + uvc_control_cs_ep.bLength
|
||||
+ uvc_streaming_intf_alt0.bLength;
|
||||
n_desc = 5;
|
||||
|
||||
for (src = (const struct usb_descriptor_header**)uvc->desc.control; *src; ++src) {
|
||||
if (speed == USB_SPEED_SUPER) {
|
||||
bytes += uvc_ss_control_comp.bLength;
|
||||
n_desc = 6;
|
||||
} else {
|
||||
n_desc = 5;
|
||||
}
|
||||
|
||||
for (src = (const struct usb_descriptor_header **)uvc_control_desc;
|
||||
*src; ++src) {
|
||||
control_size += (*src)->bLength;
|
||||
bytes += (*src)->bLength;
|
||||
n_desc++;
|
||||
}
|
||||
for (src = (const struct usb_descriptor_header**)uvc_streaming_cls; *src; ++src) {
|
||||
for (src = (const struct usb_descriptor_header **)uvc_streaming_cls;
|
||||
*src; ++src) {
|
||||
streaming_size += (*src)->bLength;
|
||||
bytes += (*src)->bLength;
|
||||
n_desc++;
|
||||
@ -433,12 +544,15 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
||||
|
||||
uvc_control_header = mem;
|
||||
UVC_COPY_DESCRIPTORS(mem, dst,
|
||||
(const struct usb_descriptor_header**)uvc->desc.control);
|
||||
(const struct usb_descriptor_header **)uvc_control_desc);
|
||||
uvc_control_header->wTotalLength = cpu_to_le16(control_size);
|
||||
uvc_control_header->bInCollection = 1;
|
||||
uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
|
||||
|
||||
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
|
||||
UVC_COPY_DESCRIPTOR(mem, dst, uvc_control_ep);
|
||||
if (speed == USB_SPEED_SUPER)
|
||||
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp);
|
||||
|
||||
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep);
|
||||
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0);
|
||||
|
||||
@ -446,7 +560,8 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
|
||||
UVC_COPY_DESCRIPTORS(mem, dst,
|
||||
(const struct usb_descriptor_header**)uvc_streaming_cls);
|
||||
uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
|
||||
uvc_streaming_header->bEndpointAddress = uvc_streaming_ep.bEndpointAddress;
|
||||
uvc_streaming_header->bEndpointAddress =
|
||||
uvc_fs_streaming_ep.bEndpointAddress;
|
||||
|
||||
UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
|
||||
|
||||
@ -482,6 +597,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
kfree(f->descriptors);
|
||||
kfree(f->hs_descriptors);
|
||||
kfree(f->ss_descriptors);
|
||||
|
||||
kfree(uvc);
|
||||
}
|
||||
@ -496,8 +612,26 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
INFO(cdev, "uvc_function_bind\n");
|
||||
|
||||
/* sanity check the streaming endpoint module parameters */
|
||||
if (streaming_interval < 1)
|
||||
streaming_interval = 1;
|
||||
if (streaming_interval > 16)
|
||||
streaming_interval = 16;
|
||||
if (streaming_mult > 2)
|
||||
streaming_mult = 2;
|
||||
if (streaming_maxburst > 15)
|
||||
streaming_maxburst = 15;
|
||||
|
||||
/*
|
||||
* fill in the FS video streaming specific descriptors from the
|
||||
* module parameters
|
||||
*/
|
||||
uvc_fs_streaming_ep.wMaxPacketSize = streaming_maxpacket > 1023 ?
|
||||
1023 : streaming_maxpacket;
|
||||
uvc_fs_streaming_ep.bInterval = streaming_interval;
|
||||
|
||||
/* Allocate endpoints. */
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_control_ep);
|
||||
if (!ep) {
|
||||
INFO(cdev, "Unable to allocate control EP\n");
|
||||
goto error;
|
||||
@ -505,7 +639,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
uvc->control_ep = ep;
|
||||
ep->driver_data = uvc;
|
||||
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_streaming_ep);
|
||||
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
|
||||
if (!ep) {
|
||||
INFO(cdev, "Unable to allocate streaming EP\n");
|
||||
goto error;
|
||||
@ -526,9 +660,52 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
uvc_streaming_intf_alt1.bInterfaceNumber = ret;
|
||||
uvc->streaming_intf = ret;
|
||||
|
||||
/* Copy descriptors. */
|
||||
/* sanity check the streaming endpoint module parameters */
|
||||
if (streaming_maxpacket > 1024)
|
||||
streaming_maxpacket = 1024;
|
||||
|
||||
/* Copy descriptors for FS. */
|
||||
f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
|
||||
f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
|
||||
|
||||
/* support high speed hardware */
|
||||
if (gadget_is_dualspeed(cdev->gadget)) {
|
||||
/*
|
||||
* Fill in the HS descriptors from the module parameters for the
|
||||
* Video Streaming endpoint.
|
||||
* NOTE: We assume that the user knows what they are doing and
|
||||
* won't give parameters that their UDC doesn't support.
|
||||
*/
|
||||
uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket;
|
||||
uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11;
|
||||
uvc_hs_streaming_ep.bInterval = streaming_interval;
|
||||
uvc_hs_streaming_ep.bEndpointAddress =
|
||||
uvc_fs_streaming_ep.bEndpointAddress;
|
||||
|
||||
/* Copy descriptors. */
|
||||
f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
|
||||
}
|
||||
|
||||
/* support super speed hardware */
|
||||
if (gadget_is_superspeed(c->cdev->gadget)) {
|
||||
/*
|
||||
* Fill in the SS descriptors from the module parameters for the
|
||||
* Video Streaming endpoint.
|
||||
* NOTE: We assume that the user knows what they are doing and
|
||||
* won't give parameters that their UDC doesn't support.
|
||||
*/
|
||||
uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket;
|
||||
uvc_ss_streaming_ep.bInterval = streaming_interval;
|
||||
uvc_ss_streaming_comp.bmAttributes = streaming_mult;
|
||||
uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
|
||||
uvc_ss_streaming_comp.wBytesPerInterval =
|
||||
streaming_maxpacket * (streaming_mult + 1) *
|
||||
(streaming_maxburst + 1);
|
||||
uvc_ss_streaming_ep.bEndpointAddress =
|
||||
uvc_fs_streaming_ep.bEndpointAddress;
|
||||
|
||||
/* Copy descriptors. */
|
||||
f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
|
||||
}
|
||||
|
||||
/* Preallocate control endpoint request. */
|
||||
uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
|
||||
@ -583,9 +760,11 @@ error:
|
||||
*/
|
||||
int __init
|
||||
uvc_bind_config(struct usb_configuration *c,
|
||||
const struct uvc_descriptor_header * const *control,
|
||||
const struct uvc_descriptor_header * const *fs_control,
|
||||
const struct uvc_descriptor_header * const *ss_control,
|
||||
const struct uvc_descriptor_header * const *fs_streaming,
|
||||
const struct uvc_descriptor_header * const *hs_streaming)
|
||||
const struct uvc_descriptor_header * const *hs_streaming,
|
||||
const struct uvc_descriptor_header * const *ss_streaming)
|
||||
{
|
||||
struct uvc_device *uvc;
|
||||
int ret = 0;
|
||||
@ -603,38 +782,54 @@ uvc_bind_config(struct usb_configuration *c,
|
||||
uvc->state = UVC_STATE_DISCONNECTED;
|
||||
|
||||
/* Validate the descriptors. */
|
||||
if (control == NULL || control[0] == NULL ||
|
||||
control[0]->bDescriptorSubType != UVC_VC_HEADER)
|
||||
if (fs_control == NULL || fs_control[0] == NULL ||
|
||||
fs_control[0]->bDescriptorSubType != UVC_VC_HEADER)
|
||||
goto error;
|
||||
|
||||
if (ss_control == NULL || ss_control[0] == NULL ||
|
||||
ss_control[0]->bDescriptorSubType != UVC_VC_HEADER)
|
||||
goto error;
|
||||
|
||||
if (fs_streaming == NULL || fs_streaming[0] == NULL ||
|
||||
fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
|
||||
fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
|
||||
goto error;
|
||||
|
||||
if (hs_streaming == NULL || hs_streaming[0] == NULL ||
|
||||
hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
|
||||
hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
|
||||
goto error;
|
||||
|
||||
uvc->desc.control = control;
|
||||
if (ss_streaming == NULL || ss_streaming[0] == NULL ||
|
||||
ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
|
||||
goto error;
|
||||
|
||||
uvc->desc.fs_control = fs_control;
|
||||
uvc->desc.ss_control = ss_control;
|
||||
uvc->desc.fs_streaming = fs_streaming;
|
||||
uvc->desc.hs_streaming = hs_streaming;
|
||||
uvc->desc.ss_streaming = ss_streaming;
|
||||
|
||||
/* Allocate string descriptor numbers. */
|
||||
if ((ret = usb_string_id(c->cdev)) < 0)
|
||||
goto error;
|
||||
uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret;
|
||||
uvc_iad.iFunction = ret;
|
||||
/* maybe allocate device-global string IDs, and patch descriptors */
|
||||
if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) {
|
||||
/* Allocate string descriptor numbers. */
|
||||
ret = usb_string_id(c->cdev);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret;
|
||||
uvc_iad.iFunction = ret;
|
||||
|
||||
if ((ret = usb_string_id(c->cdev)) < 0)
|
||||
goto error;
|
||||
uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret;
|
||||
uvc_control_intf.iInterface = ret;
|
||||
ret = usb_string_id(c->cdev);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret;
|
||||
uvc_control_intf.iInterface = ret;
|
||||
|
||||
if ((ret = usb_string_id(c->cdev)) < 0)
|
||||
goto error;
|
||||
uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret;
|
||||
uvc_streaming_intf_alt0.iInterface = ret;
|
||||
uvc_streaming_intf_alt1.iInterface = ret;
|
||||
ret = usb_string_id(c->cdev);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret;
|
||||
uvc_streaming_intf_alt0.iInterface = ret;
|
||||
uvc_streaming_intf_alt1.iInterface = ret;
|
||||
}
|
||||
|
||||
/* Register the function. */
|
||||
uvc->func.name = "uvc";
|
||||
|
@ -17,9 +17,11 @@
|
||||
#include <linux/usb/video.h>
|
||||
|
||||
extern int uvc_bind_config(struct usb_configuration *c,
|
||||
const struct uvc_descriptor_header * const *control,
|
||||
const struct uvc_descriptor_header * const *fs_streaming,
|
||||
const struct uvc_descriptor_header * const *hs_streaming);
|
||||
const struct uvc_descriptor_header * const *fs_control,
|
||||
const struct uvc_descriptor_header * const *hs_control,
|
||||
const struct uvc_descriptor_header * const *fs_streaming,
|
||||
const struct uvc_descriptor_header * const *hs_streaming,
|
||||
const struct uvc_descriptor_header * const *ss_streaming);
|
||||
|
||||
#endif /* _F_UVC_H_ */
|
||||
|
||||
|
@ -21,7 +21,8 @@
|
||||
#include <mach/hardware.h>
|
||||
|
||||
static struct clk *mxc_ahb_clk;
|
||||
static struct clk *mxc_usb_clk;
|
||||
static struct clk *mxc_per_clk;
|
||||
static struct clk *mxc_ipg_clk;
|
||||
|
||||
/* workaround ENGcm09152 for i.MX35 */
|
||||
#define USBPHYCTRL_OTGBASE_OFFSET 0x608
|
||||
@ -35,28 +36,31 @@ int fsl_udc_clk_init(struct platform_device *pdev)
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
|
||||
if (!cpu_is_mx35() && !cpu_is_mx25()) {
|
||||
mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb");
|
||||
if (IS_ERR(mxc_ahb_clk))
|
||||
return PTR_ERR(mxc_ahb_clk);
|
||||
|
||||
ret = clk_enable(mxc_ahb_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "clk_enable(\"usb_ahb\") failed\n");
|
||||
goto eenahb;
|
||||
}
|
||||
mxc_ipg_clk = devm_clk_get(&pdev->dev, "ipg");
|
||||
if (IS_ERR(mxc_ipg_clk)) {
|
||||
dev_err(&pdev->dev, "clk_get(\"ipg\") failed\n");
|
||||
return PTR_ERR(mxc_ipg_clk);
|
||||
}
|
||||
|
||||
mxc_ahb_clk = devm_clk_get(&pdev->dev, "ahb");
|
||||
if (IS_ERR(mxc_ahb_clk)) {
|
||||
dev_err(&pdev->dev, "clk_get(\"ahb\") failed\n");
|
||||
return PTR_ERR(mxc_ahb_clk);
|
||||
}
|
||||
|
||||
mxc_per_clk = devm_clk_get(&pdev->dev, "per");
|
||||
if (IS_ERR(mxc_per_clk)) {
|
||||
dev_err(&pdev->dev, "clk_get(\"per\") failed\n");
|
||||
return PTR_ERR(mxc_per_clk);
|
||||
}
|
||||
|
||||
clk_prepare_enable(mxc_ipg_clk);
|
||||
clk_prepare_enable(mxc_ahb_clk);
|
||||
clk_prepare_enable(mxc_per_clk);
|
||||
|
||||
/* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */
|
||||
mxc_usb_clk = clk_get(&pdev->dev, "usb");
|
||||
if (IS_ERR(mxc_usb_clk)) {
|
||||
dev_err(&pdev->dev, "clk_get(\"usb\") failed\n");
|
||||
ret = PTR_ERR(mxc_usb_clk);
|
||||
goto egusb;
|
||||
}
|
||||
|
||||
if (!cpu_is_mx51()) {
|
||||
freq = clk_get_rate(mxc_usb_clk);
|
||||
freq = clk_get_rate(mxc_per_clk);
|
||||
if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
|
||||
(freq < 59999000 || freq > 60001000)) {
|
||||
dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
|
||||
@ -65,24 +69,13 @@ int fsl_udc_clk_init(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_enable(mxc_usb_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "clk_enable(\"usb_clk\") failed\n");
|
||||
goto eenusb;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
eenusb:
|
||||
eclkrate:
|
||||
clk_put(mxc_usb_clk);
|
||||
mxc_usb_clk = NULL;
|
||||
egusb:
|
||||
if (!cpu_is_mx35())
|
||||
clk_disable(mxc_ahb_clk);
|
||||
eenahb:
|
||||
if (!cpu_is_mx35())
|
||||
clk_put(mxc_ahb_clk);
|
||||
clk_disable_unprepare(mxc_ipg_clk);
|
||||
clk_disable_unprepare(mxc_ahb_clk);
|
||||
clk_disable_unprepare(mxc_per_clk);
|
||||
mxc_per_clk = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -104,20 +97,15 @@ void fsl_udc_clk_finalize(struct platform_device *pdev)
|
||||
|
||||
/* ULPI transceivers don't need usbpll */
|
||||
if (pdata->phy_mode == FSL_USB2_PHY_ULPI) {
|
||||
clk_disable(mxc_usb_clk);
|
||||
clk_put(mxc_usb_clk);
|
||||
mxc_usb_clk = NULL;
|
||||
clk_disable_unprepare(mxc_per_clk);
|
||||
mxc_per_clk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void fsl_udc_clk_release(void)
|
||||
{
|
||||
if (mxc_usb_clk) {
|
||||
clk_disable(mxc_usb_clk);
|
||||
clk_put(mxc_usb_clk);
|
||||
}
|
||||
if (!cpu_is_mx35()) {
|
||||
clk_disable(mxc_ahb_clk);
|
||||
clk_put(mxc_ahb_clk);
|
||||
}
|
||||
if (mxc_per_clk)
|
||||
clk_disable_unprepare(mxc_per_clk);
|
||||
clk_disable_unprepare(mxc_ahb_clk);
|
||||
clk_disable_unprepare(mxc_ipg_clk);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
@ -1229,7 +1230,7 @@ static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
|
||||
struct fsl_udc *udc;
|
||||
|
||||
udc = container_of(gadget, struct fsl_udc, gadget);
|
||||
if (udc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
return usb_phy_set_power(udc->transceiver, mA);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
@ -1983,13 +1984,13 @@ static int fsl_start(struct usb_gadget_driver *driver,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (udc_controller->transceiver) {
|
||||
if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
|
||||
/* Suspend the controller until OTG enable it */
|
||||
udc_controller->stopped = 1;
|
||||
printk(KERN_INFO "Suspend udc for OTG auto detect\n");
|
||||
|
||||
/* connect to bus through transceiver */
|
||||
if (udc_controller->transceiver) {
|
||||
if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
|
||||
retval = otg_set_peripheral(
|
||||
udc_controller->transceiver->otg,
|
||||
&udc_controller->gadget);
|
||||
@ -2030,7 +2031,7 @@ static int fsl_stop(struct usb_gadget_driver *driver)
|
||||
if (!driver || driver != udc_controller->driver || !driver->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
if (udc_controller->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc_controller->transceiver))
|
||||
otg_set_peripheral(udc_controller->transceiver->otg, NULL);
|
||||
|
||||
/* stop DR, disable intr */
|
||||
@ -2455,8 +2456,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
||||
|
||||
#ifdef CONFIG_USB_OTG
|
||||
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
|
||||
udc_controller->transceiver = usb_get_transceiver();
|
||||
if (!udc_controller->transceiver) {
|
||||
udc_controller->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR_OR_NULL(udc_controller->transceiver)) {
|
||||
ERR("Can't find OTG driver!\n");
|
||||
ret = -ENODEV;
|
||||
goto err_kfree;
|
||||
@ -2540,7 +2541,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
if (!udc_controller->transceiver) {
|
||||
if (IS_ERR_OR_NULL(udc_controller->transceiver)) {
|
||||
/* initialize usb hw reg except for regs for EP,
|
||||
* leave usbintr reg untouched */
|
||||
dr_controller_setup(udc_controller);
|
||||
@ -2560,11 +2561,12 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
||||
dev_set_name(&udc_controller->gadget.dev, "gadget");
|
||||
udc_controller->gadget.dev.release = fsl_udc_release;
|
||||
udc_controller->gadget.dev.parent = &pdev->dev;
|
||||
udc_controller->gadget.dev.of_node = pdev->dev.of_node;
|
||||
ret = device_register(&udc_controller->gadget.dev);
|
||||
if (ret < 0)
|
||||
goto err_free_irq;
|
||||
|
||||
if (udc_controller->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc_controller->transceiver))
|
||||
udc_controller->gadget.is_otg = 1;
|
||||
|
||||
/* setup QH and epctrl for ep0 */
|
||||
|
@ -1432,7 +1432,7 @@ static int __init imx_udc_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "can't get USB clock\n");
|
||||
goto fail2;
|
||||
}
|
||||
clk_enable(clk);
|
||||
clk_prepare_enable(clk);
|
||||
|
||||
if (clk_get_rate(clk) != 48000000) {
|
||||
D_INI(&pdev->dev,
|
||||
@ -1496,7 +1496,7 @@ fail4:
|
||||
free_irq(imx_usb->usbd_int[i], imx_usb);
|
||||
fail3:
|
||||
clk_put(clk);
|
||||
clk_disable(clk);
|
||||
clk_disable_unprepare(clk);
|
||||
fail2:
|
||||
iounmap(base);
|
||||
fail1:
|
||||
@ -1521,7 +1521,7 @@ static int __exit imx_udc_remove(struct platform_device *pdev)
|
||||
free_irq(imx_usb->usbd_int[i], imx_usb);
|
||||
|
||||
clk_put(imx_usb->clk);
|
||||
clk_disable(imx_usb->clk);
|
||||
clk_disable_unprepare(imx_usb->clk);
|
||||
iounmap(imx_usb->base);
|
||||
|
||||
release_mem_region(imx_usb->res->start, resource_size(imx_usb->res));
|
||||
|
@ -165,6 +165,7 @@ struct lpc32xx_udc {
|
||||
int udp_irq[4];
|
||||
struct clk *usb_pll_clk;
|
||||
struct clk *usb_slv_clk;
|
||||
struct clk *usb_otg_clk;
|
||||
|
||||
/* DMA support */
|
||||
u32 *udca_v_base;
|
||||
@ -227,33 +228,15 @@ static inline struct lpc32xx_udc *to_udc(struct usb_gadget *g)
|
||||
#define UDCA_BUFF_SIZE (128)
|
||||
|
||||
/* TODO: When the clock framework is introduced in LPC32xx, IO_ADDRESS will
|
||||
* be replaced with an inremap()ed pointer, see USB_OTG_CLK_CTRL()
|
||||
* be replaced with an inremap()ed pointer
|
||||
* */
|
||||
#define USB_CTRL IO_ADDRESS(LPC32XX_CLK_PM_BASE + 0x64)
|
||||
#define USB_CLOCK_MASK (AHB_M_CLOCK_ON | OTG_CLOCK_ON | \
|
||||
DEV_CLOCK_ON | I2C_CLOCK_ON)
|
||||
|
||||
/* USB_CTRL bit defines */
|
||||
#define USB_SLAVE_HCLK_EN (1 << 24)
|
||||
#define USB_HOST_NEED_CLK_EN (1 << 21)
|
||||
#define USB_DEV_NEED_CLK_EN (1 << 22)
|
||||
|
||||
#define USB_OTG_CLK_CTRL(udc) ((udc)->udp_baseaddr + 0xFF4)
|
||||
#define USB_OTG_CLK_STAT(udc) ((udc)->udp_baseaddr + 0xFF8)
|
||||
|
||||
/* USB_OTG_CLK_CTRL bit defines */
|
||||
#define AHB_M_CLOCK_ON (1 << 4)
|
||||
#define OTG_CLOCK_ON (1 << 3)
|
||||
#define I2C_CLOCK_ON (1 << 2)
|
||||
#define DEV_CLOCK_ON (1 << 1)
|
||||
#define HOST_CLOCK_ON (1 << 0)
|
||||
|
||||
#define USB_OTG_STAT_CONTROL(udc) (udc->udp_baseaddr + 0x110)
|
||||
|
||||
/* USB_OTG_STAT_CONTROL bit defines */
|
||||
#define TRANSPARENT_I2C_EN (1 << 7)
|
||||
#define HOST_EN (1 << 0)
|
||||
|
||||
/**********************************************************************
|
||||
* USB device controller register offsets
|
||||
**********************************************************************/
|
||||
@ -677,7 +660,7 @@ static void isp1301_udc_configure(struct lpc32xx_udc *udc)
|
||||
ISP1301_I2C_INTERRUPT_RISING, INT_VBUS_VLD);
|
||||
|
||||
/* Enable usb_need_clk clock after transceiver is initialized */
|
||||
writel((readl(USB_CTRL) | (1 << 22)), USB_CTRL);
|
||||
writel((readl(USB_CTRL) | USB_DEV_NEED_CLK_EN), USB_CTRL);
|
||||
|
||||
dev_info(udc->dev, "ISP1301 Vendor ID : 0x%04x\n",
|
||||
i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00));
|
||||
@ -1010,11 +993,8 @@ static void udc_dd_free(struct lpc32xx_udc *udc, struct lpc32xx_usbd_dd_gad *dd)
|
||||
/* Enables or disables most of the USB system clocks when low power mode is
|
||||
* needed. Clocks are typically started on a connection event, and disabled
|
||||
* when a cable is disconnected */
|
||||
#define OTGOFF_CLK_MASK (AHB_M_CLOCK_ON | I2C_CLOCK_ON)
|
||||
static void udc_clk_set(struct lpc32xx_udc *udc, int enable)
|
||||
{
|
||||
int to = 1000;
|
||||
|
||||
if (enable != 0) {
|
||||
if (udc->clocked)
|
||||
return;
|
||||
@ -1028,14 +1008,7 @@ static void udc_clk_set(struct lpc32xx_udc *udc, int enable)
|
||||
writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN,
|
||||
USB_CTRL);
|
||||
|
||||
/* Set to enable all needed USB OTG clocks */
|
||||
writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc));
|
||||
|
||||
while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) !=
|
||||
USB_CLOCK_MASK) && (to > 0))
|
||||
to--;
|
||||
if (!to)
|
||||
dev_dbg(udc->dev, "Cannot enable USB OTG clocking\n");
|
||||
clk_enable(udc->usb_otg_clk);
|
||||
} else {
|
||||
if (!udc->clocked)
|
||||
return;
|
||||
@ -1047,19 +1020,11 @@ static void udc_clk_set(struct lpc32xx_udc *udc, int enable)
|
||||
/* 48MHz PLL dpwn */
|
||||
clk_disable(udc->usb_pll_clk);
|
||||
|
||||
/* Enable the USB device clock */
|
||||
/* Disable the USB device clock */
|
||||
writel(readl(USB_CTRL) & ~USB_DEV_NEED_CLK_EN,
|
||||
USB_CTRL);
|
||||
|
||||
/* Set to enable all needed USB OTG clocks */
|
||||
writel(OTGOFF_CLK_MASK, USB_OTG_CLK_CTRL(udc));
|
||||
|
||||
while (((readl(USB_OTG_CLK_STAT(udc)) &
|
||||
OTGOFF_CLK_MASK) !=
|
||||
OTGOFF_CLK_MASK) && (to > 0))
|
||||
to--;
|
||||
if (!to)
|
||||
dev_dbg(udc->dev, "Cannot disable USB OTG clocking\n");
|
||||
clk_disable(udc->usb_otg_clk);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3041,6 +3006,7 @@ static int lpc32xx_start(struct usb_gadget_driver *driver,
|
||||
|
||||
udc->driver = driver;
|
||||
udc->gadget.dev.driver = &driver->driver;
|
||||
udc->gadget.dev.of_node = udc->dev->of_node;
|
||||
udc->enabled = 1;
|
||||
udc->selfpowered = 1;
|
||||
udc->vbus = 0;
|
||||
@ -3239,6 +3205,12 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
|
||||
retval = PTR_ERR(udc->usb_slv_clk);
|
||||
goto usb_clk_get_fail;
|
||||
}
|
||||
udc->usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg");
|
||||
if (IS_ERR(udc->usb_otg_clk)) {
|
||||
dev_err(udc->dev, "failed to acquire USB otg clock\n");
|
||||
retval = PTR_ERR(udc->usb_slv_clk);
|
||||
goto usb_otg_clk_get_fail;
|
||||
}
|
||||
|
||||
/* Setup PLL clock to 48MHz */
|
||||
retval = clk_enable(udc->usb_pll_clk);
|
||||
@ -3262,15 +3234,12 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
|
||||
goto usb_clk_enable_fail;
|
||||
}
|
||||
|
||||
/* Set to enable all needed USB OTG clocks */
|
||||
writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc));
|
||||
|
||||
i = 1000;
|
||||
while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) !=
|
||||
USB_CLOCK_MASK) && (i > 0))
|
||||
i--;
|
||||
if (!i)
|
||||
dev_dbg(udc->dev, "USB OTG clocks not correctly enabled\n");
|
||||
/* Enable USB OTG clock */
|
||||
retval = clk_enable(udc->usb_otg_clk);
|
||||
if (retval < 0) {
|
||||
dev_err(udc->dev, "failed to start USB otg clock\n");
|
||||
goto usb_otg_clk_enable_fail;
|
||||
}
|
||||
|
||||
/* Setup deferred workqueue data */
|
||||
udc->poweron = udc->pullup = 0;
|
||||
@ -3390,12 +3359,16 @@ dma_alloc_fail:
|
||||
dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
|
||||
udc->udca_v_base, udc->udca_p_base);
|
||||
i2c_fail:
|
||||
clk_disable(udc->usb_otg_clk);
|
||||
usb_otg_clk_enable_fail:
|
||||
clk_disable(udc->usb_slv_clk);
|
||||
usb_clk_enable_fail:
|
||||
pll_set_fail:
|
||||
clk_disable(udc->usb_pll_clk);
|
||||
pll_enable_fail:
|
||||
clk_put(udc->usb_slv_clk);
|
||||
usb_otg_clk_get_fail:
|
||||
clk_put(udc->usb_otg_clk);
|
||||
usb_clk_get_fail:
|
||||
clk_put(udc->usb_pll_clk);
|
||||
pll_get_fail:
|
||||
@ -3433,6 +3406,8 @@ static int __devexit lpc32xx_udc_remove(struct platform_device *pdev)
|
||||
|
||||
device_unregister(&udc->gadget.dev);
|
||||
|
||||
clk_disable(udc->usb_otg_clk);
|
||||
clk_put(udc->usb_otg_clk);
|
||||
clk_disable(udc->usb_slv_clk);
|
||||
clk_put(udc->usb_slv_clk);
|
||||
clk_disable(udc->usb_pll_clk);
|
||||
@ -3446,7 +3421,6 @@ static int __devexit lpc32xx_udc_remove(struct platform_device *pdev)
|
||||
#ifdef CONFIG_PM
|
||||
static int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg)
|
||||
{
|
||||
int to = 1000;
|
||||
struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
|
||||
|
||||
if (udc->clocked) {
|
||||
@ -3461,15 +3435,6 @@ static int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg)
|
||||
on resume */
|
||||
udc->clocked = 1;
|
||||
|
||||
/* Kill OTG and I2C clocks */
|
||||
writel(0, USB_OTG_CLK_CTRL(udc));
|
||||
while (((readl(USB_OTG_CLK_STAT(udc)) & OTGOFF_CLK_MASK) !=
|
||||
OTGOFF_CLK_MASK) && (to > 0))
|
||||
to--;
|
||||
if (!to)
|
||||
dev_dbg(udc->dev,
|
||||
"USB OTG clocks not correctly enabled\n");
|
||||
|
||||
/* Kill global USB clock */
|
||||
clk_disable(udc->usb_slv_clk);
|
||||
}
|
||||
|
320
drivers/usb/gadget/mv_u3d.h
Normal file
320
drivers/usb/gadget/mv_u3d.h
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Marvell International Ltd. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __MV_U3D_H
|
||||
#define __MV_U3D_H
|
||||
|
||||
#define MV_U3D_EP_CONTEXT_ALIGNMENT 32
|
||||
#define MV_U3D_TRB_ALIGNMENT 16
|
||||
#define MV_U3D_DMA_BOUNDARY 4096
|
||||
#define MV_U3D_EP0_MAX_PKT_SIZE 512
|
||||
|
||||
/* ep0 transfer state */
|
||||
#define MV_U3D_WAIT_FOR_SETUP 0
|
||||
#define MV_U3D_DATA_STATE_XMIT 1
|
||||
#define MV_U3D_DATA_STATE_NEED_ZLP 2
|
||||
#define MV_U3D_WAIT_FOR_OUT_STATUS 3
|
||||
#define MV_U3D_DATA_STATE_RECV 4
|
||||
#define MV_U3D_STATUS_STAGE 5
|
||||
|
||||
#define MV_U3D_EP_MAX_LENGTH_TRANSFER 0x10000
|
||||
|
||||
/* USB3 Interrupt Status */
|
||||
#define MV_U3D_USBINT_SETUP 0x00000001
|
||||
#define MV_U3D_USBINT_RX_COMPLETE 0x00000002
|
||||
#define MV_U3D_USBINT_TX_COMPLETE 0x00000004
|
||||
#define MV_U3D_USBINT_UNDER_RUN 0x00000008
|
||||
#define MV_U3D_USBINT_RXDESC_ERR 0x00000010
|
||||
#define MV_U3D_USBINT_TXDESC_ERR 0x00000020
|
||||
#define MV_U3D_USBINT_RX_TRB_COMPLETE 0x00000040
|
||||
#define MV_U3D_USBINT_TX_TRB_COMPLETE 0x00000080
|
||||
#define MV_U3D_USBINT_VBUS_VALID 0x00010000
|
||||
#define MV_U3D_USBINT_STORAGE_CMD_FULL 0x00020000
|
||||
#define MV_U3D_USBINT_LINK_CHG 0x01000000
|
||||
|
||||
/* USB3 Interrupt Enable */
|
||||
#define MV_U3D_INTR_ENABLE_SETUP 0x00000001
|
||||
#define MV_U3D_INTR_ENABLE_RX_COMPLETE 0x00000002
|
||||
#define MV_U3D_INTR_ENABLE_TX_COMPLETE 0x00000004
|
||||
#define MV_U3D_INTR_ENABLE_UNDER_RUN 0x00000008
|
||||
#define MV_U3D_INTR_ENABLE_RXDESC_ERR 0x00000010
|
||||
#define MV_U3D_INTR_ENABLE_TXDESC_ERR 0x00000020
|
||||
#define MV_U3D_INTR_ENABLE_RX_TRB_COMPLETE 0x00000040
|
||||
#define MV_U3D_INTR_ENABLE_TX_TRB_COMPLETE 0x00000080
|
||||
#define MV_U3D_INTR_ENABLE_RX_BUFFER_ERR 0x00000100
|
||||
#define MV_U3D_INTR_ENABLE_VBUS_VALID 0x00010000
|
||||
#define MV_U3D_INTR_ENABLE_STORAGE_CMD_FULL 0x00020000
|
||||
#define MV_U3D_INTR_ENABLE_LINK_CHG 0x01000000
|
||||
#define MV_U3D_INTR_ENABLE_PRIME_STATUS 0x02000000
|
||||
|
||||
/* USB3 Link Change */
|
||||
#define MV_U3D_LINK_CHANGE_LINK_UP 0x00000001
|
||||
#define MV_U3D_LINK_CHANGE_SUSPEND 0x00000002
|
||||
#define MV_U3D_LINK_CHANGE_RESUME 0x00000004
|
||||
#define MV_U3D_LINK_CHANGE_WRESET 0x00000008
|
||||
#define MV_U3D_LINK_CHANGE_HRESET 0x00000010
|
||||
#define MV_U3D_LINK_CHANGE_VBUS_INVALID 0x00000020
|
||||
#define MV_U3D_LINK_CHANGE_INACT 0x00000040
|
||||
#define MV_U3D_LINK_CHANGE_DISABLE_AFTER_U0 0x00000080
|
||||
#define MV_U3D_LINK_CHANGE_U1 0x00000100
|
||||
#define MV_U3D_LINK_CHANGE_U2 0x00000200
|
||||
#define MV_U3D_LINK_CHANGE_U3 0x00000400
|
||||
|
||||
/* bridge setting */
|
||||
#define MV_U3D_BRIDGE_SETTING_VBUS_VALID (1 << 16)
|
||||
|
||||
/* Command Register Bit Masks */
|
||||
#define MV_U3D_CMD_RUN_STOP 0x00000001
|
||||
#define MV_U3D_CMD_CTRL_RESET 0x00000002
|
||||
|
||||
/* ep control register */
|
||||
#define MV_U3D_EPXCR_EP_TYPE_CONTROL 0
|
||||
#define MV_U3D_EPXCR_EP_TYPE_ISOC 1
|
||||
#define MV_U3D_EPXCR_EP_TYPE_BULK 2
|
||||
#define MV_U3D_EPXCR_EP_TYPE_INT 3
|
||||
#define MV_U3D_EPXCR_EP_ENABLE_SHIFT 4
|
||||
#define MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT 12
|
||||
#define MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT 16
|
||||
#define MV_U3D_USB_BULK_BURST_OUT 6
|
||||
#define MV_U3D_USB_BULK_BURST_IN 14
|
||||
|
||||
#define MV_U3D_EPXCR_EP_FLUSH (1 << 7)
|
||||
#define MV_U3D_EPXCR_EP_HALT (1 << 1)
|
||||
#define MV_U3D_EPXCR_EP_INIT (1)
|
||||
|
||||
/* TX/RX Status Register */
|
||||
#define MV_U3D_XFERSTATUS_COMPLETE_SHIFT 24
|
||||
#define MV_U3D_COMPLETE_INVALID 0
|
||||
#define MV_U3D_COMPLETE_SUCCESS 1
|
||||
#define MV_U3D_COMPLETE_BUFF_ERR 2
|
||||
#define MV_U3D_COMPLETE_SHORT_PACKET 3
|
||||
#define MV_U3D_COMPLETE_TRB_ERR 5
|
||||
#define MV_U3D_XFERSTATUS_TRB_LENGTH_MASK (0xFFFFFF)
|
||||
|
||||
#define MV_U3D_USB_LINK_BYPASS_VBUS 0x8
|
||||
|
||||
#define MV_U3D_LTSSM_PHY_INIT_DONE 0x80000000
|
||||
#define MV_U3D_LTSSM_NEVER_GO_COMPLIANCE 0x40000000
|
||||
|
||||
#define MV_U3D_USB3_OP_REGS_OFFSET 0x100
|
||||
#define MV_U3D_USB3_PHY_OFFSET 0xB800
|
||||
|
||||
#define DCS_ENABLE 0x1
|
||||
|
||||
/* timeout */
|
||||
#define MV_U3D_RESET_TIMEOUT 10000
|
||||
#define MV_U3D_FLUSH_TIMEOUT 100000
|
||||
#define MV_U3D_OWN_TIMEOUT 10000
|
||||
#define LOOPS_USEC_SHIFT 4
|
||||
#define LOOPS_USEC (1 << LOOPS_USEC_SHIFT)
|
||||
#define LOOPS(timeout) ((timeout) >> LOOPS_USEC_SHIFT)
|
||||
|
||||
/* ep direction */
|
||||
#define MV_U3D_EP_DIR_IN 1
|
||||
#define MV_U3D_EP_DIR_OUT 0
|
||||
#define mv_u3d_ep_dir(ep) (((ep)->ep_num == 0) ? \
|
||||
((ep)->u3d->ep0_dir) : ((ep)->direction))
|
||||
|
||||
/* usb capability registers */
|
||||
struct mv_u3d_cap_regs {
|
||||
u32 rsvd[5];
|
||||
u32 dboff; /* doorbell register offset */
|
||||
u32 rtsoff; /* runtime register offset */
|
||||
u32 vuoff; /* vendor unique register offset */
|
||||
};
|
||||
|
||||
/* operation registers */
|
||||
struct mv_u3d_op_regs {
|
||||
u32 usbcmd; /* Command register */
|
||||
u32 rsvd1[11];
|
||||
u32 dcbaapl; /* Device Context Base Address low register */
|
||||
u32 dcbaaph; /* Device Context Base Address high register */
|
||||
u32 rsvd2[243];
|
||||
u32 portsc; /* port status and control register*/
|
||||
u32 portlinkinfo; /* port link info register*/
|
||||
u32 rsvd3[9917];
|
||||
u32 doorbell; /* doorbell register */
|
||||
};
|
||||
|
||||
/* control enpoint enable registers */
|
||||
struct epxcr {
|
||||
u32 epxoutcr0; /* ep out control 0 register */
|
||||
u32 epxoutcr1; /* ep out control 1 register */
|
||||
u32 epxincr0; /* ep in control 0 register */
|
||||
u32 epxincr1; /* ep in control 1 register */
|
||||
};
|
||||
|
||||
/* transfer status registers */
|
||||
struct xferstatus {
|
||||
u32 curdeqlo; /* current TRB pointer low */
|
||||
u32 curdeqhi; /* current TRB pointer high */
|
||||
u32 statuslo; /* transfer status low */
|
||||
u32 statushi; /* transfer status high */
|
||||
};
|
||||
|
||||
/* vendor unique control registers */
|
||||
struct mv_u3d_vuc_regs {
|
||||
u32 ctrlepenable; /* control endpoint enable register */
|
||||
u32 setuplock; /* setup lock register */
|
||||
u32 endcomplete; /* endpoint transfer complete register */
|
||||
u32 intrcause; /* interrupt cause register */
|
||||
u32 intrenable; /* interrupt enable register */
|
||||
u32 trbcomplete; /* TRB complete register */
|
||||
u32 linkchange; /* link change register */
|
||||
u32 rsvd1[5];
|
||||
u32 trbunderrun; /* TRB underrun register */
|
||||
u32 rsvd2[43];
|
||||
u32 bridgesetting; /* bridge setting register */
|
||||
u32 rsvd3[7];
|
||||
struct xferstatus txst[16]; /* TX status register */
|
||||
struct xferstatus rxst[16]; /* RX status register */
|
||||
u32 ltssm; /* LTSSM control register */
|
||||
u32 pipe; /* PIPE control register */
|
||||
u32 linkcr0; /* link control 0 register */
|
||||
u32 linkcr1; /* link control 1 register */
|
||||
u32 rsvd6[60];
|
||||
u32 mib0; /* MIB0 counter register */
|
||||
u32 usblink; /* usb link control register */
|
||||
u32 ltssmstate; /* LTSSM state register */
|
||||
u32 linkerrorcause; /* link error cause register */
|
||||
u32 rsvd7[60];
|
||||
u32 devaddrtiebrkr; /* device address and tie breaker */
|
||||
u32 itpinfo0; /* ITP info 0 register */
|
||||
u32 itpinfo1; /* ITP info 1 register */
|
||||
u32 rsvd8[61];
|
||||
struct epxcr epcr[16]; /* ep control register */
|
||||
u32 rsvd9[64];
|
||||
u32 phyaddr; /* PHY address register */
|
||||
u32 phydata; /* PHY data register */
|
||||
};
|
||||
|
||||
/* Endpoint context structure */
|
||||
struct mv_u3d_ep_context {
|
||||
u32 rsvd0;
|
||||
u32 rsvd1;
|
||||
u32 trb_addr_lo; /* TRB address low 32 bit */
|
||||
u32 trb_addr_hi; /* TRB address high 32 bit */
|
||||
u32 rsvd2;
|
||||
u32 rsvd3;
|
||||
struct usb_ctrlrequest setup_buffer; /* setup data buffer */
|
||||
};
|
||||
|
||||
/* TRB control data structure */
|
||||
struct mv_u3d_trb_ctrl {
|
||||
u32 own:1; /* owner of TRB */
|
||||
u32 rsvd1:3;
|
||||
u32 chain:1; /* associate this TRB with the
|
||||
next TRB on the Ring */
|
||||
u32 ioc:1; /* interrupt on complete */
|
||||
u32 rsvd2:4;
|
||||
u32 type:6; /* TRB type */
|
||||
#define TYPE_NORMAL 1
|
||||
#define TYPE_DATA 3
|
||||
#define TYPE_LINK 6
|
||||
u32 dir:1; /* Working at data stage of control endpoint
|
||||
operation. 0 is OUT and 1 is IN. */
|
||||
u32 rsvd3:15;
|
||||
};
|
||||
|
||||
/* TRB data structure
|
||||
* For multiple TRB, all the TRBs' physical address should be continuous.
|
||||
*/
|
||||
struct mv_u3d_trb_hw {
|
||||
u32 buf_addr_lo; /* data buffer address low 32 bit */
|
||||
u32 buf_addr_hi; /* data buffer address high 32 bit */
|
||||
u32 trb_len; /* transfer length */
|
||||
struct mv_u3d_trb_ctrl ctrl; /* TRB control data */
|
||||
};
|
||||
|
||||
/* TRB structure */
|
||||
struct mv_u3d_trb {
|
||||
struct mv_u3d_trb_hw *trb_hw; /* point to the trb_hw structure */
|
||||
dma_addr_t trb_dma; /* dma address for this trb_hw */
|
||||
struct list_head trb_list; /* trb list */
|
||||
};
|
||||
|
||||
/* device data structure */
|
||||
struct mv_u3d {
|
||||
struct usb_gadget gadget;
|
||||
struct usb_gadget_driver *driver;
|
||||
spinlock_t lock; /* device lock */
|
||||
struct completion *done;
|
||||
struct device *dev;
|
||||
int irq;
|
||||
|
||||
/* usb controller registers */
|
||||
struct mv_u3d_cap_regs __iomem *cap_regs;
|
||||
struct mv_u3d_op_regs __iomem *op_regs;
|
||||
struct mv_u3d_vuc_regs __iomem *vuc_regs;
|
||||
void __iomem *phy_regs;
|
||||
|
||||
unsigned int max_eps;
|
||||
struct mv_u3d_ep_context *ep_context;
|
||||
size_t ep_context_size;
|
||||
dma_addr_t ep_context_dma;
|
||||
|
||||
struct dma_pool *trb_pool; /* for TRB data structure */
|
||||
struct mv_u3d_ep *eps;
|
||||
|
||||
struct mv_u3d_req *status_req; /* ep0 status request */
|
||||
struct usb_ctrlrequest local_setup_buff; /* store setup data*/
|
||||
|
||||
unsigned int resume_state; /* USB state to resume */
|
||||
unsigned int usb_state; /* USB current state */
|
||||
unsigned int ep0_state; /* Endpoint zero state */
|
||||
unsigned int ep0_dir;
|
||||
|
||||
unsigned int dev_addr; /* device address */
|
||||
|
||||
unsigned int errors;
|
||||
|
||||
unsigned softconnect:1;
|
||||
unsigned vbus_active:1; /* vbus is active or not */
|
||||
unsigned remote_wakeup:1; /* support remote wakeup */
|
||||
unsigned clock_gating:1; /* clock gating or not */
|
||||
unsigned active:1; /* udc is active or not */
|
||||
unsigned vbus_valid_detect:1; /* udc vbus detection */
|
||||
|
||||
struct mv_usb_addon_irq *vbus;
|
||||
unsigned int power;
|
||||
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
/* endpoint data structure */
|
||||
struct mv_u3d_ep {
|
||||
struct usb_ep ep;
|
||||
struct mv_u3d *u3d;
|
||||
struct list_head queue; /* ep request queued hardware */
|
||||
struct list_head req_list; /* list of ep request */
|
||||
struct mv_u3d_ep_context *ep_context; /* ep context */
|
||||
u32 direction;
|
||||
char name[14];
|
||||
u32 processing; /* there is ep request
|
||||
queued on haredware */
|
||||
spinlock_t req_lock; /* ep lock */
|
||||
unsigned wedge:1;
|
||||
unsigned enabled:1;
|
||||
unsigned ep_type:2;
|
||||
unsigned ep_num:8;
|
||||
};
|
||||
|
||||
/* request data structure */
|
||||
struct mv_u3d_req {
|
||||
struct usb_request req;
|
||||
struct mv_u3d_ep *ep;
|
||||
struct list_head queue; /* ep requst queued on hardware */
|
||||
struct list_head list; /* ep request list */
|
||||
struct list_head trb_list; /* trb list of a request */
|
||||
|
||||
struct mv_u3d_trb *trb_head; /* point to first trb of a request */
|
||||
unsigned trb_count; /* TRB number in the chain */
|
||||
unsigned chain; /* TRB chain or not */
|
||||
};
|
||||
|
||||
#endif
|
2098
drivers/usb/gadget/mv_u3d_core.c
Normal file
2098
drivers/usb/gadget/mv_u3d_core.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/list.h>
|
||||
@ -1381,7 +1382,7 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (udc->transceiver) {
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver)) {
|
||||
retval = otg_set_peripheral(udc->transceiver->otg,
|
||||
&udc->gadget);
|
||||
if (retval) {
|
||||
@ -2107,7 +2108,7 @@ static int __devexit mv_udc_remove(struct platform_device *dev)
|
||||
* then vbus irq will not be requested in udc driver.
|
||||
*/
|
||||
if (udc->pdata && udc->pdata->vbus
|
||||
&& udc->clock_gating && udc->transceiver == NULL)
|
||||
&& udc->clock_gating && IS_ERR_OR_NULL(udc->transceiver))
|
||||
free_irq(udc->pdata->vbus->irq, &dev->dev);
|
||||
|
||||
/* free memory allocated in probe */
|
||||
@ -2180,7 +2181,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
|
||||
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
if (pdata->mode == MV_USB_MODE_OTG)
|
||||
udc->transceiver = usb_get_transceiver();
|
||||
udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
#endif
|
||||
|
||||
udc->clknum = pdata->clknum;
|
||||
@ -2325,7 +2326,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
|
||||
eps_init(udc);
|
||||
|
||||
/* VBUS detect: we can disable/enable clock on demand.*/
|
||||
if (udc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
udc->clock_gating = 1;
|
||||
else if (pdata->vbus) {
|
||||
udc->clock_gating = 1;
|
||||
@ -2369,7 +2370,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
|
||||
|
||||
err_unregister:
|
||||
if (udc->pdata && udc->pdata->vbus
|
||||
&& udc->clock_gating && udc->transceiver == NULL)
|
||||
&& udc->clock_gating && IS_ERR_OR_NULL(udc->transceiver))
|
||||
free_irq(pdata->vbus->irq, &dev->dev);
|
||||
device_unregister(&udc->gadget.dev);
|
||||
err_free_irq:
|
||||
@ -2404,7 +2405,7 @@ static int mv_udc_suspend(struct device *_dev)
|
||||
struct mv_udc *udc = the_controller;
|
||||
|
||||
/* if OTG is enabled, the following will be done in OTG driver*/
|
||||
if (udc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
return 0;
|
||||
|
||||
if (udc->pdata->vbus && udc->pdata->vbus->poll)
|
||||
@ -2437,7 +2438,7 @@ static int mv_udc_resume(struct device *_dev)
|
||||
int retval;
|
||||
|
||||
/* if OTG is enabled, the following will be done in OTG driver*/
|
||||
if (udc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
return 0;
|
||||
|
||||
if (!udc->clock_gating) {
|
||||
|
@ -35,10 +35,11 @@
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/mach-types.h>
|
||||
@ -59,11 +60,6 @@
|
||||
#define DRIVER_DESC "OMAP UDC driver"
|
||||
#define DRIVER_VERSION "4 October 2004"
|
||||
|
||||
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
|
||||
|
||||
#define OMAP2_DMA_CH(ch) (((ch) - 1) << 1)
|
||||
#define OMAP24XX_DMA(name, ch) (OMAP24XX_DMA_##name + OMAP2_DMA_CH(ch))
|
||||
|
||||
/*
|
||||
* The OMAP UDC needs _very_ early endpoint setup: before enabling the
|
||||
* D+ pullup to allow enumeration. That's too early for the gadget
|
||||
@ -87,14 +83,14 @@
|
||||
#ifdef USE_ISO
|
||||
static unsigned fifo_mode = 3;
|
||||
#else
|
||||
static unsigned fifo_mode = 0;
|
||||
static unsigned fifo_mode;
|
||||
#endif
|
||||
|
||||
/* "modprobe omap_udc fifo_mode=42", or else as a kernel
|
||||
* boot parameter "omap_udc:fifo_mode=42"
|
||||
*/
|
||||
module_param (fifo_mode, uint, 0);
|
||||
MODULE_PARM_DESC (fifo_mode, "endpoint configuration");
|
||||
module_param(fifo_mode, uint, 0);
|
||||
MODULE_PARM_DESC(fifo_mode, "endpoint configuration");
|
||||
|
||||
#ifdef USE_DMA
|
||||
static bool use_dma = 1;
|
||||
@ -102,8 +98,8 @@ static bool use_dma = 1;
|
||||
/* "modprobe omap_udc use_dma=y", or else as a kernel
|
||||
* boot parameter "omap_udc:use_dma=y"
|
||||
*/
|
||||
module_param (use_dma, bool, 0);
|
||||
MODULE_PARM_DESC (use_dma, "enable/disable DMA");
|
||||
module_param(use_dma, bool, 0);
|
||||
MODULE_PARM_DESC(use_dma, "enable/disable DMA");
|
||||
#else /* !USE_DMA */
|
||||
|
||||
/* save a bit of code */
|
||||
@ -111,8 +107,8 @@ MODULE_PARM_DESC (use_dma, "enable/disable DMA");
|
||||
#endif /* !USE_DMA */
|
||||
|
||||
|
||||
static const char driver_name [] = "omap_udc";
|
||||
static const char driver_desc [] = DRIVER_DESC;
|
||||
static const char driver_name[] = "omap_udc";
|
||||
static const char driver_desc[] = DRIVER_DESC;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -250,7 +246,7 @@ static int omap_ep_disable(struct usb_ep *_ep)
|
||||
|
||||
spin_lock_irqsave(&ep->udc->lock, flags);
|
||||
ep->ep.desc = NULL;
|
||||
nuke (ep, -ESHUTDOWN);
|
||||
nuke(ep, -ESHUTDOWN);
|
||||
ep->ep.maxpacket = ep->maxpacket;
|
||||
ep->has_dma = 0;
|
||||
omap_writew(UDC_SET_HALT, UDC_CTRL);
|
||||
@ -271,10 +267,11 @@ omap_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
|
||||
struct omap_req *req;
|
||||
|
||||
req = kzalloc(sizeof(*req), gfp_flags);
|
||||
if (req) {
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
INIT_LIST_HEAD (&req->queue);
|
||||
}
|
||||
if (!req)
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&req->queue);
|
||||
|
||||
return &req->req;
|
||||
}
|
||||
|
||||
@ -283,8 +280,7 @@ omap_free_request(struct usb_ep *ep, struct usb_request *_req)
|
||||
{
|
||||
struct omap_req *req = container_of(_req, struct omap_req, req);
|
||||
|
||||
if (_req)
|
||||
kfree (req);
|
||||
kfree(req);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -292,6 +288,7 @@ omap_free_request(struct usb_ep *ep, struct usb_request *_req)
|
||||
static void
|
||||
done(struct omap_ep *ep, struct omap_req *req, int status)
|
||||
{
|
||||
struct omap_udc *udc = ep->udc;
|
||||
unsigned stopped = ep->stopped;
|
||||
|
||||
list_del_init(&req->queue);
|
||||
@ -301,22 +298,9 @@ done(struct omap_ep *ep, struct omap_req *req, int status)
|
||||
else
|
||||
status = req->req.status;
|
||||
|
||||
if (use_dma && ep->has_dma) {
|
||||
if (req->mapped) {
|
||||
dma_unmap_single(ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
(ep->bEndpointAddress & USB_DIR_IN)
|
||||
? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
req->req.dma = DMA_ADDR_INVALID;
|
||||
req->mapped = 0;
|
||||
} else
|
||||
dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
(ep->bEndpointAddress & USB_DIR_IN)
|
||||
? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
}
|
||||
if (use_dma && ep->has_dma)
|
||||
usb_gadget_unmap_request(&udc->gadget, &req->req,
|
||||
(ep->bEndpointAddress & USB_DIR_IN));
|
||||
|
||||
#ifndef USB_TRACE
|
||||
if (status && status != -ESHUTDOWN)
|
||||
@ -364,10 +348,10 @@ write_packet(u8 *buf, struct omap_req *req, unsigned max)
|
||||
return len;
|
||||
}
|
||||
|
||||
// FIXME change r/w fifo calling convention
|
||||
/* FIXME change r/w fifo calling convention */
|
||||
|
||||
|
||||
// return: 0 = still running, 1 = completed, negative = errno
|
||||
/* return: 0 = still running, 1 = completed, negative = errno */
|
||||
static int write_fifo(struct omap_ep *ep, struct omap_req *req)
|
||||
{
|
||||
u8 *buf;
|
||||
@ -429,7 +413,7 @@ read_packet(u8 *buf, struct omap_req *req, unsigned avail)
|
||||
return len;
|
||||
}
|
||||
|
||||
// return: 0 = still running, 1 = queue empty, negative = errno
|
||||
/* return: 0 = still running, 1 = queue empty, negative = errno */
|
||||
static int read_fifo(struct omap_ep *ep, struct omap_req *req)
|
||||
{
|
||||
u8 *buf;
|
||||
@ -536,12 +520,8 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
|
||||
: OMAP_DMA_SYNC_ELEMENT;
|
||||
int dma_trigger = 0;
|
||||
|
||||
if (cpu_is_omap24xx())
|
||||
dma_trigger = OMAP24XX_DMA(USB_W2FC_TX0, ep->dma_channel);
|
||||
|
||||
/* measure length in either bytes or packets */
|
||||
if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
|
||||
|| (cpu_is_omap24xx() && length < ep->maxpacket)
|
||||
|| (cpu_is_omap15xx() && length < ep->maxpacket)) {
|
||||
txdma_ctrl = UDC_TXN_EOT | length;
|
||||
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
|
||||
@ -600,28 +580,14 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
|
||||
int dma_trigger = 0;
|
||||
u16 w;
|
||||
|
||||
if (cpu_is_omap24xx())
|
||||
dma_trigger = OMAP24XX_DMA(USB_W2FC_RX0, ep->dma_channel);
|
||||
|
||||
/* NOTE: we filtered out "short reads" before, so we know
|
||||
* the buffer has only whole numbers of packets.
|
||||
* except MODE SELECT(6) sent the 24 bytes data in OMAP24XX DMA mode
|
||||
*/
|
||||
if (cpu_is_omap24xx() && packets < ep->maxpacket) {
|
||||
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
|
||||
packets, 1, OMAP_DMA_SYNC_ELEMENT,
|
||||
dma_trigger, 0);
|
||||
req->dma_bytes = packets;
|
||||
} else {
|
||||
/* set up this DMA transfer, enable the fifo, start */
|
||||
packets /= ep->ep.maxpacket;
|
||||
packets = min(packets, (unsigned)UDC_RXN_TC + 1);
|
||||
req->dma_bytes = packets * ep->ep.maxpacket;
|
||||
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
|
||||
ep->ep.maxpacket >> 1, packets,
|
||||
OMAP_DMA_SYNC_ELEMENT,
|
||||
dma_trigger, 0);
|
||||
}
|
||||
/* set up this DMA transfer, enable the fifo, start */
|
||||
packets /= ep->ep.maxpacket;
|
||||
packets = min(packets, (unsigned)UDC_RXN_TC + 1);
|
||||
req->dma_bytes = packets * ep->ep.maxpacket;
|
||||
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
|
||||
ep->ep.maxpacket >> 1, packets,
|
||||
OMAP_DMA_SYNC_ELEMENT,
|
||||
dma_trigger, 0);
|
||||
omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
|
||||
OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
|
||||
0, 0);
|
||||
@ -683,7 +649,7 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
|
||||
}
|
||||
omap_writew(UDC_TXN_DONE, UDC_IRQ_SRC);
|
||||
|
||||
if (!list_empty (&ep->queue)) {
|
||||
if (!list_empty(&ep->queue)) {
|
||||
req = container_of(ep->queue.next,
|
||||
struct omap_req, queue);
|
||||
next_in_dma(ep, req);
|
||||
@ -702,7 +668,7 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
|
||||
}
|
||||
omap_writew(UDC_RXN_EOT, UDC_IRQ_SRC);
|
||||
|
||||
if (!list_empty (&ep->queue)) {
|
||||
if (!list_empty(&ep->queue)) {
|
||||
req = container_of(ep->queue.next,
|
||||
struct omap_req, queue);
|
||||
next_out_dma(ep, req);
|
||||
@ -760,10 +726,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
|
||||
ep->dma_channel = channel;
|
||||
|
||||
if (is_in) {
|
||||
if (cpu_is_omap24xx())
|
||||
dma_channel = OMAP24XX_DMA(USB_W2FC_TX0, channel);
|
||||
else
|
||||
dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel;
|
||||
dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel;
|
||||
status = omap_request_dma(dma_channel,
|
||||
ep->ep.name, dma_error, ep, &ep->lch);
|
||||
if (status == 0) {
|
||||
@ -780,11 +743,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
|
||||
0, 0);
|
||||
}
|
||||
} else {
|
||||
if (cpu_is_omap24xx())
|
||||
dma_channel = OMAP24XX_DMA(USB_W2FC_RX0, channel);
|
||||
else
|
||||
dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel;
|
||||
|
||||
dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel;
|
||||
status = omap_request_dma(dma_channel,
|
||||
ep->ep.name, dma_error, ep, &ep->lch);
|
||||
if (status == 0) {
|
||||
@ -808,7 +767,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
|
||||
omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
|
||||
|
||||
/* channel type P: hw synch (fifo) */
|
||||
if (cpu_class_is_omap1() && !cpu_is_omap15xx())
|
||||
if (!cpu_is_omap15xx())
|
||||
omap_set_dma_channel_mode(ep->lch, OMAP_DMA_LCH_P);
|
||||
}
|
||||
|
||||
@ -928,13 +887,11 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
||||
|
||||
/* this isn't bogus, but OMAP DMA isn't the only hardware to
|
||||
* have a hard time with partial packet reads... reject it.
|
||||
* Except OMAP2 can handle the small packets.
|
||||
*/
|
||||
if (use_dma
|
||||
&& ep->has_dma
|
||||
&& ep->bEndpointAddress != 0
|
||||
&& (ep->bEndpointAddress & USB_DIR_IN) == 0
|
||||
&& !cpu_class_is_omap2()
|
||||
&& (req->req.length % ep->ep.maxpacket) != 0) {
|
||||
DBG("%s, no partial packet OUT reads\n", __func__);
|
||||
return -EMSGSIZE;
|
||||
@ -944,26 +901,9 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
||||
if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
|
||||
return -ESHUTDOWN;
|
||||
|
||||
if (use_dma && ep->has_dma) {
|
||||
if (req->req.dma == DMA_ADDR_INVALID) {
|
||||
req->req.dma = dma_map_single(
|
||||
ep->udc->gadget.dev.parent,
|
||||
req->req.buf,
|
||||
req->req.length,
|
||||
(ep->bEndpointAddress & USB_DIR_IN)
|
||||
? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
req->mapped = 1;
|
||||
} else {
|
||||
dma_sync_single_for_device(
|
||||
ep->udc->gadget.dev.parent,
|
||||
req->req.dma, req->req.length,
|
||||
(ep->bEndpointAddress & USB_DIR_IN)
|
||||
? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
req->mapped = 0;
|
||||
}
|
||||
}
|
||||
if (use_dma && ep->has_dma)
|
||||
usb_gadget_map_request(&udc->gadget, &req->req,
|
||||
(ep->bEndpointAddress & USB_DIR_IN));
|
||||
|
||||
VDBG("%s queue req %p, len %d buf %p\n",
|
||||
ep->ep.name, _req, _req->length, _req->buf);
|
||||
@ -984,7 +924,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
||||
int is_in;
|
||||
|
||||
if (ep->bEndpointAddress == 0) {
|
||||
if (!udc->ep0_pending || !list_empty (&ep->queue)) {
|
||||
if (!udc->ep0_pending || !list_empty(&ep->queue)) {
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
return -EL2HLT;
|
||||
}
|
||||
@ -1011,7 +951,8 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
||||
* always an IN ... even for IN transfers,
|
||||
* a weird case which seem to stall OMAP.
|
||||
*/
|
||||
omap_writew(UDC_EP_SEL | UDC_EP_DIR, UDC_EP_NUM);
|
||||
omap_writew(UDC_EP_SEL | UDC_EP_DIR,
|
||||
UDC_EP_NUM);
|
||||
omap_writew(UDC_CLR_EP, UDC_CTRL);
|
||||
omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
|
||||
omap_writew(UDC_EP_DIR, UDC_EP_NUM);
|
||||
@ -1023,7 +964,8 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|
||||
|
||||
/* non-empty DATA stage */
|
||||
} else if (is_in) {
|
||||
omap_writew(UDC_EP_SEL | UDC_EP_DIR, UDC_EP_NUM);
|
||||
omap_writew(UDC_EP_SEL | UDC_EP_DIR,
|
||||
UDC_EP_NUM);
|
||||
} else {
|
||||
if (udc->ep0_setup)
|
||||
goto irq_wait;
|
||||
@ -1071,7 +1013,7 @@ static int omap_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
|
||||
spin_lock_irqsave(&ep->udc->lock, flags);
|
||||
|
||||
/* make sure it's actually queued on this endpoint */
|
||||
list_for_each_entry (req, &ep->queue, queue) {
|
||||
list_for_each_entry(req, &ep->queue, queue) {
|
||||
if (&req->req == _req)
|
||||
break;
|
||||
}
|
||||
@ -1178,8 +1120,8 @@ static struct usb_ep_ops omap_ep_ops = {
|
||||
.dequeue = omap_ep_dequeue,
|
||||
|
||||
.set_halt = omap_ep_set_halt,
|
||||
// fifo_status ... report bytes in fifo
|
||||
// fifo_flush ... flush fifo
|
||||
/* fifo_status ... report bytes in fifo */
|
||||
/* fifo_flush ... flush fifo */
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -1211,7 +1153,7 @@ static int omap_wakeup(struct usb_gadget *gadget)
|
||||
|
||||
/* NOTE: non-OTG systems may use SRP TOO... */
|
||||
} else if (!(udc->devstat & UDC_ATT)) {
|
||||
if (udc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
retval = otg_start_srp(udc->transceiver->otg);
|
||||
}
|
||||
spin_unlock_irqrestore(&udc->lock, flags);
|
||||
@ -1343,7 +1285,7 @@ static int omap_vbus_draw(struct usb_gadget *gadget, unsigned mA)
|
||||
struct omap_udc *udc;
|
||||
|
||||
udc = container_of(gadget, struct omap_udc, gadget);
|
||||
if (udc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
return usb_phy_set_power(udc->transceiver, mA);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@ -1409,7 +1351,7 @@ static void udc_quiesce(struct omap_udc *udc)
|
||||
|
||||
udc->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
nuke(&udc->ep[0], -ESHUTDOWN);
|
||||
list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list)
|
||||
list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list)
|
||||
nuke(ep, -ESHUTDOWN);
|
||||
}
|
||||
|
||||
@ -1525,7 +1467,8 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
|
||||
/* read next OUT packet of request, maybe
|
||||
* reactiviting the fifo; stall on errors.
|
||||
*/
|
||||
if (!req || (stat = read_fifo(ep0, req)) < 0) {
|
||||
stat = read_fifo(ep0, req);
|
||||
if (!req || stat < 0) {
|
||||
omap_writew(UDC_STALL_CMD, UDC_SYSCON2);
|
||||
udc->ep0_pending = 0;
|
||||
stat = 0;
|
||||
@ -1658,7 +1601,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
|
||||
/* this has rude side-effects (aborts) and
|
||||
* can't really work if DMA-IN is active
|
||||
*/
|
||||
DBG("%s host set_halt, NYET \n", ep->name);
|
||||
DBG("%s host set_halt, NYET\n", ep->name);
|
||||
goto do_stall;
|
||||
}
|
||||
use_ep(ep, 0);
|
||||
@ -1749,7 +1692,7 @@ delegate:
|
||||
*/
|
||||
udc->ep0_setup = 1;
|
||||
spin_unlock(&udc->lock);
|
||||
status = udc->driver->setup (&udc->gadget, &u.r);
|
||||
status = udc->driver->setup(&udc->gadget, &u.r);
|
||||
spin_lock(&udc->lock);
|
||||
udc->ep0_setup = 0;
|
||||
}
|
||||
@ -1792,12 +1735,12 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
|
||||
if (devstat & UDC_ATT) {
|
||||
udc->gadget.speed = USB_SPEED_FULL;
|
||||
VDBG("connect\n");
|
||||
if (!udc->transceiver)
|
||||
if (IS_ERR_OR_NULL(udc->transceiver))
|
||||
pullup_enable(udc);
|
||||
// if (driver->connect) call it
|
||||
/* if (driver->connect) call it */
|
||||
} else if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
|
||||
udc->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
if (!udc->transceiver)
|
||||
if (IS_ERR_OR_NULL(udc->transceiver))
|
||||
pullup_disable(udc);
|
||||
DBG("disconnect, gadget %s\n",
|
||||
udc->driver->driver.name);
|
||||
@ -1826,7 +1769,7 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
|
||||
}
|
||||
if (change & UDC_SUS) {
|
||||
if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
|
||||
// FIXME tell isp1301 to suspend/resume (?)
|
||||
/* FIXME tell isp1301 to suspend/resume (?) */
|
||||
if (devstat & UDC_SUS) {
|
||||
VDBG("suspend\n");
|
||||
update_otg(udc);
|
||||
@ -1837,12 +1780,12 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
|
||||
udc->driver->suspend(&udc->gadget);
|
||||
spin_lock(&udc->lock);
|
||||
}
|
||||
if (udc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
usb_phy_set_suspend(
|
||||
udc->transceiver, 1);
|
||||
} else {
|
||||
VDBG("resume\n");
|
||||
if (udc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
usb_phy_set_suspend(
|
||||
udc->transceiver, 0);
|
||||
if (udc->gadget.speed == USB_SPEED_FULL
|
||||
@ -2029,7 +1972,7 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
|
||||
/* handle all non-DMA ISO transfers */
|
||||
list_for_each_entry (ep, &udc->iso, iso) {
|
||||
list_for_each_entry(ep, &udc->iso, iso) {
|
||||
u16 stat;
|
||||
struct omap_req *req;
|
||||
|
||||
@ -2088,15 +2031,11 @@ static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)
|
||||
|
||||
static inline int machine_without_vbus_sense(void)
|
||||
{
|
||||
return (machine_is_omap_innovator()
|
||||
return machine_is_omap_innovator()
|
||||
|| machine_is_omap_osk()
|
||||
|| machine_is_omap_apollon()
|
||||
#ifndef CONFIG_MACH_OMAP_H4_OTG
|
||||
|| machine_is_omap_h4()
|
||||
#endif
|
||||
|| machine_is_sx1()
|
||||
|| cpu_is_omap7xx() /* No known omap7xx boards with vbus sense */
|
||||
);
|
||||
/* No known omap7xx boards with vbus sense */
|
||||
|| cpu_is_omap7xx();
|
||||
}
|
||||
|
||||
static int omap_udc_start(struct usb_gadget_driver *driver,
|
||||
@ -2110,7 +2049,7 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
|
||||
if (!udc)
|
||||
return -ENODEV;
|
||||
if (!driver
|
||||
// FIXME if otg, check: driver->is_otg
|
||||
/* FIXME if otg, check: driver->is_otg */
|
||||
|| driver->max_speed < USB_SPEED_FULL
|
||||
|| !bind || !driver->setup)
|
||||
return -EINVAL;
|
||||
@ -2122,7 +2061,7 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
|
||||
}
|
||||
|
||||
/* reset state */
|
||||
list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
|
||||
list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
|
||||
ep->irqs = 0;
|
||||
if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
|
||||
continue;
|
||||
@ -2154,13 +2093,13 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
|
||||
omap_writew(UDC_IRQ_SRC_MASK, UDC_IRQ_SRC);
|
||||
|
||||
/* connect to bus through transceiver */
|
||||
if (udc->transceiver) {
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver)) {
|
||||
status = otg_set_peripheral(udc->transceiver->otg,
|
||||
&udc->gadget);
|
||||
if (status < 0) {
|
||||
ERR("can't bind to transceiver\n");
|
||||
if (driver->unbind) {
|
||||
driver->unbind (&udc->gadget);
|
||||
driver->unbind(&udc->gadget);
|
||||
udc->gadget.dev.driver = NULL;
|
||||
udc->driver = NULL;
|
||||
}
|
||||
@ -2168,9 +2107,9 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
|
||||
}
|
||||
} else {
|
||||
if (can_pullup(udc))
|
||||
pullup_enable (udc);
|
||||
pullup_enable(udc);
|
||||
else
|
||||
pullup_disable (udc);
|
||||
pullup_disable(udc);
|
||||
}
|
||||
|
||||
/* boards that don't have VBUS sensing can't autogate 48MHz;
|
||||
@ -2201,7 +2140,7 @@ static int omap_udc_stop(struct usb_gadget_driver *driver)
|
||||
if (machine_without_vbus_sense())
|
||||
omap_vbus_session(&udc->gadget, 0);
|
||||
|
||||
if (udc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
(void) otg_set_peripheral(udc->transceiver->otg, NULL);
|
||||
else
|
||||
pullup_disable(udc);
|
||||
@ -2229,7 +2168,7 @@ static int omap_udc_stop(struct usb_gadget_driver *driver)
|
||||
static const char proc_filename[] = "driver/udc";
|
||||
|
||||
#define FOURBITS "%s%s%s%s"
|
||||
#define EIGHTBITS FOURBITS FOURBITS
|
||||
#define EIGHTBITS "%s%s%s%s%s%s%s%s"
|
||||
|
||||
static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
|
||||
{
|
||||
@ -2251,12 +2190,21 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
|
||||
"\n%s %s%s%sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n",
|
||||
ep->name, buf,
|
||||
ep->double_buf ? "dbuf " : "",
|
||||
({char *s; switch(ep->ackwait){
|
||||
case 0: s = ""; break;
|
||||
case 1: s = "(ackw) "; break;
|
||||
case 2: s = "(ackw2) "; break;
|
||||
default: s = "(?) "; break;
|
||||
} s;}),
|
||||
({ char *s;
|
||||
switch (ep->ackwait) {
|
||||
case 0:
|
||||
s = "";
|
||||
break;
|
||||
case 1:
|
||||
s = "(ackw) ";
|
||||
break;
|
||||
case 2:
|
||||
s = "(ackw2) ";
|
||||
break;
|
||||
default:
|
||||
s = "(?) ";
|
||||
break;
|
||||
} s; }),
|
||||
ep->irqs, stat_flg,
|
||||
(stat_flg & UDC_NO_RXPACKET) ? "no_rxpacket " : "",
|
||||
(stat_flg & UDC_MISS_IN) ? "miss_in " : "",
|
||||
@ -2272,10 +2220,10 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
|
||||
(stat_flg & UDC_NON_ISO_FIFO_EMPTY) ? "fifo_empty " : "",
|
||||
(stat_flg & UDC_NON_ISO_FIFO_FULL) ? "fifo_full " : "");
|
||||
|
||||
if (list_empty (&ep->queue))
|
||||
if (list_empty(&ep->queue))
|
||||
seq_printf(s, "\t(queue empty)\n");
|
||||
else
|
||||
list_for_each_entry (req, &ep->queue, queue) {
|
||||
list_for_each_entry(req, &ep->queue, queue) {
|
||||
unsigned length = req->req.actual;
|
||||
|
||||
if (use_dma && buf[0]) {
|
||||
@ -2293,11 +2241,16 @@ static void proc_ep_show(struct seq_file *s, struct omap_ep *ep)
|
||||
static char *trx_mode(unsigned m, int enabled)
|
||||
{
|
||||
switch (m) {
|
||||
case 0: return enabled ? "*6wire" : "unused";
|
||||
case 1: return "4wire";
|
||||
case 2: return "3wire";
|
||||
case 3: return "6wire";
|
||||
default: return "unknown";
|
||||
case 0:
|
||||
return enabled ? "*6wire" : "unused";
|
||||
case 1:
|
||||
return "4wire";
|
||||
case 2:
|
||||
return "3wire";
|
||||
case 3:
|
||||
return "6wire";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@ -2307,12 +2260,9 @@ static int proc_otg_show(struct seq_file *s)
|
||||
u32 trans = 0;
|
||||
char *ctrl_name = "(UNKNOWN)";
|
||||
|
||||
/* XXX This needs major revision for OMAP2+ */
|
||||
tmp = omap_readl(OTG_REV);
|
||||
if (cpu_class_is_omap1()) {
|
||||
ctrl_name = "tranceiver_ctrl";
|
||||
trans = omap_readw(USB_TRANSCEIVER_CTRL);
|
||||
}
|
||||
ctrl_name = "tranceiver_ctrl";
|
||||
trans = omap_readw(USB_TRANSCEIVER_CTRL);
|
||||
seq_printf(s, "\nOTG rev %d.%d, %s %05x\n",
|
||||
tmp >> 4, tmp & 0xf, ctrl_name, trans);
|
||||
tmp = omap_readw(OTG_SYSCON_1);
|
||||
@ -2332,7 +2282,7 @@ static int proc_otg_show(struct seq_file *s)
|
||||
" b_ase_brst=%d hmc=%d\n", tmp,
|
||||
(tmp & OTG_EN) ? " otg_en" : "",
|
||||
(tmp & USBX_SYNCHRO) ? " synchro" : "",
|
||||
// much more SRP stuff
|
||||
/* much more SRP stuff */
|
||||
(tmp & SRP_DATA) ? " srp_data" : "",
|
||||
(tmp & SRP_VBUS) ? " srp_vbus" : "",
|
||||
(tmp & OTG_PADEN) ? " otg_paden" : "",
|
||||
@ -2399,14 +2349,12 @@ static int proc_udc_show(struct seq_file *s, void *_)
|
||||
HMC,
|
||||
udc->transceiver
|
||||
? udc->transceiver->label
|
||||
: ((cpu_is_omap1710() || cpu_is_omap24xx())
|
||||
: (cpu_is_omap1710()
|
||||
? "external" : "(none)"));
|
||||
if (cpu_class_is_omap1()) {
|
||||
seq_printf(s, "ULPD control %04x req %04x status %04x\n",
|
||||
omap_readw(ULPD_CLOCK_CTRL),
|
||||
omap_readw(ULPD_SOFT_REQ),
|
||||
omap_readw(ULPD_STATUS_REQ));
|
||||
}
|
||||
seq_printf(s, "ULPD control %04x req %04x status %04x\n",
|
||||
omap_readw(ULPD_CLOCK_CTRL),
|
||||
omap_readw(ULPD_SOFT_REQ),
|
||||
omap_readw(ULPD_STATUS_REQ));
|
||||
|
||||
/* OTG controller registers */
|
||||
if (!cpu_is_omap15xx())
|
||||
@ -2422,7 +2370,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
|
||||
(tmp & UDC_SELF_PWR) ? " self_pwr" : "",
|
||||
(tmp & UDC_SOFF_DIS) ? " soff_dis" : "",
|
||||
(tmp & UDC_PULLUP_EN) ? " PULLUP" : "");
|
||||
// syscon2 is write-only
|
||||
/* syscon2 is write-only */
|
||||
|
||||
/* UDC controller registers */
|
||||
if (!(tmp & UDC_PULLUP_EN)) {
|
||||
@ -2506,7 +2454,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
|
||||
if (tmp & UDC_ATT) {
|
||||
proc_ep_show(s, &udc->ep[0]);
|
||||
if (tmp & UDC_ADD) {
|
||||
list_for_each_entry (ep, &udc->gadget.ep_list,
|
||||
list_for_each_entry(ep, &udc->gadget.ep_list,
|
||||
ep.ep_list) {
|
||||
if (ep->ep.desc)
|
||||
proc_ep_show(s, ep);
|
||||
@ -2557,7 +2505,7 @@ static inline void remove_proc_file(void) {}
|
||||
* UDC_SYSCON_1.CFG_LOCK is set can now work. We won't use that
|
||||
* capability yet though.
|
||||
*/
|
||||
static unsigned __init
|
||||
static unsigned __devinit
|
||||
omap_ep_setup(char *name, u8 addr, u8 type,
|
||||
unsigned buf, unsigned maxp, int dbuf)
|
||||
{
|
||||
@ -2575,14 +2523,29 @@ omap_ep_setup(char *name, u8 addr, u8 type,
|
||||
/* chip setup ... bit values are same for IN, OUT */
|
||||
if (type == USB_ENDPOINT_XFER_ISOC) {
|
||||
switch (maxp) {
|
||||
case 8: epn_rxtx = 0 << 12; break;
|
||||
case 16: epn_rxtx = 1 << 12; break;
|
||||
case 32: epn_rxtx = 2 << 12; break;
|
||||
case 64: epn_rxtx = 3 << 12; break;
|
||||
case 128: epn_rxtx = 4 << 12; break;
|
||||
case 256: epn_rxtx = 5 << 12; break;
|
||||
case 512: epn_rxtx = 6 << 12; break;
|
||||
default: BUG();
|
||||
case 8:
|
||||
epn_rxtx = 0 << 12;
|
||||
break;
|
||||
case 16:
|
||||
epn_rxtx = 1 << 12;
|
||||
break;
|
||||
case 32:
|
||||
epn_rxtx = 2 << 12;
|
||||
break;
|
||||
case 64:
|
||||
epn_rxtx = 3 << 12;
|
||||
break;
|
||||
case 128:
|
||||
epn_rxtx = 4 << 12;
|
||||
break;
|
||||
case 256:
|
||||
epn_rxtx = 5 << 12;
|
||||
break;
|
||||
case 512:
|
||||
epn_rxtx = 6 << 12;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
epn_rxtx |= UDC_EPN_RX_ISO;
|
||||
dbuf = 1;
|
||||
@ -2591,15 +2554,24 @@ omap_ep_setup(char *name, u8 addr, u8 type,
|
||||
* and ignored for PIO-IN on newer chips
|
||||
* (for more reliable behavior)
|
||||
*/
|
||||
if (!use_dma || cpu_is_omap15xx() || cpu_is_omap24xx())
|
||||
if (!use_dma || cpu_is_omap15xx())
|
||||
dbuf = 0;
|
||||
|
||||
switch (maxp) {
|
||||
case 8: epn_rxtx = 0 << 12; break;
|
||||
case 16: epn_rxtx = 1 << 12; break;
|
||||
case 32: epn_rxtx = 2 << 12; break;
|
||||
case 64: epn_rxtx = 3 << 12; break;
|
||||
default: BUG();
|
||||
case 8:
|
||||
epn_rxtx = 0 << 12;
|
||||
break;
|
||||
case 16:
|
||||
epn_rxtx = 1 << 12;
|
||||
break;
|
||||
case 32:
|
||||
epn_rxtx = 2 << 12;
|
||||
break;
|
||||
case 64:
|
||||
epn_rxtx = 3 << 12;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
if (dbuf && addr)
|
||||
epn_rxtx |= UDC_EPN_RX_DB;
|
||||
@ -2639,7 +2611,7 @@ omap_ep_setup(char *name, u8 addr, u8 type,
|
||||
ep->ep.name = ep->name;
|
||||
ep->ep.ops = &omap_ep_ops;
|
||||
ep->ep.maxpacket = ep->maxpacket = maxp;
|
||||
list_add_tail (&ep->ep.ep_list, &udc->gadget.ep_list);
|
||||
list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@ -2647,11 +2619,11 @@ omap_ep_setup(char *name, u8 addr, u8 type,
|
||||
static void omap_udc_release(struct device *dev)
|
||||
{
|
||||
complete(udc->done);
|
||||
kfree (udc);
|
||||
kfree(udc);
|
||||
udc = NULL;
|
||||
}
|
||||
|
||||
static int __init
|
||||
static int __devinit
|
||||
omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
|
||||
{
|
||||
unsigned tmp, buf;
|
||||
@ -2665,13 +2637,13 @@ omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
|
||||
omap_writew(0, UDC_TXDMA_CFG);
|
||||
|
||||
/* UDC_PULLUP_EN gates the chip clock */
|
||||
// OTG_SYSCON_1 |= DEV_IDLE_EN;
|
||||
/* OTG_SYSCON_1 |= DEV_IDLE_EN; */
|
||||
|
||||
udc = kzalloc(sizeof(*udc), GFP_KERNEL);
|
||||
if (!udc)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init (&udc->lock);
|
||||
spin_lock_init(&udc->lock);
|
||||
|
||||
udc->gadget.ops = &omap_gadget_ops;
|
||||
udc->gadget.ep0 = &udc->ep[0].ep;
|
||||
@ -2701,13 +2673,13 @@ omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
|
||||
omap_writew(0, UDC_EP_TX(tmp));
|
||||
}
|
||||
|
||||
#define OMAP_BULK_EP(name,addr) \
|
||||
#define OMAP_BULK_EP(name, addr) \
|
||||
buf = omap_ep_setup(name "-bulk", addr, \
|
||||
USB_ENDPOINT_XFER_BULK, buf, 64, 1);
|
||||
#define OMAP_INT_EP(name,addr, maxp) \
|
||||
#define OMAP_INT_EP(name, addr, maxp) \
|
||||
buf = omap_ep_setup(name "-int", addr, \
|
||||
USB_ENDPOINT_XFER_INT, buf, maxp, 0);
|
||||
#define OMAP_ISO_EP(name,addr, maxp) \
|
||||
#define OMAP_ISO_EP(name, addr, maxp) \
|
||||
buf = omap_ep_setup(name "-iso", addr, \
|
||||
USB_ENDPOINT_XFER_ISOC, buf, maxp, 1);
|
||||
|
||||
@ -2788,15 +2760,18 @@ omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init omap_udc_probe(struct platform_device *pdev)
|
||||
static int __devinit omap_udc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int status = -ENODEV;
|
||||
int hmc;
|
||||
struct usb_phy *xceiv = NULL;
|
||||
const char *type = NULL;
|
||||
struct omap_usb_config *config = pdev->dev.platform_data;
|
||||
struct clk *dc_clk;
|
||||
struct clk *hhc_clk;
|
||||
struct clk *dc_clk = NULL;
|
||||
struct clk *hhc_clk = NULL;
|
||||
|
||||
if (cpu_is_omap7xx())
|
||||
use_dma = 0;
|
||||
|
||||
/* NOTE: "knows" the order of the resources! */
|
||||
if (!request_mem_region(pdev->resource[0].start,
|
||||
@ -2816,16 +2791,6 @@ static int __init omap_udc_probe(struct platform_device *pdev)
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
if (cpu_is_omap24xx()) {
|
||||
dc_clk = clk_get(&pdev->dev, "usb_fck");
|
||||
hhc_clk = clk_get(&pdev->dev, "usb_l4_ick");
|
||||
BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk));
|
||||
/* can't use omap_udc_enable_clock yet */
|
||||
clk_enable(dc_clk);
|
||||
clk_enable(hhc_clk);
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
if (cpu_is_omap7xx()) {
|
||||
dc_clk = clk_get(&pdev->dev, "usb_dc_ck");
|
||||
hhc_clk = clk_get(&pdev->dev, "l3_ocpi_ck");
|
||||
@ -2865,8 +2830,8 @@ static int __init omap_udc_probe(struct platform_device *pdev)
|
||||
* use it. Except for OTG, we don't _need_ to talk to one;
|
||||
* but not having one probably means no VBUS detection.
|
||||
*/
|
||||
xceiv = usb_get_transceiver();
|
||||
if (xceiv)
|
||||
xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (!IS_ERR_OR_NULL(xceiv))
|
||||
type = xceiv->label;
|
||||
else if (config->otg) {
|
||||
DBG("OTG requires external transceiver!\n");
|
||||
@ -2875,14 +2840,6 @@ static int __init omap_udc_probe(struct platform_device *pdev)
|
||||
|
||||
hmc = HMC_1610;
|
||||
|
||||
if (cpu_is_omap24xx()) {
|
||||
/* this could be transceiverless in one of the
|
||||
* "we don't need to know" modes.
|
||||
*/
|
||||
type = "external";
|
||||
goto known;
|
||||
}
|
||||
|
||||
switch (hmc) {
|
||||
case 0: /* POWERUP DEFAULT == 0 */
|
||||
case 4:
|
||||
@ -2898,7 +2855,7 @@ static int __init omap_udc_probe(struct platform_device *pdev)
|
||||
case 16:
|
||||
case 19:
|
||||
case 25:
|
||||
if (!xceiv) {
|
||||
if (IS_ERR_OR_NULL(xceiv)) {
|
||||
DBG("external transceiver not registered!\n");
|
||||
type = "unknown";
|
||||
}
|
||||
@ -2921,16 +2878,16 @@ bad_on_1710:
|
||||
goto cleanup0;
|
||||
}
|
||||
}
|
||||
known:
|
||||
|
||||
INFO("hmc mode %d, %s transceiver\n", hmc, type);
|
||||
|
||||
/* a "gadget" abstracts/virtualizes the controller */
|
||||
status = omap_udc_setup(pdev, xceiv);
|
||||
if (status) {
|
||||
if (status)
|
||||
goto cleanup0;
|
||||
}
|
||||
|
||||
xceiv = NULL;
|
||||
// "udc" is now valid
|
||||
/* "udc" is now valid */
|
||||
pullup_disable(udc);
|
||||
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
|
||||
udc->gadget.is_otg = (config->otg != 0);
|
||||
@ -2944,7 +2901,7 @@ known:
|
||||
|
||||
/* USB general purpose IRQ: ep0, state changes, dma, etc */
|
||||
status = request_irq(pdev->resource[1].start, omap_udc_irq,
|
||||
IRQF_SAMPLE_RANDOM, driver_name, udc);
|
||||
0, driver_name, udc);
|
||||
if (status != 0) {
|
||||
ERR("can't get irq %d, err %d\n",
|
||||
(int) pdev->resource[1].start, status);
|
||||
@ -2953,7 +2910,7 @@ known:
|
||||
|
||||
/* USB "non-iso" IRQ (PIO for all but ep0) */
|
||||
status = request_irq(pdev->resource[2].start, omap_udc_pio_irq,
|
||||
IRQF_SAMPLE_RANDOM, "omap_udc pio", udc);
|
||||
0, "omap_udc pio", udc);
|
||||
if (status != 0) {
|
||||
ERR("can't get irq %d, err %d\n",
|
||||
(int) pdev->resource[2].start, status);
|
||||
@ -2975,16 +2932,6 @@ known:
|
||||
clk_disable(dc_clk);
|
||||
}
|
||||
|
||||
if (cpu_is_omap24xx()) {
|
||||
udc->dc_clk = dc_clk;
|
||||
udc->hhc_clk = hhc_clk;
|
||||
/* FIXME OMAP2 don't release hhc & dc clock */
|
||||
#if 0
|
||||
clk_disable(hhc_clk);
|
||||
clk_disable(dc_clk);
|
||||
#endif
|
||||
}
|
||||
|
||||
create_proc_file();
|
||||
status = device_add(&udc->gadget.dev);
|
||||
if (status)
|
||||
@ -3006,14 +2953,14 @@ cleanup2:
|
||||
free_irq(pdev->resource[1].start, udc);
|
||||
|
||||
cleanup1:
|
||||
kfree (udc);
|
||||
kfree(udc);
|
||||
udc = NULL;
|
||||
|
||||
cleanup0:
|
||||
if (xceiv)
|
||||
usb_put_transceiver(xceiv);
|
||||
if (!IS_ERR_OR_NULL(xceiv))
|
||||
usb_put_phy(xceiv);
|
||||
|
||||
if (cpu_is_omap16xx() || cpu_is_omap24xx() || cpu_is_omap7xx()) {
|
||||
if (cpu_is_omap16xx() || cpu_is_omap7xx()) {
|
||||
clk_disable(hhc_clk);
|
||||
clk_disable(dc_clk);
|
||||
clk_put(hhc_clk);
|
||||
@ -3026,7 +2973,7 @@ cleanup0:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __exit omap_udc_remove(struct platform_device *pdev)
|
||||
static int __devexit omap_udc_remove(struct platform_device *pdev)
|
||||
{
|
||||
DECLARE_COMPLETION_ONSTACK(done);
|
||||
|
||||
@ -3040,8 +2987,8 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
|
||||
udc->done = &done;
|
||||
|
||||
pullup_disable(udc);
|
||||
if (udc->transceiver) {
|
||||
usb_put_transceiver(udc->transceiver);
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver)) {
|
||||
usb_put_phy(udc->transceiver);
|
||||
udc->transceiver = NULL;
|
||||
}
|
||||
omap_writew(0, UDC_SYSCON1);
|
||||
@ -3111,7 +3058,8 @@ static int omap_udc_resume(struct platform_device *dev)
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static struct platform_driver udc_driver = {
|
||||
.remove = __exit_p(omap_udc_remove),
|
||||
.probe = omap_udc_probe,
|
||||
.remove = __devexit_p(omap_udc_remove),
|
||||
.suspend = omap_udc_suspend,
|
||||
.resume = omap_udc_resume,
|
||||
.driver = {
|
||||
@ -3120,27 +3068,7 @@ static struct platform_driver udc_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init udc_init(void)
|
||||
{
|
||||
/* Disable DMA for omap7xx -- it doesn't work right. */
|
||||
if (cpu_is_omap7xx())
|
||||
use_dma = 0;
|
||||
|
||||
INFO("%s, version: " DRIVER_VERSION
|
||||
#ifdef USE_ISO
|
||||
" (iso)"
|
||||
#endif
|
||||
"%s\n", driver_desc,
|
||||
use_dma ? " (dma)" : "");
|
||||
return platform_driver_probe(&udc_driver, omap_udc_probe);
|
||||
}
|
||||
module_init(udc_init);
|
||||
|
||||
static void __exit udc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&udc_driver);
|
||||
}
|
||||
module_exit(udc_exit);
|
||||
module_platform_driver(udc_driver);
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -2208,7 +2208,7 @@ static void pch_udc_complete_receiver(struct pch_udc_ep *ep)
|
||||
return;
|
||||
}
|
||||
if ((td->status & PCH_UDC_BUFF_STS) == PCH_UDC_BS_DMA_DONE)
|
||||
if (td->status | PCH_UDC_DMA_LAST) {
|
||||
if (td->status & PCH_UDC_DMA_LAST) {
|
||||
count = td->status & PCH_UDC_RXTX_BYTES;
|
||||
break;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
@ -993,7 +994,7 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
|
||||
|
||||
udc = container_of(_gadget, struct pxa25x_udc, gadget);
|
||||
|
||||
if (udc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
return usb_phy_set_power(udc->transceiver, mA);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@ -1299,7 +1300,7 @@ fail:
|
||||
DMSG("registered gadget driver '%s'\n", driver->driver.name);
|
||||
|
||||
/* connect to bus through transceiver */
|
||||
if (dev->transceiver) {
|
||||
if (!IS_ERR_OR_NULL(dev->transceiver)) {
|
||||
retval = otg_set_peripheral(dev->transceiver->otg,
|
||||
&dev->gadget);
|
||||
if (retval) {
|
||||
@ -1359,7 +1360,7 @@ static int pxa25x_stop(struct usb_gadget_driver *driver)
|
||||
stop_activity(dev, driver);
|
||||
local_irq_enable();
|
||||
|
||||
if (dev->transceiver)
|
||||
if (!IS_ERR_OR_NULL(dev->transceiver))
|
||||
(void) otg_set_peripheral(dev->transceiver->otg, NULL);
|
||||
|
||||
driver->unbind(&dev->gadget);
|
||||
@ -2159,7 +2160,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
|
||||
dev->dev = &pdev->dev;
|
||||
dev->mach = pdev->dev.platform_data;
|
||||
|
||||
dev->transceiver = usb_get_transceiver();
|
||||
dev->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
|
||||
if (gpio_is_valid(dev->mach->gpio_pullup)) {
|
||||
if ((retval = gpio_request(dev->mach->gpio_pullup,
|
||||
@ -2237,8 +2238,8 @@ lubbock_fail0:
|
||||
if (gpio_is_valid(dev->mach->gpio_pullup))
|
||||
gpio_free(dev->mach->gpio_pullup);
|
||||
err_gpio_pullup:
|
||||
if (dev->transceiver) {
|
||||
usb_put_transceiver(dev->transceiver);
|
||||
if (!IS_ERR_OR_NULL(dev->transceiver)) {
|
||||
usb_put_phy(dev->transceiver);
|
||||
dev->transceiver = NULL;
|
||||
}
|
||||
clk_put(dev->clk);
|
||||
@ -2279,8 +2280,8 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
|
||||
|
||||
clk_put(dev->clk);
|
||||
|
||||
if (dev->transceiver) {
|
||||
usb_put_transceiver(dev->transceiver);
|
||||
if (!IS_ERR_OR_NULL(dev->transceiver)) {
|
||||
usb_put_phy(dev->transceiver);
|
||||
dev->transceiver = NULL;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/list.h>
|
||||
@ -1573,7 +1574,7 @@ static int should_enable_udc(struct pxa_udc *udc)
|
||||
int put_on;
|
||||
|
||||
put_on = ((udc->pullup_on) && (udc->driver));
|
||||
put_on &= ((udc->vbus_sensed) || (!udc->transceiver));
|
||||
put_on &= ((udc->vbus_sensed) || (IS_ERR_OR_NULL(udc->transceiver)));
|
||||
return put_on;
|
||||
}
|
||||
|
||||
@ -1594,7 +1595,7 @@ static int should_disable_udc(struct pxa_udc *udc)
|
||||
int put_off;
|
||||
|
||||
put_off = ((!udc->pullup_on) || (!udc->driver));
|
||||
put_off |= ((!udc->vbus_sensed) && (udc->transceiver));
|
||||
put_off |= ((!udc->vbus_sensed) && (!IS_ERR_OR_NULL(udc->transceiver)));
|
||||
return put_off;
|
||||
}
|
||||
|
||||
@ -1665,7 +1666,7 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
|
||||
struct pxa_udc *udc;
|
||||
|
||||
udc = to_gadget_udc(_gadget);
|
||||
if (udc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
return usb_phy_set_power(udc->transceiver, mA);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@ -1834,7 +1835,7 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver,
|
||||
dev_dbg(udc->dev, "registered gadget driver '%s'\n",
|
||||
driver->driver.name);
|
||||
|
||||
if (udc->transceiver) {
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver)) {
|
||||
retval = otg_set_peripheral(udc->transceiver->otg,
|
||||
&udc->gadget);
|
||||
if (retval) {
|
||||
@ -1908,7 +1909,7 @@ static int pxa27x_udc_stop(struct usb_gadget_driver *driver)
|
||||
dev_info(udc->dev, "unregistered gadget driver '%s'\n",
|
||||
driver->driver.name);
|
||||
|
||||
if (udc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(udc->transceiver))
|
||||
return otg_set_peripheral(udc->transceiver->otg, NULL);
|
||||
return 0;
|
||||
}
|
||||
@ -2464,7 +2465,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
|
||||
|
||||
udc->dev = &pdev->dev;
|
||||
udc->mach = pdev->dev.platform_data;
|
||||
udc->transceiver = usb_get_transceiver();
|
||||
udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
|
||||
gpio = udc->mach->gpio_pullup;
|
||||
if (gpio_is_valid(gpio)) {
|
||||
@ -2543,7 +2544,7 @@ static int __exit pxa_udc_remove(struct platform_device *_dev)
|
||||
if (gpio_is_valid(gpio))
|
||||
gpio_free(gpio);
|
||||
|
||||
usb_put_transceiver(udc->transceiver);
|
||||
usb_put_phy(udc->transceiver);
|
||||
|
||||
udc->transceiver = NULL;
|
||||
platform_set_drvdata(_dev, NULL);
|
||||
|
@ -112,7 +112,6 @@ struct s3c_hsotg_ep {
|
||||
struct s3c_hsotg_req *req;
|
||||
struct dentry *debugfs;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
unsigned long total_data;
|
||||
unsigned int size_loaded;
|
||||
@ -136,7 +135,6 @@ struct s3c_hsotg_ep {
|
||||
* @driver: USB gadget driver
|
||||
* @plat: The platform specific configuration data.
|
||||
* @regs: The memory area mapped for accessing registers.
|
||||
* @regs_res: The resource that was allocated when claiming register space.
|
||||
* @irq: The IRQ number we are using
|
||||
* @supplies: Definition of USB power supplies
|
||||
* @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
|
||||
@ -157,8 +155,9 @@ struct s3c_hsotg {
|
||||
struct usb_gadget_driver *driver;
|
||||
struct s3c_hsotg_plat *plat;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
void __iomem *regs;
|
||||
struct resource *regs_res;
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
|
||||
@ -896,7 +895,6 @@ static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
|
||||
struct s3c_hsotg_req *hs_req = our_req(req);
|
||||
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
|
||||
struct s3c_hsotg *hs = hs_ep->parent;
|
||||
unsigned long irqflags;
|
||||
bool first;
|
||||
|
||||
dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n",
|
||||
@ -915,19 +913,30 @@ static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
|
||||
return ret;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&hs_ep->lock, irqflags);
|
||||
|
||||
first = list_empty(&hs_ep->queue);
|
||||
list_add_tail(&hs_req->queue, &hs_ep->queue);
|
||||
|
||||
if (first)
|
||||
s3c_hsotg_start_req(hs, hs_ep, hs_req, false);
|
||||
|
||||
spin_unlock_irqrestore(&hs_ep->lock, irqflags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
|
||||
struct s3c_hsotg *hs = hs_ep->parent;
|
||||
unsigned long flags = 0;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&hs->lock, flags);
|
||||
ret = s3c_hsotg_ep_queue(ep, req, gfp_flags);
|
||||
spin_unlock_irqrestore(&hs->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void s3c_hsotg_ep_free_request(struct usb_ep *ep,
|
||||
struct usb_request *req)
|
||||
{
|
||||
@ -1383,9 +1392,9 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
|
||||
*/
|
||||
|
||||
if (hs_req->req.complete) {
|
||||
spin_unlock(&hs_ep->lock);
|
||||
spin_unlock(&hsotg->lock);
|
||||
hs_req->req.complete(&hs_ep->ep, &hs_req->req);
|
||||
spin_lock(&hs_ep->lock);
|
||||
spin_lock(&hsotg->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1403,28 +1412,6 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_complete_request_lock - complete a request given to us (locked)
|
||||
* @hsotg: The device state.
|
||||
* @hs_ep: The endpoint the request was on.
|
||||
* @hs_req: The request to complete.
|
||||
* @result: The result code (0 => Ok, otherwise errno)
|
||||
*
|
||||
* See s3c_hsotg_complete_request(), but called with the endpoint's
|
||||
* lock held.
|
||||
*/
|
||||
static void s3c_hsotg_complete_request_lock(struct s3c_hsotg *hsotg,
|
||||
struct s3c_hsotg_ep *hs_ep,
|
||||
struct s3c_hsotg_req *hs_req,
|
||||
int result)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&hs_ep->lock, flags);
|
||||
s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
|
||||
spin_unlock_irqrestore(&hs_ep->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_rx_data - receive data from the FIFO for an endpoint
|
||||
* @hsotg: The device state.
|
||||
@ -1444,6 +1431,7 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
|
||||
int max_req;
|
||||
int read_ptr;
|
||||
|
||||
|
||||
if (!hs_req) {
|
||||
u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx));
|
||||
int ptr;
|
||||
@ -1459,8 +1447,6 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock(&hs_ep->lock);
|
||||
|
||||
to_read = size;
|
||||
read_ptr = hs_req->req.actual;
|
||||
max_req = hs_req->req.length - read_ptr;
|
||||
@ -1487,8 +1473,6 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
|
||||
* alignment of the data.
|
||||
*/
|
||||
readsl(fifo, hs_req->req.buf + read_ptr, to_read);
|
||||
|
||||
spin_unlock(&hs_ep->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1609,7 +1593,7 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
|
||||
s3c_hsotg_send_zlp(hsotg, hs_req);
|
||||
}
|
||||
|
||||
s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, result);
|
||||
s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1864,7 +1848,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
|
||||
/* Finish ZLP handling for IN EP0 transactions */
|
||||
if (hsotg->eps[0].sent_zlp) {
|
||||
dev_dbg(hsotg->dev, "zlp packet received\n");
|
||||
s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0);
|
||||
s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1915,7 +1899,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
|
||||
dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__);
|
||||
s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true);
|
||||
} else
|
||||
s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0);
|
||||
s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2123,9 +2107,6 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
|
||||
int result, bool force)
|
||||
{
|
||||
struct s3c_hsotg_req *req, *treq;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ep->lock, flags);
|
||||
|
||||
list_for_each_entry_safe(req, treq, &ep->queue, queue) {
|
||||
/*
|
||||
@ -2139,14 +2120,15 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
|
||||
s3c_hsotg_complete_request(hsotg, ep, req,
|
||||
result);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ep->lock, flags);
|
||||
}
|
||||
|
||||
#define call_gadget(_hs, _entry) \
|
||||
if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \
|
||||
(_hs)->driver && (_hs)->driver->_entry) \
|
||||
(_hs)->driver->_entry(&(_hs)->gadget);
|
||||
(_hs)->driver && (_hs)->driver->_entry) { \
|
||||
spin_unlock(&_hs->lock); \
|
||||
(_hs)->driver->_entry(&(_hs)->gadget); \
|
||||
spin_lock(&_hs->lock); \
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_disconnect - disconnect service
|
||||
@ -2388,6 +2370,7 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
|
||||
u32 gintsts;
|
||||
u32 gintmsk;
|
||||
|
||||
spin_lock(&hsotg->lock);
|
||||
irq_retry:
|
||||
gintsts = readl(hsotg->regs + GINTSTS);
|
||||
gintmsk = readl(hsotg->regs + GINTMSK);
|
||||
@ -2557,6 +2540,8 @@ irq_retry:
|
||||
if (gintsts & IRQ_RETRY_MASK && --retry_count > 0)
|
||||
goto irq_retry;
|
||||
|
||||
spin_unlock(&hsotg->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -2604,7 +2589,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
|
||||
dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n",
|
||||
__func__, epctrl, epctrl_reg);
|
||||
|
||||
spin_lock_irqsave(&hs_ep->lock, flags);
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
|
||||
epctrl &= ~(DxEPCTL_EPType_MASK | DxEPCTL_MPS_MASK);
|
||||
epctrl |= DxEPCTL_MPS(mps);
|
||||
@ -2683,7 +2668,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
|
||||
s3c_hsotg_ctrl_epint(hsotg, index, dir_in, 1);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&hs_ep->lock, flags);
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2710,10 +2695,10 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
|
||||
|
||||
epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
/* terminate all requests with shutdown */
|
||||
kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false);
|
||||
|
||||
spin_lock_irqsave(&hs_ep->lock, flags);
|
||||
|
||||
ctrl = readl(hsotg->regs + epctrl_reg);
|
||||
ctrl &= ~DxEPCTL_EPEna;
|
||||
@ -2726,7 +2711,7 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
|
||||
/* disable endpoint interrupts */
|
||||
s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0);
|
||||
|
||||
spin_unlock_irqrestore(&hs_ep->lock, flags);
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2761,15 +2746,15 @@ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
|
||||
|
||||
dev_info(hs->dev, "ep_dequeue(%p,%p)\n", ep, req);
|
||||
|
||||
spin_lock_irqsave(&hs_ep->lock, flags);
|
||||
spin_lock_irqsave(&hs->lock, flags);
|
||||
|
||||
if (!on_list(hs_ep, hs_req)) {
|
||||
spin_unlock_irqrestore(&hs_ep->lock, flags);
|
||||
spin_unlock_irqrestore(&hs->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s3c_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET);
|
||||
spin_unlock_irqrestore(&hs_ep->lock, flags);
|
||||
spin_unlock_irqrestore(&hs->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2784,15 +2769,12 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
|
||||
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
|
||||
struct s3c_hsotg *hs = hs_ep->parent;
|
||||
int index = hs_ep->index;
|
||||
unsigned long irqflags;
|
||||
u32 epreg;
|
||||
u32 epctl;
|
||||
u32 xfertype;
|
||||
|
||||
dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value);
|
||||
|
||||
spin_lock_irqsave(&hs_ep->lock, irqflags);
|
||||
|
||||
/* write both IN and OUT control registers */
|
||||
|
||||
epreg = DIEPCTL(index);
|
||||
@ -2827,19 +2809,36 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
|
||||
|
||||
writel(epctl, hs->regs + epreg);
|
||||
|
||||
spin_unlock_irqrestore(&hs_ep->lock, irqflags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held
|
||||
* @ep: The endpoint to set halt.
|
||||
* @value: Set or unset the halt.
|
||||
*/
|
||||
static int s3c_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value)
|
||||
{
|
||||
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
|
||||
struct s3c_hsotg *hs = hs_ep->parent;
|
||||
unsigned long flags = 0;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&hs->lock, flags);
|
||||
ret = s3c_hsotg_ep_sethalt(ep, value);
|
||||
spin_unlock_irqrestore(&hs->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct usb_ep_ops s3c_hsotg_ep_ops = {
|
||||
.enable = s3c_hsotg_ep_enable,
|
||||
.disable = s3c_hsotg_ep_disable,
|
||||
.alloc_request = s3c_hsotg_ep_alloc_request,
|
||||
.free_request = s3c_hsotg_ep_free_request,
|
||||
.queue = s3c_hsotg_ep_queue,
|
||||
.queue = s3c_hsotg_ep_queue_lock,
|
||||
.dequeue = s3c_hsotg_ep_dequeue,
|
||||
.set_halt = s3c_hsotg_ep_sethalt,
|
||||
.set_halt = s3c_hsotg_ep_sethalt_lock,
|
||||
/* note, don't believe we have any call for the fifo routines */
|
||||
};
|
||||
|
||||
@ -2954,6 +2953,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
|
||||
driver->driver.bus = NULL;
|
||||
hsotg->driver = driver;
|
||||
hsotg->gadget.dev.driver = &driver->driver;
|
||||
hsotg->gadget.dev.of_node = hsotg->dev->of_node;
|
||||
hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask;
|
||||
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
|
||||
@ -2964,9 +2964,6 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
|
||||
goto err;
|
||||
}
|
||||
|
||||
s3c_hsotg_phy_enable(hsotg);
|
||||
|
||||
s3c_hsotg_core_init(hsotg);
|
||||
hsotg->last_rst = jiffies;
|
||||
dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
|
||||
return 0;
|
||||
@ -2988,6 +2985,7 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
struct s3c_hsotg *hsotg = to_hsotg(gadget);
|
||||
unsigned long flags = 0;
|
||||
int ep;
|
||||
|
||||
if (!hsotg)
|
||||
@ -3000,6 +2998,8 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
|
||||
for (ep = 0; ep < hsotg->num_of_eps; ep++)
|
||||
s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
|
||||
s3c_hsotg_phy_disable(hsotg);
|
||||
regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
|
||||
|
||||
@ -3007,6 +3007,8 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
|
||||
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
hsotg->gadget.dev.driver = NULL;
|
||||
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
dev_info(hsotg->dev, "unregistered gadget driver '%s'\n",
|
||||
driver->driver.name);
|
||||
|
||||
@ -3024,10 +3026,40 @@ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
|
||||
return s3c_hsotg_read_frameno(to_hsotg(gadget));
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_pullup - connect/disconnect the USB PHY
|
||||
* @gadget: The usb gadget state
|
||||
* @is_on: Current state of the USB PHY
|
||||
*
|
||||
* Connect/Disconnect the USB PHY pullup
|
||||
*/
|
||||
static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on)
|
||||
{
|
||||
struct s3c_hsotg *hsotg = to_hsotg(gadget);
|
||||
unsigned long flags = 0;
|
||||
|
||||
dev_dbg(hsotg->dev, "%s: is_in: %d\n", __func__, is_on);
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
if (is_on) {
|
||||
s3c_hsotg_phy_enable(hsotg);
|
||||
s3c_hsotg_core_init(hsotg);
|
||||
} else {
|
||||
s3c_hsotg_disconnect(hsotg);
|
||||
s3c_hsotg_phy_disable(hsotg);
|
||||
}
|
||||
|
||||
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_gadget_ops s3c_hsotg_gadget_ops = {
|
||||
.get_frame = s3c_hsotg_gadget_getframe,
|
||||
.udc_start = s3c_hsotg_udc_start,
|
||||
.udc_stop = s3c_hsotg_udc_stop,
|
||||
.pullup = s3c_hsotg_pullup,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -3063,8 +3095,6 @@ static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg,
|
||||
INIT_LIST_HEAD(&hs_ep->queue);
|
||||
INIT_LIST_HEAD(&hs_ep->ep.ep_list);
|
||||
|
||||
spin_lock_init(&hs_ep->lock);
|
||||
|
||||
/* add to the list of endpoints known by the gadget driver */
|
||||
if (epnum)
|
||||
list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list);
|
||||
@ -3342,7 +3372,7 @@ static int ep_show(struct seq_file *seq, void *v)
|
||||
seq_printf(seq, "request list (%p,%p):\n",
|
||||
ep->queue.next, ep->queue.prev);
|
||||
|
||||
spin_lock_irqsave(&ep->lock, flags);
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
|
||||
list_for_each_entry(req, &ep->queue, queue) {
|
||||
if (--show_limit < 0) {
|
||||
@ -3357,7 +3387,7 @@ static int ep_show(struct seq_file *seq, void *v)
|
||||
req->req.actual, req->req.status);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ep->lock, flags);
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3477,7 +3507,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hsotg = kzalloc(sizeof(struct s3c_hsotg), GFP_KERNEL);
|
||||
hsotg = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsotg), GFP_KERNEL);
|
||||
if (!hsotg) {
|
||||
dev_err(dev, "cannot get memory\n");
|
||||
return -ENOMEM;
|
||||
@ -3489,46 +3519,35 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
|
||||
hsotg->clk = clk_get(&pdev->dev, "otg");
|
||||
if (IS_ERR(hsotg->clk)) {
|
||||
dev_err(dev, "cannot get otg clock\n");
|
||||
ret = PTR_ERR(hsotg->clk);
|
||||
goto err_mem;
|
||||
return PTR_ERR(hsotg->clk);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, hsotg);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "cannot find register resource 0\n");
|
||||
ret = -EINVAL;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
hsotg->regs_res = request_mem_region(res->start, resource_size(res),
|
||||
dev_name(dev));
|
||||
if (!hsotg->regs_res) {
|
||||
dev_err(dev, "cannot reserve registers\n");
|
||||
ret = -ENOENT;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
hsotg->regs = ioremap(res->start, resource_size(res));
|
||||
hsotg->regs = devm_request_and_ioremap(&pdev->dev, res);
|
||||
if (!hsotg->regs) {
|
||||
dev_err(dev, "cannot map registers\n");
|
||||
ret = -ENXIO;
|
||||
goto err_regs_res;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot find IRQ\n");
|
||||
goto err_regs;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
spin_lock_init(&hsotg->lock);
|
||||
|
||||
hsotg->irq = ret;
|
||||
|
||||
ret = request_irq(ret, s3c_hsotg_irq, 0, dev_name(dev), hsotg);
|
||||
ret = devm_request_irq(&pdev->dev, hsotg->irq, s3c_hsotg_irq, 0,
|
||||
dev_name(dev), hsotg);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot claim IRQ\n");
|
||||
goto err_regs;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq);
|
||||
@ -3558,7 +3577,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
|
||||
hsotg->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request supplies: %d\n", ret);
|
||||
goto err_irq;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
|
||||
@ -3642,19 +3661,11 @@ err_ep_mem:
|
||||
err_supplies:
|
||||
s3c_hsotg_phy_disable(hsotg);
|
||||
regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
|
||||
err_irq:
|
||||
free_irq(hsotg->irq, hsotg);
|
||||
err_regs:
|
||||
iounmap(hsotg->regs);
|
||||
|
||||
err_regs_res:
|
||||
release_resource(hsotg->regs_res);
|
||||
kfree(hsotg->regs_res);
|
||||
err_clk:
|
||||
clk_disable_unprepare(hsotg->clk);
|
||||
clk_put(hsotg->clk);
|
||||
err_mem:
|
||||
kfree(hsotg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -3675,12 +3686,6 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
|
||||
usb_gadget_unregister_driver(hsotg->driver);
|
||||
}
|
||||
|
||||
free_irq(hsotg->irq, hsotg);
|
||||
iounmap(hsotg->regs);
|
||||
|
||||
release_resource(hsotg->regs_res);
|
||||
kfree(hsotg->regs_res);
|
||||
|
||||
s3c_hsotg_phy_disable(hsotg);
|
||||
regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/otg.h>
|
||||
@ -1165,7 +1166,7 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
|
||||
}
|
||||
|
||||
/* connect to bus through transceiver */
|
||||
if (hsudc->transceiver) {
|
||||
if (!IS_ERR_OR_NULL(hsudc->transceiver)) {
|
||||
ret = otg_set_peripheral(hsudc->transceiver->otg,
|
||||
&hsudc->gadget);
|
||||
if (ret) {
|
||||
@ -1220,7 +1221,7 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget,
|
||||
s3c_hsudc_stop_activity(hsudc);
|
||||
spin_unlock_irqrestore(&hsudc->lock, flags);
|
||||
|
||||
if (hsudc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(hsudc->transceiver))
|
||||
(void) otg_set_peripheral(hsudc->transceiver->otg, NULL);
|
||||
|
||||
disable_irq(hsudc->irq);
|
||||
@ -1249,7 +1250,7 @@ static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
|
||||
if (!hsudc)
|
||||
return -ENODEV;
|
||||
|
||||
if (hsudc->transceiver)
|
||||
if (!IS_ERR_OR_NULL(hsudc->transceiver))
|
||||
return usb_phy_set_power(hsudc->transceiver, mA);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
@ -1282,7 +1283,7 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
|
||||
hsudc->dev = dev;
|
||||
hsudc->pd = pdev->dev.platform_data;
|
||||
|
||||
hsudc->transceiver = usb_get_transceiver();
|
||||
hsudc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
|
||||
hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
|
||||
@ -1385,8 +1386,8 @@ err_irq:
|
||||
err_remap:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
err_res:
|
||||
if (hsudc->transceiver)
|
||||
usb_put_transceiver(hsudc->transceiver);
|
||||
if (!IS_ERR_OR_NULL(hsudc->transceiver))
|
||||
usb_put_phy(hsudc->transceiver);
|
||||
|
||||
regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
|
||||
err_supplies:
|
||||
|
@ -37,12 +37,6 @@
|
||||
* When FSG_NO_OTG is defined fsg_otg_desc won't be defined.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included
|
||||
* the fsg_buffhd structure's buf field will be an array of FSG_BUFLEN
|
||||
* characters rather then a pointer to void.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When USB_GADGET_DEBUG_FILES is defined the module param num_buffers
|
||||
* sets the number of pipeline buffers (length of the fsg_buffhd array).
|
||||
@ -260,11 +254,7 @@ enum fsg_buffer_state {
|
||||
};
|
||||
|
||||
struct fsg_buffhd {
|
||||
#ifdef FSG_BUFFHD_STATIC_BUFFER
|
||||
char buf[FSG_BUFLEN];
|
||||
#else
|
||||
void *buf;
|
||||
#endif
|
||||
enum fsg_buffer_state state;
|
||||
struct fsg_buffhd *next;
|
||||
|
||||
@ -627,6 +617,16 @@ static struct usb_gadget_strings fsg_stringtab = {
|
||||
* the caller must own fsg->filesem for writing.
|
||||
*/
|
||||
|
||||
static void fsg_lun_close(struct fsg_lun *curlun)
|
||||
{
|
||||
if (curlun->filp) {
|
||||
LDBG(curlun, "close backing file\n");
|
||||
fput(curlun->filp);
|
||||
curlun->filp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
|
||||
{
|
||||
int ro;
|
||||
@ -636,6 +636,8 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
|
||||
loff_t size;
|
||||
loff_t num_sectors;
|
||||
loff_t min_sectors;
|
||||
unsigned int blkbits;
|
||||
unsigned int blksize;
|
||||
|
||||
/* R/W if we can, R/O if we must */
|
||||
ro = curlun->initially_ro;
|
||||
@ -680,17 +682,17 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
|
||||
}
|
||||
|
||||
if (curlun->cdrom) {
|
||||
curlun->blksize = 2048;
|
||||
curlun->blkbits = 11;
|
||||
blksize = 2048;
|
||||
blkbits = 11;
|
||||
} else if (inode->i_bdev) {
|
||||
curlun->blksize = bdev_logical_block_size(inode->i_bdev);
|
||||
curlun->blkbits = blksize_bits(curlun->blksize);
|
||||
blksize = bdev_logical_block_size(inode->i_bdev);
|
||||
blkbits = blksize_bits(blksize);
|
||||
} else {
|
||||
curlun->blksize = 512;
|
||||
curlun->blkbits = 9;
|
||||
blksize = 512;
|
||||
blkbits = 9;
|
||||
}
|
||||
|
||||
num_sectors = size >> curlun->blkbits; /* File size in logic-block-size blocks */
|
||||
num_sectors = size >> blkbits; /* File size in logic-block-size blocks */
|
||||
min_sectors = 1;
|
||||
if (curlun->cdrom) {
|
||||
min_sectors = 300; /* Smallest track is 300 frames */
|
||||
@ -707,7 +709,12 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fsg_lun_is_open(curlun))
|
||||
fsg_lun_close(curlun);
|
||||
|
||||
get_file(filp);
|
||||
curlun->blksize = blksize;
|
||||
curlun->blkbits = blkbits;
|
||||
curlun->ro = ro;
|
||||
curlun->filp = filp;
|
||||
curlun->file_length = size;
|
||||
@ -721,16 +728,6 @@ out:
|
||||
}
|
||||
|
||||
|
||||
static void fsg_lun_close(struct fsg_lun *curlun)
|
||||
{
|
||||
if (curlun->filp) {
|
||||
LDBG(curlun, "close backing file\n");
|
||||
fput(curlun->filp);
|
||||
curlun->filp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
@ -881,19 +878,17 @@ static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
|
||||
if (count > 0 && buf[count-1] == '\n')
|
||||
((char *) buf)[count-1] = 0; /* Ugh! */
|
||||
|
||||
/* Eject current medium */
|
||||
down_write(filesem);
|
||||
if (fsg_lun_is_open(curlun)) {
|
||||
fsg_lun_close(curlun);
|
||||
curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
|
||||
}
|
||||
|
||||
/* Load new medium */
|
||||
down_write(filesem);
|
||||
if (count > 0 && buf[0]) {
|
||||
/* fsg_lun_open() will close existing file if any. */
|
||||
rc = fsg_lun_open(curlun, buf);
|
||||
if (rc == 0)
|
||||
curlun->unit_attention_data =
|
||||
SS_NOT_READY_TO_READY_TRANSITION;
|
||||
} else if (fsg_lun_is_open(curlun)) {
|
||||
fsg_lun_close(curlun);
|
||||
curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
|
||||
}
|
||||
up_write(filesem);
|
||||
return (rc < 0 ? rc : count);
|
||||
|
@ -798,12 +798,6 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
|
||||
|
||||
SET_ETHTOOL_OPS(net, &ops);
|
||||
|
||||
/* two kinds of host-initiated state changes:
|
||||
* - iff DATA transfer is active, carrier is "on"
|
||||
* - tx queueing enabled if open *and* carrier is "on"
|
||||
*/
|
||||
netif_carrier_off(net);
|
||||
|
||||
dev->gadget = g;
|
||||
SET_NETDEV_DEV(net, &g->dev);
|
||||
SET_NETDEV_DEVTYPE(net, &gadget_type);
|
||||
@ -817,6 +811,12 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
|
||||
INFO(dev, "HOST MAC %pM\n", dev->host_mac);
|
||||
|
||||
the_dev = dev;
|
||||
|
||||
/* two kinds of host-initiated state changes:
|
||||
* - iff DATA transfer is active, carrier is "on"
|
||||
* - tx queueing enabled if open *and* carrier is "on"
|
||||
*/
|
||||
netif_carrier_off(net);
|
||||
}
|
||||
|
||||
return status;
|
||||
|
@ -153,9 +153,11 @@ struct uvc_device
|
||||
|
||||
/* Descriptors */
|
||||
struct {
|
||||
const struct uvc_descriptor_header * const *control;
|
||||
const struct uvc_descriptor_header * const *fs_control;
|
||||
const struct uvc_descriptor_header * const *ss_control;
|
||||
const struct uvc_descriptor_header * const *fs_streaming;
|
||||
const struct uvc_descriptor_header * const *hs_streaming;
|
||||
const struct uvc_descriptor_header * const *ss_streaming;
|
||||
} desc;
|
||||
|
||||
unsigned int control_intf;
|
||||
|
@ -272,7 +272,15 @@ static const struct uvc_color_matching_descriptor uvc_color_matching = {
|
||||
.bMatrixCoefficients = 4,
|
||||
};
|
||||
|
||||
static const struct uvc_descriptor_header * const uvc_control_cls[] = {
|
||||
static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
|
||||
(const struct uvc_descriptor_header *) &uvc_control_header,
|
||||
(const struct uvc_descriptor_header *) &uvc_camera_terminal,
|
||||
(const struct uvc_descriptor_header *) &uvc_processing,
|
||||
(const struct uvc_descriptor_header *) &uvc_output_terminal,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
|
||||
(const struct uvc_descriptor_header *) &uvc_control_header,
|
||||
(const struct uvc_descriptor_header *) &uvc_camera_terminal,
|
||||
(const struct uvc_descriptor_header *) &uvc_processing,
|
||||
@ -304,6 +312,18 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
|
||||
(const struct uvc_descriptor_header *) &uvc_input_header,
|
||||
(const struct uvc_descriptor_header *) &uvc_format_yuv,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
|
||||
(const struct uvc_descriptor_header *) &uvc_format_mjpg,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
|
||||
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
|
||||
(const struct uvc_descriptor_header *) &uvc_color_matching,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* USB configuration
|
||||
*/
|
||||
@ -311,8 +331,9 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
|
||||
static int __init
|
||||
webcam_config_bind(struct usb_configuration *c)
|
||||
{
|
||||
return uvc_bind_config(c, uvc_control_cls, uvc_fs_streaming_cls,
|
||||
uvc_hs_streaming_cls);
|
||||
return uvc_bind_config(c, uvc_fs_control_cls, uvc_ss_control_cls,
|
||||
uvc_fs_streaming_cls, uvc_hs_streaming_cls,
|
||||
uvc_ss_streaming_cls);
|
||||
}
|
||||
|
||||
static struct usb_configuration webcam_config_driver = {
|
||||
@ -373,7 +394,7 @@ static struct usb_composite_driver webcam_driver = {
|
||||
.name = "g_webcam",
|
||||
.dev = &webcam_device_descriptor,
|
||||
.strings = webcam_device_strings,
|
||||
.max_speed = USB_SPEED_HIGH,
|
||||
.max_speed = USB_SPEED_SUPER,
|
||||
.unbind = webcam_unbind,
|
||||
};
|
||||
|
||||
|
@ -652,7 +652,7 @@ config USB_HCD_BCMA
|
||||
select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
|
||||
select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
|
||||
help
|
||||
Enbale support for the EHCI and OCHI host controller on an bcma bus.
|
||||
Enable support for the EHCI and OCHI host controller on an bcma bus.
|
||||
It converts the bcma driver into two platform device drivers
|
||||
for ehci and ohci.
|
||||
|
||||
@ -664,7 +664,7 @@ config USB_HCD_SSB
|
||||
select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
|
||||
select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
|
||||
help
|
||||
Enbale support for the EHCI and OCHI host controller on an bcma bus.
|
||||
Enable support for the EHCI and OCHI host controller on an bcma bus.
|
||||
It converts the bcma driver into two platform device drivers
|
||||
for ehci and ohci.
|
||||
|
||||
|
@ -53,30 +53,15 @@ static void atmel_stop_ehci(struct platform_device *pdev)
|
||||
static int ehci_atmel_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval = 0;
|
||||
int retval;
|
||||
|
||||
/* registers start at offset 0x0 */
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
retval = ehci_setup(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* data structure init */
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
ehci_reset(ehci);
|
||||
ehci_port_power(ehci, 0);
|
||||
|
||||
return retval;
|
||||
|
@ -20,10 +20,12 @@ extern int usb_disabled(void);
|
||||
static int au1xxx_ehci_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int ret = ehci_init(hcd);
|
||||
int ret;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ret = ehci_setup(hcd);
|
||||
|
||||
ehci->need_io_watchdog = 0;
|
||||
ehci_reset(ehci);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -78,7 +80,6 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
|
||||
static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct ehci_hcd *ehci;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
@ -116,13 +117,6 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
|
||||
goto err3;
|
||||
}
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||
|
||||
ret = usb_add_hcd(hcd, pdev->resource[1].start,
|
||||
IRQF_SHARED);
|
||||
if (ret == 0) {
|
||||
@ -158,28 +152,10 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
|
||||
static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(10);
|
||||
|
||||
/* Root hub was already suspended. Disable irq emission and
|
||||
* mark HW unaccessible. The PM and USB cores make sure that
|
||||
* the root hub is either suspended or stopped.
|
||||
*/
|
||||
ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
|
||||
// could save FLADJ in case of Vaux power loss
|
||||
// ... we'd only use it to handle clock skew
|
||||
bool do_wakeup = device_may_wakeup(dev);
|
||||
int rc;
|
||||
|
||||
rc = ehci_suspend(hcd, do_wakeup);
|
||||
alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
|
||||
|
||||
return rc;
|
||||
@ -188,56 +164,9 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
|
||||
static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
alchemy_usb_control(ALCHEMY_USB_EHCI0, 1);
|
||||
|
||||
// maybe restore FLADJ
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(100);
|
||||
|
||||
/* Mark hardware accessible again as we are out of D3 state by now */
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* If CF is still set, we maintained PCI Vaux power.
|
||||
* Just undo the effect of ehci_pci_suspend().
|
||||
*/
|
||||
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
|
||||
int mask = INTR_MASK;
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
if (!hcd->self.root_hub->do_remote_wakeup)
|
||||
mask &= ~STS_PCD;
|
||||
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
|
||||
ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ehci_dbg(ehci, "lost power, restarting\n");
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
|
||||
/* Else reset, to cope with power loss or flush-to-storage
|
||||
* style "resume" having let BIOS kick in during reboot.
|
||||
*/
|
||||
(void) ehci_halt(ehci);
|
||||
(void) ehci_reset(ehci);
|
||||
|
||||
/* emptying the schedule aborts any urbs */
|
||||
spin_lock_irq(&ehci->lock);
|
||||
if (ehci->reclaim)
|
||||
end_unlink_async(ehci);
|
||||
ehci_work(ehci);
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
|
||||
ehci_writel(ehci, ehci->command, &ehci->regs->command);
|
||||
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
|
||||
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
|
||||
|
||||
/* here we "know" root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
ehci_resume(hcd, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -33,14 +33,10 @@ static int cns3xxx_ehci_init(struct usb_hcd *hcd)
|
||||
}
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs
|
||||
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
hcd->has_tt = 0;
|
||||
ehci_reset(ehci);
|
||||
|
||||
retval = ehci_init(hcd);
|
||||
retval = ehci_setup(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/fsl_devices.h>
|
||||
|
||||
@ -142,19 +143,19 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
|
||||
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
ehci->transceiver = usb_get_transceiver();
|
||||
dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, transceiver=0x%p\n",
|
||||
hcd, ehci, ehci->transceiver);
|
||||
hcd->phy = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, phy=0x%p\n",
|
||||
hcd, ehci, hcd->phy);
|
||||
|
||||
if (ehci->transceiver) {
|
||||
retval = otg_set_host(ehci->transceiver->otg,
|
||||
if (!IS_ERR_OR_NULL(hcd->phy)) {
|
||||
retval = otg_set_host(hcd->phy->otg,
|
||||
&ehci_to_hcd(ehci)->self);
|
||||
if (retval) {
|
||||
usb_put_transceiver(ehci->transceiver);
|
||||
usb_put_phy(hcd->phy);
|
||||
goto err4;
|
||||
}
|
||||
} else {
|
||||
dev_err(&pdev->dev, "can't find transceiver\n");
|
||||
dev_err(&pdev->dev, "can't find phy\n");
|
||||
retval = -ENODEV;
|
||||
goto err4;
|
||||
}
|
||||
@ -190,11 +191,10 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
if (ehci->transceiver) {
|
||||
otg_set_host(ehci->transceiver->otg, NULL);
|
||||
usb_put_transceiver(ehci->transceiver);
|
||||
if (!IS_ERR_OR_NULL(hcd->phy)) {
|
||||
otg_set_host(hcd->phy->otg, NULL);
|
||||
usb_put_phy(hcd->phy);
|
||||
}
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
@ -348,29 +348,13 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
|
||||
|
||||
/* EHCI registers start at offset 0x100 */
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
hcd->has_tt = 1;
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
retval = ehci_setup(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* data structure init */
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
if (of_device_is_compatible(dev->parent->of_node,
|
||||
"fsl,mpc5121-usb2-dr")) {
|
||||
/*
|
||||
|
@ -40,18 +40,13 @@ static int ehci_grlib_setup(struct usb_hcd *hcd)
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
retval = ehci_setup(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci->sbrn = 0x20;
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
return ehci_reset(ehci);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -164,12 +159,6 @@ static int __devinit ehci_hcd_grlib_probe(struct platform_device *op)
|
||||
ehci->big_endian_capbase = 1;
|
||||
}
|
||||
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
rv = usb_add_hcd(hcd, irq, 0);
|
||||
if (rv)
|
||||
goto err_ehci;
|
||||
|
@ -203,11 +203,9 @@ static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
|
||||
/* check TDI/ARC silicon is in host mode */
|
||||
static int tdi_in_host_mode (struct ehci_hcd *ehci)
|
||||
{
|
||||
u32 __iomem *reg_ptr;
|
||||
u32 tmp;
|
||||
|
||||
reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE);
|
||||
tmp = ehci_readl(ehci, reg_ptr);
|
||||
tmp = ehci_readl(ehci, &ehci->regs->usbmode);
|
||||
return (tmp & 3) == USBMODE_CM_HC;
|
||||
}
|
||||
|
||||
@ -303,11 +301,9 @@ static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
|
||||
/* put TDI/ARC silicon into EHCI mode */
|
||||
static void tdi_reset (struct ehci_hcd *ehci)
|
||||
{
|
||||
u32 __iomem *reg_ptr;
|
||||
u32 tmp;
|
||||
|
||||
reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE);
|
||||
tmp = ehci_readl(ehci, reg_ptr);
|
||||
tmp = ehci_readl(ehci, &ehci->regs->usbmode);
|
||||
tmp |= USBMODE_CM_HC;
|
||||
/* The default byte access to MMR space is LE after
|
||||
* controller reset. Set the required endian mode
|
||||
@ -315,7 +311,7 @@ static void tdi_reset (struct ehci_hcd *ehci)
|
||||
*/
|
||||
if (ehci_big_endian_mmio(ehci))
|
||||
tmp |= USBMODE_BE;
|
||||
ehci_writel(ehci, tmp, reg_ptr);
|
||||
ehci_writel(ehci, tmp, &ehci->regs->usbmode);
|
||||
}
|
||||
|
||||
/* reset a non-running (STS_HALT == 1) controller */
|
||||
@ -339,9 +335,8 @@ static int ehci_reset (struct ehci_hcd *ehci)
|
||||
|
||||
if (ehci->has_hostpc) {
|
||||
ehci_writel(ehci, USBMODE_EX_HC | USBMODE_EX_VBPS,
|
||||
(u32 __iomem *)(((u8 *)ehci->regs) + USBMODE_EX));
|
||||
ehci_writel(ehci, TXFIFO_DEFAULT,
|
||||
(u32 __iomem *)(((u8 *)ehci->regs) + TXFILLTUNING));
|
||||
&ehci->regs->usbmode_ex);
|
||||
ehci_writel(ehci, TXFIFO_DEFAULT, &ehci->regs->txfill_tuning);
|
||||
}
|
||||
if (retval)
|
||||
return retval;
|
||||
@ -813,7 +808,7 @@ static int ehci_run (struct usb_hcd *hcd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused ehci_setup (struct usb_hcd *hcd)
|
||||
static int ehci_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
@ -837,6 +832,9 @@ static int __maybe_unused ehci_setup (struct usb_hcd *hcd)
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (ehci_is_TDI(ehci))
|
||||
tdi_reset(ehci);
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
return 0;
|
||||
@ -1247,6 +1245,95 @@ static int ehci_get_frame (struct usb_hcd *hcd)
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/* suspend/resume, section 4.3 */
|
||||
|
||||
/* These routines handle the generic parts of controller suspend/resume */
|
||||
|
||||
static int __maybe_unused ehci_suspend(struct usb_hcd *hcd, bool do_wakeup)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(10);
|
||||
|
||||
/*
|
||||
* Root hub was already suspended. Disable IRQ emission and
|
||||
* mark HW unaccessible. The PM and USB cores make sure that
|
||||
* the root hub is either suspended or stopped.
|
||||
*/
|
||||
ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
|
||||
|
||||
spin_lock_irq(&ehci->lock);
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
(void) ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 0 if power was preserved, 1 if power was lost */
|
||||
static int __maybe_unused ehci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(100);
|
||||
|
||||
/* Mark hardware accessible again as we are back to full power by now */
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/*
|
||||
* If CF is still set and we aren't resuming from hibernation
|
||||
* then we maintained suspend power.
|
||||
* Just undo the effect of ehci_suspend().
|
||||
*/
|
||||
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
|
||||
!hibernated) {
|
||||
int mask = INTR_MASK;
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
if (!hcd->self.root_hub->do_remote_wakeup)
|
||||
mask &= ~STS_PCD;
|
||||
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
|
||||
ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Else reset, to cope with power loss or resume from hibernation
|
||||
* having let the firmware kick in during reboot.
|
||||
*/
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
(void) ehci_halt(ehci);
|
||||
(void) ehci_reset(ehci);
|
||||
|
||||
/* emptying the schedule aborts any urbs */
|
||||
spin_lock_irq(&ehci->lock);
|
||||
if (ehci->reclaim)
|
||||
end_unlink_async(ehci);
|
||||
ehci_work(ehci);
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
|
||||
ehci_writel(ehci, ehci->command, &ehci->regs->command);
|
||||
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
|
||||
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
|
||||
|
||||
/* here we "know" root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The EHCI in ChipIdea HDRC cannot be a separate module or device,
|
||||
* because its registers (and irq) are shared between host/gadget/otg
|
||||
|
@ -107,7 +107,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
|
||||
ehci->owned_ports = 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
|
||||
static int ehci_port_change(struct ehci_hcd *ehci)
|
||||
{
|
||||
int i = HCS_N_PORTS(ehci->hcs_params);
|
||||
|
||||
@ -128,7 +128,7 @@ static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
|
||||
static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
|
||||
bool suspending, bool do_wakeup)
|
||||
{
|
||||
int port;
|
||||
@ -149,10 +149,8 @@ static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
|
||||
if (ehci->has_hostpc) {
|
||||
port = HCS_N_PORTS(ehci->hcs_params);
|
||||
while (port--) {
|
||||
u32 __iomem *hostpc_reg;
|
||||
u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port];
|
||||
|
||||
hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
|
||||
+ HOSTPC0 + 4 * port);
|
||||
temp = ehci_readl(ehci, hostpc_reg);
|
||||
ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
|
||||
}
|
||||
@ -185,10 +183,8 @@ static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
|
||||
if (ehci->has_hostpc) {
|
||||
port = HCS_N_PORTS(ehci->hcs_params);
|
||||
while (port--) {
|
||||
u32 __iomem *hostpc_reg;
|
||||
u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port];
|
||||
|
||||
hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
|
||||
+ HOSTPC0 + 4 * port);
|
||||
temp = ehci_readl(ehci, hostpc_reg);
|
||||
ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg);
|
||||
}
|
||||
@ -285,11 +281,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
|
||||
|
||||
port = HCS_N_PORTS(ehci->hcs_params);
|
||||
while (port--) {
|
||||
u32 __iomem *hostpc_reg;
|
||||
u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port];
|
||||
u32 t3;
|
||||
|
||||
hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
|
||||
+ HOSTPC0 + 4 * port);
|
||||
t3 = ehci_readl(ehci, hostpc_reg);
|
||||
ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
|
||||
t3 = ehci_readl(ehci, hostpc_reg);
|
||||
@ -388,10 +382,9 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
|
||||
i = HCS_N_PORTS(ehci->hcs_params);
|
||||
while (i--) {
|
||||
if (test_bit(i, &ehci->bus_suspended)) {
|
||||
u32 __iomem *hostpc_reg;
|
||||
u32 __iomem *hostpc_reg =
|
||||
&ehci->regs->hostpc[i];
|
||||
|
||||
hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
|
||||
+ HOSTPC0 + 4 * i);
|
||||
temp = ehci_readl(ehci, hostpc_reg);
|
||||
ehci_writel(ehci, temp & ~HOSTPC_PHCD,
|
||||
hostpc_reg);
|
||||
@ -667,7 +660,7 @@ static int ehci_hub_control (
|
||||
int ports = HCS_N_PORTS (ehci->hcs_params);
|
||||
u32 __iomem *status_reg = &ehci->regs->port_status[
|
||||
(wIndex & 0xff) - 1];
|
||||
u32 __iomem *hostpc_reg = NULL;
|
||||
u32 __iomem *hostpc_reg = &ehci->regs->hostpc[(wIndex & 0xff) - 1];
|
||||
u32 temp, temp1, status;
|
||||
unsigned long flags;
|
||||
int retval = 0;
|
||||
@ -680,9 +673,6 @@ static int ehci_hub_control (
|
||||
* power, "this is the one", etc. EHCI spec supports this.
|
||||
*/
|
||||
|
||||
if (ehci->has_hostpc)
|
||||
hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
|
||||
+ HOSTPC0 + 4 * ((wIndex & 0xff) - 1));
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
switch (typeReq) {
|
||||
case ClearHubFeature:
|
||||
@ -724,7 +714,7 @@ static int ehci_hub_control (
|
||||
#ifdef CONFIG_USB_OTG
|
||||
if ((hcd->self.otg_port == (wIndex + 1))
|
||||
&& hcd->self.b_hnp_enable) {
|
||||
otg_start_hnp(ehci->transceiver->otg);
|
||||
otg_start_hnp(hcd->phy->otg);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -734,7 +724,7 @@ static int ehci_hub_control (
|
||||
goto error;
|
||||
|
||||
/* clear phy low-power mode before resume */
|
||||
if (hostpc_reg) {
|
||||
if (ehci->has_hostpc) {
|
||||
temp1 = ehci_readl(ehci, hostpc_reg);
|
||||
ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
|
||||
hostpc_reg);
|
||||
@ -984,7 +974,7 @@ static int ehci_hub_control (
|
||||
temp &= ~PORT_WKCONN_E;
|
||||
temp |= PORT_WKDISC_E | PORT_WKOC_E;
|
||||
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
|
||||
if (hostpc_reg) {
|
||||
if (ehci->has_hostpc) {
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
msleep(5);/* 5ms for HCD enter low pwr mode */
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
|
@ -22,14 +22,10 @@ static int ixp4xx_ehci_init(struct usb_hcd *hcd)
|
||||
ehci->big_endian_mmio = 1;
|
||||
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100
|
||||
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
hcd->has_tt = 1;
|
||||
ehci_reset(ehci);
|
||||
|
||||
retval = ehci_init(hcd);
|
||||
retval = ehci_setup(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
@ -145,8 +145,8 @@ static int ehci_msm_probe(struct platform_device *pdev)
|
||||
* powering up VBUS, mapping of registers address space and power
|
||||
* management.
|
||||
*/
|
||||
phy = usb_get_transceiver();
|
||||
if (!phy) {
|
||||
phy = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR_OR_NULL(phy)) {
|
||||
dev_err(&pdev->dev, "unable to find transceiver\n");
|
||||
ret = -ENODEV;
|
||||
goto unmap;
|
||||
@ -169,7 +169,7 @@ static int ehci_msm_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
put_transceiver:
|
||||
usb_put_transceiver(phy);
|
||||
usb_put_phy(phy);
|
||||
unmap:
|
||||
iounmap(hcd->regs);
|
||||
put_hcd:
|
||||
@ -187,7 +187,7 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev)
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
|
||||
otg_set_host(phy->otg, NULL);
|
||||
usb_put_transceiver(phy);
|
||||
usb_put_phy(phy);
|
||||
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
@ -198,24 +198,11 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev)
|
||||
static int ehci_msm_pm_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
bool wakeup = device_may_wakeup(dev);
|
||||
bool do_wakeup = device_may_wakeup(dev);
|
||||
|
||||
dev_dbg(dev, "ehci-msm PM suspend\n");
|
||||
|
||||
/*
|
||||
* EHCI helper function has also the same check before manipulating
|
||||
* port wakeup flags. We do check here the same condition before
|
||||
* calling the same helper function to avoid bringing hardware
|
||||
* from Low power mode when there is no need for adjusting port
|
||||
* wakeup flags.
|
||||
*/
|
||||
if (hcd->self.root_hub->do_remote_wakeup && !wakeup) {
|
||||
pm_runtime_resume(dev);
|
||||
ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
|
||||
wakeup);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ehci_suspend(hcd, do_wakeup);
|
||||
}
|
||||
|
||||
static int ehci_msm_pm_resume(struct device *dev)
|
||||
@ -223,7 +210,7 @@ static int ehci_msm_pm_resume(struct device *dev)
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(dev, "ehci-msm PM resume\n");
|
||||
ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
|
||||
ehci_resume(hcd, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/platform_data/mv_usb.h>
|
||||
|
||||
@ -76,7 +77,6 @@ static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv)
|
||||
|
||||
static int mv_ehci_reset(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct device *dev = hcd->self.controller;
|
||||
struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev);
|
||||
int retval;
|
||||
@ -86,25 +86,13 @@ static int mv_ehci_reset(struct usb_hcd *hcd)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* data structure init
|
||||
*/
|
||||
retval = ehci_init(hcd);
|
||||
if (retval) {
|
||||
dev_err(dev, "ehci_init failed %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
hcd->has_tt = 1;
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
retval = ehci_reset(ehci);
|
||||
if (retval) {
|
||||
dev_err(dev, "ehci_reset failed %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
retval = ehci_setup(hcd);
|
||||
if (retval)
|
||||
dev_err(dev, "ehci_setup failed %d\n", retval);
|
||||
|
||||
return 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const struct hc_driver mv_ehci_hc_driver = {
|
||||
@ -247,14 +235,12 @@ static int mv_ehci_probe(struct platform_device *pdev)
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs;
|
||||
ehci->regs = (struct ehci_regs *) ehci_mv->op_regs;
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
ehci_mv->mode = pdata->mode;
|
||||
if (ehci_mv->mode == MV_USB_MODE_OTG) {
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
ehci_mv->otg = usb_get_transceiver();
|
||||
if (!ehci_mv->otg) {
|
||||
ehci_mv->otg = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR_OR_NULL(ehci_mv->otg)) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to find transceiver\n");
|
||||
retval = -ENODEV;
|
||||
@ -302,8 +288,8 @@ err_set_vbus:
|
||||
pdata->set_vbus(0);
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
err_put_transceiver:
|
||||
if (ehci_mv->otg)
|
||||
usb_put_transceiver(ehci_mv->otg);
|
||||
if (!IS_ERR_OR_NULL(ehci_mv->otg))
|
||||
usb_put_phy(ehci_mv->otg);
|
||||
#endif
|
||||
err_disable_clk:
|
||||
mv_ehci_disable(ehci_mv);
|
||||
@ -331,9 +317,9 @@ static int mv_ehci_remove(struct platform_device *pdev)
|
||||
if (hcd->rh_registered)
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
if (ehci_mv->otg) {
|
||||
if (!IS_ERR_OR_NULL(ehci_mv->otg)) {
|
||||
otg_set_host(ehci_mv->otg->otg, NULL);
|
||||
usb_put_transceiver(ehci_mv->otg);
|
||||
usb_put_phy(ehci_mv->otg);
|
||||
}
|
||||
|
||||
if (ehci_mv->mode == MV_USB_MODE_HOST) {
|
||||
|
@ -42,27 +42,12 @@ static int ehci_mxc_setup(struct usb_hcd *hcd)
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
hcd->has_tt = 1;
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
retval = ehci_setup(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* data structure init */
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
ehci_port_power(ehci, 0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ static const struct hc_driver ehci_octeon_hc_driver = {
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_init,
|
||||
.reset = ehci_setup,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
@ -150,12 +150,6 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)
|
||||
#endif
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (ret) {
|
||||
|
@ -145,6 +145,56 @@ static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port)
|
||||
}
|
||||
}
|
||||
|
||||
static int omap_ehci_init(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int rc;
|
||||
struct ehci_hcd_omap_platform_data *pdata;
|
||||
|
||||
pdata = hcd->self.controller->platform_data;
|
||||
if (pdata->phy_reset) {
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[0]))
|
||||
gpio_request_one(pdata->reset_gpio_port[0],
|
||||
GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
|
||||
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[1]))
|
||||
gpio_request_one(pdata->reset_gpio_port[1],
|
||||
GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
|
||||
|
||||
/* Hold the PHY in RESET for enough time till DIR is high */
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
/* Soft reset the PHY using PHY reset command over ULPI */
|
||||
if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY)
|
||||
omap_ehci_soft_phy_reset(pdev, 0);
|
||||
if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY)
|
||||
omap_ehci_soft_phy_reset(pdev, 1);
|
||||
|
||||
/* we know this is the memory we want, no need to ioremap again */
|
||||
ehci->caps = hcd->regs;
|
||||
|
||||
rc = ehci_setup(hcd);
|
||||
|
||||
if (pdata->phy_reset) {
|
||||
/* Hold the PHY in RESET for enough time till
|
||||
* PHY is settled and ready
|
||||
*/
|
||||
udelay(10);
|
||||
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[0]))
|
||||
gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
|
||||
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[1]))
|
||||
gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
|
||||
}
|
||||
|
||||
/* root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int omap_ehci_hub_control(
|
||||
struct usb_hcd *hcd,
|
||||
u16 typeReq,
|
||||
@ -219,7 +269,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
struct usb_hcd *hcd;
|
||||
void __iomem *regs;
|
||||
struct ehci_hcd *omap_ehci;
|
||||
int ret = -ENODEV;
|
||||
int irq;
|
||||
int i;
|
||||
@ -281,18 +330,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
/* Hold PHYs in reset while initializing EHCI controller */
|
||||
if (pdata->phy_reset) {
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[0]))
|
||||
gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);
|
||||
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[1]))
|
||||
gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);
|
||||
|
||||
/* Hold the PHY in RESET for enough time till DIR is high */
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
@ -308,49 +345,12 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
|
||||
ehci_write(regs, EHCI_INSNREG04,
|
||||
EHCI_INSNREG04_DISABLE_UNSUSPEND);
|
||||
|
||||
/* Soft reset the PHY using PHY reset command over ULPI */
|
||||
if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY)
|
||||
omap_ehci_soft_phy_reset(pdev, 0);
|
||||
if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY)
|
||||
omap_ehci_soft_phy_reset(pdev, 1);
|
||||
|
||||
omap_ehci = hcd_to_ehci(hcd);
|
||||
omap_ehci->sbrn = 0x20;
|
||||
|
||||
/* we know this is the memory we want, no need to ioremap again */
|
||||
omap_ehci->caps = hcd->regs;
|
||||
omap_ehci->regs = hcd->regs
|
||||
+ HC_LENGTH(ehci, readl(&omap_ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(omap_ehci, "reset");
|
||||
dbg_hcc_params(omap_ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);
|
||||
|
||||
ehci_reset(omap_ehci);
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add hcd with err %d\n", ret);
|
||||
goto err_add_hcd;
|
||||
goto err_pm_runtime;
|
||||
}
|
||||
|
||||
if (pdata->phy_reset) {
|
||||
/* Hold the PHY in RESET for enough time till
|
||||
* PHY is settled and ready
|
||||
*/
|
||||
udelay(10);
|
||||
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[0]))
|
||||
gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
|
||||
|
||||
if (gpio_is_valid(pdata->reset_gpio_port[1]))
|
||||
gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
|
||||
}
|
||||
|
||||
/* root ports should always stay powered */
|
||||
ehci_port_power(omap_ehci, 1);
|
||||
|
||||
/* get clocks */
|
||||
utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
|
||||
if (IS_ERR(utmi_p1_fck)) {
|
||||
@ -422,8 +422,12 @@ err_utmi_p1_fck:
|
||||
clk_put(utmi_p1_fck);
|
||||
|
||||
err_add_hcd:
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
err_pm_runtime:
|
||||
disable_put_regulator(pdata);
|
||||
pm_runtime_put_sync(dev);
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
err_io:
|
||||
iounmap(regs);
|
||||
@ -506,7 +510,7 @@ static const struct hc_driver ehci_omap_hc_driver = {
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_init,
|
||||
.reset = omap_ehci_init,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
@ -106,21 +106,10 @@ static int ehci_orion_setup(struct usb_hcd *hcd)
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
|
||||
hcd->has_tt = 1;
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
retval = ehci_setup(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* data structure init
|
||||
*/
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
ehci_port_power(ehci, 0);
|
||||
|
||||
return retval;
|
||||
@ -261,11 +250,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
hcd->has_tt = 1;
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
/*
|
||||
* (Re-)program MBUS remapping windows if we are asked to.
|
||||
|
@ -54,6 +54,17 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
u32 temp;
|
||||
int retval;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
|
||||
/*
|
||||
* ehci_init() causes memory for DMA transfers to be
|
||||
* allocated. Thus, any vendor-specific workarounds based on
|
||||
* limiting the type of memory used for DMA transfers must
|
||||
* happen before ehci_setup() is called.
|
||||
*
|
||||
* Most other workarounds can be done either before or after
|
||||
* init and reset; they are located here too.
|
||||
*/
|
||||
switch (pdev->vendor) {
|
||||
case PCI_VENDOR_ID_TOSHIBA_2:
|
||||
/* celleb's companion chip */
|
||||
@ -66,20 +77,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* ehci_init() causes memory for DMA transfers to be
|
||||
* allocated. Thus, any vendor-specific workarounds based on
|
||||
* limiting the type of memory used for DMA transfers must
|
||||
* happen before ehci_init() is called. */
|
||||
switch (pdev->vendor) {
|
||||
case PCI_VENDOR_ID_NVIDIA:
|
||||
/* NVidia reports that certain chips don't handle
|
||||
* QH, ITD, or SITD addresses above 2GB. (But TD,
|
||||
@ -95,61 +92,28 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
ehci_warn(ehci, "can't enable NVidia "
|
||||
"workaround for >2GB RAM\n");
|
||||
break;
|
||||
|
||||
/* Some NForce2 chips have problems with selective suspend;
|
||||
* fixed in newer silicon.
|
||||
*/
|
||||
case 0x0068:
|
||||
if (pdev->revision < 0xa4)
|
||||
ehci->no_selective_suspend = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x7808) ||
|
||||
(pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x4396)) {
|
||||
/* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
|
||||
* read/write memory space which does not belong to it when
|
||||
* there is NULL pointer with T-bit set to 1 in the frame list
|
||||
* table. To avoid the issue, the frame list link pointer
|
||||
* should always contain a valid pointer to a inactive qh.
|
||||
*/
|
||||
ehci->use_dummy_qh = 1;
|
||||
ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI "
|
||||
"dummy qh workaround\n");
|
||||
}
|
||||
|
||||
/* data structure init */
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
switch (pdev->vendor) {
|
||||
case PCI_VENDOR_ID_NEC:
|
||||
ehci->need_io_watchdog = 0;
|
||||
break;
|
||||
case PCI_VENDOR_ID_INTEL:
|
||||
ehci->need_io_watchdog = 0;
|
||||
ehci->fs_i_thresh = 1;
|
||||
if (pdev->device == 0x27cc) {
|
||||
ehci->broken_periodic = 1;
|
||||
ehci_info(ehci, "using broken periodic workaround\n");
|
||||
}
|
||||
if (pdev->device == 0x0806 || pdev->device == 0x0811
|
||||
|| pdev->device == 0x0829) {
|
||||
ehci_info(ehci, "disable lpm for langwell/penwell\n");
|
||||
ehci->has_lpm = 0;
|
||||
}
|
||||
if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB) {
|
||||
if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB)
|
||||
hcd->has_tt = 1;
|
||||
tdi_reset(ehci);
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_TDI:
|
||||
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
|
||||
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI)
|
||||
hcd->has_tt = 1;
|
||||
tdi_reset(ehci);
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_AMD:
|
||||
/* AMD PLL quirk */
|
||||
@ -161,28 +125,17 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_NVIDIA:
|
||||
switch (pdev->device) {
|
||||
/* Some NForce2 chips have problems with selective suspend;
|
||||
* fixed in newer silicon.
|
||||
*/
|
||||
case 0x0068:
|
||||
if (pdev->revision < 0xa4)
|
||||
ehci->no_selective_suspend = 1;
|
||||
break;
|
||||
|
||||
/* MCP89 chips on the MacBookAir3,1 give EPROTO when
|
||||
* fetching device descriptors unless LPM is disabled.
|
||||
* There are also intermittent problems enumerating
|
||||
* devices with PPCD enabled.
|
||||
/*
|
||||
* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
|
||||
* read/write memory space which does not belong to it when
|
||||
* there is NULL pointer with T-bit set to 1 in the frame list
|
||||
* table. To avoid the issue, the frame list link pointer
|
||||
* should always contain a valid pointer to a inactive qh.
|
||||
*/
|
||||
case 0x0d9d:
|
||||
ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89");
|
||||
ehci->has_lpm = 0;
|
||||
ehci->has_ppcd = 0;
|
||||
ehci->command &= ~CMD_PPCEE;
|
||||
break;
|
||||
if (pdev->device == 0x7808) {
|
||||
ehci->use_dummy_qh = 1;
|
||||
ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI dummy qh workaround\n");
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_VIA:
|
||||
@ -203,6 +156,18 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
/* AMD PLL quirk */
|
||||
if (usb_amd_find_chipset_info())
|
||||
ehci->amd_pll_fix = 1;
|
||||
|
||||
/*
|
||||
* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may
|
||||
* read/write memory space which does not belong to it when
|
||||
* there is NULL pointer with T-bit set to 1 in the frame list
|
||||
* table. To avoid the issue, the frame list link pointer
|
||||
* should always contain a valid pointer to a inactive qh.
|
||||
*/
|
||||
if (pdev->device == 0x4396) {
|
||||
ehci->use_dummy_qh = 1;
|
||||
ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI dummy qh workaround\n");
|
||||
}
|
||||
/* SB600 and old version of SB700 have a bug in EHCI controller,
|
||||
* which causes usb devices lose response in some cases.
|
||||
*/
|
||||
@ -231,6 +196,40 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
break;
|
||||
}
|
||||
|
||||
retval = ehci_setup(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* These workarounds need to be applied after ehci_setup() */
|
||||
switch (pdev->vendor) {
|
||||
case PCI_VENDOR_ID_NEC:
|
||||
ehci->need_io_watchdog = 0;
|
||||
break;
|
||||
case PCI_VENDOR_ID_INTEL:
|
||||
ehci->need_io_watchdog = 0;
|
||||
if (pdev->device == 0x0806 || pdev->device == 0x0811
|
||||
|| pdev->device == 0x0829) {
|
||||
ehci_info(ehci, "disable lpm for langwell/penwell\n");
|
||||
ehci->has_lpm = 0;
|
||||
}
|
||||
break;
|
||||
case PCI_VENDOR_ID_NVIDIA:
|
||||
switch (pdev->device) {
|
||||
/* MCP89 chips on the MacBookAir3,1 give EPROTO when
|
||||
* fetching device descriptors unless LPM is disabled.
|
||||
* There are also intermittent problems enumerating
|
||||
* devices with PPCD enabled.
|
||||
*/
|
||||
case 0x0d9d:
|
||||
ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89");
|
||||
ehci->has_lpm = 0;
|
||||
ehci->has_ppcd = 0;
|
||||
ehci->command &= ~CMD_PPCEE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* optional debug port, normally in the first BAR */
|
||||
temp = pci_find_capability(pdev, 0x0a);
|
||||
if (temp) {
|
||||
@ -238,7 +237,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
temp >>= 16;
|
||||
if ((temp & (3 << 13)) == (1 << 13)) {
|
||||
temp &= 0x1fff;
|
||||
ehci->debug = ehci_to_hcd(ehci)->regs + temp;
|
||||
ehci->debug = hcd->regs + temp;
|
||||
temp = ehci_readl(ehci, &ehci->debug->control);
|
||||
ehci_info(ehci, "debug port %d%s\n",
|
||||
HCS_DEBUG_PORT(ehci->hcs_params),
|
||||
@ -250,8 +249,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
}
|
||||
}
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
/* at least the Genesys GL880S needs fixup here */
|
||||
temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
|
||||
temp &= 0x0f;
|
||||
@ -275,10 +272,11 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
}
|
||||
|
||||
/* Serial Bus Release Number is at PCI 0x60 offset */
|
||||
pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
|
||||
if (pdev->vendor == PCI_VENDOR_ID_STMICRO
|
||||
&& pdev->device == PCI_DEVICE_ID_STMICRO_USB_HOST)
|
||||
ehci->sbrn = 0x20; /* ConneXT has no sbrn register */
|
||||
; /* ConneXT has no sbrn register */
|
||||
else
|
||||
pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
|
||||
|
||||
/* Keep this around for a while just in case some EHCI
|
||||
* implementation uses legacy PCI PM support. This test
|
||||
@ -331,29 +329,7 @@ done:
|
||||
|
||||
static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(10);
|
||||
|
||||
/* Root hub was already suspended. Disable irq emission and
|
||||
* mark HW unaccessible. The PM and USB cores make sure that
|
||||
* the root hub is either suspended or stopped.
|
||||
*/
|
||||
ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
|
||||
spin_lock_irqsave (&ehci->lock, flags);
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
spin_unlock_irqrestore (&ehci->lock, flags);
|
||||
|
||||
// could save FLADJ in case of Vaux power loss
|
||||
// ... we'd only use it to handle clock skew
|
||||
|
||||
return rc;
|
||||
return ehci_suspend(hcd, do_wakeup);
|
||||
}
|
||||
|
||||
static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
|
||||
@ -402,54 +378,8 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||
if (usb_is_intel_switchable_ehci(pdev))
|
||||
ehci_enable_xhci_companion();
|
||||
|
||||
// maybe restore FLADJ
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(100);
|
||||
|
||||
/* Mark hardware accessible again as we are out of D3 state by now */
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* If CF is still set and we aren't resuming from hibernation
|
||||
* then we maintained PCI Vaux power.
|
||||
* Just undo the effect of ehci_pci_suspend().
|
||||
*/
|
||||
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
|
||||
!hibernated) {
|
||||
int mask = INTR_MASK;
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
if (!hcd->self.root_hub->do_remote_wakeup)
|
||||
mask &= ~STS_PCD;
|
||||
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
|
||||
ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
|
||||
/* Else reset, to cope with power loss or flush-to-storage
|
||||
* style "resume" having let BIOS kick in during reboot.
|
||||
*/
|
||||
(void) ehci_halt(ehci);
|
||||
(void) ehci_reset(ehci);
|
||||
(void) ehci_pci_reinit(ehci, pdev);
|
||||
|
||||
/* emptying the schedule aborts any urbs */
|
||||
spin_lock_irq(&ehci->lock);
|
||||
if (ehci->reclaim)
|
||||
end_unlink_async(ehci);
|
||||
ehci_work(ehci);
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
|
||||
ehci_writel(ehci, ehci->command, &ehci->regs->command);
|
||||
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
|
||||
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
|
||||
|
||||
/* here we "know" root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
if (ehci_resume(hcd, hibernated) != 0)
|
||||
(void) ehci_pci_reinit(ehci, pdev);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -153,17 +153,16 @@ static int __devexit ehci_platform_remove(struct platform_device *dev)
|
||||
static int ehci_platform_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
bool wakeup = device_may_wakeup(dev);
|
||||
bool do_wakeup = device_may_wakeup(dev);
|
||||
|
||||
ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), wakeup);
|
||||
return 0;
|
||||
return ehci_suspend(hcd, do_wakeup);
|
||||
}
|
||||
|
||||
static int ehci_platform_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
|
||||
ehci_resume(hcd, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -78,27 +78,14 @@ static int ehci_msp_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
|
||||
ehci->big_endian_mmio = 1;
|
||||
ehci->big_endian_desc = 1;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
hcd->has_tt = 1;
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
/* data structure init */
|
||||
retval = ehci_init(hcd);
|
||||
retval = ehci_setup(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
@ -17,24 +17,6 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
/* called during probe() after chip reset completes */
|
||||
static int ehci_ppc_of_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci->sbrn = 0x20;
|
||||
return ehci_reset(ehci);
|
||||
}
|
||||
|
||||
|
||||
static const struct hc_driver ehci_ppc_of_hc_driver = {
|
||||
.description = hcd_name,
|
||||
@ -50,7 +32,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_ppc_of_setup,
|
||||
.reset = ehci_setup,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
@ -178,11 +160,6 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
|
||||
ehci->big_endian_desc = 1;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) {
|
||||
rv = ppc44x_enable_bmt(dn);
|
||||
|
@ -55,28 +55,12 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
ehci->big_endian_mmio = 1;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
|
||||
&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
result = ehci_halt(ehci);
|
||||
|
||||
result = ehci_setup(hcd);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = ehci_init(hcd);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
ps3_ehci_setup_insnreg(ehci);
|
||||
|
||||
return result;
|
||||
|
@ -40,7 +40,7 @@ static const struct hc_driver s5p_ehci_hc_driver = {
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB2,
|
||||
|
||||
.reset = ehci_init,
|
||||
.reset = ehci_setup,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
@ -79,7 +79,8 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s5p_ehci = kzalloc(sizeof(struct s5p_ehci_hcd), GFP_KERNEL);
|
||||
s5p_ehci = devm_kzalloc(&pdev->dev, sizeof(struct s5p_ehci_hcd),
|
||||
GFP_KERNEL);
|
||||
if (!s5p_ehci)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -89,8 +90,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
|
||||
dev_name(&pdev->dev));
|
||||
if (!hcd) {
|
||||
dev_err(&pdev->dev, "Unable to create HCD\n");
|
||||
err = -ENOMEM;
|
||||
goto fail_hcd;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
s5p_ehci->hcd = hcd;
|
||||
@ -115,7 +115,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
|
||||
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = resource_size(res);
|
||||
hcd->regs = ioremap(res->start, resource_size(res));
|
||||
hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len);
|
||||
if (!hcd->regs) {
|
||||
dev_err(&pdev->dev, "Failed to remap I/O memory\n");
|
||||
err = -ENOMEM;
|
||||
@ -126,7 +126,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
|
||||
if (!irq) {
|
||||
dev_err(&pdev->dev, "Failed to get IRQ\n");
|
||||
err = -ENODEV;
|
||||
goto fail;
|
||||
goto fail_io;
|
||||
}
|
||||
|
||||
if (pdata->phy_init)
|
||||
@ -134,40 +134,26 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
|
||||
|
||||
/* DMA burst Enable */
|
||||
writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to add USB HCD\n");
|
||||
goto fail;
|
||||
goto fail_io;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, s5p_ehci);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
iounmap(hcd->regs);
|
||||
fail_io:
|
||||
clk_disable(s5p_ehci->clk);
|
||||
fail_clken:
|
||||
clk_put(s5p_ehci->clk);
|
||||
fail_clk:
|
||||
usb_put_hcd(hcd);
|
||||
fail_hcd:
|
||||
kfree(s5p_ehci);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -182,13 +168,10 @@ static int __devexit s5p_ehci_remove(struct platform_device *pdev)
|
||||
if (pdata && pdata->phy_exit)
|
||||
pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
|
||||
|
||||
iounmap(hcd->regs);
|
||||
|
||||
clk_disable(s5p_ehci->clk);
|
||||
clk_put(s5p_ehci->clk);
|
||||
|
||||
usb_put_hcd(hcd);
|
||||
kfree(s5p_ehci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -207,27 +190,12 @@ static int s5p_ehci_suspend(struct device *dev)
|
||||
{
|
||||
struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
|
||||
struct usb_hcd *hcd = s5p_ehci->hcd;
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
bool do_wakeup = device_may_wakeup(dev);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
int rc;
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(20);
|
||||
|
||||
/*
|
||||
* Root hub was already suspended. Disable irq emission and
|
||||
* mark HW unaccessible. The PM and USB cores make sure that
|
||||
* the root hub is either suspended or stopped.
|
||||
*/
|
||||
ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
rc = ehci_suspend(hcd, do_wakeup);
|
||||
|
||||
if (pdata && pdata->phy_exit)
|
||||
pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
|
||||
@ -241,7 +209,6 @@ static int s5p_ehci_resume(struct device *dev)
|
||||
{
|
||||
struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
|
||||
struct usb_hcd *hcd = s5p_ehci->hcd;
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
|
||||
|
||||
@ -253,44 +220,7 @@ static int s5p_ehci_resume(struct device *dev)
|
||||
/* DMA burst Enable */
|
||||
writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(100);
|
||||
|
||||
/* Mark hardware accessible again as we are out of D3 state by now */
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
|
||||
int mask = INTR_MASK;
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
if (!hcd->self.root_hub->do_remote_wakeup)
|
||||
mask &= ~STS_PCD;
|
||||
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
|
||||
ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
|
||||
(void) ehci_halt(ehci);
|
||||
(void) ehci_reset(ehci);
|
||||
|
||||
/* emptying the schedule aborts any urbs */
|
||||
spin_lock_irq(&ehci->lock);
|
||||
if (ehci->reclaim)
|
||||
end_unlink_async(ehci);
|
||||
ehci_work(ehci);
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
|
||||
ehci_writel(ehci, ehci->command, &ehci->regs->command);
|
||||
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
|
||||
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
|
||||
|
||||
/* here we "know" root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
|
||||
ehci_resume(hcd, false);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
@ -160,84 +160,16 @@ static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev)
|
||||
static int ehci_hcd_sead3_drv_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
bool do_wakeup = device_may_wakeup(dev);
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(20);
|
||||
|
||||
/* Root hub was already suspended. Disable irq emission and
|
||||
* mark HW unaccessible. The PM and USB cores make sure that
|
||||
* the root hub is either suspended or stopped.
|
||||
*/
|
||||
ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
|
||||
/* could save FLADJ in case of Vaux power loss
|
||||
* ... we'd only use it to handle clock skew
|
||||
*/
|
||||
|
||||
return rc;
|
||||
return ehci_suspend(hcd, do_wakeup);
|
||||
}
|
||||
|
||||
static int ehci_hcd_sead3_drv_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
/* maybe restore FLADJ. */
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(100);
|
||||
|
||||
/* Mark hardware accessible again as we are out of D3 state by now */
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* If CF is still set, we maintained PCI Vaux power.
|
||||
* Just undo the effect of ehci_pci_suspend().
|
||||
*/
|
||||
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
|
||||
int mask = INTR_MASK;
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
if (!hcd->self.root_hub->do_remote_wakeup)
|
||||
mask &= ~STS_PCD;
|
||||
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
|
||||
ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ehci_dbg(ehci, "lost power, restarting\n");
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
|
||||
/* Else reset, to cope with power loss or flush-to-storage
|
||||
* style "resume" having let BIOS kick in during reboot.
|
||||
*/
|
||||
(void) ehci_halt(ehci);
|
||||
(void) ehci_reset(ehci);
|
||||
|
||||
/* emptying the schedule aborts any urbs */
|
||||
spin_lock_irq(&ehci->lock);
|
||||
if (ehci->reclaim)
|
||||
end_unlink_async(ehci);
|
||||
ehci_work(ehci);
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
|
||||
ehci_writel(ehci, ehci->command, &ehci->regs->command);
|
||||
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
|
||||
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
|
||||
|
||||
/* here we "know" root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
ehci->rh_state = EHCI_RH_SUSPENDED;
|
||||
|
||||
ehci_resume(hcd, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -24,25 +24,11 @@ static int ehci_sh_reset(struct usb_hcd *hcd)
|
||||
int ret;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
|
||||
&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
ret = ehci_halt(ehci);
|
||||
ret = ehci_setup(hcd);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
|
||||
ret = ehci_init(hcd);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
ehci_reset(ehci);
|
||||
ehci_port_power(ehci, 0);
|
||||
|
||||
return ret;
|
||||
|
@ -41,19 +41,11 @@ static int ehci_spear_setup(struct usb_hcd *hcd)
|
||||
|
||||
/* registers start at offset 0x0 */
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci,
|
||||
&ehci->caps->hc_capbase));
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
retval = ehci_halt(ehci);
|
||||
|
||||
retval = ehci_setup(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci_reset(ehci);
|
||||
ehci_port_power(ehci, 0);
|
||||
|
||||
return retval;
|
||||
@ -97,71 +89,16 @@ static const struct hc_driver ehci_spear_hc_driver = {
|
||||
static int ehci_spear_drv_suspend(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
bool do_wakeup = device_may_wakeup(dev);
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(10);
|
||||
|
||||
/*
|
||||
* Root hub was already suspended. Disable irq emission and mark HW
|
||||
* unaccessible. The PM and USB cores make sure that the root hub is
|
||||
* either suspended or stopped.
|
||||
*/
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
|
||||
return rc;
|
||||
return ehci_suspend(hcd, do_wakeup);
|
||||
}
|
||||
|
||||
static int ehci_spear_drv_resume(struct device *dev)
|
||||
{
|
||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
if (time_before(jiffies, ehci->next_statechange))
|
||||
msleep(100);
|
||||
|
||||
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
|
||||
int mask = INTR_MASK;
|
||||
|
||||
ehci_prepare_ports_for_controller_resume(ehci);
|
||||
|
||||
if (!hcd->self.root_hub->do_remote_wakeup)
|
||||
mask &= ~STS_PCD;
|
||||
|
||||
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
|
||||
ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
|
||||
/*
|
||||
* Else reset, to cope with power loss or flush-to-storage style
|
||||
* "resume" having let BIOS kick in during reboot.
|
||||
*/
|
||||
ehci_halt(ehci);
|
||||
ehci_reset(ehci);
|
||||
|
||||
/* emptying the schedule aborts any urbs */
|
||||
spin_lock_irq(&ehci->lock);
|
||||
if (ehci->reclaim)
|
||||
end_unlink_async(ehci);
|
||||
|
||||
ehci_work(ehci);
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
|
||||
ehci_writel(ehci, ehci->command, &ehci->regs->command);
|
||||
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
|
||||
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
|
||||
|
||||
/* here we "know" root ports should always stay powered */
|
||||
ehci_port_power(ehci, 1);
|
||||
ehci_resume(hcd, false);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/tegra_usb.h>
|
||||
#include <linux/irq.h>
|
||||
@ -280,30 +281,14 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
|
||||
|
||||
/* EHCI registers start at offset 0x100 */
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||
|
||||
/* switch to host mode */
|
||||
hcd->has_tt = 1;
|
||||
ehci_reset(ehci);
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
retval = ehci_setup(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* data structure init */
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
ehci_port_power(ehci, 1);
|
||||
return retval;
|
||||
}
|
||||
@ -749,8 +734,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
|
||||
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
if (pdata->operating_mode == TEGRA_USB_OTG) {
|
||||
tegra->transceiver = usb_get_transceiver();
|
||||
if (tegra->transceiver)
|
||||
tegra->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (!IS_ERR_OR_NULL(tegra->transceiver))
|
||||
otg_set_host(tegra->transceiver->otg, &hcd->self);
|
||||
}
|
||||
#endif
|
||||
@ -773,9 +758,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)
|
||||
|
||||
fail:
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
if (tegra->transceiver) {
|
||||
if (!IS_ERR_OR_NULL(tegra->transceiver)) {
|
||||
otg_set_host(tegra->transceiver->otg, NULL);
|
||||
usb_put_transceiver(tegra->transceiver);
|
||||
usb_put_phy(tegra->transceiver);
|
||||
}
|
||||
#endif
|
||||
tegra_usb_phy_close(tegra->phy);
|
||||
@ -808,9 +793,9 @@ static int tegra_ehci_remove(struct platform_device *pdev)
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
#ifdef CONFIG_USB_OTG_UTILS
|
||||
if (tegra->transceiver) {
|
||||
if (!IS_ERR_OR_NULL(tegra->transceiver)) {
|
||||
otg_set_host(tegra->transceiver->otg, NULL);
|
||||
usb_put_transceiver(tegra->transceiver);
|
||||
usb_put_phy(tegra->transceiver);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -48,7 +48,7 @@ static const struct hc_driver vt8500_ehci_hc_driver = {
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_init,
|
||||
.reset = ehci_setup,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
@ -121,18 +121,6 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
|
||||
|
||||
ehci = hcd_to_ehci(hcd);
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
|
||||
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||
|
||||
ehci_port_power(ehci, 1);
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
ret = usb_add_hcd(hcd, pdev->resource[1].start,
|
||||
IRQF_SHARED);
|
||||
|
@ -71,21 +71,14 @@ static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
|
||||
val |= ENPHY;
|
||||
__raw_writel(val, ehci->regs+PHY1_CTR);
|
||||
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
goto err4;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (retval != 0)
|
||||
goto err4;
|
||||
|
||||
ehci_writel(ehci, 1, &ehci->regs->configured_flag);
|
||||
|
||||
return retval;
|
||||
err4:
|
||||
iounmap(hcd->regs);
|
||||
@ -120,7 +113,7 @@ static const struct hc_driver ehci_w90x900_hc_driver = {
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_init,
|
||||
.reset = ehci_setup,
|
||||
.start = ehci_run,
|
||||
|
||||
.stop = ehci_stop,
|
||||
|
@ -31,30 +31,6 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
/**
|
||||
* ehci_xilinx_of_setup - Initialize the device for ehci_reset()
|
||||
* @hcd: Pointer to the usb_hcd device to which the host controller bound
|
||||
*
|
||||
* called during probe() after chip reset completes.
|
||||
*/
|
||||
static int ehci_xilinx_of_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
return ehci_reset(ehci);
|
||||
}
|
||||
|
||||
/**
|
||||
* ehci_xilinx_port_handed_over - hand the port out if failed to enable it
|
||||
* @hcd: Pointer to the usb_hcd device to which the host controller bound
|
||||
@ -107,7 +83,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = {
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_xilinx_of_setup,
|
||||
.reset = ehci_setup,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
@ -219,11 +195,6 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
|
||||
/* Debug registers are at the first 0x100 region
|
||||
*/
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
ehci->regs = hcd->regs + 0x100 +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
rv = usb_add_hcd(hcd, irq, 0);
|
||||
if (rv == 0)
|
||||
|
@ -14,30 +14,11 @@
|
||||
|
||||
static int ehci_xls_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
int retval;
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
ehci->regs = hcd->regs +
|
||||
HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||
dbg_hcs_params(ehci, "reset");
|
||||
dbg_hcc_params(ehci, "reset");
|
||||
|
||||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* data structure init */
|
||||
retval = ehci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
||||
return retval;
|
||||
return ehci_setup(ehci);
|
||||
}
|
||||
|
||||
int ehci_xls_probe_internal(const struct hc_driver *driver,
|
||||
|
@ -175,10 +175,6 @@ struct ehci_hcd { /* one per controller */
|
||||
#ifdef DEBUG
|
||||
struct dentry *debug_dir;
|
||||
#endif
|
||||
/*
|
||||
* OTG controllers and transceivers need software interaction
|
||||
*/
|
||||
struct usb_phy *transceiver;
|
||||
};
|
||||
|
||||
/* convert between an HCD pointer and the corresponding EHCI_HCD */
|
||||
|
@ -41,7 +41,7 @@ void fhci_dbg_isr(struct fhci_hcd *fhci, int usb_er)
|
||||
static int fhci_dfs_regs_show(struct seq_file *s, void *v)
|
||||
{
|
||||
struct fhci_hcd *fhci = s->private;
|
||||
struct fhci_regs __iomem *regs = fhci->regs;
|
||||
struct qe_usb_ctlr __iomem *regs = fhci->regs;
|
||||
|
||||
seq_printf(s,
|
||||
"mode: 0x%x\n" "addr: 0x%x\n"
|
||||
@ -50,11 +50,11 @@ static int fhci_dfs_regs_show(struct seq_file *s, void *v)
|
||||
"status: 0x%x\n" "SOF timer: %d\n"
|
||||
"frame number: %d\n"
|
||||
"lines status: 0x%x\n",
|
||||
in_8(®s->usb_mod), in_8(®s->usb_addr),
|
||||
in_8(®s->usb_comm), in_be16(®s->usb_ep[0]),
|
||||
in_be16(®s->usb_event), in_be16(®s->usb_mask),
|
||||
in_8(®s->usb_status), in_be16(®s->usb_sof_tmr),
|
||||
in_be16(®s->usb_frame_num),
|
||||
in_8(®s->usb_usmod), in_8(®s->usb_usadr),
|
||||
in_8(®s->usb_uscom), in_be16(®s->usb_usep[0]),
|
||||
in_be16(®s->usb_usber), in_be16(®s->usb_usbmr),
|
||||
in_8(®s->usb_usbs), in_be16(®s->usb_ussft),
|
||||
in_be16(®s->usb_usfrn),
|
||||
fhci_ioports_check_bus_state(fhci));
|
||||
|
||||
return 0;
|
||||
|
@ -40,8 +40,8 @@ void fhci_start_sof_timer(struct fhci_hcd *fhci)
|
||||
/* clear frame_n */
|
||||
out_be16(&fhci->pram->frame_num, 0);
|
||||
|
||||
out_be16(&fhci->regs->usb_sof_tmr, 0);
|
||||
setbits8(&fhci->regs->usb_mod, USB_MODE_SFTE);
|
||||
out_be16(&fhci->regs->usb_ussft, 0);
|
||||
setbits8(&fhci->regs->usb_usmod, USB_MODE_SFTE);
|
||||
|
||||
fhci_dbg(fhci, "<- %s\n", __func__);
|
||||
}
|
||||
@ -50,7 +50,7 @@ void fhci_stop_sof_timer(struct fhci_hcd *fhci)
|
||||
{
|
||||
fhci_dbg(fhci, "-> %s\n", __func__);
|
||||
|
||||
clrbits8(&fhci->regs->usb_mod, USB_MODE_SFTE);
|
||||
clrbits8(&fhci->regs->usb_usmod, USB_MODE_SFTE);
|
||||
gtm_stop_timer16(fhci->timer);
|
||||
|
||||
fhci_dbg(fhci, "<- %s\n", __func__);
|
||||
@ -58,7 +58,7 @@ void fhci_stop_sof_timer(struct fhci_hcd *fhci)
|
||||
|
||||
u16 fhci_get_sof_timer_count(struct fhci_usb *usb)
|
||||
{
|
||||
return be16_to_cpu(in_be16(&usb->fhci->regs->usb_sof_tmr) / 12);
|
||||
return be16_to_cpu(in_be16(&usb->fhci->regs->usb_ussft) / 12);
|
||||
}
|
||||
|
||||
/* initialize the endpoint zero */
|
||||
@ -88,8 +88,8 @@ void fhci_usb_enable_interrupt(struct fhci_usb *usb)
|
||||
enable_irq(fhci_to_hcd(fhci)->irq);
|
||||
|
||||
/* initialize the event register and mask register */
|
||||
out_be16(&usb->fhci->regs->usb_event, 0xffff);
|
||||
out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
|
||||
out_be16(&usb->fhci->regs->usb_usber, 0xffff);
|
||||
out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
|
||||
|
||||
/* enable the timer interrupts */
|
||||
enable_irq(fhci->timer->irq);
|
||||
@ -109,7 +109,7 @@ void fhci_usb_disable_interrupt(struct fhci_usb *usb)
|
||||
|
||||
/* disable the usb interrupt */
|
||||
disable_irq_nosync(fhci_to_hcd(fhci)->irq);
|
||||
out_be16(&usb->fhci->regs->usb_mask, 0);
|
||||
out_be16(&usb->fhci->regs->usb_usbmr, 0);
|
||||
}
|
||||
usb->intr_nesting_cnt++;
|
||||
}
|
||||
@ -119,9 +119,9 @@ static u32 fhci_usb_enable(struct fhci_hcd *fhci)
|
||||
{
|
||||
struct fhci_usb *usb = fhci->usb_lld;
|
||||
|
||||
out_be16(&usb->fhci->regs->usb_event, 0xffff);
|
||||
out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
|
||||
setbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN);
|
||||
out_be16(&usb->fhci->regs->usb_usber, 0xffff);
|
||||
out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
|
||||
setbits8(&usb->fhci->regs->usb_usmod, USB_MODE_EN);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
@ -141,7 +141,7 @@ static u32 fhci_usb_disable(struct fhci_hcd *fhci)
|
||||
usb->port_status == FHCI_PORT_LOW)
|
||||
fhci_device_disconnected_interrupt(fhci);
|
||||
|
||||
clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN);
|
||||
clrbits8(&usb->fhci->regs->usb_usmod, USB_MODE_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -285,13 +285,13 @@ static int fhci_usb_init(struct fhci_hcd *fhci)
|
||||
USB_E_IDLE_MASK |
|
||||
USB_E_RESET_MASK | USB_E_SFT_MASK | USB_E_MSF_MASK);
|
||||
|
||||
out_8(&usb->fhci->regs->usb_mod, USB_MODE_HOST | USB_MODE_EN);
|
||||
out_8(&usb->fhci->regs->usb_usmod, USB_MODE_HOST | USB_MODE_EN);
|
||||
|
||||
/* clearing the mask register */
|
||||
out_be16(&usb->fhci->regs->usb_mask, 0);
|
||||
out_be16(&usb->fhci->regs->usb_usbmr, 0);
|
||||
|
||||
/* initialing the event register */
|
||||
out_be16(&usb->fhci->regs->usb_event, 0xffff);
|
||||
out_be16(&usb->fhci->regs->usb_usber, 0xffff);
|
||||
|
||||
if (endpoint_zero_init(usb, DEFAULT_DATA_MEM, DEFAULT_RING_LEN) != 0) {
|
||||
fhci_usb_free(usb);
|
||||
@ -745,8 +745,8 @@ static int __devinit of_fhci_probe(struct platform_device *ofdev)
|
||||
}
|
||||
|
||||
/* Clear and disable any pending interrupts. */
|
||||
out_be16(&fhci->regs->usb_event, 0xffff);
|
||||
out_be16(&fhci->regs->usb_mask, 0);
|
||||
out_be16(&fhci->regs->usb_usber, 0xffff);
|
||||
out_be16(&fhci->regs->usb_usbmr, 0);
|
||||
|
||||
ret = usb_add_hcd(hcd, usb_irq, 0);
|
||||
if (ret < 0)
|
||||
|
@ -97,7 +97,7 @@ void fhci_port_disable(struct fhci_hcd *fhci)
|
||||
|
||||
/* Enable IDLE since we want to know if something comes along */
|
||||
usb->saved_msk |= USB_E_IDLE_MASK;
|
||||
out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
|
||||
out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
|
||||
|
||||
/* check if during the disconnection process attached new device */
|
||||
if (port_status == FHCI_PORT_WAITING)
|
||||
@ -158,21 +158,21 @@ void fhci_port_reset(void *lld)
|
||||
|
||||
fhci_stop_sof_timer(fhci);
|
||||
/* disable the USB controller */
|
||||
mode = in_8(&fhci->regs->usb_mod);
|
||||
out_8(&fhci->regs->usb_mod, mode & (~USB_MODE_EN));
|
||||
mode = in_8(&fhci->regs->usb_usmod);
|
||||
out_8(&fhci->regs->usb_usmod, mode & (~USB_MODE_EN));
|
||||
|
||||
/* disable idle interrupts */
|
||||
mask = in_be16(&fhci->regs->usb_mask);
|
||||
out_be16(&fhci->regs->usb_mask, mask & (~USB_E_IDLE_MASK));
|
||||
mask = in_be16(&fhci->regs->usb_usbmr);
|
||||
out_be16(&fhci->regs->usb_usbmr, mask & (~USB_E_IDLE_MASK));
|
||||
|
||||
fhci_io_port_generate_reset(fhci);
|
||||
|
||||
/* enable interrupt on this endpoint */
|
||||
out_be16(&fhci->regs->usb_mask, mask);
|
||||
out_be16(&fhci->regs->usb_usbmr, mask);
|
||||
|
||||
/* enable the USB controller */
|
||||
mode = in_8(&fhci->regs->usb_mod);
|
||||
out_8(&fhci->regs->usb_mod, mode | USB_MODE_EN);
|
||||
mode = in_8(&fhci->regs->usb_usmod);
|
||||
out_8(&fhci->regs->usb_usmod, mode | USB_MODE_EN);
|
||||
fhci_start_sof_timer(fhci);
|
||||
|
||||
fhci_dbg(fhci, "<- %s\n", __func__);
|
||||
|
@ -132,8 +132,8 @@ void fhci_flush_all_transmissions(struct fhci_usb *usb)
|
||||
u8 mode;
|
||||
struct td *td;
|
||||
|
||||
mode = in_8(&usb->fhci->regs->usb_mod);
|
||||
clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN);
|
||||
mode = in_8(&usb->fhci->regs->usb_usmod);
|
||||
clrbits8(&usb->fhci->regs->usb_usmod, USB_MODE_EN);
|
||||
|
||||
fhci_flush_bds(usb);
|
||||
|
||||
@ -147,9 +147,9 @@ void fhci_flush_all_transmissions(struct fhci_usb *usb)
|
||||
usb->actual_frame->frame_status = FRAME_END_TRANSMISSION;
|
||||
|
||||
/* reset the event register */
|
||||
out_be16(&usb->fhci->regs->usb_event, 0xffff);
|
||||
out_be16(&usb->fhci->regs->usb_usber, 0xffff);
|
||||
/* enable the USB controller */
|
||||
out_8(&usb->fhci->regs->usb_mod, mode | USB_MODE_EN);
|
||||
out_8(&usb->fhci->regs->usb_usmod, mode | USB_MODE_EN);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -414,7 +414,7 @@ static void sof_interrupt(struct fhci_hcd *fhci)
|
||||
usb->port_status = FHCI_PORT_FULL;
|
||||
/* Disable IDLE */
|
||||
usb->saved_msk &= ~USB_E_IDLE_MASK;
|
||||
out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
|
||||
out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
|
||||
}
|
||||
|
||||
gtm_set_exact_timer16(fhci->timer, usb->max_frame_usage, false);
|
||||
@ -433,14 +433,14 @@ void fhci_device_disconnected_interrupt(struct fhci_hcd *fhci)
|
||||
fhci_dbg(fhci, "-> %s\n", __func__);
|
||||
|
||||
fhci_usb_disable_interrupt(usb);
|
||||
clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS);
|
||||
clrbits8(&usb->fhci->regs->usb_usmod, USB_MODE_LSS);
|
||||
usb->port_status = FHCI_PORT_DISABLED;
|
||||
|
||||
fhci_stop_sof_timer(fhci);
|
||||
|
||||
/* Enable IDLE since we want to know if something comes along */
|
||||
usb->saved_msk |= USB_E_IDLE_MASK;
|
||||
out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);
|
||||
out_be16(&usb->fhci->regs->usb_usbmr, usb->saved_msk);
|
||||
|
||||
usb->vroot_hub->port.wPortStatus &= ~USB_PORT_STAT_CONNECTION;
|
||||
usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_CONNECTION;
|
||||
@ -473,7 +473,7 @@ void fhci_device_connected_interrupt(struct fhci_hcd *fhci)
|
||||
}
|
||||
|
||||
usb->port_status = FHCI_PORT_LOW;
|
||||
setbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS);
|
||||
setbits8(&usb->fhci->regs->usb_usmod, USB_MODE_LSS);
|
||||
usb->vroot_hub->port.wPortStatus |=
|
||||
(USB_PORT_STAT_LOW_SPEED |
|
||||
USB_PORT_STAT_CONNECTION);
|
||||
@ -491,7 +491,7 @@ void fhci_device_connected_interrupt(struct fhci_hcd *fhci)
|
||||
}
|
||||
|
||||
usb->port_status = FHCI_PORT_FULL;
|
||||
clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS);
|
||||
clrbits8(&usb->fhci->regs->usb_usmod, USB_MODE_LSS);
|
||||
usb->vroot_hub->port.wPortStatus &=
|
||||
~USB_PORT_STAT_LOW_SPEED;
|
||||
usb->vroot_hub->port.wPortStatus |=
|
||||
@ -535,7 +535,7 @@ static void abort_transmission(struct fhci_usb *usb)
|
||||
/* issue stop Tx command */
|
||||
qe_issue_cmd(QE_USB_STOP_TX, QE_CR_SUBBLOCK_USB, EP_ZERO, 0);
|
||||
/* flush Tx FIFOs */
|
||||
out_8(&usb->fhci->regs->usb_comm, USB_CMD_FLUSH_FIFO | EP_ZERO);
|
||||
out_8(&usb->fhci->regs->usb_uscom, USB_CMD_FLUSH_FIFO | EP_ZERO);
|
||||
udelay(1000);
|
||||
/* reset Tx BDs */
|
||||
fhci_flush_bds(usb);
|
||||
@ -555,11 +555,11 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd)
|
||||
|
||||
usb = fhci->usb_lld;
|
||||
|
||||
usb_er |= in_be16(&usb->fhci->regs->usb_event) &
|
||||
in_be16(&usb->fhci->regs->usb_mask);
|
||||
usb_er |= in_be16(&usb->fhci->regs->usb_usber) &
|
||||
in_be16(&usb->fhci->regs->usb_usbmr);
|
||||
|
||||
/* clear event bits for next time */
|
||||
out_be16(&usb->fhci->regs->usb_event, usb_er);
|
||||
out_be16(&usb->fhci->regs->usb_usber, usb_er);
|
||||
|
||||
fhci_dbg_isr(fhci, usb_er);
|
||||
|
||||
@ -573,7 +573,7 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd)
|
||||
|
||||
/* Turn on IDLE since we want to disconnect */
|
||||
usb->saved_msk |= USB_E_IDLE_MASK;
|
||||
out_be16(&usb->fhci->regs->usb_event,
|
||||
out_be16(&usb->fhci->regs->usb_usber,
|
||||
usb->saved_msk);
|
||||
} else if (usb->port_status == FHCI_PORT_DISABLED) {
|
||||
if (fhci_ioports_check_bus_state(fhci) == 1)
|
||||
@ -611,7 +611,7 @@ irqreturn_t fhci_irq(struct usb_hcd *hcd)
|
||||
/* XXX usb->port_status = FHCI_PORT_WAITING; */
|
||||
/* Disable IDLE */
|
||||
usb->saved_msk &= ~USB_E_IDLE_MASK;
|
||||
out_be16(&usb->fhci->regs->usb_mask,
|
||||
out_be16(&usb->fhci->regs->usb_usbmr,
|
||||
usb->saved_msk);
|
||||
} else {
|
||||
fhci_dbg_isr(fhci, -1);
|
||||
|
@ -249,7 +249,7 @@ void fhci_init_ep_registers(struct fhci_usb *usb, struct endpoint *ep,
|
||||
u8 rt;
|
||||
|
||||
/* set the endpoint registers according to the endpoint */
|
||||
out_be16(&usb->fhci->regs->usb_ep[0],
|
||||
out_be16(&usb->fhci->regs->usb_usep[0],
|
||||
USB_TRANS_CTR | USB_EP_MF | USB_EP_RTE);
|
||||
out_be16(&usb->fhci->pram->ep_ptr[0],
|
||||
cpm_muram_offset(ep->ep_pram_ptr));
|
||||
@ -463,7 +463,7 @@ u32 fhci_host_transaction(struct fhci_usb *usb,
|
||||
cq_put(&ep->conf_frame_Q, pkt);
|
||||
|
||||
if (cq_howmany(&ep->conf_frame_Q) == 1)
|
||||
out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO);
|
||||
out_8(&usb->fhci->regs->usb_uscom, USB_CMD_STR_FIFO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -535,8 +535,8 @@ void fhci_flush_actual_frame(struct fhci_usb *usb)
|
||||
struct endpoint *ep = usb->ep0;
|
||||
|
||||
/* disable the USB controller */
|
||||
mode = in_8(&usb->fhci->regs->usb_mod);
|
||||
out_8(&usb->fhci->regs->usb_mod, mode & ~USB_MODE_EN);
|
||||
mode = in_8(&usb->fhci->regs->usb_usmod);
|
||||
out_8(&usb->fhci->regs->usb_usmod, mode & ~USB_MODE_EN);
|
||||
|
||||
tb_ptr = in_be16(&ep->ep_pram_ptr->tx_bd_ptr);
|
||||
td = cpm_muram_addr(tb_ptr);
|
||||
@ -571,9 +571,9 @@ void fhci_flush_actual_frame(struct fhci_usb *usb)
|
||||
usb->actual_frame->frame_status = FRAME_TIMER_END_TRANSMISSION;
|
||||
|
||||
/* reset the event register */
|
||||
out_be16(&usb->fhci->regs->usb_event, 0xffff);
|
||||
out_be16(&usb->fhci->regs->usb_usber, 0xffff);
|
||||
/* enable the USB controller */
|
||||
out_8(&usb->fhci->regs->usb_mod, mode | USB_MODE_EN);
|
||||
out_8(&usb->fhci->regs->usb_usmod, mode | USB_MODE_EN);
|
||||
}
|
||||
|
||||
/* handles Tx confirm and Tx error interrupt */
|
||||
@ -613,7 +613,7 @@ void fhci_host_transmit_actual_frame(struct fhci_usb *usb)
|
||||
|
||||
/* start transmit only if we have something in the TDs */
|
||||
if (in_be16(&td->status) & TD_R)
|
||||
out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO);
|
||||
out_8(&usb->fhci->regs->usb_uscom, USB_CMD_STR_FIFO);
|
||||
|
||||
if (in_be32(&ep->conf_td->buf_ptr) == DUMMY_BD_BUFFER) {
|
||||
out_be32(&old_td->buf_ptr, 0);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <asm/qe.h>
|
||||
#include <asm/immap_qe.h>
|
||||
|
||||
#define USB_CLOCK 48000000
|
||||
|
||||
@ -173,25 +174,6 @@
|
||||
#define USB_E_TXB_MASK 0x0002
|
||||
#define USB_E_RXB_MASK 0x0001
|
||||
|
||||
/* Freescale USB Host controller registers */
|
||||
struct fhci_regs {
|
||||
u8 usb_mod; /* mode register */
|
||||
u8 usb_addr; /* address register */
|
||||
u8 usb_comm; /* command register */
|
||||
u8 reserved1[1];
|
||||
__be16 usb_ep[4]; /* endpoint register */
|
||||
u8 reserved2[4];
|
||||
__be16 usb_event; /* event register */
|
||||
u8 reserved3[2];
|
||||
__be16 usb_mask; /* mask register */
|
||||
u8 reserved4[1];
|
||||
u8 usb_status; /* status register */
|
||||
__be16 usb_sof_tmr; /* Start Of Frame timer */
|
||||
u8 reserved5[2];
|
||||
__be16 usb_frame_num; /* frame number register */
|
||||
u8 reserved6[1];
|
||||
};
|
||||
|
||||
/* Freescale USB HOST */
|
||||
struct fhci_pram {
|
||||
__be16 ep_ptr[4]; /* Endpoint porter reg */
|
||||
@ -267,7 +249,7 @@ struct fhci_hcd {
|
||||
int gpios[NUM_GPIOS];
|
||||
bool alow_gpios[NUM_GPIOS];
|
||||
|
||||
struct fhci_regs __iomem *regs; /* I/O memory used to communicate */
|
||||
struct qe_usb_ctlr __iomem *regs; /* I/O memory used to communicate */
|
||||
struct fhci_pram __iomem *pram; /* Parameter RAM */
|
||||
struct gtm_timer *timer;
|
||||
|
||||
|
@ -1811,7 +1811,7 @@ static int imx21_remove(struct platform_device *pdev)
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
if (res != NULL) {
|
||||
clk_disable(imx21->clk);
|
||||
clk_disable_unprepare(imx21->clk);
|
||||
clk_put(imx21->clk);
|
||||
iounmap(imx21->regs);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
@ -1884,7 +1884,7 @@ static int imx21_probe(struct platform_device *pdev)
|
||||
ret = clk_set_rate(imx21->clk, clk_round_rate(imx21->clk, 48000000));
|
||||
if (ret)
|
||||
goto failed_clock_set;
|
||||
ret = clk_enable(imx21->clk);
|
||||
ret = clk_prepare_enable(imx21->clk);
|
||||
if (ret)
|
||||
goto failed_clock_enable;
|
||||
|
||||
@ -1900,7 +1900,7 @@ static int imx21_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
failed_add_hcd:
|
||||
clk_disable(imx21->clk);
|
||||
clk_disable_unprepare(imx21->clk);
|
||||
failed_clock_enable:
|
||||
failed_clock_set:
|
||||
clk_put(imx21->clk);
|
||||
|
@ -87,7 +87,8 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
exynos_ohci = kzalloc(sizeof(struct exynos_ohci_hcd), GFP_KERNEL);
|
||||
exynos_ohci = devm_kzalloc(&pdev->dev, sizeof(struct exynos_ohci_hcd),
|
||||
GFP_KERNEL);
|
||||
if (!exynos_ohci)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -97,8 +98,7 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev)
|
||||
dev_name(&pdev->dev));
|
||||
if (!hcd) {
|
||||
dev_err(&pdev->dev, "Unable to create HCD\n");
|
||||
err = -ENOMEM;
|
||||
goto fail_hcd;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
exynos_ohci->hcd = hcd;
|
||||
@ -123,7 +123,7 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev)
|
||||
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = resource_size(res);
|
||||
hcd->regs = ioremap(res->start, resource_size(res));
|
||||
hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len);
|
||||
if (!hcd->regs) {
|
||||
dev_err(&pdev->dev, "Failed to remap I/O memory\n");
|
||||
err = -ENOMEM;
|
||||
@ -134,7 +134,7 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev)
|
||||
if (!irq) {
|
||||
dev_err(&pdev->dev, "Failed to get IRQ\n");
|
||||
err = -ENODEV;
|
||||
goto fail;
|
||||
goto fail_io;
|
||||
}
|
||||
|
||||
if (pdata->phy_init)
|
||||
@ -146,23 +146,19 @@ static int __devinit exynos_ohci_probe(struct platform_device *pdev)
|
||||
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to add USB HCD\n");
|
||||
goto fail;
|
||||
goto fail_io;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, exynos_ohci);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
iounmap(hcd->regs);
|
||||
fail_io:
|
||||
clk_disable(exynos_ohci->clk);
|
||||
fail_clken:
|
||||
clk_put(exynos_ohci->clk);
|
||||
fail_clk:
|
||||
usb_put_hcd(hcd);
|
||||
fail_hcd:
|
||||
kfree(exynos_ohci);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -177,13 +173,10 @@ static int __devexit exynos_ohci_remove(struct platform_device *pdev)
|
||||
if (pdata && pdata->phy_exit)
|
||||
pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
|
||||
|
||||
iounmap(hcd->regs);
|
||||
|
||||
clk_disable(exynos_ohci->clk);
|
||||
clk_put(exynos_ohci->clk);
|
||||
|
||||
usb_put_hcd(hcd);
|
||||
kfree(exynos_ohci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -225,6 +218,9 @@ static int exynos_ohci_suspend(struct device *dev)
|
||||
|
||||
if (pdata && pdata->phy_exit)
|
||||
pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
|
||||
|
||||
clk_disable(exynos_ohci->clk);
|
||||
|
||||
fail:
|
||||
spin_unlock_irqrestore(&ohci->lock, flags);
|
||||
|
||||
@ -238,6 +234,8 @@ static int exynos_ohci_resume(struct device *dev)
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
|
||||
|
||||
clk_enable(exynos_ohci->clk);
|
||||
|
||||
if (pdata && pdata->phy_init)
|
||||
pdata->phy_init(pdev, S5P_USB_PHY_HOST);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user