usb: changes for v3.14 merge window
This pull request is quite extensive, containing 105 non-merge commits. Because of that, we describe the changes in sections below: New drivers: - Keystone PHY driver and DWC3 Glue Layer - Aeroflex Gaisler GRUSBDC - Tahvo PHY driver for N770 - JZ4740 MUSB gluer Layer - Broadcom PHY Driver Important new features: - MUSB DSPS learned about suspend/resume - New quirk_ep_out_aligned_size flag added to struct usb_gadget - DWC3 initializes the new quirk flag so gadget drivers can use it. - AM335x PHY Driver learns about remote wakeup - Renesas USBHS now requests DMA Engine only once - s3c-hsotg is now re-used on Broadcom devices - USB PHY layer now makes sure to initialize the notifier for all drivers - omap-control learned about TI's new AM437x devices - few other usb gadget/function drivers learned about the new configfs-based binding. Misc Fixes and Clean Ups: - Several sparse fixes all over the place - Removal of redundant of_match_ptr() - r-car gen2 phy now uses usb_add_phy_dev() - removal of DEFINE_PCI_DEVICE_TABLE() from a few drivers - conversion to clk_prepare/clk_unprepare on r8a66597-udc - some randconfig errors and build warnings were fixed - removal of unnecessary lock on dwc3-omap.c Signed-of-by: Felipe Balbi <balbi@ti.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.15 (GNU/Linux) iQIcBAABAgAGBQJSvK5dAAoJEIaOsuA1yqREKrEP/jdrhxgkavR39dgpWj3ujsjf jnH9GH9jhLgphpL8jHVxnbu7YHCy2qlHeZMiVksSYwZuAZY3fp00xTpzOCKVyRmr LTRvyqTKh90SOqRcx/3MX4DdUf+paG75z7QMQM362fjdogh41sJK76rk+loPjOWf mBOmSphQrfDrqBunigdtSVsq3c/kiwWSbU3kzF/wttu//DuMsahxu1D9+UN0yxMl NpI84E06ii1qyOt4H5UyN/jWwIcrleC3YFCe5EF+8lRluOjNJCfUD7qOgAOoEVJ/ OAhgBj+Q47KY39Tz/vfgCuIvKLsnLcnX8SS3mvQQgpa0Rw0EEHyakrD4p07Qfnuk H4WfYH0NB/BxKmH6IqQHg/pLWlqAvrqWuHpgO8Y2Mlfr5ILFhzcAM2mTvLVfn6+D VJslKXWhVpHWiFsstDdwzqwI9sxoHo1E2QTikkh4jPiD8duaQraneXPkoQn7FW4A wMYsPDL1T4wkYfE7vpY2iX76KjRa48FjuQbrxb6hZoKUEWhAqKcaEZWcz8d42DH5 LmfrpzJPCONos4yfEoxIZJ/Jve2eR82Tx+Pd+OV3/edVCi5VR/RJsxtLdXF6dNkm VmZsVT1s9D4QllsTp8/pJyUMRFoxDyhIdlC/22dlULIYq9FYqkc+5lTwpvt621t9 n/iKABz1jGfM6hhi8Kkj =N4// -----END PGP SIGNATURE----- Merge tag 'usb-for-v3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next Felipe writes: usb: changes for v3.14 merge window This pull request is quite extensive, containing 105 non-merge commits. Because of that, we describe the changes in sections below: New drivers: - Keystone PHY driver and DWC3 Glue Layer - Aeroflex Gaisler GRUSBDC - Tahvo PHY driver for N770 - JZ4740 MUSB gluer Layer - Broadcom PHY Driver Important new features: - MUSB DSPS learned about suspend/resume - New quirk_ep_out_aligned_size flag added to struct usb_gadget - DWC3 initializes the new quirk flag so gadget drivers can use it. - AM335x PHY Driver learns about remote wakeup - Renesas USBHS now requests DMA Engine only once - s3c-hsotg is now re-used on Broadcom devices - USB PHY layer now makes sure to initialize the notifier for all drivers - omap-control learned about TI's new AM437x devices - few other usb gadget/function drivers learned about the new configfs-based binding. Misc Fixes and Clean Ups: - Several sparse fixes all over the place - Removal of redundant of_match_ptr() - r-car gen2 phy now uses usb_add_phy_dev() - removal of DEFINE_PCI_DEVICE_TABLE() from a few drivers - conversion to clk_prepare/clk_unprepare on r8a66597-udc - some randconfig errors and build warnings were fixed - removal of unnecessary lock on dwc3-omap.c Signed-of-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
commit
73ad0adcb6
9
Documentation/ABI/testing/configfs-usb-gadget-ffs
Normal file
9
Documentation/ABI/testing/configfs-usb-gadget-ffs
Normal file
@ -0,0 +1,9 @@
|
||||
What: /config/usb-gadget/gadget/functions/ffs.name
|
||||
Date: Nov 2013
|
||||
KenelVersion: 3.13
|
||||
Description: The purpose of this directory is to create and remove it.
|
||||
|
||||
A corresponding USB function instance is created/removed.
|
||||
There are no attributes here.
|
||||
|
||||
All parameters are set through FunctionFS.
|
8
Documentation/ABI/testing/configfs-usb-gadget-loopback
Normal file
8
Documentation/ABI/testing/configfs-usb-gadget-loopback
Normal file
@ -0,0 +1,8 @@
|
||||
What: /config/usb-gadget/gadget/functions/Loopback.name
|
||||
Date: Nov 2013
|
||||
KenelVersion: 3.13
|
||||
Description:
|
||||
The attributes:
|
||||
|
||||
qlen - depth of loopback queue
|
||||
bulk_buflen - buffer length
|
12
Documentation/ABI/testing/configfs-usb-gadget-sourcesink
Normal file
12
Documentation/ABI/testing/configfs-usb-gadget-sourcesink
Normal file
@ -0,0 +1,12 @@
|
||||
What: /config/usb-gadget/gadget/functions/SourceSink.name
|
||||
Date: Nov 2013
|
||||
KenelVersion: 3.13
|
||||
Description:
|
||||
The attributes:
|
||||
|
||||
pattern - 0 (all zeros), 1 (mod63), 2 (none)
|
||||
isoc_interval - 1..16
|
||||
isoc_maxpacket - 0 - 1023 (fs), 0 - 1024 (hs/ss)
|
||||
isoc_mult - 0..2 (hs/ss only)
|
||||
isoc_maxburst - 0..15 (ss only)
|
||||
qlen - buffer length
|
16
Documentation/ABI/testing/sysfs-platform-tahvo-usb
Normal file
16
Documentation/ABI/testing/sysfs-platform-tahvo-usb
Normal file
@ -0,0 +1,16 @@
|
||||
What: /sys/bus/platform/devices/tahvo-usb/otg_mode
|
||||
Date: December 2013
|
||||
Contact: Aaro Koskinen <aaro.koskinen@iki.fi>
|
||||
Description:
|
||||
Set or read the current OTG mode. Valid values are "host" and
|
||||
"peripheral".
|
||||
|
||||
Reading: returns the current mode.
|
||||
|
||||
What: /sys/bus/platform/devices/tahvo-usb/vbus
|
||||
Date: December 2013
|
||||
Contact: Aaro Koskinen <aaro.koskinen@iki.fi>
|
||||
Description:
|
||||
Read the current VBUS state.
|
||||
|
||||
Reading: returns "on" or "off".
|
15
Documentation/devicetree/bindings/phy/bcm-phy.txt
Normal file
15
Documentation/devicetree/bindings/phy/bcm-phy.txt
Normal file
@ -0,0 +1,15 @@
|
||||
BROADCOM KONA USB2 PHY
|
||||
|
||||
Required properties:
|
||||
- compatible: brcm,kona-usb2-phy
|
||||
- reg: offset and length of the PHY registers
|
||||
- #phy-cells: must be 0
|
||||
Refer to phy/phy-bindings.txt for the generic PHY binding properties
|
||||
|
||||
Example:
|
||||
|
||||
usbphy: usb-phy@3f130000 {
|
||||
compatible = "brcm,kona-usb2-phy";
|
||||
reg = <0x3f130000 0x28>;
|
||||
#phy-cells = <0>;
|
||||
};
|
@ -5,6 +5,14 @@ Required properties:
|
||||
- compatible : "snps,dwc2"
|
||||
- reg : Should contain 1 register range (address and length)
|
||||
- interrupts : Should contain 1 interrupt
|
||||
- clocks: clock provider specifier
|
||||
- clock-names: shall be "otg"
|
||||
Refer to clk/clock-bindings.txt for generic clock consumer properties
|
||||
|
||||
Optional properties:
|
||||
- phys: phy provider specifier
|
||||
- phy-names: shall be "device"
|
||||
Refer to phy/phy-bindings.txt for generic phy consumer properties
|
||||
|
||||
Example:
|
||||
|
||||
@ -12,4 +20,8 @@ Example:
|
||||
compatible = "ralink,rt3050-usb, snps,dwc2";
|
||||
reg = <0x101c0000 40000>;
|
||||
interrupts = <18>;
|
||||
clocks = <&usb_otg_ahb_clk>;
|
||||
clock-names = "otg";
|
||||
phys = <&usbphy>;
|
||||
phy-names = "usb2-phy";
|
||||
};
|
||||
|
28
Documentation/devicetree/bindings/usb/gr-udc.txt
Normal file
28
Documentation/devicetree/bindings/usb/gr-udc.txt
Normal file
@ -0,0 +1,28 @@
|
||||
USB Peripheral Controller driver for Aeroflex Gaisler GRUSBDC.
|
||||
|
||||
The GRUSBDC USB Device Controller core is available in the GRLIB VHDL
|
||||
IP core library.
|
||||
|
||||
Note: In the ordinary environment for the core, a Leon SPARC system,
|
||||
these properties are built from information in the AMBA plug&play.
|
||||
|
||||
Required properties:
|
||||
|
||||
- name : Should be "GAISLER_USBDC" or "01_021"
|
||||
|
||||
- reg : Address and length of the register set for the device
|
||||
|
||||
- interrupts : Interrupt numbers for this device
|
||||
|
||||
Optional properties:
|
||||
|
||||
- epobufsizes : An array of buffer sizes for OUT endpoints. If the property is
|
||||
not present, or for endpoints outside of the array, 1024 is assumed by
|
||||
the driver.
|
||||
|
||||
- epibufsizes : An array of buffer sizes for IN endpoints. If the property is
|
||||
not present, or for endpoints outside of the array, 1024 is assumed by
|
||||
the driver.
|
||||
|
||||
For further information look in the documentation for the GLIB IP core library:
|
||||
http://www.gaisler.com/products/grlib/grip.pdf
|
@ -87,6 +87,8 @@ Required properties:
|
||||
e.g. USB3 PHY and SATA PHY on OMAP5.
|
||||
"ti,control-phy-dra7usb2" - if it has power down register like USB2 PHY on
|
||||
DRA7 platform.
|
||||
"ti,control-phy-am437usb2" - if it has power down register like USB2 PHY on
|
||||
AM437 platform.
|
||||
- reg : Address and length of the register set for the device. It contains
|
||||
the address of "otghs_control" for control-phy-otghs or "power" register
|
||||
for other types.
|
||||
|
@ -8,43 +8,7 @@
|
||||
#define is_usb0_device(config) 0
|
||||
#endif
|
||||
|
||||
struct omap_usb_config {
|
||||
/* Configure drivers according to the connectors on your board:
|
||||
* - "A" connector (rectagular)
|
||||
* ... for host/OHCI use, set "register_host".
|
||||
* - "B" connector (squarish) or "Mini-B"
|
||||
* ... for device/gadget use, set "register_dev".
|
||||
* - "Mini-AB" connector (very similar to Mini-B)
|
||||
* ... for OTG use as device OR host, initialize "otg"
|
||||
*/
|
||||
unsigned register_host:1;
|
||||
unsigned register_dev:1;
|
||||
u8 otg; /* port number, 1-based: usb1 == 2 */
|
||||
|
||||
u8 hmc_mode;
|
||||
|
||||
/* implicitly true if otg: host supports remote wakeup? */
|
||||
u8 rwc;
|
||||
|
||||
/* signaling pins used to talk to transceiver on usbN:
|
||||
* 0 == usbN unused
|
||||
* 2 == usb0-only, using internal transceiver
|
||||
* 3 == 3 wire bidirectional
|
||||
* 4 == 4 wire bidirectional
|
||||
* 6 == 6 wire unidirectional (or TLL)
|
||||
*/
|
||||
u8 pins[3];
|
||||
|
||||
struct platform_device *udc_device;
|
||||
struct platform_device *ohci_device;
|
||||
struct platform_device *otg_device;
|
||||
|
||||
u32 (*usb0_init)(unsigned nwires, unsigned is_device);
|
||||
u32 (*usb1_init)(unsigned nwires);
|
||||
u32 (*usb2_init)(unsigned nwires, unsigned alt_pingroup);
|
||||
|
||||
int (*ocpi_enable)(void);
|
||||
};
|
||||
#include <linux/platform_data/usb-omap1.h>
|
||||
|
||||
void omap_otg_init(struct omap_usb_config *config);
|
||||
|
||||
|
@ -51,4 +51,10 @@ config PHY_EXYNOS_DP_VIDEO
|
||||
help
|
||||
Support for Display Port PHY found on Samsung EXYNOS SoCs.
|
||||
|
||||
config BCM_KONA_USB2_PHY
|
||||
tristate "Broadcom Kona USB2 PHY Driver"
|
||||
depends on GENERIC_PHY
|
||||
help
|
||||
Enable this to support the Broadcom Kona USB 2.0 PHY.
|
||||
|
||||
endmenu
|
||||
|
@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_GENERIC_PHY) += phy-core.o
|
||||
obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o
|
||||
obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o
|
||||
obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o
|
||||
obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o
|
||||
|
158
drivers/phy/phy-bcm-kona-usb2.c
Normal file
158
drivers/phy/phy-bcm-kona-usb2.c
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* phy-bcm-kona-usb2.c - Broadcom Kona USB2 Phy Driver
|
||||
*
|
||||
* Copyright (C) 2013 Linaro Limited
|
||||
* Matt Porter <mporter@linaro.org>
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define OTGCTL (0)
|
||||
#define OTGCTL_OTGSTAT2 BIT(31)
|
||||
#define OTGCTL_OTGSTAT1 BIT(30)
|
||||
#define OTGCTL_PRST_N_SW BIT(11)
|
||||
#define OTGCTL_HRESET_N BIT(10)
|
||||
#define OTGCTL_UTMI_LINE_STATE1 BIT(9)
|
||||
#define OTGCTL_UTMI_LINE_STATE0 BIT(8)
|
||||
|
||||
#define P1CTL (8)
|
||||
#define P1CTL_SOFT_RESET BIT(1)
|
||||
#define P1CTL_NON_DRIVING BIT(0)
|
||||
|
||||
struct bcm_kona_usb {
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
static void bcm_kona_usb_phy_power(struct bcm_kona_usb *phy, int on)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(phy->regs + OTGCTL);
|
||||
if (on) {
|
||||
/* Configure and power PHY */
|
||||
val &= ~(OTGCTL_OTGSTAT2 | OTGCTL_OTGSTAT1 |
|
||||
OTGCTL_UTMI_LINE_STATE1 | OTGCTL_UTMI_LINE_STATE0);
|
||||
val |= OTGCTL_PRST_N_SW | OTGCTL_HRESET_N;
|
||||
} else {
|
||||
val &= ~(OTGCTL_PRST_N_SW | OTGCTL_HRESET_N);
|
||||
}
|
||||
writel(val, phy->regs + OTGCTL);
|
||||
}
|
||||
|
||||
static int bcm_kona_usb_phy_init(struct phy *gphy)
|
||||
{
|
||||
struct bcm_kona_usb *phy = phy_get_drvdata(gphy);
|
||||
u32 val;
|
||||
|
||||
/* Soft reset PHY */
|
||||
val = readl(phy->regs + P1CTL);
|
||||
val &= ~P1CTL_NON_DRIVING;
|
||||
val |= P1CTL_SOFT_RESET;
|
||||
writel(val, phy->regs + P1CTL);
|
||||
writel(val & ~P1CTL_SOFT_RESET, phy->regs + P1CTL);
|
||||
/* Reset needs to be asserted for 2ms */
|
||||
mdelay(2);
|
||||
writel(val | P1CTL_SOFT_RESET, phy->regs + P1CTL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm_kona_usb_phy_power_on(struct phy *gphy)
|
||||
{
|
||||
struct bcm_kona_usb *phy = phy_get_drvdata(gphy);
|
||||
|
||||
bcm_kona_usb_phy_power(phy, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm_kona_usb_phy_power_off(struct phy *gphy)
|
||||
{
|
||||
struct bcm_kona_usb *phy = phy_get_drvdata(gphy);
|
||||
|
||||
bcm_kona_usb_phy_power(phy, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops ops = {
|
||||
.init = bcm_kona_usb_phy_init,
|
||||
.power_on = bcm_kona_usb_phy_power_on,
|
||||
.power_off = bcm_kona_usb_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int bcm_kona_usb2_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bcm_kona_usb *phy;
|
||||
struct resource *res;
|
||||
struct phy *gphy;
|
||||
struct phy_provider *phy_provider;
|
||||
|
||||
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
|
||||
if (!phy)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
phy->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(phy->regs))
|
||||
return PTR_ERR(phy->regs);
|
||||
|
||||
platform_set_drvdata(pdev, phy);
|
||||
|
||||
gphy = devm_phy_create(dev, &ops, NULL);
|
||||
if (IS_ERR(gphy))
|
||||
return PTR_ERR(gphy);
|
||||
|
||||
/* The Kona PHY supports an 8-bit wide UTMI interface */
|
||||
phy_set_bus_width(gphy, 8);
|
||||
|
||||
phy_set_drvdata(gphy, phy);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev,
|
||||
of_phy_simple_xlate);
|
||||
if (IS_ERR(phy_provider))
|
||||
return PTR_ERR(phy_provider);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id bcm_kona_usb2_dt_ids[] = {
|
||||
{ .compatible = "brcm,kona-usb2-phy" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, bcm_kona_usb2_dt_ids);
|
||||
|
||||
static struct platform_driver bcm_kona_usb2_driver = {
|
||||
.probe = bcm_kona_usb2_probe,
|
||||
.driver = {
|
||||
.name = "bcm-kona-usb2",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = bcm_kona_usb2_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(bcm_kona_usb2_driver);
|
||||
|
||||
MODULE_ALIAS("platform:bcm-kona-usb2");
|
||||
MODULE_AUTHOR("Matt Porter <mporter@linaro.org>");
|
||||
MODULE_DESCRIPTION("BCM Kona USB 2.0 PHY driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -94,8 +94,6 @@ source "drivers/usb/wusbcore/Kconfig"
|
||||
|
||||
source "drivers/usb/host/Kconfig"
|
||||
|
||||
source "drivers/usb/musb/Kconfig"
|
||||
|
||||
source "drivers/usb/renesas_usbhs/Kconfig"
|
||||
|
||||
source "drivers/usb/class/Kconfig"
|
||||
@ -106,6 +104,8 @@ source "drivers/usb/image/Kconfig"
|
||||
|
||||
endif
|
||||
|
||||
source "drivers/usb/musb/Kconfig"
|
||||
|
||||
source "drivers/usb/dwc3/Kconfig"
|
||||
|
||||
source "drivers/usb/chipidea/Kconfig"
|
||||
|
@ -1566,7 +1566,7 @@ static int init_eps(struct ci_hdrc *ci)
|
||||
* eps, maxP is set by epautoconfig() called
|
||||
* by gadget layer
|
||||
*/
|
||||
hwep->ep.maxpacket = (unsigned short)~0;
|
||||
usb_ep_set_maxpacket_limit(&hwep->ep, (unsigned short)~0);
|
||||
|
||||
INIT_LIST_HEAD(&hwep->qh.queue);
|
||||
hwep->qh.ptr = dma_pool_alloc(ci->qh_pool, GFP_KERNEL,
|
||||
@ -1586,7 +1586,7 @@ static int init_eps(struct ci_hdrc *ci)
|
||||
else
|
||||
ci->ep0in = hwep;
|
||||
|
||||
hwep->ep.maxpacket = CTRL_PAYLOAD_MAX;
|
||||
usb_ep_set_maxpacket_limit(&hwep->ep, CTRL_PAYLOAD_MAX);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,13 @@ config USB_DWC3_PCI
|
||||
One such PCIe-based platform is Synopsys' PCIe HAPS model of
|
||||
this IP.
|
||||
|
||||
config USB_DWC3_KEYSTONE
|
||||
tristate "Texas Instruments Keystone2 Platforms"
|
||||
default USB_DWC3
|
||||
help
|
||||
Support of USB2/3 functionality in TI Keystone2 platforms.
|
||||
Say 'Y' or 'M' here if you have one such device
|
||||
|
||||
comment "Debugging features"
|
||||
|
||||
config USB_DWC3_DEBUG
|
||||
|
@ -32,3 +32,4 @@ endif
|
||||
obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o
|
||||
obj-$(CONFIG_USB_DWC3_EXYNOS) += dwc3-exynos.o
|
||||
obj-$(CONFIG_USB_DWC3_PCI) += dwc3-pci.o
|
||||
obj-$(CONFIG_USB_DWC3_KEYSTONE) += dwc3-keystone.o
|
||||
|
@ -50,6 +50,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
|
||||
|
||||
exynos->usb2_phy = pdev;
|
||||
pdata.type = USB_PHY_TYPE_USB2;
|
||||
pdata.gpio_reset = -1;
|
||||
|
||||
ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata));
|
||||
if (ret)
|
||||
|
202
drivers/usb/dwc3/dwc3-keystone.c
Normal file
202
drivers/usb/dwc3/dwc3-keystone.c
Normal file
@ -0,0 +1,202 @@
|
||||
/**
|
||||
* dwc3-keystone.c - Keystone Specific Glue layer
|
||||
*
|
||||
* Copyright (C) 2010-2013 Texas Instruments Incorporated - http://www.ti.com
|
||||
*
|
||||
* Author: WingMan Kwok <w-kwok2@ti.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 of
|
||||
* the License as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
/* USBSS register offsets */
|
||||
#define USBSS_REVISION 0x0000
|
||||
#define USBSS_SYSCONFIG 0x0010
|
||||
#define USBSS_IRQ_EOI 0x0018
|
||||
#define USBSS_IRQSTATUS_RAW_0 0x0020
|
||||
#define USBSS_IRQSTATUS_0 0x0024
|
||||
#define USBSS_IRQENABLE_SET_0 0x0028
|
||||
#define USBSS_IRQENABLE_CLR_0 0x002c
|
||||
|
||||
/* IRQ register bits */
|
||||
#define USBSS_IRQ_EOI_LINE(n) BIT(n)
|
||||
#define USBSS_IRQ_EVENT_ST BIT(0)
|
||||
#define USBSS_IRQ_COREIRQ_EN BIT(0)
|
||||
#define USBSS_IRQ_COREIRQ_CLR BIT(0)
|
||||
|
||||
static u64 kdwc3_dma_mask;
|
||||
|
||||
struct dwc3_keystone {
|
||||
struct device *dev;
|
||||
struct clk *clk;
|
||||
void __iomem *usbss;
|
||||
};
|
||||
|
||||
static inline u32 kdwc3_readl(void __iomem *base, u32 offset)
|
||||
{
|
||||
return readl(base + offset);
|
||||
}
|
||||
|
||||
static inline void kdwc3_writel(void __iomem *base, u32 offset, u32 value)
|
||||
{
|
||||
writel(value, base + offset);
|
||||
}
|
||||
|
||||
static void kdwc3_enable_irqs(struct dwc3_keystone *kdwc)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = kdwc3_readl(kdwc->usbss, USBSS_IRQENABLE_SET_0);
|
||||
val |= USBSS_IRQ_COREIRQ_EN;
|
||||
kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, val);
|
||||
}
|
||||
|
||||
static void kdwc3_disable_irqs(struct dwc3_keystone *kdwc)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = kdwc3_readl(kdwc->usbss, USBSS_IRQENABLE_SET_0);
|
||||
val &= ~USBSS_IRQ_COREIRQ_EN;
|
||||
kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, val);
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_keystone_interrupt(int irq, void *_kdwc)
|
||||
{
|
||||
struct dwc3_keystone *kdwc = _kdwc;
|
||||
|
||||
kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_CLR_0, USBSS_IRQ_COREIRQ_CLR);
|
||||
kdwc3_writel(kdwc->usbss, USBSS_IRQSTATUS_0, USBSS_IRQ_EVENT_ST);
|
||||
kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, USBSS_IRQ_COREIRQ_EN);
|
||||
kdwc3_writel(kdwc->usbss, USBSS_IRQ_EOI, USBSS_IRQ_EOI_LINE(0));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int kdwc3_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct dwc3_keystone *kdwc;
|
||||
struct resource *res;
|
||||
int error, irq;
|
||||
|
||||
kdwc = devm_kzalloc(dev, sizeof(*kdwc), GFP_KERNEL);
|
||||
if (!kdwc)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, kdwc);
|
||||
|
||||
kdwc->dev = dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "missing usbss resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
kdwc->usbss = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(kdwc->usbss))
|
||||
return PTR_ERR(kdwc->usbss);
|
||||
|
||||
kdwc3_dma_mask = dma_get_mask(dev);
|
||||
dev->dma_mask = &kdwc3_dma_mask;
|
||||
|
||||
kdwc->clk = devm_clk_get(kdwc->dev, "usb");
|
||||
|
||||
error = clk_prepare_enable(kdwc->clk);
|
||||
if (error < 0) {
|
||||
dev_dbg(kdwc->dev, "unable to enable usb clock, err %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "missing irq\n");
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
error = devm_request_irq(dev, irq, dwc3_keystone_interrupt, IRQF_SHARED,
|
||||
dev_name(dev), kdwc);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to request IRQ #%d --> %d\n",
|
||||
irq, error);
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
kdwc3_enable_irqs(kdwc);
|
||||
|
||||
error = of_platform_populate(node, NULL, NULL, dev);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to create dwc3 core\n");
|
||||
goto err_core;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_core:
|
||||
kdwc3_disable_irqs(kdwc);
|
||||
err_irq:
|
||||
clk_disable_unprepare(kdwc->clk);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int kdwc3_remove_core(struct device *dev, void *c)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kdwc3_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_keystone *kdwc = platform_get_drvdata(pdev);
|
||||
|
||||
kdwc3_disable_irqs(kdwc);
|
||||
device_for_each_child(&pdev->dev, NULL, kdwc3_remove_core);
|
||||
clk_disable_unprepare(kdwc->clk);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id kdwc3_of_match[] = {
|
||||
{ .compatible = "ti,keystone-dwc3", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, kdwc3_of_match);
|
||||
|
||||
static struct platform_driver kdwc3_driver = {
|
||||
.probe = kdwc3_probe,
|
||||
.remove = kdwc3_remove,
|
||||
.driver = {
|
||||
.name = "keystone-dwc3",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = kdwc3_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(kdwc3_driver);
|
||||
|
||||
MODULE_ALIAS("platform:keystone-dwc3");
|
||||
MODULE_AUTHOR("WingMan Kwok <w-kwok2@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("DesignWare USB3 KEYSTONE Glue Layer");
|
@ -20,7 +20,6 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/dwc3-omap.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@ -120,9 +119,6 @@
|
||||
#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID (1 << 1)
|
||||
|
||||
struct dwc3_omap {
|
||||
/* device lock */
|
||||
spinlock_t lock;
|
||||
|
||||
struct device *dev;
|
||||
|
||||
int irq;
|
||||
@ -280,8 +276,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
|
||||
struct dwc3_omap *omap = _omap;
|
||||
u32 reg;
|
||||
|
||||
spin_lock(&omap->lock);
|
||||
|
||||
reg = dwc3_omap_read_irqmisc_status(omap);
|
||||
|
||||
if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) {
|
||||
@ -322,8 +316,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
|
||||
|
||||
dwc3_omap_write_irq0_status(omap, reg);
|
||||
|
||||
spin_unlock(&omap->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -449,8 +441,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_init(&omap->lock);
|
||||
|
||||
omap->dev = dev;
|
||||
omap->irq = irq;
|
||||
omap->base = base;
|
||||
@ -535,7 +525,7 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
||||
edev = of_extcon_get_extcon_dev(dev, 0);
|
||||
if (IS_ERR(edev)) {
|
||||
dev_vdbg(dev, "couldn't get extcon device\n");
|
||||
ret = PTR_ERR(edev);
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,7 @@ static int dwc3_pci_register_phys(struct dwc3_pci *glue)
|
||||
|
||||
glue->usb2_phy = pdev;
|
||||
pdata.type = USB_PHY_TYPE_USB2;
|
||||
pdata.gpio_reset = -1;
|
||||
|
||||
ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
|
||||
if (ret)
|
||||
|
@ -1650,7 +1650,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
||||
dev_vdbg(dwc->dev, "initializing %s\n", dep->name);
|
||||
|
||||
if (epnum == 0 || epnum == 1) {
|
||||
dep->endpoint.maxpacket = 512;
|
||||
usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
|
||||
dep->endpoint.maxburst = 1;
|
||||
dep->endpoint.ops = &dwc3_gadget_ep0_ops;
|
||||
if (!epnum)
|
||||
@ -1658,7 +1658,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
||||
} else {
|
||||
int ret;
|
||||
|
||||
dep->endpoint.maxpacket = 1024;
|
||||
usb_ep_set_maxpacket_limit(&dep->endpoint, 1024);
|
||||
dep->endpoint.max_streams = 15;
|
||||
dep->endpoint.ops = &dwc3_gadget_ep_ops;
|
||||
list_add_tail(&dep->endpoint.ep_list,
|
||||
@ -2596,6 +2596,12 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
||||
dwc->gadget.sg_supported = true;
|
||||
dwc->gadget.name = "dwc3-gadget";
|
||||
|
||||
/*
|
||||
* Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize
|
||||
* on ep out.
|
||||
*/
|
||||
dwc->gadget.quirk_ep_out_aligned_size = true;
|
||||
|
||||
/*
|
||||
* REVISIT: Here we should clear all pending IRQs to be
|
||||
* sure we're starting from a well known location.
|
||||
|
@ -216,6 +216,13 @@ config USB_FOTG210_UDC
|
||||
Say "y" to link the driver statically, or "m" to build a
|
||||
dynamically linked module called "fotg210_udc".
|
||||
|
||||
config USB_GR_UDC
|
||||
tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver"
|
||||
depends on HAS_DMA
|
||||
help
|
||||
Select this to support Aeroflex Gaisler GRUSBDC cores from the GRLIB
|
||||
VHDL IP core library.
|
||||
|
||||
config USB_OMAP
|
||||
tristate "OMAP USB Device Controller"
|
||||
depends on ARCH_OMAP1
|
||||
@ -294,11 +301,11 @@ config USB_PXA27X
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_S3C_HSOTG
|
||||
tristate "S3C HS/OtG USB Device controller"
|
||||
depends on S3C_DEV_USB_HSOTG
|
||||
depends on ARM
|
||||
tristate "Designware/S3C HS/OtG USB Device controller"
|
||||
help
|
||||
The Samsung S3C64XX USB2.0 high-speed gadget controller
|
||||
integrated into the S3C64XX series SoC.
|
||||
The Designware USB2.0 high-speed gadget controller
|
||||
integrated into many SoCs.
|
||||
|
||||
config USB_S3C2410
|
||||
tristate "S3C2410 USB Device Controller"
|
||||
@ -512,9 +519,6 @@ config USB_U_SERIAL
|
||||
config USB_U_ETHER
|
||||
tristate
|
||||
|
||||
config USB_U_RNDIS
|
||||
tristate
|
||||
|
||||
config USB_F_SERIAL
|
||||
tristate
|
||||
|
||||
@ -542,6 +546,9 @@ config USB_F_RNDIS
|
||||
config USB_F_MASS_STORAGE
|
||||
tristate
|
||||
|
||||
config USB_F_FS
|
||||
tristate
|
||||
|
||||
choice
|
||||
tristate "USB Gadget Drivers"
|
||||
default USB_ETH
|
||||
@ -642,7 +649,6 @@ config USB_CONFIGFS_RNDIS
|
||||
depends on USB_CONFIGFS
|
||||
depends on NET
|
||||
select USB_U_ETHER
|
||||
select USB_U_RNDIS
|
||||
select USB_F_RNDIS
|
||||
help
|
||||
Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol,
|
||||
@ -690,6 +696,31 @@ config USB_CONFIGFS_MASS_STORAGE
|
||||
device (in much the same way as the "loop" device driver),
|
||||
specified as a module parameter or sysfs option.
|
||||
|
||||
config USB_CONFIGFS_F_LB_SS
|
||||
boolean "Loopback and sourcesink function (for testing)"
|
||||
depends on USB_CONFIGFS
|
||||
select USB_F_SS_LB
|
||||
help
|
||||
Loopback function loops back a configurable number of transfers.
|
||||
Sourcesink function either sinks and sources bulk data.
|
||||
It also implements control requests, for "chapter 9" conformance.
|
||||
Make this be the first driver you try using on top of any new
|
||||
USB peripheral controller driver. Then you can use host-side
|
||||
test software, like the "usbtest" driver, to put your hardware
|
||||
and its driver through a basic set of functional tests.
|
||||
|
||||
config USB_CONFIGFS_F_FS
|
||||
boolean "Function filesystem (FunctionFS)"
|
||||
depends on USB_CONFIGFS
|
||||
select USB_F_FS
|
||||
help
|
||||
The Function Filesystem (FunctionFS) lets one create USB
|
||||
composite functions in user space in the same way GadgetFS
|
||||
lets one create USB gadgets in user space. This allows creation
|
||||
of composite gadgets such that some of the functions are
|
||||
implemented in kernel space (for instance Ethernet, serial or
|
||||
mass storage) and other are implemented in user space.
|
||||
|
||||
config USB_ZERO
|
||||
tristate "Gadget Zero (DEVELOPMENT)"
|
||||
select USB_LIBCOMPOSITE
|
||||
@ -760,7 +791,6 @@ config USB_ETH
|
||||
depends on NET
|
||||
select USB_LIBCOMPOSITE
|
||||
select USB_U_ETHER
|
||||
select USB_U_RNDIS
|
||||
select USB_F_ECM
|
||||
select USB_F_SUBSET
|
||||
select CRC32
|
||||
@ -864,6 +894,7 @@ config USB_GADGETFS
|
||||
config USB_FUNCTIONFS
|
||||
tristate "Function Filesystem"
|
||||
select USB_LIBCOMPOSITE
|
||||
select USB_F_FS
|
||||
select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)
|
||||
help
|
||||
The Function Filesystem (FunctionFS) lets one create USB
|
||||
@ -883,6 +914,8 @@ config USB_FUNCTIONFS_ETH
|
||||
bool "Include configuration with CDC ECM (Ethernet)"
|
||||
depends on USB_FUNCTIONFS && NET
|
||||
select USB_U_ETHER
|
||||
select USB_F_ECM
|
||||
select USB_F_SUBSET
|
||||
help
|
||||
Include a configuration with CDC ECM function (Ethernet) and the
|
||||
Function Filesystem.
|
||||
@ -891,7 +924,7 @@ config USB_FUNCTIONFS_RNDIS
|
||||
bool "Include configuration with RNDIS (Ethernet)"
|
||||
depends on USB_FUNCTIONFS && NET
|
||||
select USB_U_ETHER
|
||||
select USB_U_RNDIS
|
||||
select USB_F_RNDIS
|
||||
help
|
||||
Include a configuration with RNDIS function (Ethernet) and the Filesystem.
|
||||
|
||||
@ -1065,7 +1098,6 @@ config USB_G_MULTI
|
||||
config USB_G_MULTI_RNDIS
|
||||
bool "RNDIS + CDC Serial + Storage configuration"
|
||||
depends on USB_G_MULTI
|
||||
select USB_U_RNDIS
|
||||
select USB_F_RNDIS
|
||||
default y
|
||||
help
|
||||
|
@ -7,7 +7,7 @@ ccflags-$(CONFIG_USB_GADGET_VERBOSE) += -DVERBOSE_DEBUG
|
||||
obj-$(CONFIG_USB_GADGET) += udc-core.o
|
||||
obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o
|
||||
libcomposite-y := usbstring.o config.o epautoconf.o
|
||||
libcomposite-y += composite.o functions.o configfs.o
|
||||
libcomposite-y += composite.o functions.o configfs.o u_f.o
|
||||
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
|
||||
obj-$(CONFIG_USB_NET2272) += net2272.o
|
||||
obj-$(CONFIG_USB_NET2280) += net2280.o
|
||||
@ -35,6 +35,7 @@ mv_udc-y := mv_udc_core.o
|
||||
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
|
||||
obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
|
||||
obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
|
||||
obj-$(CONFIG_USB_GR_UDC) += gr_udc.o
|
||||
|
||||
# USB Functions
|
||||
usb_f_acm-y := f_acm.o
|
||||
@ -47,8 +48,6 @@ obj-$(CONFIG_USB_F_SERIAL) += usb_f_serial.o
|
||||
usb_f_obex-y := f_obex.o
|
||||
obj-$(CONFIG_USB_F_OBEX) += usb_f_obex.o
|
||||
obj-$(CONFIG_USB_U_ETHER) += u_ether.o
|
||||
u_rndis-y := rndis.o
|
||||
obj-$(CONFIG_USB_U_RNDIS) += u_rndis.o
|
||||
usb_f_ncm-y := f_ncm.o
|
||||
obj-$(CONFIG_USB_F_NCM) += usb_f_ncm.o
|
||||
usb_f_ecm-y := f_ecm.o
|
||||
@ -59,10 +58,12 @@ usb_f_eem-y := f_eem.o
|
||||
obj-$(CONFIG_USB_F_EEM) += usb_f_eem.o
|
||||
usb_f_ecm_subset-y := f_subset.o
|
||||
obj-$(CONFIG_USB_F_SUBSET) += usb_f_ecm_subset.o
|
||||
usb_f_rndis-y := f_rndis.o
|
||||
usb_f_rndis-y := f_rndis.o rndis.o
|
||||
obj-$(CONFIG_USB_F_RNDIS) += usb_f_rndis.o
|
||||
usb_f_mass_storage-y := f_mass_storage.o storage_common.o
|
||||
obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o
|
||||
usb_f_fs-y := f_fs.o
|
||||
obj-$(CONFIG_USB_F_FS) += usb_f_fs.o
|
||||
|
||||
#
|
||||
# USB gadget drivers
|
||||
|
@ -446,7 +446,7 @@ static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
|
||||
ep->ep.ops = &udc_ep_ops;
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
|
||||
ep->ep.maxpacket = (u16) ~0;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep,(u16) ~0);
|
||||
/* set NAK */
|
||||
tmp = readl(&ep->regs->ctl);
|
||||
tmp |= AMD_BIT(UDC_EPCTL_SNAK);
|
||||
@ -1564,12 +1564,15 @@ static void udc_setup_endpoints(struct udc *dev)
|
||||
}
|
||||
/* EP0 max packet */
|
||||
if (dev->gadget.speed == USB_SPEED_FULL) {
|
||||
dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE;
|
||||
dev->ep[UDC_EP0OUT_IX].ep.maxpacket =
|
||||
UDC_FS_EP0OUT_MAX_PKT_SIZE;
|
||||
usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IX].ep,
|
||||
UDC_FS_EP0IN_MAX_PKT_SIZE);
|
||||
usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IX].ep,
|
||||
UDC_FS_EP0OUT_MAX_PKT_SIZE);
|
||||
} else if (dev->gadget.speed == USB_SPEED_HIGH) {
|
||||
dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
|
||||
dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
|
||||
usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IX].ep,
|
||||
UDC_EP0IN_MAX_PKT_SIZE);
|
||||
usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IX].ep,
|
||||
UDC_EP0OUT_MAX_PKT_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -834,7 +834,7 @@ static void udc_reinit(struct at91_udc *udc)
|
||||
ep->ep.desc = NULL;
|
||||
ep->stopped = 0;
|
||||
ep->fifo_bank = 0;
|
||||
ep->ep.maxpacket = ep->maxpacket;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket);
|
||||
ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);
|
||||
/* initialize one queue per endpoint */
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
@ -1759,15 +1759,15 @@ static int at91udc_probe(struct platform_device *pdev)
|
||||
|
||||
/* newer chips have more FIFO memory than rm9200 */
|
||||
if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) {
|
||||
udc->ep[0].maxpacket = 64;
|
||||
udc->ep[3].maxpacket = 64;
|
||||
udc->ep[4].maxpacket = 512;
|
||||
udc->ep[5].maxpacket = 512;
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[0].ep, 64);
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[3].ep, 64);
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[4].ep, 512);
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[5].ep, 512);
|
||||
} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
|
||||
udc->ep[3].maxpacket = 64;
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[3].ep, 64);
|
||||
} else if (cpu_is_at91sam9263()) {
|
||||
udc->ep[0].maxpacket = 64;
|
||||
udc->ep[3].maxpacket = 64;
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[0].ep, 64);
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[3].ep, 64);
|
||||
}
|
||||
|
||||
udc->udp_baseaddr = ioremap(res->start, resource_size(res));
|
||||
|
@ -1012,7 +1012,7 @@ static void nop_release(struct device *dev)
|
||||
|
||||
}
|
||||
|
||||
struct usb_gadget usba_gadget_template = {
|
||||
static struct usb_gadget usba_gadget_template = {
|
||||
.ops = &usba_udc_ops,
|
||||
.max_speed = USB_SPEED_HIGH,
|
||||
.name = "atmel_usba_udc",
|
||||
@ -1904,7 +1904,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
|
||||
ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
|
||||
ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
|
||||
ep->ep.ops = &usba_ep_ops;
|
||||
ep->ep.maxpacket = ep->fifo_size;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size);
|
||||
ep->udc = udc;
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
|
||||
@ -1957,7 +1957,8 @@ static struct usba_ep * usba_udc_pdata(struct platform_device *pdev,
|
||||
ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
|
||||
ep->ep.ops = &usba_ep_ops;
|
||||
ep->ep.name = pdata->ep[i].name;
|
||||
ep->fifo_size = ep->ep.maxpacket = pdata->ep[i].fifo_size;
|
||||
ep->fifo_size = pdata->ep[i].fifo_size;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size);
|
||||
ep->udc = udc;
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
ep->nr_banks = pdata->ep[i].nr_banks;
|
||||
@ -1995,14 +1996,12 @@ static int __init usba_udc_probe(struct platform_device *pdev)
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
pclk = clk_get(&pdev->dev, "pclk");
|
||||
pclk = devm_clk_get(&pdev->dev, "pclk");
|
||||
if (IS_ERR(pclk))
|
||||
return PTR_ERR(pclk);
|
||||
hclk = clk_get(&pdev->dev, "hclk");
|
||||
if (IS_ERR(hclk)) {
|
||||
ret = PTR_ERR(hclk);
|
||||
goto err_get_hclk;
|
||||
}
|
||||
hclk = devm_clk_get(&pdev->dev, "hclk");
|
||||
if (IS_ERR(hclk))
|
||||
return PTR_ERR(hclk);
|
||||
|
||||
spin_lock_init(&udc->lock);
|
||||
udc->pdev = pdev;
|
||||
@ -2011,17 +2010,17 @@ static int __init usba_udc_probe(struct platform_device *pdev)
|
||||
udc->vbus_pin = -ENODEV;
|
||||
|
||||
ret = -ENOMEM;
|
||||
udc->regs = ioremap(regs->start, resource_size(regs));
|
||||
udc->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
|
||||
if (!udc->regs) {
|
||||
dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
|
||||
goto err_map_regs;
|
||||
return ret;
|
||||
}
|
||||
dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
|
||||
(unsigned long)regs->start, udc->regs);
|
||||
udc->fifo = ioremap(fifo->start, resource_size(fifo));
|
||||
udc->fifo = devm_ioremap(&pdev->dev, fifo->start, resource_size(fifo));
|
||||
if (!udc->fifo) {
|
||||
dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
|
||||
goto err_map_fifo;
|
||||
return ret;
|
||||
}
|
||||
dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
|
||||
(unsigned long)fifo->start, udc->fifo);
|
||||
@ -2032,7 +2031,7 @@ static int __init usba_udc_probe(struct platform_device *pdev)
|
||||
ret = clk_prepare_enable(pclk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n");
|
||||
goto err_clk_enable;
|
||||
return ret;
|
||||
}
|
||||
toggle_bias(0);
|
||||
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
|
||||
@ -2043,22 +2042,22 @@ static int __init usba_udc_probe(struct platform_device *pdev)
|
||||
else
|
||||
udc->usba_ep = usba_udc_pdata(pdev, udc);
|
||||
|
||||
if (IS_ERR(udc->usba_ep)) {
|
||||
ret = PTR_ERR(udc->usba_ep);
|
||||
goto err_alloc_ep;
|
||||
}
|
||||
if (IS_ERR(udc->usba_ep))
|
||||
return PTR_ERR(udc->usba_ep);
|
||||
|
||||
ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc);
|
||||
ret = devm_request_irq(&pdev->dev, irq, usba_udc_irq, 0,
|
||||
"atmel_usba_udc", udc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n",
|
||||
irq, ret);
|
||||
goto err_request_irq;
|
||||
return ret;
|
||||
}
|
||||
udc->irq = irq;
|
||||
|
||||
if (gpio_is_valid(udc->vbus_pin)) {
|
||||
if (!devm_gpio_request(&pdev->dev, udc->vbus_pin, "atmel_usba_udc")) {
|
||||
ret = request_irq(gpio_to_irq(udc->vbus_pin),
|
||||
ret = devm_request_irq(&pdev->dev,
|
||||
gpio_to_irq(udc->vbus_pin),
|
||||
usba_vbus_irq, 0,
|
||||
"atmel_usba_udc", udc);
|
||||
if (ret) {
|
||||
@ -2077,31 +2076,13 @@ static int __init usba_udc_probe(struct platform_device *pdev)
|
||||
|
||||
ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
|
||||
if (ret)
|
||||
goto err_add_udc;
|
||||
return ret;
|
||||
|
||||
usba_init_debugfs(udc);
|
||||
for (i = 1; i < udc->num_ep; i++)
|
||||
usba_ep_init_debugfs(udc, &udc->usba_ep[i]);
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_udc:
|
||||
if (gpio_is_valid(udc->vbus_pin))
|
||||
free_irq(gpio_to_irq(udc->vbus_pin), udc);
|
||||
|
||||
free_irq(irq, udc);
|
||||
err_request_irq:
|
||||
err_alloc_ep:
|
||||
err_clk_enable:
|
||||
iounmap(udc->fifo);
|
||||
err_map_fifo:
|
||||
iounmap(udc->regs);
|
||||
err_map_regs:
|
||||
clk_put(hclk);
|
||||
err_get_hclk:
|
||||
clk_put(pclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit usba_udc_remove(struct platform_device *pdev)
|
||||
@ -2117,16 +2098,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
|
||||
usba_ep_cleanup_debugfs(&udc->usba_ep[i]);
|
||||
usba_cleanup_debugfs(udc);
|
||||
|
||||
if (gpio_is_valid(udc->vbus_pin)) {
|
||||
free_irq(gpio_to_irq(udc->vbus_pin), udc);
|
||||
}
|
||||
|
||||
free_irq(udc->irq, udc);
|
||||
iounmap(udc->fifo);
|
||||
iounmap(udc->regs);
|
||||
clk_put(udc->hclk);
|
||||
clk_put(udc->pclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -549,7 +549,7 @@ static void bcm63xx_ep_setup(struct bcm63xx_udc *udc)
|
||||
|
||||
if (idx < 0)
|
||||
continue;
|
||||
udc->bep[idx].ep.maxpacket = max_pkt;
|
||||
usb_ep_set_maxpacket_limit(&udc->bep[idx].ep, max_pkt);
|
||||
|
||||
val = (idx << USBD_CSR_EP_LOG_SHIFT) |
|
||||
(cfg->dir << USBD_CSR_EP_DIR_SHIFT) |
|
||||
@ -943,7 +943,7 @@ static int bcm63xx_init_udc_hw(struct bcm63xx_udc *udc)
|
||||
bep->ep.ops = &bcm63xx_udc_ep_ops;
|
||||
list_add_tail(&bep->ep.ep_list, &udc->gadget.ep_list);
|
||||
bep->halted = 0;
|
||||
bep->ep.maxpacket = BCM63XX_MAX_CTRL_PKT;
|
||||
usb_ep_set_maxpacket_limit(&bep->ep, BCM63XX_MAX_CTRL_PKT);
|
||||
bep->udc = udc;
|
||||
bep->ep.desc = NULL;
|
||||
INIT_LIST_HEAD(&bep->queue);
|
||||
|
@ -1452,8 +1452,22 @@ unknown:
|
||||
struct usb_configuration *c;
|
||||
|
||||
c = cdev->config;
|
||||
if (c && c->setup)
|
||||
if (!c)
|
||||
goto done;
|
||||
|
||||
/* try current config's setup */
|
||||
if (c->setup) {
|
||||
value = c->setup(c, ctrl);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* try the only function in the current config */
|
||||
if (!list_is_singular(&c->functions))
|
||||
goto done;
|
||||
f = list_first_entry(&c->functions, struct usb_function,
|
||||
list);
|
||||
if (f->setup)
|
||||
value = f->setup(f, ctrl);
|
||||
}
|
||||
|
||||
goto done;
|
||||
@ -1714,7 +1728,7 @@ composite_resume(struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
struct usb_function *f;
|
||||
u8 maxpower;
|
||||
u16 maxpower;
|
||||
|
||||
/* REVISIT: should we have config level
|
||||
* suspend/resume callbacks?
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/usb/composite.h>
|
||||
#include <linux/usb/gadget_configfs.h>
|
||||
#include "configfs.h"
|
||||
|
||||
int check_user_usb_string(const char *name,
|
||||
struct usb_gadget_strings *stringtab_dev)
|
||||
@ -564,6 +565,13 @@ static struct config_group *function_make(
|
||||
usb_put_function_instance(fi);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
if (fi->set_inst_name) {
|
||||
ret = fi->set_inst_name(fi, instance_name);
|
||||
if (ret) {
|
||||
usb_put_function_instance(fi);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
|
||||
gi = container_of(group, struct gadget_info, functions_group);
|
||||
|
||||
|
@ -951,7 +951,7 @@ static void init_dummy_udc_hw(struct dummy *dum)
|
||||
list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list);
|
||||
ep->halted = ep->wedged = ep->already_seen =
|
||||
ep->setup_stage = 0;
|
||||
ep->ep.maxpacket = ~0;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, ~0);
|
||||
ep->ep.max_streams = 16;
|
||||
ep->last_io = jiffies;
|
||||
ep->gadget = &dum->gadget;
|
||||
|
@ -58,7 +58,7 @@ ep_matches (
|
||||
return 0;
|
||||
|
||||
/* only support ep0 for portable CONTROL traffic */
|
||||
type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
|
||||
type = usb_endpoint_type(desc);
|
||||
if (USB_ENDPOINT_XFER_CONTROL == type)
|
||||
return 0;
|
||||
|
||||
@ -129,7 +129,7 @@ ep_matches (
|
||||
* and wants to know the maximum possible, provide the info.
|
||||
*/
|
||||
if (desc->wMaxPacketSize == 0)
|
||||
desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket);
|
||||
desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit);
|
||||
|
||||
/* endpoint maxpacket size is an input parameter, except for bulk
|
||||
* where it's an output parameter representing the full speed limit.
|
||||
@ -145,7 +145,7 @@ ep_matches (
|
||||
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
/* ISO: limit 1023 bytes full speed, 1024 high/super speed */
|
||||
if (ep->maxpacket < max)
|
||||
if (ep->maxpacket_limit < max)
|
||||
return 0;
|
||||
if (!gadget_is_dualspeed(gadget) && max > 1023)
|
||||
return 0;
|
||||
@ -178,7 +178,7 @@ ep_matches (
|
||||
|
||||
/* report (variable) full speed bulk maxpacket */
|
||||
if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {
|
||||
int size = ep->maxpacket;
|
||||
int size = ep->maxpacket_limit;
|
||||
|
||||
/* min() doesn't work on bitfields with gcc-3.5 */
|
||||
if (size > 64)
|
||||
|
@ -691,7 +691,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
int status;
|
||||
struct usb_ep *ep;
|
||||
|
||||
#ifndef USBF_ECM_INCLUDED
|
||||
struct f_ecm_opts *ecm_opts;
|
||||
|
||||
if (!can_support_ecm(cdev->gadget))
|
||||
@ -715,7 +714,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
return status;
|
||||
ecm_opts->bound = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
us = usb_gstrings_attach(cdev, ecm_strings,
|
||||
ARRAY_SIZE(ecm_string_defs));
|
||||
if (IS_ERR(us))
|
||||
@ -834,74 +833,6 @@ fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef USBF_ECM_INCLUDED
|
||||
|
||||
static void
|
||||
ecm_old_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct f_ecm *ecm = func_to_ecm(f);
|
||||
|
||||
DBG(c->cdev, "ecm unbind\n");
|
||||
|
||||
usb_free_all_descriptors(f);
|
||||
|
||||
kfree(ecm->notify_req->buf);
|
||||
usb_ep_free_request(ecm->notify, ecm->notify_req);
|
||||
kfree(ecm);
|
||||
}
|
||||
|
||||
/**
|
||||
* ecm_bind_config - add CDC Ethernet network link to a configuration
|
||||
* @c: the configuration to support the network link
|
||||
* @ethaddr: a buffer in which the ethernet address of the host side
|
||||
* side of the link was recorded
|
||||
* @dev: eth_dev structure
|
||||
* Context: single threaded during gadget setup
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*
|
||||
* Caller must have called @gether_setup(). Caller is also responsible
|
||||
* for calling @gether_cleanup() before module unload.
|
||||
*/
|
||||
int
|
||||
ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev)
|
||||
{
|
||||
struct f_ecm *ecm;
|
||||
int status;
|
||||
|
||||
if (!can_support_ecm(c->cdev->gadget) || !ethaddr)
|
||||
return -EINVAL;
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
ecm = kzalloc(sizeof *ecm, GFP_KERNEL);
|
||||
if (!ecm)
|
||||
return -ENOMEM;
|
||||
|
||||
/* export host's Ethernet address in CDC format */
|
||||
snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr);
|
||||
ecm_string_defs[1].s = ecm->ethaddr;
|
||||
|
||||
ecm->port.ioport = dev;
|
||||
ecm->port.cdc_filter = DEFAULT_FILTER;
|
||||
|
||||
ecm->port.func.name = "cdc_ethernet";
|
||||
/* descriptors are per-instance copies */
|
||||
ecm->port.func.bind = ecm_bind;
|
||||
ecm->port.func.unbind = ecm_old_unbind;
|
||||
ecm->port.func.set_alt = ecm_set_alt;
|
||||
ecm->port.func.get_alt = ecm_get_alt;
|
||||
ecm->port.func.setup = ecm_setup;
|
||||
ecm->port.func.disable = ecm_disable;
|
||||
|
||||
status = usb_add_function(c, &ecm->port.func);
|
||||
if (status)
|
||||
kfree(ecm);
|
||||
return status;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline struct f_ecm_opts *to_f_ecm_opts(struct config_item *item)
|
||||
{
|
||||
return container_of(to_config_group(item), struct f_ecm_opts,
|
||||
@ -1040,5 +971,3 @@ static struct usb_function *ecm_alloc(struct usb_function_instance *fi)
|
||||
DECLARE_USB_FUNCTION_INIT(ecm, ecm_alloc_inst, ecm_alloc);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,8 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/usb/g_hid.h>
|
||||
|
||||
#include "u_f.h"
|
||||
|
||||
static int major, minors;
|
||||
static struct class *hidg_class;
|
||||
|
||||
@ -334,20 +336,10 @@ 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)
|
||||
static inline 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;
|
||||
return alloc_ep_req(ep, length, length);
|
||||
}
|
||||
|
||||
static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/usb/composite.h>
|
||||
|
||||
#include "g_zero.h"
|
||||
#include "u_f.h"
|
||||
|
||||
/*
|
||||
* LOOPBACK FUNCTION ... a testing vehicle for USB peripherals,
|
||||
@ -119,7 +120,7 @@ static struct usb_endpoint_descriptor ss_loop_source_desc = {
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
};
|
||||
|
||||
struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = {
|
||||
static struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = {
|
||||
.bLength = USB_DT_SS_EP_COMP_SIZE,
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
.bMaxBurst = 0,
|
||||
@ -135,7 +136,7 @@ static struct usb_endpoint_descriptor ss_loop_sink_desc = {
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
};
|
||||
|
||||
struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = {
|
||||
static struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = {
|
||||
.bLength = USB_DT_SS_EP_COMP_SIZE,
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
.bMaxBurst = 0,
|
||||
@ -230,6 +231,14 @@ autoconf_fail:
|
||||
|
||||
static void lb_free_func(struct usb_function *f)
|
||||
{
|
||||
struct f_lb_opts *opts;
|
||||
|
||||
opts = container_of(f->fi, struct f_lb_opts, func_inst);
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
opts->refcnt--;
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(func_to_loop(f));
|
||||
}
|
||||
@ -293,6 +302,11 @@ static void disable_loopback(struct f_loopback *loop)
|
||||
VDBG(cdev, "%s disabled\n", loop->function.name);
|
||||
}
|
||||
|
||||
static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len)
|
||||
{
|
||||
return alloc_ep_req(ep, len, buflen);
|
||||
}
|
||||
|
||||
static int
|
||||
enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
|
||||
{
|
||||
@ -332,7 +346,7 @@ fail0:
|
||||
* than 'buflen' bytes each.
|
||||
*/
|
||||
for (i = 0; i < qlen && result == 0; i++) {
|
||||
req = alloc_ep_req(ep, 0);
|
||||
req = lb_alloc_ep_req(ep, 0);
|
||||
if (req) {
|
||||
req->complete = loopback_complete;
|
||||
result = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
@ -380,6 +394,11 @@ static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
lb_opts = container_of(fi, struct f_lb_opts, func_inst);
|
||||
|
||||
mutex_lock(&lb_opts->lock);
|
||||
lb_opts->refcnt++;
|
||||
mutex_unlock(&lb_opts->lock);
|
||||
|
||||
buflen = lb_opts->bulk_buflen;
|
||||
qlen = lb_opts->qlen;
|
||||
if (!qlen)
|
||||
@ -396,6 +415,118 @@ static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
|
||||
return &loop->function;
|
||||
}
|
||||
|
||||
static inline struct f_lb_opts *to_f_lb_opts(struct config_item *item)
|
||||
{
|
||||
return container_of(to_config_group(item), struct f_lb_opts,
|
||||
func_inst.group);
|
||||
}
|
||||
|
||||
CONFIGFS_ATTR_STRUCT(f_lb_opts);
|
||||
CONFIGFS_ATTR_OPS(f_lb_opts);
|
||||
|
||||
static void lb_attr_release(struct config_item *item)
|
||||
{
|
||||
struct f_lb_opts *lb_opts = to_f_lb_opts(item);
|
||||
|
||||
usb_put_function_instance(&lb_opts->func_inst);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations lb_item_ops = {
|
||||
.release = lb_attr_release,
|
||||
.show_attribute = f_lb_opts_attr_show,
|
||||
.store_attribute = f_lb_opts_attr_store,
|
||||
};
|
||||
|
||||
static ssize_t f_lb_opts_qlen_show(struct f_lb_opts *opts, char *page)
|
||||
{
|
||||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->qlen);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t f_lb_opts_qlen_store(struct f_lb_opts *opts,
|
||||
const char *page, size_t len)
|
||||
{
|
||||
int ret;
|
||||
u32 num;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
if (opts->refcnt) {
|
||||
ret = -EBUSY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = kstrtou32(page, 0, &num);
|
||||
if (ret)
|
||||
goto end;
|
||||
|
||||
opts->qlen = num;
|
||||
ret = len;
|
||||
end:
|
||||
mutex_unlock(&opts->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct f_lb_opts_attribute f_lb_opts_qlen =
|
||||
__CONFIGFS_ATTR(qlen, S_IRUGO | S_IWUSR,
|
||||
f_lb_opts_qlen_show,
|
||||
f_lb_opts_qlen_store);
|
||||
|
||||
static ssize_t f_lb_opts_bulk_buflen_show(struct f_lb_opts *opts, char *page)
|
||||
{
|
||||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->bulk_buflen);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t f_lb_opts_bulk_buflen_store(struct f_lb_opts *opts,
|
||||
const char *page, size_t len)
|
||||
{
|
||||
int ret;
|
||||
u32 num;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
if (opts->refcnt) {
|
||||
ret = -EBUSY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = kstrtou32(page, 0, &num);
|
||||
if (ret)
|
||||
goto end;
|
||||
|
||||
opts->bulk_buflen = num;
|
||||
ret = len;
|
||||
end:
|
||||
mutex_unlock(&opts->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct f_lb_opts_attribute f_lb_opts_bulk_buflen =
|
||||
__CONFIGFS_ATTR(buflen, S_IRUGO | S_IWUSR,
|
||||
f_lb_opts_bulk_buflen_show,
|
||||
f_lb_opts_bulk_buflen_store);
|
||||
|
||||
static struct configfs_attribute *lb_attrs[] = {
|
||||
&f_lb_opts_qlen.attr,
|
||||
&f_lb_opts_bulk_buflen.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct config_item_type lb_func_type = {
|
||||
.ct_item_ops = &lb_item_ops,
|
||||
.ct_attrs = lb_attrs,
|
||||
.ct_owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void lb_free_instance(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_lb_opts *lb_opts;
|
||||
@ -411,7 +542,14 @@ static struct usb_function_instance *loopback_alloc_instance(void)
|
||||
lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL);
|
||||
if (!lb_opts)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
mutex_init(&lb_opts->lock);
|
||||
lb_opts->func_inst.free_func_inst = lb_free_instance;
|
||||
lb_opts->bulk_buflen = GZERO_BULK_BUFLEN;
|
||||
lb_opts->qlen = GZERO_QLEN;
|
||||
|
||||
config_group_init_type_name(&lb_opts->func_inst.group, "",
|
||||
&lb_func_type);
|
||||
|
||||
return &lb_opts->func_inst;
|
||||
}
|
||||
DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc);
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include <linux/usb/audio.h>
|
||||
#include <linux/usb/midi.h>
|
||||
|
||||
#include "u_f.h"
|
||||
|
||||
MODULE_AUTHOR("Ben Williamson");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@ -191,20 +193,10 @@ static struct usb_gadget_strings *midi_strings[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
|
||||
static inline struct usb_request *midi_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;
|
||||
return alloc_ep_req(ep, length, length);
|
||||
}
|
||||
|
||||
static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
|
||||
@ -365,7 +357,7 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
/* allocate a bunch of read buffers and queue them all at once. */
|
||||
for (i = 0; i < midi->qlen && err == 0; i++) {
|
||||
struct usb_request *req =
|
||||
alloc_ep_req(midi->out_ep, midi->buflen);
|
||||
midi_alloc_ep_req(midi->out_ep, midi->buflen);
|
||||
if (req == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -546,7 +538,7 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
|
||||
return;
|
||||
|
||||
if (!req)
|
||||
req = alloc_ep_req(ep, midi->buflen);
|
||||
req = midi_alloc_ep_req(ep, midi->buflen);
|
||||
|
||||
if (!req) {
|
||||
ERROR(midi, "gmidi_transmit: alloc_ep_request failed\n");
|
||||
|
@ -1386,7 +1386,7 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
usb_ep_free_request(ncm->notify, ncm->notify_req);
|
||||
}
|
||||
|
||||
struct usb_function *ncm_alloc(struct usb_function_instance *fi)
|
||||
static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_ncm *ncm;
|
||||
struct f_ncm_opts *opts;
|
||||
|
@ -499,7 +499,7 @@ static void obex_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
usb_free_all_descriptors(f);
|
||||
}
|
||||
|
||||
struct usb_function *obex_alloc(struct usb_function_instance *fi)
|
||||
static struct usb_function *obex_alloc(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_obex *obex;
|
||||
struct f_serial_opts *opts;
|
||||
|
@ -689,7 +689,7 @@ static void pn_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
usb_free_all_descriptors(f);
|
||||
}
|
||||
|
||||
struct usb_function *phonet_alloc(struct usb_function_instance *fi)
|
||||
static struct usb_function *phonet_alloc(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_phonet *fp;
|
||||
struct f_phonet_opts *opts;
|
||||
|
@ -675,7 +675,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
int status;
|
||||
struct usb_ep *ep;
|
||||
|
||||
#ifndef USB_FRNDIS_INCLUDED
|
||||
struct f_rndis_opts *rndis_opts;
|
||||
|
||||
if (!can_support_rndis(c))
|
||||
@ -697,7 +696,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
return status;
|
||||
rndis_opts->bound = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
us = usb_gstrings_attach(cdev, rndis_strings,
|
||||
ARRAY_SIZE(rndis_string_defs));
|
||||
if (IS_ERR(us))
|
||||
@ -782,13 +781,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
rndis->port.open = rndis_open;
|
||||
rndis->port.close = rndis_close;
|
||||
|
||||
#ifdef USB_FRNDIS_INCLUDED
|
||||
status = rndis_register(rndis_response_available, rndis);
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
rndis->config = status;
|
||||
#endif
|
||||
|
||||
rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
|
||||
rndis_set_host_mac(rndis->config, rndis->ethaddr);
|
||||
|
||||
@ -830,66 +822,6 @@ fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef USB_FRNDIS_INCLUDED
|
||||
|
||||
static void
|
||||
rndis_old_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct f_rndis *rndis = func_to_rndis(f);
|
||||
|
||||
rndis_deregister(rndis->config);
|
||||
|
||||
usb_free_all_descriptors(f);
|
||||
|
||||
kfree(rndis->notify_req->buf);
|
||||
usb_ep_free_request(rndis->notify, rndis->notify_req);
|
||||
|
||||
kfree(rndis);
|
||||
}
|
||||
|
||||
int
|
||||
rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
u32 vendorID, const char *manufacturer, struct eth_dev *dev)
|
||||
{
|
||||
struct f_rndis *rndis;
|
||||
int status;
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
status = -ENOMEM;
|
||||
rndis = kzalloc(sizeof *rndis, GFP_KERNEL);
|
||||
if (!rndis)
|
||||
goto fail;
|
||||
|
||||
memcpy(rndis->ethaddr, ethaddr, ETH_ALEN);
|
||||
rndis->vendorID = vendorID;
|
||||
rndis->manufacturer = manufacturer;
|
||||
|
||||
rndis->port.ioport = dev;
|
||||
/* RNDIS activates when the host changes this filter */
|
||||
rndis->port.cdc_filter = 0;
|
||||
|
||||
/* RNDIS has special (and complex) framing */
|
||||
rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
|
||||
rndis->port.wrap = rndis_add_header;
|
||||
rndis->port.unwrap = rndis_rm_hdr;
|
||||
|
||||
rndis->port.func.name = "rndis";
|
||||
/* descriptors are per-instance copies */
|
||||
rndis->port.func.bind = rndis_bind;
|
||||
rndis->port.func.unbind = rndis_old_unbind;
|
||||
rndis->port.func.set_alt = rndis_set_alt;
|
||||
rndis->port.func.setup = rndis_setup;
|
||||
rndis->port.func.disable = rndis_disable;
|
||||
|
||||
status = usb_add_function(c, &rndis->port.func);
|
||||
if (status)
|
||||
kfree(rndis);
|
||||
fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)
|
||||
{
|
||||
struct f_rndis_opts *opts;
|
||||
@ -1047,8 +979,26 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
|
||||
return &rndis->port.func;
|
||||
}
|
||||
|
||||
DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc);
|
||||
DECLARE_USB_FUNCTION(rndis, rndis_alloc_inst, rndis_alloc);
|
||||
|
||||
static int __init rndis_mod_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rndis_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return usb_function_register(&rndisusb_func);
|
||||
}
|
||||
module_init(rndis_mod_init);
|
||||
|
||||
static void __exit rndis_mod_exit(void)
|
||||
{
|
||||
usb_function_unregister(&rndisusb_func);
|
||||
rndis_exit();
|
||||
}
|
||||
module_exit(rndis_mod_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
|
||||
#endif
|
||||
|
@ -354,7 +354,7 @@ static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
usb_free_all_descriptors(f);
|
||||
}
|
||||
|
||||
struct usb_function *gser_alloc(struct usb_function_instance *fi)
|
||||
static struct usb_function *gser_alloc(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_gser *gser;
|
||||
struct f_serial_opts *opts;
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "g_zero.h"
|
||||
#include "gadget_chips.h"
|
||||
#include "u_f.h"
|
||||
|
||||
/*
|
||||
* SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral
|
||||
@ -201,7 +202,7 @@ static struct usb_endpoint_descriptor ss_source_desc = {
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
};
|
||||
|
||||
struct usb_ss_ep_comp_descriptor ss_source_comp_desc = {
|
||||
static struct usb_ss_ep_comp_descriptor ss_source_comp_desc = {
|
||||
.bLength = USB_DT_SS_EP_COMP_SIZE,
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
|
||||
@ -218,7 +219,7 @@ static struct usb_endpoint_descriptor ss_sink_desc = {
|
||||
.wMaxPacketSize = cpu_to_le16(1024),
|
||||
};
|
||||
|
||||
struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = {
|
||||
static struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = {
|
||||
.bLength = USB_DT_SS_EP_COMP_SIZE,
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
|
||||
@ -236,7 +237,7 @@ static struct usb_endpoint_descriptor ss_iso_source_desc = {
|
||||
.bInterval = 4,
|
||||
};
|
||||
|
||||
struct usb_ss_ep_comp_descriptor ss_iso_source_comp_desc = {
|
||||
static struct usb_ss_ep_comp_descriptor ss_iso_source_comp_desc = {
|
||||
.bLength = USB_DT_SS_EP_COMP_SIZE,
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
|
||||
@ -254,7 +255,7 @@ static struct usb_endpoint_descriptor ss_iso_sink_desc = {
|
||||
.bInterval = 4,
|
||||
};
|
||||
|
||||
struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {
|
||||
static struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {
|
||||
.bLength = USB_DT_SS_EP_COMP_SIZE,
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
||||
|
||||
@ -301,23 +302,9 @@ static struct usb_gadget_strings *sourcesink_strings[] = {
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
struct usb_request *alloc_ep_req(struct usb_ep *ep, int len)
|
||||
static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)
|
||||
{
|
||||
struct usb_request *req;
|
||||
|
||||
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
|
||||
if (req) {
|
||||
if (len)
|
||||
req->length = len;
|
||||
else
|
||||
req->length = buflen;
|
||||
req->buf = kmalloc(req->length, GFP_ATOMIC);
|
||||
if (!req->buf) {
|
||||
usb_ep_free_request(ep, req);
|
||||
req = NULL;
|
||||
}
|
||||
}
|
||||
return req;
|
||||
return alloc_ep_req(ep, len, buflen);
|
||||
}
|
||||
|
||||
void free_ep_req(struct usb_ep *ep, struct usb_request *req)
|
||||
@ -490,6 +477,14 @@ no_iso:
|
||||
static void
|
||||
sourcesink_free_func(struct usb_function *f)
|
||||
{
|
||||
struct f_ss_opts *opts;
|
||||
|
||||
opts = container_of(f->fi, struct f_ss_opts, func_inst);
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
opts->refcnt--;
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(func_to_ss(f));
|
||||
}
|
||||
@ -628,10 +623,10 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
|
||||
break;
|
||||
}
|
||||
ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
|
||||
req = alloc_ep_req(ep, size);
|
||||
req = ss_alloc_ep_req(ep, size);
|
||||
} else {
|
||||
ep = is_in ? ss->in_ep : ss->out_ep;
|
||||
req = alloc_ep_req(ep, 0);
|
||||
req = ss_alloc_ep_req(ep, 0);
|
||||
}
|
||||
|
||||
if (!req)
|
||||
@ -878,6 +873,11 @@ static struct usb_function *source_sink_alloc_func(
|
||||
return NULL;
|
||||
|
||||
ss_opts = container_of(fi, struct f_ss_opts, func_inst);
|
||||
|
||||
mutex_lock(&ss_opts->lock);
|
||||
ss_opts->refcnt++;
|
||||
mutex_unlock(&ss_opts->lock);
|
||||
|
||||
pattern = ss_opts->pattern;
|
||||
isoc_interval = ss_opts->isoc_interval;
|
||||
isoc_maxpacket = ss_opts->isoc_maxpacket;
|
||||
@ -898,6 +898,303 @@ static struct usb_function *source_sink_alloc_func(
|
||||
return &ss->function;
|
||||
}
|
||||
|
||||
static inline struct f_ss_opts *to_f_ss_opts(struct config_item *item)
|
||||
{
|
||||
return container_of(to_config_group(item), struct f_ss_opts,
|
||||
func_inst.group);
|
||||
}
|
||||
|
||||
CONFIGFS_ATTR_STRUCT(f_ss_opts);
|
||||
CONFIGFS_ATTR_OPS(f_ss_opts);
|
||||
|
||||
static void ss_attr_release(struct config_item *item)
|
||||
{
|
||||
struct f_ss_opts *ss_opts = to_f_ss_opts(item);
|
||||
|
||||
usb_put_function_instance(&ss_opts->func_inst);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations ss_item_ops = {
|
||||
.release = ss_attr_release,
|
||||
.show_attribute = f_ss_opts_attr_show,
|
||||
.store_attribute = f_ss_opts_attr_store,
|
||||
};
|
||||
|
||||
static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page)
|
||||
{
|
||||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->pattern);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t f_ss_opts_pattern_store(struct f_ss_opts *opts,
|
||||
const char *page, size_t len)
|
||||
{
|
||||
int ret;
|
||||
u8 num;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
if (opts->refcnt) {
|
||||
ret = -EBUSY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = kstrtou8(page, 0, &num);
|
||||
if (ret)
|
||||
goto end;
|
||||
|
||||
if (num != 0 && num != 1 && num != 2) {
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
opts->pattern = num;
|
||||
ret = len;
|
||||
end:
|
||||
mutex_unlock(&opts->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct f_ss_opts_attribute f_ss_opts_pattern =
|
||||
__CONFIGFS_ATTR(pattern, S_IRUGO | S_IWUSR,
|
||||
f_ss_opts_pattern_show,
|
||||
f_ss_opts_pattern_store);
|
||||
|
||||
static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page)
|
||||
{
|
||||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->isoc_interval);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t f_ss_opts_isoc_interval_store(struct f_ss_opts *opts,
|
||||
const char *page, size_t len)
|
||||
{
|
||||
int ret;
|
||||
u8 num;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
if (opts->refcnt) {
|
||||
ret = -EBUSY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = kstrtou8(page, 0, &num);
|
||||
if (ret)
|
||||
goto end;
|
||||
|
||||
if (num > 16) {
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
opts->isoc_interval = num;
|
||||
ret = len;
|
||||
end:
|
||||
mutex_unlock(&opts->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct f_ss_opts_attribute f_ss_opts_isoc_interval =
|
||||
__CONFIGFS_ATTR(isoc_interval, S_IRUGO | S_IWUSR,
|
||||
f_ss_opts_isoc_interval_show,
|
||||
f_ss_opts_isoc_interval_store);
|
||||
|
||||
static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page)
|
||||
{
|
||||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->isoc_maxpacket);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t f_ss_opts_isoc_maxpacket_store(struct f_ss_opts *opts,
|
||||
const char *page, size_t len)
|
||||
{
|
||||
int ret;
|
||||
u16 num;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
if (opts->refcnt) {
|
||||
ret = -EBUSY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = kstrtou16(page, 0, &num);
|
||||
if (ret)
|
||||
goto end;
|
||||
|
||||
if (num > 1024) {
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
opts->isoc_maxpacket = num;
|
||||
ret = len;
|
||||
end:
|
||||
mutex_unlock(&opts->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct f_ss_opts_attribute f_ss_opts_isoc_maxpacket =
|
||||
__CONFIGFS_ATTR(isoc_maxpacket, S_IRUGO | S_IWUSR,
|
||||
f_ss_opts_isoc_maxpacket_show,
|
||||
f_ss_opts_isoc_maxpacket_store);
|
||||
|
||||
static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page)
|
||||
{
|
||||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->isoc_mult);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t f_ss_opts_isoc_mult_store(struct f_ss_opts *opts,
|
||||
const char *page, size_t len)
|
||||
{
|
||||
int ret;
|
||||
u8 num;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
if (opts->refcnt) {
|
||||
ret = -EBUSY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = kstrtou8(page, 0, &num);
|
||||
if (ret)
|
||||
goto end;
|
||||
|
||||
if (num > 2) {
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
opts->isoc_mult = num;
|
||||
ret = len;
|
||||
end:
|
||||
mutex_unlock(&opts->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct f_ss_opts_attribute f_ss_opts_isoc_mult =
|
||||
__CONFIGFS_ATTR(isoc_mult, S_IRUGO | S_IWUSR,
|
||||
f_ss_opts_isoc_mult_show,
|
||||
f_ss_opts_isoc_mult_store);
|
||||
|
||||
static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page)
|
||||
{
|
||||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->isoc_maxburst);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t f_ss_opts_isoc_maxburst_store(struct f_ss_opts *opts,
|
||||
const char *page, size_t len)
|
||||
{
|
||||
int ret;
|
||||
u8 num;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
if (opts->refcnt) {
|
||||
ret = -EBUSY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = kstrtou8(page, 0, &num);
|
||||
if (ret)
|
||||
goto end;
|
||||
|
||||
if (num > 15) {
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
opts->isoc_maxburst = num;
|
||||
ret = len;
|
||||
end:
|
||||
mutex_unlock(&opts->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct f_ss_opts_attribute f_ss_opts_isoc_maxburst =
|
||||
__CONFIGFS_ATTR(isoc_maxburst, S_IRUGO | S_IWUSR,
|
||||
f_ss_opts_isoc_maxburst_show,
|
||||
f_ss_opts_isoc_maxburst_store);
|
||||
|
||||
static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page)
|
||||
{
|
||||
int result;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
result = sprintf(page, "%d", opts->bulk_buflen);
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t f_ss_opts_bulk_buflen_store(struct f_ss_opts *opts,
|
||||
const char *page, size_t len)
|
||||
{
|
||||
int ret;
|
||||
u32 num;
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
if (opts->refcnt) {
|
||||
ret = -EBUSY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = kstrtou32(page, 0, &num);
|
||||
if (ret)
|
||||
goto end;
|
||||
|
||||
opts->bulk_buflen = num;
|
||||
ret = len;
|
||||
end:
|
||||
mutex_unlock(&opts->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct f_ss_opts_attribute f_ss_opts_bulk_buflen =
|
||||
__CONFIGFS_ATTR(buflen, S_IRUGO | S_IWUSR,
|
||||
f_ss_opts_bulk_buflen_show,
|
||||
f_ss_opts_bulk_buflen_store);
|
||||
|
||||
static struct configfs_attribute *ss_attrs[] = {
|
||||
&f_ss_opts_pattern.attr,
|
||||
&f_ss_opts_isoc_interval.attr,
|
||||
&f_ss_opts_isoc_maxpacket.attr,
|
||||
&f_ss_opts_isoc_mult.attr,
|
||||
&f_ss_opts_isoc_maxburst.attr,
|
||||
&f_ss_opts_bulk_buflen.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct config_item_type ss_func_type = {
|
||||
.ct_item_ops = &ss_item_ops,
|
||||
.ct_attrs = ss_attrs,
|
||||
.ct_owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void source_sink_free_instance(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_ss_opts *ss_opts;
|
||||
@ -913,7 +1210,15 @@ static struct usb_function_instance *source_sink_alloc_inst(void)
|
||||
ss_opts = kzalloc(sizeof(*ss_opts), GFP_KERNEL);
|
||||
if (!ss_opts)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
mutex_init(&ss_opts->lock);
|
||||
ss_opts->func_inst.free_func_inst = source_sink_free_instance;
|
||||
ss_opts->isoc_interval = GZERO_ISOC_INTERVAL;
|
||||
ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET;
|
||||
ss_opts->bulk_buflen = GZERO_BULK_BUFLEN;
|
||||
|
||||
config_group_init_type_name(&ss_opts->func_inst.group, "",
|
||||
&ss_func_type);
|
||||
|
||||
return &ss_opts->func_inst;
|
||||
}
|
||||
DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst,
|
||||
|
@ -301,7 +301,6 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
int status;
|
||||
struct usb_ep *ep;
|
||||
|
||||
#ifndef USB_FSUBSET_INCLUDED
|
||||
struct f_gether_opts *gether_opts;
|
||||
|
||||
gether_opts = container_of(f->fi, struct f_gether_opts, func_inst);
|
||||
@ -322,7 +321,7 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
return status;
|
||||
gether_opts->bound = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
us = usb_gstrings_attach(cdev, geth_strings,
|
||||
ARRAY_SIZE(geth_string_defs));
|
||||
if (IS_ERR(us))
|
||||
@ -393,61 +392,6 @@ fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef USB_FSUBSET_INCLUDED
|
||||
|
||||
static void
|
||||
geth_old_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
geth_string_defs[0].id = 0;
|
||||
usb_free_all_descriptors(f);
|
||||
kfree(func_to_geth(f));
|
||||
}
|
||||
|
||||
/**
|
||||
* geth_bind_config - add CDC Subset network link to a configuration
|
||||
* @c: the configuration to support the network link
|
||||
* @ethaddr: a buffer in which the ethernet address of the host side
|
||||
* side of the link was recorded
|
||||
* @dev: eth_dev structure
|
||||
* Context: single threaded during gadget setup
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*
|
||||
* Caller must have called @gether_setup(). Caller is also responsible
|
||||
* for calling @gether_cleanup() before module unload.
|
||||
*/
|
||||
int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev)
|
||||
{
|
||||
struct f_gether *geth;
|
||||
int status;
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
geth = kzalloc(sizeof *geth, GFP_KERNEL);
|
||||
if (!geth)
|
||||
return -ENOMEM;
|
||||
|
||||
/* export host's Ethernet address in CDC format */
|
||||
snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr);
|
||||
geth_string_defs[1].s = geth->ethaddr;
|
||||
|
||||
geth->port.ioport = dev;
|
||||
geth->port.cdc_filter = DEFAULT_FILTER;
|
||||
|
||||
geth->port.func.name = "cdc_subset";
|
||||
geth->port.func.bind = geth_bind;
|
||||
geth->port.func.unbind = geth_old_unbind;
|
||||
geth->port.func.set_alt = geth_set_alt;
|
||||
geth->port.func.disable = geth_disable;
|
||||
|
||||
status = usb_add_function(c, &geth->port.func);
|
||||
if (status)
|
||||
kfree(geth);
|
||||
return status;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline struct f_gether_opts *to_f_gether_opts(struct config_item *item)
|
||||
{
|
||||
return container_of(to_config_group(item), struct f_gether_opts,
|
||||
@ -573,5 +517,3 @@ static struct usb_function *geth_alloc(struct usb_function_instance *fi)
|
||||
DECLARE_USB_FUNCTION_INIT(geth, geth_alloc_inst, geth_alloc);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
|
||||
#endif
|
||||
|
@ -1157,8 +1157,9 @@ static int fotg210_udc_probe(struct platform_device *pdev)
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
ep->ep.name = fotg210_ep_name[i];
|
||||
ep->ep.ops = &fotg210_ep_ops;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);
|
||||
}
|
||||
fotg210->ep[0]->ep.maxpacket = 0x40;
|
||||
usb_ep_set_maxpacket_limit(&fotg210->ep[0]->ep, 0x40);
|
||||
fotg210->gadget.ep0 = &fotg210->ep[0]->ep;
|
||||
INIT_LIST_HEAD(&fotg210->gadget.ep0->ep_list);
|
||||
|
||||
|
@ -2429,7 +2429,7 @@ static int qe_ep_config(struct qe_udc *udc, unsigned char pipe_num)
|
||||
|
||||
ep->ep.ops = &qe_ep_ops;
|
||||
ep->stopped = 1;
|
||||
ep->ep.maxpacket = (unsigned short) ~0;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);
|
||||
ep->ep.desc = NULL;
|
||||
ep->dir = 0xff;
|
||||
ep->epnum = (u8)pipe_num;
|
||||
|
@ -2311,7 +2311,7 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,
|
||||
/* for ep0: maxP defined in desc
|
||||
* for other eps, maxP is set by epautoconfig() called by gadget layer
|
||||
*/
|
||||
ep->ep.maxpacket = (unsigned short) ~0;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);
|
||||
|
||||
/* the queue lists any req for this ep */
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
@ -2469,7 +2469,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
|
||||
* for other eps, gadget layer called ep_enable with defined desc
|
||||
*/
|
||||
udc_controller->eps[0].ep.desc = &fsl_ep0_desc;
|
||||
udc_controller->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD;
|
||||
usb_ep_set_maxpacket_limit(&udc_controller->eps[0].ep,
|
||||
USB_MAX_CTRL_PAYLOAD);
|
||||
|
||||
/* setup the udc->eps[] for non-control endpoints and link
|
||||
* to gadget.ep_list */
|
||||
|
@ -1452,9 +1452,9 @@ static int __init fusb300_probe(struct platform_device *pdev)
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
ep->ep.name = fusb300_ep_name[i];
|
||||
ep->ep.ops = &fusb300_ep_ops;
|
||||
ep->ep.maxpacket = HS_BULK_MAX_PACKET_SIZE;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, HS_BULK_MAX_PACKET_SIZE);
|
||||
}
|
||||
fusb300->ep[0]->ep.maxpacket = HS_CTL_MAX_PACKET_SIZE;
|
||||
usb_ep_set_maxpacket_limit(&fusb300->ep[0]->ep, HS_CTL_MAX_PACKET_SIZE);
|
||||
fusb300->ep[0]->epnum = 0;
|
||||
fusb300->gadget.ep0 = &fusb300->ep[0]->ep;
|
||||
INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list);
|
||||
|
@ -13,14 +13,10 @@
|
||||
#define pr_fmt(fmt) "g_ffs: " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
/*
|
||||
* kbuild is not very cooperative with respect to linking separately
|
||||
* compiled library objects into one module. So for now we won't use
|
||||
* separate compilation ... ensuring init/exit sections work to shrink
|
||||
* the runtime footprint, and giving us at least some parts of what
|
||||
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
|
||||
*/
|
||||
|
||||
#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
# if defined USB_ETH_RNDIS
|
||||
# undef USB_ETH_RNDIS
|
||||
# endif
|
||||
@ -28,31 +24,31 @@
|
||||
# define USB_ETH_RNDIS y
|
||||
# endif
|
||||
|
||||
#define USBF_ECM_INCLUDED
|
||||
# include "f_ecm.c"
|
||||
#define USB_FSUBSET_INCLUDED
|
||||
# include "f_subset.c"
|
||||
# include "u_ecm.h"
|
||||
# include "u_gether.h"
|
||||
# ifdef USB_ETH_RNDIS
|
||||
# define USB_FRNDIS_INCLUDED
|
||||
# include "f_rndis.c"
|
||||
# include "u_rndis.h"
|
||||
# include "rndis.h"
|
||||
# endif
|
||||
# include "u_ether.h"
|
||||
|
||||
static u8 gfs_host_mac[ETH_ALEN];
|
||||
static struct eth_dev *the_dev;
|
||||
USB_ETHERNET_MODULE_PARAMETERS();
|
||||
|
||||
# ifdef CONFIG_USB_FUNCTIONFS_ETH
|
||||
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev);
|
||||
static int eth_bind_config(struct usb_configuration *c);
|
||||
static struct usb_function_instance *fi_ecm;
|
||||
static struct usb_function *f_ecm;
|
||||
static struct usb_function_instance *fi_geth;
|
||||
static struct usb_function *f_geth;
|
||||
# endif
|
||||
# ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
static int bind_rndis_config(struct usb_configuration *c);
|
||||
static struct usb_function_instance *fi_rndis;
|
||||
static struct usb_function *f_rndis;
|
||||
# endif
|
||||
#else
|
||||
# define the_dev NULL
|
||||
# define gether_cleanup(dev) do { } while (0)
|
||||
# define gfs_host_mac NULL
|
||||
struct eth_dev;
|
||||
#endif
|
||||
|
||||
#include "f_fs.c"
|
||||
#include "u_fs.h"
|
||||
|
||||
#define DRIVER_NAME "g_ffs"
|
||||
#define DRIVER_DESC "USB Function Filesystem"
|
||||
@ -67,19 +63,8 @@ MODULE_LICENSE("GPL");
|
||||
|
||||
#define GFS_MAX_DEVS 10
|
||||
|
||||
struct gfs_ffs_obj {
|
||||
const char *name;
|
||||
bool mounted;
|
||||
bool desc_ready;
|
||||
struct ffs_data *ffs_data;
|
||||
};
|
||||
|
||||
USB_GADGET_COMPOSITE_OPTIONS();
|
||||
|
||||
#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
USB_ETHERNET_MODULE_PARAMETERS();
|
||||
#endif
|
||||
|
||||
static struct usb_device_descriptor gfs_dev_desc = {
|
||||
.bLength = sizeof gfs_dev_desc,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
@ -146,12 +131,12 @@ static struct usb_gadget_strings *gfs_dev_strings[] = {
|
||||
|
||||
struct gfs_configuration {
|
||||
struct usb_configuration c;
|
||||
int (*eth)(struct usb_configuration *c, u8 *ethaddr,
|
||||
struct eth_dev *dev);
|
||||
int (*eth)(struct usb_configuration *c);
|
||||
int num;
|
||||
} gfs_configurations[] = {
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
{
|
||||
.eth = rndis_bind_config,
|
||||
.eth = bind_rndis_config,
|
||||
},
|
||||
#endif
|
||||
|
||||
@ -167,10 +152,15 @@ struct gfs_configuration {
|
||||
#endif
|
||||
};
|
||||
|
||||
static void *functionfs_acquire_dev(struct ffs_dev *dev);
|
||||
static void functionfs_release_dev(struct ffs_dev *dev);
|
||||
static int functionfs_ready_callback(struct ffs_data *ffs);
|
||||
static void functionfs_closed_callback(struct ffs_data *ffs);
|
||||
static int gfs_bind(struct usb_composite_dev *cdev);
|
||||
static int gfs_unbind(struct usb_composite_dev *cdev);
|
||||
static int gfs_do_config(struct usb_configuration *c);
|
||||
|
||||
|
||||
static __refdata struct usb_composite_driver gfs_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.dev = &gfs_dev_desc,
|
||||
@ -180,205 +170,243 @@ static __refdata struct usb_composite_driver gfs_driver = {
|
||||
.unbind = gfs_unbind,
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(gfs_lock);
|
||||
static unsigned int missing_funcs;
|
||||
static bool gfs_ether_setup;
|
||||
static bool gfs_registered;
|
||||
static bool gfs_single_func;
|
||||
static struct gfs_ffs_obj *ffs_tab;
|
||||
static struct usb_function_instance **fi_ffs;
|
||||
static struct usb_function **f_ffs[] = {
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
NULL,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_ETH
|
||||
NULL,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
|
||||
NULL,
|
||||
#endif
|
||||
};
|
||||
|
||||
#define N_CONF ARRAY_SIZE(f_ffs)
|
||||
|
||||
static int __init gfs_init(void)
|
||||
{
|
||||
struct f_fs_opts *opts;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (!func_num) {
|
||||
if (func_num < 2) {
|
||||
gfs_single_func = true;
|
||||
func_num = 1;
|
||||
}
|
||||
|
||||
ffs_tab = kcalloc(func_num, sizeof *ffs_tab, GFP_KERNEL);
|
||||
if (!ffs_tab)
|
||||
return -ENOMEM;
|
||||
/*
|
||||
* Allocate in one chunk for easier maintenance
|
||||
*/
|
||||
f_ffs[0] = kcalloc(func_num * N_CONF, sizeof(*f_ffs), GFP_KERNEL);
|
||||
if (!f_ffs[0]) {
|
||||
ret = -ENOMEM;
|
||||
goto no_func;
|
||||
}
|
||||
for (i = 1; i < N_CONF; ++i)
|
||||
f_ffs[i] = f_ffs[0] + i * func_num;
|
||||
|
||||
if (!gfs_single_func)
|
||||
for (i = 0; i < func_num; i++)
|
||||
ffs_tab[i].name = func_names[i];
|
||||
fi_ffs = kcalloc(func_num, sizeof(*fi_ffs), GFP_KERNEL);
|
||||
if (!fi_ffs) {
|
||||
ret = -ENOMEM;
|
||||
goto no_func;
|
||||
}
|
||||
|
||||
for (i = 0; i < func_num; i++) {
|
||||
fi_ffs[i] = usb_get_function_instance("ffs");
|
||||
if (IS_ERR(fi_ffs[i])) {
|
||||
ret = PTR_ERR(fi_ffs[i]);
|
||||
--i;
|
||||
goto no_dev;
|
||||
}
|
||||
opts = to_f_fs_opts(fi_ffs[i]);
|
||||
if (gfs_single_func)
|
||||
ret = ffs_single_dev(opts->dev);
|
||||
else
|
||||
ret = ffs_name_dev(opts->dev, func_names[i]);
|
||||
if (ret)
|
||||
goto no_dev;
|
||||
opts->dev->ffs_ready_callback = functionfs_ready_callback;
|
||||
opts->dev->ffs_closed_callback = functionfs_closed_callback;
|
||||
opts->dev->ffs_acquire_dev_callback = functionfs_acquire_dev;
|
||||
opts->dev->ffs_release_dev_callback = functionfs_release_dev;
|
||||
opts->no_configfs = true;
|
||||
}
|
||||
|
||||
missing_funcs = func_num;
|
||||
|
||||
return functionfs_init();
|
||||
return 0;
|
||||
no_dev:
|
||||
while (i >= 0)
|
||||
usb_put_function_instance(fi_ffs[i--]);
|
||||
kfree(fi_ffs);
|
||||
no_func:
|
||||
kfree(f_ffs[0]);
|
||||
return ret;
|
||||
}
|
||||
module_init(gfs_init);
|
||||
|
||||
static void __exit gfs_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
ENTER();
|
||||
mutex_lock(&gfs_lock);
|
||||
|
||||
if (gfs_registered)
|
||||
usb_composite_unregister(&gfs_driver);
|
||||
gfs_registered = false;
|
||||
|
||||
functionfs_cleanup();
|
||||
kfree(f_ffs[0]);
|
||||
|
||||
mutex_unlock(&gfs_lock);
|
||||
kfree(ffs_tab);
|
||||
for (i = 0; i < func_num; i++)
|
||||
usb_put_function_instance(fi_ffs[i]);
|
||||
|
||||
kfree(fi_ffs);
|
||||
}
|
||||
module_exit(gfs_exit);
|
||||
|
||||
static struct gfs_ffs_obj *gfs_find_dev(const char *dev_name)
|
||||
static void *functionfs_acquire_dev(struct ffs_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (gfs_single_func)
|
||||
return &ffs_tab[0];
|
||||
|
||||
for (i = 0; i < func_num; i++)
|
||||
if (strcmp(ffs_tab[i].name, dev_name) == 0)
|
||||
return &ffs_tab[i];
|
||||
|
||||
return NULL;
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void functionfs_release_dev(struct ffs_dev *dev)
|
||||
{
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
/*
|
||||
* The caller of this function takes ffs_lock
|
||||
*/
|
||||
static int functionfs_ready_callback(struct ffs_data *ffs)
|
||||
{
|
||||
struct gfs_ffs_obj *ffs_obj;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
ENTER();
|
||||
mutex_lock(&gfs_lock);
|
||||
if (--missing_funcs)
|
||||
return 0;
|
||||
|
||||
ffs_obj = ffs->private_data;
|
||||
if (!ffs_obj) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (gfs_registered)
|
||||
return -EBUSY;
|
||||
|
||||
if (WARN_ON(ffs_obj->desc_ready)) {
|
||||
ret = -EBUSY;
|
||||
goto done;
|
||||
}
|
||||
ffs_obj->desc_ready = true;
|
||||
ffs_obj->ffs_data = ffs;
|
||||
|
||||
if (--missing_funcs) {
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (gfs_registered) {
|
||||
ret = -EBUSY;
|
||||
goto done;
|
||||
}
|
||||
gfs_registered = true;
|
||||
|
||||
ret = usb_composite_probe(&gfs_driver);
|
||||
if (unlikely(ret < 0))
|
||||
gfs_registered = false;
|
||||
|
||||
done:
|
||||
mutex_unlock(&gfs_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* The caller of this function takes ffs_lock
|
||||
*/
|
||||
static void functionfs_closed_callback(struct ffs_data *ffs)
|
||||
{
|
||||
struct gfs_ffs_obj *ffs_obj;
|
||||
|
||||
ENTER();
|
||||
mutex_lock(&gfs_lock);
|
||||
|
||||
ffs_obj = ffs->private_data;
|
||||
if (!ffs_obj)
|
||||
goto done;
|
||||
|
||||
ffs_obj->desc_ready = false;
|
||||
missing_funcs++;
|
||||
|
||||
if (gfs_registered)
|
||||
usb_composite_unregister(&gfs_driver);
|
||||
gfs_registered = false;
|
||||
|
||||
done:
|
||||
mutex_unlock(&gfs_lock);
|
||||
}
|
||||
|
||||
static void *functionfs_acquire_dev_callback(const char *dev_name)
|
||||
{
|
||||
struct gfs_ffs_obj *ffs_dev;
|
||||
|
||||
ENTER();
|
||||
mutex_lock(&gfs_lock);
|
||||
|
||||
ffs_dev = gfs_find_dev(dev_name);
|
||||
if (!ffs_dev) {
|
||||
ffs_dev = ERR_PTR(-ENODEV);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ffs_dev->mounted) {
|
||||
ffs_dev = ERR_PTR(-EBUSY);
|
||||
goto done;
|
||||
}
|
||||
ffs_dev->mounted = true;
|
||||
|
||||
done:
|
||||
mutex_unlock(&gfs_lock);
|
||||
return ffs_dev;
|
||||
}
|
||||
|
||||
static void functionfs_release_dev_callback(struct ffs_data *ffs_data)
|
||||
{
|
||||
struct gfs_ffs_obj *ffs_dev;
|
||||
|
||||
ENTER();
|
||||
mutex_lock(&gfs_lock);
|
||||
|
||||
ffs_dev = ffs_data->private_data;
|
||||
if (ffs_dev)
|
||||
ffs_dev->mounted = false;
|
||||
|
||||
mutex_unlock(&gfs_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* It is assumed that gfs_bind is called from a context where gfs_lock is held
|
||||
* It is assumed that gfs_bind is called from a context where ffs_lock is held
|
||||
*/
|
||||
static int gfs_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
struct net_device *net;
|
||||
#endif
|
||||
int ret, i;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (missing_funcs)
|
||||
return -ENODEV;
|
||||
#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, gfs_host_mac,
|
||||
qmult);
|
||||
#endif
|
||||
if (IS_ERR(the_dev)) {
|
||||
ret = PTR_ERR(the_dev);
|
||||
goto error_quick;
|
||||
#if defined CONFIG_USB_FUNCTIONFS_ETH
|
||||
if (can_support_ecm(cdev->gadget)) {
|
||||
struct f_ecm_opts *ecm_opts;
|
||||
|
||||
fi_ecm = usb_get_function_instance("ecm");
|
||||
if (IS_ERR(fi_ecm))
|
||||
return PTR_ERR(fi_ecm);
|
||||
ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
|
||||
net = ecm_opts->net;
|
||||
} else {
|
||||
struct f_gether_opts *geth_opts;
|
||||
|
||||
fi_geth = usb_get_function_instance("geth");
|
||||
if (IS_ERR(fi_geth))
|
||||
return PTR_ERR(fi_geth);
|
||||
geth_opts = container_of(fi_geth, struct f_gether_opts,
|
||||
func_inst);
|
||||
net = geth_opts->net;
|
||||
}
|
||||
gfs_ether_setup = true;
|
||||
#endif
|
||||
|
||||
ret = usb_string_ids_tab(cdev, gfs_strings);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id;
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
{
|
||||
struct f_rndis_opts *rndis_opts;
|
||||
|
||||
for (i = func_num; i--; ) {
|
||||
ret = functionfs_bind(ffs_tab[i].ffs_data, cdev);
|
||||
if (unlikely(ret < 0)) {
|
||||
while (++i < func_num)
|
||||
functionfs_unbind(ffs_tab[i].ffs_data);
|
||||
fi_rndis = usb_get_function_instance("rndis");
|
||||
if (IS_ERR(fi_rndis)) {
|
||||
ret = PTR_ERR(fi_rndis);
|
||||
goto error;
|
||||
}
|
||||
rndis_opts = container_of(fi_rndis, struct f_rndis_opts,
|
||||
func_inst);
|
||||
#ifndef CONFIG_USB_FUNCTIONFS_ETH
|
||||
net = rndis_opts->net;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
gether_set_qmult(net, qmult);
|
||||
if (!gether_set_host_addr(net, host_addr))
|
||||
pr_info("using host ethernet address: %s", host_addr);
|
||||
if (!gether_set_dev_addr(net, dev_addr))
|
||||
pr_info("using self ethernet address: %s", dev_addr);
|
||||
#endif
|
||||
|
||||
#if defined CONFIG_USB_FUNCTIONFS_RNDIS && defined CONFIG_USB_FUNCTIONFS_ETH
|
||||
gether_set_gadget(net, cdev->gadget);
|
||||
ret = gether_register_netdev(net);
|
||||
if (ret)
|
||||
goto error_rndis;
|
||||
|
||||
if (can_support_ecm(cdev->gadget)) {
|
||||
struct f_ecm_opts *ecm_opts;
|
||||
|
||||
ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
|
||||
ecm_opts->bound = true;
|
||||
} else {
|
||||
struct f_gether_opts *geth_opts;
|
||||
|
||||
geth_opts = container_of(fi_geth, struct f_gether_opts,
|
||||
func_inst);
|
||||
geth_opts->bound = true;
|
||||
}
|
||||
|
||||
rndis_borrow_net(fi_rndis, net);
|
||||
#endif
|
||||
|
||||
/* TODO: gstrings_attach? */
|
||||
ret = usb_string_ids_tab(cdev, gfs_strings);
|
||||
if (unlikely(ret < 0))
|
||||
goto error_rndis;
|
||||
gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
|
||||
struct gfs_configuration *c = gfs_configurations + i;
|
||||
@ -389,6 +417,8 @@ static int gfs_bind(struct usb_composite_dev *cdev)
|
||||
c->c.bConfigurationValue = 1 + i;
|
||||
c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER;
|
||||
|
||||
c->num = i;
|
||||
|
||||
ret = usb_add_config(cdev, &c->c, gfs_do_config);
|
||||
if (unlikely(ret < 0))
|
||||
goto error_unbind;
|
||||
@ -396,18 +426,24 @@ static int gfs_bind(struct usb_composite_dev *cdev)
|
||||
usb_composite_overwrite_options(cdev, &coverwrite);
|
||||
return 0;
|
||||
|
||||
/* TODO */
|
||||
error_unbind:
|
||||
for (i = 0; i < func_num; i++)
|
||||
functionfs_unbind(ffs_tab[i].ffs_data);
|
||||
error_rndis:
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
usb_put_function_instance(fi_rndis);
|
||||
error:
|
||||
gether_cleanup(the_dev);
|
||||
error_quick:
|
||||
gfs_ether_setup = false;
|
||||
#endif
|
||||
#if defined CONFIG_USB_FUNCTIONFS_ETH
|
||||
if (can_support_ecm(cdev->gadget))
|
||||
usb_put_function_instance(fi_ecm);
|
||||
else
|
||||
usb_put_function_instance(fi_geth);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* It is assumed that gfs_unbind is called from a context where gfs_lock is held
|
||||
* It is assumed that gfs_unbind is called from a context where ffs_lock is held
|
||||
*/
|
||||
static int gfs_unbind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
@ -415,28 +451,30 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
|
||||
|
||||
ENTER();
|
||||
|
||||
/*
|
||||
* We may have been called in an error recovery from
|
||||
* composite_bind() after gfs_unbind() failure so we need to
|
||||
* check if gfs_ffs_data is not NULL since gfs_bind() handles
|
||||
* all error recovery itself. I'd rather we werent called
|
||||
* from composite on orror recovery, but what you're gonna
|
||||
* do...?
|
||||
*/
|
||||
if (gfs_ether_setup)
|
||||
gether_cleanup(the_dev);
|
||||
gfs_ether_setup = false;
|
||||
|
||||
for (i = func_num; i--; )
|
||||
if (ffs_tab[i].ffs_data)
|
||||
functionfs_unbind(ffs_tab[i].ffs_data);
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
usb_put_function(f_rndis);
|
||||
usb_put_function_instance(fi_rndis);
|
||||
#endif
|
||||
|
||||
#if defined CONFIG_USB_FUNCTIONFS_ETH
|
||||
if (can_support_ecm(cdev->gadget)) {
|
||||
usb_put_function(f_ecm);
|
||||
usb_put_function_instance(fi_ecm);
|
||||
} else {
|
||||
usb_put_function(f_geth);
|
||||
usb_put_function_instance(fi_geth);
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < N_CONF * func_num; ++i)
|
||||
usb_put_function(*(f_ffs[0] + i));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* It is assumed that gfs_do_config is called from a context where
|
||||
* gfs_lock is held
|
||||
* ffs_lock is held
|
||||
*/
|
||||
static int gfs_do_config(struct usb_configuration *c)
|
||||
{
|
||||
@ -454,15 +492,22 @@ static int gfs_do_config(struct usb_configuration *c)
|
||||
}
|
||||
|
||||
if (gc->eth) {
|
||||
ret = gc->eth(c, gfs_host_mac, the_dev);
|
||||
ret = gc->eth(c);
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < func_num; i++) {
|
||||
ret = functionfs_bind_config(c->cdev, c, ffs_tab[i].ffs_data);
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
f_ffs[gc->num][i] = usb_get_function(fi_ffs[i]);
|
||||
if (IS_ERR(f_ffs[gc->num][i])) {
|
||||
ret = PTR_ERR(f_ffs[gc->num][i]);
|
||||
goto error;
|
||||
}
|
||||
ret = usb_add_function(c, f_ffs[gc->num][i]);
|
||||
if (ret < 0) {
|
||||
usb_put_function(f_ffs[gc->num][i]);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -479,16 +524,59 @@ static int gfs_do_config(struct usb_configuration *c)
|
||||
c->interface[c->next_interface_id] = NULL;
|
||||
|
||||
return 0;
|
||||
error:
|
||||
while (--i >= 0) {
|
||||
if (!IS_ERR(f_ffs[gc->num][i]))
|
||||
usb_remove_function(c, f_ffs[gc->num][i]);
|
||||
usb_put_function(f_ffs[gc->num][i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_ETH
|
||||
|
||||
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev)
|
||||
static int eth_bind_config(struct usb_configuration *c)
|
||||
{
|
||||
return can_support_ecm(c->cdev->gadget)
|
||||
? ecm_bind_config(c, ethaddr, dev)
|
||||
: geth_bind_config(c, ethaddr, dev);
|
||||
int status = 0;
|
||||
|
||||
if (can_support_ecm(c->cdev->gadget)) {
|
||||
f_ecm = usb_get_function(fi_ecm);
|
||||
if (IS_ERR(f_ecm))
|
||||
return PTR_ERR(f_ecm);
|
||||
|
||||
status = usb_add_function(c, f_ecm);
|
||||
if (status < 0)
|
||||
usb_put_function(f_ecm);
|
||||
|
||||
} else {
|
||||
f_geth = usb_get_function(fi_geth);
|
||||
if (IS_ERR(f_geth))
|
||||
return PTR_ERR(f_geth);
|
||||
|
||||
status = usb_add_function(c, f_geth);
|
||||
if (status < 0)
|
||||
usb_put_function(f_geth);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
|
||||
static int bind_rndis_config(struct usb_configuration *c)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
f_rndis = usb_get_function(fi_rndis);
|
||||
if (IS_ERR(f_rndis))
|
||||
return PTR_ERR(f_rndis);
|
||||
|
||||
status = usb_add_function(c, f_rndis);
|
||||
if (status < 0)
|
||||
usb_put_function(f_rndis);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,6 +6,11 @@
|
||||
#ifndef __G_ZERO_H
|
||||
#define __G_ZERO_H
|
||||
|
||||
#define GZERO_BULK_BUFLEN 4096
|
||||
#define GZERO_QLEN 32
|
||||
#define GZERO_ISOC_INTERVAL 4
|
||||
#define GZERO_ISOC_MAXPACKET 1024
|
||||
|
||||
struct usb_zero_options {
|
||||
unsigned pattern;
|
||||
unsigned isoc_interval;
|
||||
@ -24,19 +29,36 @@ struct f_ss_opts {
|
||||
unsigned isoc_mult;
|
||||
unsigned isoc_maxburst;
|
||||
unsigned bulk_buflen;
|
||||
|
||||
/*
|
||||
* Read/write access to configfs attributes is handled by configfs.
|
||||
*
|
||||
* This is to protect the data from concurrent access by read/write
|
||||
* and create symlink/remove symlink.
|
||||
*/
|
||||
struct mutex lock;
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
struct f_lb_opts {
|
||||
struct usb_function_instance func_inst;
|
||||
unsigned bulk_buflen;
|
||||
unsigned qlen;
|
||||
|
||||
/*
|
||||
* Read/write access to configfs attributes is handled by configfs.
|
||||
*
|
||||
* This is to protect the data from concurrent access by read/write
|
||||
* and create symlink/remove symlink.
|
||||
*/
|
||||
struct mutex lock;
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
void lb_modexit(void);
|
||||
int lb_modinit(void);
|
||||
|
||||
/* common utilities */
|
||||
struct usb_request *alloc_ep_req(struct usb_ep *ep, int len);
|
||||
void free_ep_req(struct usb_ep *ep, struct usb_request *req);
|
||||
void disable_endpoints(struct usb_composite_dev *cdev,
|
||||
struct usb_ep *in, struct usb_ep *out,
|
||||
|
@ -231,7 +231,7 @@ static void ep_reset(struct goku_udc_regs __iomem *regs, struct goku_ep *ep)
|
||||
}
|
||||
}
|
||||
|
||||
ep->ep.maxpacket = MAX_FIFO_SIZE;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, MAX_FIFO_SIZE);
|
||||
ep->ep.desc = NULL;
|
||||
ep->stopped = 1;
|
||||
ep->irqs = 0;
|
||||
@ -1251,7 +1251,7 @@ static void udc_reinit (struct goku_udc *dev)
|
||||
}
|
||||
|
||||
dev->ep[0].reg_mode = NULL;
|
||||
dev->ep[0].ep.maxpacket = MAX_EP0_SIZE;
|
||||
usb_ep_set_maxpacket_limit(&dev->ep[0].ep, MAX_EP0_SIZE);
|
||||
list_del_init (&dev->ep[0].ep.ep_list);
|
||||
}
|
||||
|
||||
@ -1350,16 +1350,12 @@ static int goku_udc_start(struct usb_gadget *g,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
|
||||
static void stop_activity(struct goku_udc *dev)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
DBG (dev, "%s\n", __func__);
|
||||
|
||||
if (dev->gadget.speed == USB_SPEED_UNKNOWN)
|
||||
driver = NULL;
|
||||
|
||||
/* disconnect gadget driver after quiesceing hw and the driver */
|
||||
udc_reset (dev);
|
||||
for (i = 0; i < 4; i++)
|
||||
@ -1377,7 +1373,7 @@ static int goku_udc_stop(struct usb_gadget *g,
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
dev->driver = NULL;
|
||||
stop_activity(dev, driver);
|
||||
stop_activity(dev);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
return 0;
|
||||
@ -1521,7 +1517,7 @@ rescan:
|
||||
if (unlikely(stat & INT_DEVWIDE)) {
|
||||
if (stat & INT_SYSERROR) {
|
||||
ERROR(dev, "system error\n");
|
||||
stop_activity(dev, dev->driver);
|
||||
stop_activity(dev);
|
||||
stat = 0;
|
||||
handled = 1;
|
||||
// FIXME have a neater way to prevent re-enumeration
|
||||
@ -1536,7 +1532,7 @@ rescan:
|
||||
} else {
|
||||
DBG(dev, "disconnect\n");
|
||||
if (dev->gadget.speed == USB_SPEED_FULL)
|
||||
stop_activity(dev, dev->driver);
|
||||
stop_activity(dev);
|
||||
dev->ep0state = EP0_DISCONNECT;
|
||||
dev->int_enable = INT_DEVWIDE;
|
||||
writel(dev->int_enable, &dev->regs->int_enable);
|
||||
|
2242
drivers/usb/gadget/gr_udc.c
Normal file
2242
drivers/usb/gadget/gr_udc.c
Normal file
File diff suppressed because it is too large
Load Diff
220
drivers/usb/gadget/gr_udc.h
Normal file
220
drivers/usb/gadget/gr_udc.h
Normal file
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* USB Peripheral Controller driver for Aeroflex Gaisler GRUSBDC.
|
||||
*
|
||||
* 2013 (c) Aeroflex Gaisler AB
|
||||
*
|
||||
* This driver supports GRUSBDC USB Device Controller cores available in the
|
||||
* GRLIB VHDL IP core library.
|
||||
*
|
||||
* Full documentation of the GRUSBDC core can be found here:
|
||||
* http://www.gaisler.com/products/grlib/grip.pdf
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Contributors:
|
||||
* - Andreas Larsson <andreas@gaisler.com>
|
||||
* - Marko Isomaki
|
||||
*/
|
||||
|
||||
/* Control registers on the AMBA bus */
|
||||
|
||||
#define GR_MAXEP 16 /* Max # endpoints for *each* direction */
|
||||
|
||||
struct gr_epregs {
|
||||
u32 epctrl;
|
||||
union {
|
||||
struct { /* Slave mode*/
|
||||
u32 slvctrl;
|
||||
u32 slvdata;
|
||||
};
|
||||
struct { /* DMA mode*/
|
||||
u32 dmactrl;
|
||||
u32 dmaaddr;
|
||||
};
|
||||
};
|
||||
u32 epstat;
|
||||
};
|
||||
|
||||
struct gr_regs {
|
||||
struct gr_epregs epo[GR_MAXEP]; /* 0x000 - 0x0fc */
|
||||
struct gr_epregs epi[GR_MAXEP]; /* 0x100 - 0x1fc */
|
||||
u32 control; /* 0x200 */
|
||||
u32 status; /* 0x204 */
|
||||
};
|
||||
|
||||
#define GR_EPCTRL_BUFSZ_SCALER 8
|
||||
#define GR_EPCTRL_BUFSZ_MASK 0xffe00000
|
||||
#define GR_EPCTRL_BUFSZ_POS 21
|
||||
#define GR_EPCTRL_PI BIT(20)
|
||||
#define GR_EPCTRL_CB BIT(19)
|
||||
#define GR_EPCTRL_CS BIT(18)
|
||||
#define GR_EPCTRL_MAXPL_MASK 0x0003ff80
|
||||
#define GR_EPCTRL_MAXPL_POS 7
|
||||
#define GR_EPCTRL_NT_MASK 0x00000060
|
||||
#define GR_EPCTRL_NT_POS 5
|
||||
#define GR_EPCTRL_TT_MASK 0x00000018
|
||||
#define GR_EPCTRL_TT_POS 3
|
||||
#define GR_EPCTRL_EH BIT(2)
|
||||
#define GR_EPCTRL_ED BIT(1)
|
||||
#define GR_EPCTRL_EV BIT(0)
|
||||
|
||||
#define GR_DMACTRL_AE BIT(10)
|
||||
#define GR_DMACTRL_AD BIT(3)
|
||||
#define GR_DMACTRL_AI BIT(2)
|
||||
#define GR_DMACTRL_IE BIT(1)
|
||||
#define GR_DMACTRL_DA BIT(0)
|
||||
|
||||
#define GR_EPSTAT_PT BIT(29)
|
||||
#define GR_EPSTAT_PR BIT(29)
|
||||
#define GR_EPSTAT_B1CNT_MASK 0x1fff0000
|
||||
#define GR_EPSTAT_B1CNT_POS 16
|
||||
#define GR_EPSTAT_B0CNT_MASK 0x0000fff8
|
||||
#define GR_EPSTAT_B0CNT_POS 3
|
||||
#define GR_EPSTAT_B1 BIT(2)
|
||||
#define GR_EPSTAT_B0 BIT(1)
|
||||
#define GR_EPSTAT_BS BIT(0)
|
||||
|
||||
#define GR_CONTROL_SI BIT(31)
|
||||
#define GR_CONTROL_UI BIT(30)
|
||||
#define GR_CONTROL_VI BIT(29)
|
||||
#define GR_CONTROL_SP BIT(28)
|
||||
#define GR_CONTROL_FI BIT(27)
|
||||
#define GR_CONTROL_EP BIT(14)
|
||||
#define GR_CONTROL_DH BIT(13)
|
||||
#define GR_CONTROL_RW BIT(12)
|
||||
#define GR_CONTROL_TS_MASK 0x00000e00
|
||||
#define GR_CONTROL_TS_POS 9
|
||||
#define GR_CONTROL_TM BIT(8)
|
||||
#define GR_CONTROL_UA_MASK 0x000000fe
|
||||
#define GR_CONTROL_UA_POS 1
|
||||
#define GR_CONTROL_SU BIT(0)
|
||||
|
||||
#define GR_STATUS_NEPI_MASK 0xf0000000
|
||||
#define GR_STATUS_NEPI_POS 28
|
||||
#define GR_STATUS_NEPO_MASK 0x0f000000
|
||||
#define GR_STATUS_NEPO_POS 24
|
||||
#define GR_STATUS_DM BIT(23)
|
||||
#define GR_STATUS_SU BIT(17)
|
||||
#define GR_STATUS_UR BIT(16)
|
||||
#define GR_STATUS_VB BIT(15)
|
||||
#define GR_STATUS_SP BIT(14)
|
||||
#define GR_STATUS_AF_MASK 0x00003800
|
||||
#define GR_STATUS_AF_POS 11
|
||||
#define GR_STATUS_FN_MASK 0x000007ff
|
||||
#define GR_STATUS_FN_POS 0
|
||||
|
||||
|
||||
#define MAX_CTRL_PL_SIZE 64 /* As per USB standard for full and high speed */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* Driver data structures and utilities */
|
||||
|
||||
struct gr_dma_desc {
|
||||
u32 ctrl;
|
||||
u32 data;
|
||||
u32 next;
|
||||
|
||||
/* These must be last because hw uses the previous three */
|
||||
u32 paddr;
|
||||
struct gr_dma_desc *next_desc;
|
||||
};
|
||||
|
||||
#define GR_DESC_OUT_CTRL_SE BIT(17)
|
||||
#define GR_DESC_OUT_CTRL_IE BIT(15)
|
||||
#define GR_DESC_OUT_CTRL_NX BIT(14)
|
||||
#define GR_DESC_OUT_CTRL_EN BIT(13)
|
||||
#define GR_DESC_OUT_CTRL_LEN_MASK 0x00001fff
|
||||
|
||||
#define GR_DESC_IN_CTRL_MO BIT(18)
|
||||
#define GR_DESC_IN_CTRL_PI BIT(17)
|
||||
#define GR_DESC_IN_CTRL_ML BIT(16)
|
||||
#define GR_DESC_IN_CTRL_IE BIT(15)
|
||||
#define GR_DESC_IN_CTRL_NX BIT(14)
|
||||
#define GR_DESC_IN_CTRL_EN BIT(13)
|
||||
#define GR_DESC_IN_CTRL_LEN_MASK 0x00001fff
|
||||
|
||||
#define GR_DESC_DMAADDR_MASK 0xfffffffc
|
||||
|
||||
struct gr_ep {
|
||||
struct usb_ep ep;
|
||||
struct gr_udc *dev;
|
||||
u16 bytes_per_buffer;
|
||||
unsigned int dma_start;
|
||||
struct gr_epregs __iomem *regs;
|
||||
|
||||
unsigned num:8;
|
||||
unsigned is_in:1;
|
||||
unsigned stopped:1;
|
||||
unsigned wedged:1;
|
||||
unsigned callback:1;
|
||||
|
||||
/* analogous to a host-side qh */
|
||||
struct list_head queue;
|
||||
|
||||
struct list_head ep_list;
|
||||
};
|
||||
|
||||
struct gr_request {
|
||||
struct usb_request req;
|
||||
struct list_head queue;
|
||||
|
||||
/* Chain of dma descriptors */
|
||||
struct gr_dma_desc *first_desc; /* First in the chain */
|
||||
struct gr_dma_desc *curr_desc; /* Current descriptor */
|
||||
struct gr_dma_desc *last_desc; /* Last in the chain */
|
||||
|
||||
u8 setup; /* Setup packet */
|
||||
};
|
||||
|
||||
enum gr_ep0state {
|
||||
GR_EP0_DISCONNECT = 0, /* No host */
|
||||
GR_EP0_SETUP, /* Between STATUS ack and SETUP report */
|
||||
GR_EP0_IDATA, /* IN data stage */
|
||||
GR_EP0_ODATA, /* OUT data stage */
|
||||
GR_EP0_ISTATUS, /* Status stage after IN data stage */
|
||||
GR_EP0_OSTATUS, /* Status stage after OUT data stage */
|
||||
GR_EP0_STALL, /* Data or status stages */
|
||||
GR_EP0_SUSPEND, /* USB suspend */
|
||||
};
|
||||
|
||||
struct gr_udc {
|
||||
struct usb_gadget gadget;
|
||||
struct gr_ep epi[GR_MAXEP];
|
||||
struct gr_ep epo[GR_MAXEP];
|
||||
struct usb_gadget_driver *driver;
|
||||
struct dma_pool *desc_pool;
|
||||
struct device *dev;
|
||||
|
||||
enum gr_ep0state ep0state;
|
||||
struct gr_request *ep0reqo;
|
||||
struct gr_request *ep0reqi;
|
||||
|
||||
struct gr_regs __iomem *regs;
|
||||
int irq;
|
||||
int irqi;
|
||||
int irqo;
|
||||
|
||||
unsigned added:1;
|
||||
unsigned irq_enabled:1;
|
||||
unsigned remote_wakeup:1;
|
||||
|
||||
u8 test_mode;
|
||||
|
||||
enum usb_device_state suspended_from;
|
||||
|
||||
unsigned int nepi;
|
||||
unsigned int nepo;
|
||||
|
||||
struct list_head ep_list;
|
||||
|
||||
spinlock_t lock; /* General lock, a.k.a. "dev->lock" in comments */
|
||||
|
||||
struct dentry *dfs_root;
|
||||
struct dentry *dfs_state;
|
||||
};
|
||||
|
||||
#define to_gr_udc(gadget) (container_of((gadget), struct gr_udc, gadget))
|
@ -1449,7 +1449,7 @@ static void udc_reinit(struct lpc32xx_udc *udc)
|
||||
|
||||
if (i != 0)
|
||||
list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
|
||||
ep->ep.maxpacket = ep->maxpacket;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket);
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
ep->req_pending = 0;
|
||||
}
|
||||
|
@ -1647,9 +1647,9 @@ static int __init m66592_probe(struct platform_device *pdev)
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
ep->ep.name = m66592_ep_name[i];
|
||||
ep->ep.ops = &m66592_ep_ops;
|
||||
ep->ep.maxpacket = 512;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, 512);
|
||||
}
|
||||
m66592->ep[0].ep.maxpacket = 64;
|
||||
usb_ep_set_maxpacket_limit(&m66592->ep[0].ep, 64);
|
||||
m66592->ep[0].pipenum = 0;
|
||||
m66592->ep[0].fifoaddr = M66592_CFIFO;
|
||||
m66592->ep[0].fifosel = M66592_CFIFOSEL;
|
||||
|
@ -1336,7 +1336,7 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d)
|
||||
ep->ep.name = ep->name;
|
||||
ep->ep.ops = &mv_u3d_ep_ops;
|
||||
ep->wedge = 0;
|
||||
ep->ep.maxpacket = MV_U3D_EP0_MAX_PKT_SIZE;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, MV_U3D_EP0_MAX_PKT_SIZE);
|
||||
ep->ep_num = 0;
|
||||
ep->ep.desc = &mv_u3d_ep0_desc;
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
@ -1361,7 +1361,7 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d)
|
||||
ep->ep.name = ep->name;
|
||||
|
||||
ep->ep.ops = &mv_u3d_ep_ops;
|
||||
ep->ep.maxpacket = (unsigned short) ~0;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);
|
||||
ep->ep_num = i / 2;
|
||||
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
|
@ -1261,7 +1261,7 @@ static int eps_init(struct mv_udc *udc)
|
||||
ep->ep.ops = &mv_ep_ops;
|
||||
ep->wedge = 0;
|
||||
ep->stopped = 0;
|
||||
ep->ep.maxpacket = EP0_MAX_PKT_SIZE;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, EP0_MAX_PKT_SIZE);
|
||||
ep->ep_num = 0;
|
||||
ep->ep.desc = &mv_ep0_desc;
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
@ -1284,7 +1284,7 @@ static int eps_init(struct mv_udc *udc)
|
||||
|
||||
ep->ep.ops = &mv_ep_ops;
|
||||
ep->stopped = 0;
|
||||
ep->ep.maxpacket = (unsigned short) ~0;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);
|
||||
ep->ep_num = i / 2;
|
||||
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
|
@ -266,7 +266,7 @@ static void net2272_ep_reset(struct net2272_ep *ep)
|
||||
ep->desc = NULL;
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
|
||||
ep->ep.maxpacket = ~0;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, ~0);
|
||||
ep->ep.ops = &net2272_ep_ops;
|
||||
|
||||
/* disable irqs, endpoint */
|
||||
@ -1409,7 +1409,7 @@ net2272_usb_reinit(struct net2272 *dev)
|
||||
ep->fifo_size = 64;
|
||||
net2272_ep_reset(ep);
|
||||
}
|
||||
dev->ep[0].ep.maxpacket = 64;
|
||||
usb_ep_set_maxpacket_limit(&dev->ep[0].ep, 64);
|
||||
|
||||
dev->gadget.ep0 = &dev->ep[0].ep;
|
||||
dev->ep[0].stopped = 0;
|
||||
|
@ -293,7 +293,7 @@ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)
|
||||
ep->desc = NULL;
|
||||
INIT_LIST_HEAD (&ep->queue);
|
||||
|
||||
ep->ep.maxpacket = ~0;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, ~0);
|
||||
ep->ep.ops = &net2280_ep_ops;
|
||||
|
||||
/* disable the dma, irqs, endpoint... */
|
||||
@ -1805,9 +1805,9 @@ static void usb_reinit (struct net2280 *dev)
|
||||
ep->regs = &dev->epregs [tmp];
|
||||
ep_reset (dev->regs, ep);
|
||||
}
|
||||
dev->ep [0].ep.maxpacket = 64;
|
||||
dev->ep [5].ep.maxpacket = 64;
|
||||
dev->ep [6].ep.maxpacket = 64;
|
||||
usb_ep_set_maxpacket_limit(&dev->ep [0].ep, 64);
|
||||
usb_ep_set_maxpacket_limit(&dev->ep [5].ep, 64);
|
||||
usb_ep_set_maxpacket_limit(&dev->ep [6].ep, 64);
|
||||
|
||||
dev->gadget.ep0 = &dev->ep [0].ep;
|
||||
dev->ep [0].stopped = 0;
|
||||
|
@ -126,9 +126,9 @@ static int __init nokia_bind_config(struct usb_configuration *c)
|
||||
struct usb_function *f_ecm;
|
||||
struct usb_function *f_obex2 = NULL;
|
||||
int status = 0;
|
||||
int obex1_stat = 0;
|
||||
int obex2_stat = 0;
|
||||
int phonet_stat = 0;
|
||||
int obex1_stat = -1;
|
||||
int obex2_stat = -1;
|
||||
int phonet_stat = -1;
|
||||
|
||||
if (!IS_ERR(fi_phonet)) {
|
||||
f_phonet = usb_get_function(fi_phonet);
|
||||
|
@ -2586,7 +2586,8 @@ 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;
|
||||
ep->maxpacket = maxp;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket);
|
||||
list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
|
||||
|
||||
return buf;
|
||||
|
@ -2896,12 +2896,12 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev)
|
||||
ep->offset_addr = (UDC_EPINT_OUT_SHIFT + ep->num) *
|
||||
UDC_EP_REG_SHIFT;
|
||||
/* need to set ep->ep.maxpacket and set Default Configuration?*/
|
||||
ep->ep.maxpacket = UDC_BULK_MAX_PKT_SIZE;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, UDC_BULK_MAX_PKT_SIZE);
|
||||
list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
}
|
||||
dev->ep[UDC_EP0IN_IDX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
|
||||
dev->ep[UDC_EP0OUT_IDX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
|
||||
usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IDX].ep, UDC_EP0IN_MAX_PKT_SIZE);
|
||||
usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IDX].ep, UDC_EP0OUT_MAX_PKT_SIZE);
|
||||
|
||||
/* remove ep0 in and out from the list. They have own pointer */
|
||||
list_del_init(&dev->ep[UDC_EP0IN_IDX].ep.ep_list);
|
||||
|
@ -1194,6 +1194,7 @@ static void udc_reinit(struct pxa25x_udc *dev)
|
||||
ep->stopped = 0;
|
||||
INIT_LIST_HEAD (&ep->queue);
|
||||
ep->pio_irqs = 0;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket);
|
||||
}
|
||||
|
||||
/* the rest was statically initialized, and is read-only */
|
||||
|
@ -1737,9 +1737,12 @@ static void udc_init_data(struct pxa_udc *dev)
|
||||
}
|
||||
|
||||
/* USB endpoints init */
|
||||
for (i = 1; i < NR_USB_ENDPOINTS; i++)
|
||||
for (i = 1; i < NR_USB_ENDPOINTS; i++) {
|
||||
list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list,
|
||||
&dev->gadget.ep_list);
|
||||
usb_ep_set_maxpacket_limit(&dev->udc_usb_ep[i].usb_ep,
|
||||
dev->udc_usb_ep[i].usb_ep.maxpacket);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1833,7 +1833,7 @@ static int __exit r8a66597_remove(struct platform_device *pdev)
|
||||
r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
|
||||
|
||||
if (r8a66597->pdata->on_chip) {
|
||||
clk_disable(r8a66597->clk);
|
||||
clk_disable_unprepare(r8a66597->clk);
|
||||
clk_put(r8a66597->clk);
|
||||
}
|
||||
|
||||
@ -1931,7 +1931,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
|
||||
ret = PTR_ERR(r8a66597->clk);
|
||||
goto clean_up;
|
||||
}
|
||||
clk_enable(r8a66597->clk);
|
||||
clk_prepare_enable(r8a66597->clk);
|
||||
}
|
||||
|
||||
if (r8a66597->pdata->sudmac) {
|
||||
@ -1964,9 +1964,9 @@ static int __init r8a66597_probe(struct platform_device *pdev)
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
ep->ep.name = r8a66597_ep_name[i];
|
||||
ep->ep.ops = &r8a66597_ep_ops;
|
||||
ep->ep.maxpacket = 512;
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, 512);
|
||||
}
|
||||
r8a66597->ep[0].ep.maxpacket = 64;
|
||||
usb_ep_set_maxpacket_limit(&r8a66597->ep[0].ep, 64);
|
||||
r8a66597->ep[0].pipenum = 0;
|
||||
r8a66597->ep[0].fifoaddr = CFIFO;
|
||||
r8a66597->ep[0].fifosel = CFIFOSEL;
|
||||
@ -1996,7 +1996,7 @@ clean_up3:
|
||||
free_irq(irq, r8a66597);
|
||||
clean_up2:
|
||||
if (r8a66597->pdata->on_chip) {
|
||||
clk_disable(r8a66597->clk);
|
||||
clk_disable_unprepare(r8a66597->clk);
|
||||
clk_put(r8a66597->clk);
|
||||
}
|
||||
clean_up:
|
||||
|
@ -1142,7 +1142,7 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
|
||||
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
|
||||
|
||||
|
||||
static int rndis_init(void)
|
||||
int rndis_init(void)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
@ -1174,9 +1174,8 @@ static int rndis_init(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(rndis_init);
|
||||
|
||||
static void rndis_exit(void)
|
||||
void rndis_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
||||
u8 i;
|
||||
@ -1188,6 +1187,4 @@ static void rndis_exit(void)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
module_exit(rndis_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -30,14 +30,14 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/usb/phy.h>
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/phy.h>
|
||||
#include <linux/platform_data/s3c-hsotg.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
|
||||
#include "s3c-hsotg.h"
|
||||
|
||||
static const char * const s3c_hsotg_supply_names[] = {
|
||||
@ -140,11 +140,13 @@ struct s3c_hsotg_ep {
|
||||
* @dev: The parent device supplied to the probe function
|
||||
* @driver: USB gadget driver
|
||||
* @phy: The otg phy transceiver structure for phy control.
|
||||
* @uphy: The otg phy transceiver structure for old USB phy control.
|
||||
* @plat: The platform specific configuration data. This can be removed once
|
||||
* all SoCs support usb transceiver.
|
||||
* @regs: The memory area mapped for accessing registers.
|
||||
* @irq: The IRQ number we are using
|
||||
* @supplies: Definition of USB power supplies
|
||||
* @phyif: PHY interface width
|
||||
* @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
|
||||
* @num_of_eps: Number of available EPs (excluding EP0)
|
||||
* @debug_root: root directrory for debugfs.
|
||||
@ -161,7 +163,8 @@ struct s3c_hsotg_ep {
|
||||
struct s3c_hsotg {
|
||||
struct device *dev;
|
||||
struct usb_gadget_driver *driver;
|
||||
struct usb_phy *phy;
|
||||
struct phy *phy;
|
||||
struct usb_phy *uphy;
|
||||
struct s3c_hsotg_plat *plat;
|
||||
|
||||
spinlock_t lock;
|
||||
@ -172,6 +175,7 @@ struct s3c_hsotg {
|
||||
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)];
|
||||
|
||||
u32 phyif;
|
||||
unsigned int dedicated_fifos:1;
|
||||
unsigned char num_of_eps;
|
||||
|
||||
@ -2086,13 +2090,13 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)
|
||||
case DSTS_EnumSpd_FS48:
|
||||
hsotg->gadget.speed = USB_SPEED_FULL;
|
||||
ep0_mps = EP0_MPS_LIMIT;
|
||||
ep_mps = 64;
|
||||
ep_mps = 1023;
|
||||
break;
|
||||
|
||||
case DSTS_EnumSpd_HS:
|
||||
hsotg->gadget.speed = USB_SPEED_HIGH;
|
||||
ep0_mps = EP0_MPS_LIMIT;
|
||||
ep_mps = 512;
|
||||
ep_mps = 1024;
|
||||
break;
|
||||
|
||||
case DSTS_EnumSpd_LS:
|
||||
@ -2156,6 +2160,9 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
|
||||
s3c_hsotg_complete_request(hsotg, ep, req,
|
||||
result);
|
||||
}
|
||||
if(hsotg->dedicated_fifos)
|
||||
if ((readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4 < 3072)
|
||||
s3c_hsotg_txfifo_flush(hsotg, ep->index);
|
||||
}
|
||||
|
||||
#define call_gadget(_hs, _entry) \
|
||||
@ -2283,7 +2290,7 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg)
|
||||
*/
|
||||
|
||||
/* set the PLL on, remove the HNP/SRP and set the PHY */
|
||||
writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) |
|
||||
writel(hsotg->phyif | GUSBCFG_TOutCal(7) |
|
||||
(0x5 << 10), hsotg->regs + GUSBCFG);
|
||||
|
||||
s3c_hsotg_init_fifo(hsotg);
|
||||
@ -2908,8 +2915,11 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
|
||||
|
||||
dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
|
||||
|
||||
if (hsotg->phy)
|
||||
usb_phy_init(hsotg->phy);
|
||||
if (hsotg->phy) {
|
||||
phy_init(hsotg->phy);
|
||||
phy_power_on(hsotg->phy);
|
||||
} else if (hsotg->uphy)
|
||||
usb_phy_init(hsotg->uphy);
|
||||
else if (hsotg->plat->phy_init)
|
||||
hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
|
||||
}
|
||||
@ -2925,8 +2935,11 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(hsotg->dev);
|
||||
|
||||
if (hsotg->phy)
|
||||
usb_phy_shutdown(hsotg->phy);
|
||||
if (hsotg->phy) {
|
||||
phy_power_off(hsotg->phy);
|
||||
phy_exit(hsotg->phy);
|
||||
} else if (hsotg->uphy)
|
||||
usb_phy_shutdown(hsotg->uphy);
|
||||
else if (hsotg->plat->phy_exit)
|
||||
hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
|
||||
}
|
||||
@ -3152,7 +3165,7 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg,
|
||||
|
||||
hs_ep->parent = hsotg;
|
||||
hs_ep->ep.name = hs_ep->name;
|
||||
hs_ep->ep.maxpacket = epnum ? 1024 : EP0_MPS_LIMIT;
|
||||
usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT);
|
||||
hs_ep->ep.ops = &s3c_hsotg_ep_ops;
|
||||
|
||||
/*
|
||||
@ -3533,7 +3546,8 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
|
||||
static int s3c_hsotg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
|
||||
struct usb_phy *phy;
|
||||
struct phy *phy;
|
||||
struct usb_phy *uphy;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct s3c_hsotg_ep *eps;
|
||||
struct s3c_hsotg *hsotg;
|
||||
@ -3548,19 +3562,26 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
|
||||
/*
|
||||
* Attempt to find a generic PHY, then look for an old style
|
||||
* USB PHY, finally fall back to pdata
|
||||
*/
|
||||
phy = devm_phy_get(&pdev->dev, "usb2-phy");
|
||||
if (IS_ERR(phy)) {
|
||||
/* Fallback for pdata */
|
||||
plat = dev_get_platdata(&pdev->dev);
|
||||
if (!plat) {
|
||||
dev_err(&pdev->dev, "no platform data or transceiver defined\n");
|
||||
return -EPROBE_DEFER;
|
||||
} else {
|
||||
uphy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
|
||||
if (IS_ERR(uphy)) {
|
||||
/* Fallback for pdata */
|
||||
plat = dev_get_platdata(&pdev->dev);
|
||||
if (!plat) {
|
||||
dev_err(&pdev->dev,
|
||||
"no platform data or transceiver defined\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
hsotg->plat = plat;
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
hsotg->uphy = uphy;
|
||||
} else
|
||||
hsotg->phy = phy;
|
||||
}
|
||||
|
||||
hsotg->dev = dev;
|
||||
|
||||
@ -3627,6 +3648,19 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
|
||||
goto err_supplies;
|
||||
}
|
||||
|
||||
/* Set default UTMI width */
|
||||
hsotg->phyif = GUSBCFG_PHYIf16;
|
||||
|
||||
/*
|
||||
* If using the generic PHY framework, check if the PHY bus
|
||||
* width is 8-bit and set the phyif appropriately.
|
||||
*/
|
||||
if (hsotg->phy && (phy_get_bus_width(phy) == 8))
|
||||
hsotg->phyif = GUSBCFG_PHYIf8;
|
||||
|
||||
if (hsotg->phy)
|
||||
phy_init(hsotg->phy);
|
||||
|
||||
/* usb phy enable */
|
||||
s3c_hsotg_phy_enable(hsotg);
|
||||
|
||||
@ -3720,6 +3754,8 @@ static int s3c_hsotg_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
s3c_hsotg_phy_disable(hsotg);
|
||||
if (hsotg->phy)
|
||||
phy_exit(hsotg->phy);
|
||||
clk_disable_unprepare(hsotg->clk);
|
||||
|
||||
return 0;
|
||||
@ -3733,6 +3769,7 @@ static int s3c_hsotg_remove(struct platform_device *pdev)
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id s3c_hsotg_of_ids[] = {
|
||||
{ .compatible = "samsung,s3c6400-hsotg", },
|
||||
{ .compatible = "snps,dwc2", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, s3c_hsotg_of_ids);
|
||||
|
@ -55,6 +55,7 @@
|
||||
#define GUSBCFG_HNPCap (1 << 9)
|
||||
#define GUSBCFG_SRPCap (1 << 8)
|
||||
#define GUSBCFG_PHYIf16 (1 << 3)
|
||||
#define GUSBCFG_PHYIf8 (0 << 3)
|
||||
#define GUSBCFG_TOutCal_MASK (0x7 << 0)
|
||||
#define GUSBCFG_TOutCal_SHIFT (0)
|
||||
#define GUSBCFG_TOutCal_LIMIT (0x7)
|
||||
|
@ -999,7 +999,7 @@ static void s3c_hsudc_initep(struct s3c_hsudc *hsudc,
|
||||
|
||||
hsep->dev = hsudc;
|
||||
hsep->ep.name = hsep->name;
|
||||
hsep->ep.maxpacket = epnum ? 512 : 64;
|
||||
usb_ep_set_maxpacket_limit(&hsep->ep, epnum ? 512 : 64);
|
||||
hsep->ep.ops = &s3c_hsudc_ep_ops;
|
||||
hsep->fifo = hsudc->regs + S3C_BR(epnum);
|
||||
hsep->ep.desc = NULL;
|
||||
|
@ -1629,6 +1629,7 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev)
|
||||
ep->ep.desc = NULL;
|
||||
ep->halted = 0;
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
usb_ep_set_maxpacket_limit(&ep->ep, &ep->ep.maxpacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -753,7 +753,7 @@ static struct device_type gadget_type = {
|
||||
* gadget driver using this framework. The link layer addresses are
|
||||
* set up using module parameters.
|
||||
*
|
||||
* Returns negative errno, or zero on success
|
||||
* Returns an eth_dev pointer on success, or an ERR_PTR on failure.
|
||||
*/
|
||||
struct eth_dev *gether_setup_name(struct usb_gadget *g,
|
||||
const char *dev_addr, const char *host_addr,
|
||||
|
@ -106,7 +106,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,
|
||||
* gadget driver using this framework. The link layer addresses are
|
||||
* set up using module parameters.
|
||||
*
|
||||
* Returns negative errno, or zero on success
|
||||
* Returns a eth_dev pointer on success, or an ERR_PTR on failure
|
||||
*/
|
||||
static inline struct eth_dev *gether_setup(struct usb_gadget *g,
|
||||
const char *dev_addr, const char *host_addr,
|
||||
@ -267,45 +267,4 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* each configuration may bind one instance of an ethernet link */
|
||||
int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev);
|
||||
int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
struct eth_dev *dev);
|
||||
|
||||
#ifdef USB_ETH_RNDIS
|
||||
|
||||
int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
u32 vendorID, const char *manufacturer, struct eth_dev *dev);
|
||||
|
||||
#else
|
||||
|
||||
static inline int
|
||||
rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
|
||||
u32 vendorID, const char *manufacturer, struct eth_dev *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* rndis_bind_config - add RNDIS network link to a configuration
|
||||
* @c: the configuration to support the network link
|
||||
* @ethaddr: a buffer in which the ethernet address of the host side
|
||||
* side of the link was recorded
|
||||
* Context: single threaded during gadget setup
|
||||
*
|
||||
* Returns zero on success, else negative errno.
|
||||
*
|
||||
* Caller must have called @gether_setup(). Caller is also responsible
|
||||
* for calling @gether_cleanup() before module unload.
|
||||
*/
|
||||
static inline int rndis_bind_config(struct usb_configuration *c,
|
||||
u8 ethaddr[ETH_ALEN], struct eth_dev *dev)
|
||||
{
|
||||
return rndis_bind_config_vendor(c, ethaddr, 0, NULL, dev);
|
||||
}
|
||||
|
||||
|
||||
#endif /* __U_ETHER_H */
|
||||
|
32
drivers/usb/gadget/u_f.c
Normal file
32
drivers/usb/gadget/u_f.c
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* u_f.c -- USB function utilities for Gadget stack
|
||||
*
|
||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/usb/gadget.h>
|
||||
#include "u_f.h"
|
||||
|
||||
struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len)
|
||||
{
|
||||
struct usb_request *req;
|
||||
|
||||
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
|
||||
if (req) {
|
||||
req->length = len ?: default_len;
|
||||
req->buf = kmalloc(req->length, GFP_ATOMIC);
|
||||
if (!req->buf) {
|
||||
usb_ep_free_request(ep, req);
|
||||
req = NULL;
|
||||
}
|
||||
}
|
||||
return req;
|
||||
}
|
||||
EXPORT_SYMBOL(alloc_ep_req);
|
26
drivers/usb/gadget/u_f.h
Normal file
26
drivers/usb/gadget/u_f.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* u_f.h
|
||||
*
|
||||
* Utility definitions for USB functions
|
||||
*
|
||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __U_F_H__
|
||||
#define __U_F_H__
|
||||
|
||||
struct usb_ep;
|
||||
struct usb_request;
|
||||
|
||||
struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len);
|
||||
|
||||
#endif /* __U_F_H__ */
|
||||
|
||||
|
267
drivers/usb/gadget/u_fs.h
Normal file
267
drivers/usb/gadget/u_fs.h
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* u_fs.h
|
||||
*
|
||||
* Utility definitions for the FunctionFS
|
||||
*
|
||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef U_FFS_H
|
||||
#define U_FFS_H
|
||||
|
||||
#include <linux/usb/composite.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#ifndef pr_vdebug
|
||||
# define pr_vdebug pr_debug
|
||||
#endif /* pr_vdebug */
|
||||
# define ffs_dump_mem(prefix, ptr, len) \
|
||||
print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len)
|
||||
#else
|
||||
#ifndef pr_vdebug
|
||||
# define pr_vdebug(...) do { } while (0)
|
||||
#endif /* pr_vdebug */
|
||||
# define ffs_dump_mem(prefix, ptr, len) do { } while (0)
|
||||
#endif /* VERBOSE_DEBUG */
|
||||
|
||||
#define ENTER() pr_vdebug("%s()\n", __func__)
|
||||
|
||||
struct f_fs_opts;
|
||||
|
||||
struct ffs_dev {
|
||||
const char *name;
|
||||
bool name_allocated;
|
||||
bool mounted;
|
||||
bool desc_ready;
|
||||
bool single;
|
||||
struct ffs_data *ffs_data;
|
||||
struct f_fs_opts *opts;
|
||||
struct list_head entry;
|
||||
|
||||
int (*ffs_ready_callback)(struct ffs_data *ffs);
|
||||
void (*ffs_closed_callback)(struct ffs_data *ffs);
|
||||
void *(*ffs_acquire_dev_callback)(struct ffs_dev *dev);
|
||||
void (*ffs_release_dev_callback)(struct ffs_dev *dev);
|
||||
};
|
||||
|
||||
extern struct mutex ffs_lock;
|
||||
|
||||
static inline void ffs_dev_lock(void)
|
||||
{
|
||||
mutex_lock(&ffs_lock);
|
||||
}
|
||||
|
||||
static inline void ffs_dev_unlock(void)
|
||||
{
|
||||
mutex_unlock(&ffs_lock);
|
||||
}
|
||||
|
||||
struct ffs_dev *ffs_alloc_dev(void);
|
||||
int ffs_name_dev(struct ffs_dev *dev, const char *name);
|
||||
int ffs_single_dev(struct ffs_dev *dev);
|
||||
void ffs_free_dev(struct ffs_dev *dev);
|
||||
|
||||
struct ffs_epfile;
|
||||
struct ffs_function;
|
||||
|
||||
enum ffs_state {
|
||||
/*
|
||||
* Waiting for descriptors and strings.
|
||||
*
|
||||
* In this state no open(2), read(2) or write(2) on epfiles
|
||||
* may succeed (which should not be the problem as there
|
||||
* should be no such files opened in the first place).
|
||||
*/
|
||||
FFS_READ_DESCRIPTORS,
|
||||
FFS_READ_STRINGS,
|
||||
|
||||
/*
|
||||
* We've got descriptors and strings. We are or have called
|
||||
* functionfs_ready_callback(). functionfs_bind() may have
|
||||
* been called but we don't know.
|
||||
*
|
||||
* This is the only state in which operations on epfiles may
|
||||
* succeed.
|
||||
*/
|
||||
FFS_ACTIVE,
|
||||
|
||||
/*
|
||||
* All endpoints have been closed. This state is also set if
|
||||
* we encounter an unrecoverable error. The only
|
||||
* unrecoverable error is situation when after reading strings
|
||||
* from user space we fail to initialise epfiles or
|
||||
* functionfs_ready_callback() returns with error (<0).
|
||||
*
|
||||
* In this state no open(2), read(2) or write(2) (both on ep0
|
||||
* as well as epfile) may succeed (at this point epfiles are
|
||||
* unlinked and all closed so this is not a problem; ep0 is
|
||||
* also closed but ep0 file exists and so open(2) on ep0 must
|
||||
* fail).
|
||||
*/
|
||||
FFS_CLOSING
|
||||
};
|
||||
|
||||
enum ffs_setup_state {
|
||||
/* There is no setup request pending. */
|
||||
FFS_NO_SETUP,
|
||||
/*
|
||||
* User has read events and there was a setup request event
|
||||
* there. The next read/write on ep0 will handle the
|
||||
* request.
|
||||
*/
|
||||
FFS_SETUP_PENDING,
|
||||
/*
|
||||
* There was event pending but before user space handled it
|
||||
* some other event was introduced which canceled existing
|
||||
* setup. If this state is set read/write on ep0 return
|
||||
* -EIDRM. This state is only set when adding event.
|
||||
*/
|
||||
FFS_SETUP_CANCELED
|
||||
};
|
||||
|
||||
struct ffs_data {
|
||||
struct usb_gadget *gadget;
|
||||
|
||||
/*
|
||||
* Protect access read/write operations, only one read/write
|
||||
* at a time. As a consequence protects ep0req and company.
|
||||
* While setup request is being processed (queued) this is
|
||||
* held.
|
||||
*/
|
||||
struct mutex mutex;
|
||||
|
||||
/*
|
||||
* Protect access to endpoint related structures (basically
|
||||
* usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for
|
||||
* endpoint zero.
|
||||
*/
|
||||
spinlock_t eps_lock;
|
||||
|
||||
/*
|
||||
* XXX REVISIT do we need our own request? Since we are not
|
||||
* handling setup requests immediately user space may be so
|
||||
* slow that another setup will be sent to the gadget but this
|
||||
* time not to us but another function and then there could be
|
||||
* a race. Is that the case? Or maybe we can use cdev->req
|
||||
* after all, maybe we just need some spinlock for that?
|
||||
*/
|
||||
struct usb_request *ep0req; /* P: mutex */
|
||||
struct completion ep0req_completion; /* P: mutex */
|
||||
int ep0req_status; /* P: mutex */
|
||||
|
||||
/* reference counter */
|
||||
atomic_t ref;
|
||||
/* how many files are opened (EP0 and others) */
|
||||
atomic_t opened;
|
||||
|
||||
/* EP0 state */
|
||||
enum ffs_state state;
|
||||
|
||||
/*
|
||||
* Possible transitions:
|
||||
* + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock
|
||||
* happens only in ep0 read which is P: mutex
|
||||
* + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock
|
||||
* happens only in ep0 i/o which is P: mutex
|
||||
* + FFS_SETUP_PENDING -> FFS_SETUP_CANCELED -- P: ev.waitq.lock
|
||||
* + FFS_SETUP_CANCELED -> FFS_NO_SETUP -- cmpxchg
|
||||
*/
|
||||
enum ffs_setup_state setup_state;
|
||||
|
||||
#define FFS_SETUP_STATE(ffs) \
|
||||
((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state, \
|
||||
FFS_SETUP_CANCELED, FFS_NO_SETUP))
|
||||
|
||||
/* Events & such. */
|
||||
struct {
|
||||
u8 types[4];
|
||||
unsigned short count;
|
||||
/* XXX REVISIT need to update it in some places, or do we? */
|
||||
unsigned short can_stall;
|
||||
struct usb_ctrlrequest setup;
|
||||
|
||||
wait_queue_head_t waitq;
|
||||
} ev; /* the whole structure, P: ev.waitq.lock */
|
||||
|
||||
/* Flags */
|
||||
unsigned long flags;
|
||||
#define FFS_FL_CALL_CLOSED_CALLBACK 0
|
||||
#define FFS_FL_BOUND 1
|
||||
|
||||
/* Active function */
|
||||
struct ffs_function *func;
|
||||
|
||||
/*
|
||||
* Device name, write once when file system is mounted.
|
||||
* Intended for user to read if she wants.
|
||||
*/
|
||||
const char *dev_name;
|
||||
/* Private data for our user (ie. gadget). Managed by user. */
|
||||
void *private_data;
|
||||
|
||||
/* filled by __ffs_data_got_descs() */
|
||||
/*
|
||||
* Real descriptors are 16 bytes after raw_descs (so you need
|
||||
* to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the
|
||||
* first full speed descriptor). raw_descs_length and
|
||||
* raw_fs_descs_length do not have those 16 bytes added.
|
||||
*/
|
||||
const void *raw_descs;
|
||||
unsigned raw_descs_length;
|
||||
unsigned raw_fs_descs_length;
|
||||
unsigned fs_descs_count;
|
||||
unsigned hs_descs_count;
|
||||
|
||||
unsigned short strings_count;
|
||||
unsigned short interfaces_count;
|
||||
unsigned short eps_count;
|
||||
unsigned short _pad1;
|
||||
|
||||
/* filled by __ffs_data_got_strings() */
|
||||
/* ids in stringtabs are set in functionfs_bind() */
|
||||
const void *raw_strings;
|
||||
struct usb_gadget_strings **stringtabs;
|
||||
|
||||
/*
|
||||
* File system's super block, write once when file system is
|
||||
* mounted.
|
||||
*/
|
||||
struct super_block *sb;
|
||||
|
||||
/* File permissions, written once when fs is mounted */
|
||||
struct ffs_file_perms {
|
||||
umode_t mode;
|
||||
kuid_t uid;
|
||||
kgid_t gid;
|
||||
} file_perms;
|
||||
|
||||
/*
|
||||
* The endpoint files, filled by ffs_epfiles_create(),
|
||||
* destroyed by ffs_epfiles_destroy().
|
||||
*/
|
||||
struct ffs_epfile *epfiles;
|
||||
};
|
||||
|
||||
|
||||
struct f_fs_opts {
|
||||
struct usb_function_instance func_inst;
|
||||
struct ffs_dev *dev;
|
||||
unsigned refcnt;
|
||||
bool no_configfs;
|
||||
};
|
||||
|
||||
static inline struct f_fs_opts *to_f_fs_opts(struct usb_function_instance *fi)
|
||||
{
|
||||
return container_of(fi, struct f_fs_opts, func_inst);
|
||||
}
|
||||
|
||||
#endif /* U_FFS_H */
|
@ -36,6 +36,8 @@ struct f_rndis_opts {
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
int rndis_init(void);
|
||||
void rndis_exit(void);
|
||||
void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net);
|
||||
|
||||
#endif /* U_RNDIS_H */
|
||||
|
@ -64,10 +64,10 @@ static bool loopdefault = 0;
|
||||
module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
|
||||
|
||||
static struct usb_zero_options gzero_options = {
|
||||
.isoc_interval = 4,
|
||||
.isoc_maxpacket = 1024,
|
||||
.bulk_buflen = 4096,
|
||||
.qlen = 32,
|
||||
.isoc_interval = GZERO_ISOC_INTERVAL,
|
||||
.isoc_maxpacket = GZERO_ISOC_MAXPACKET,
|
||||
.bulk_buflen = GZERO_BULK_BUFLEN,
|
||||
.qlen = GZERO_QLEN,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -6,7 +6,7 @@
|
||||
# (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
|
||||
config USB_MUSB_HDRC
|
||||
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
|
||||
depends on USB_GADGET
|
||||
depends on (USB || USB_GADGET)
|
||||
help
|
||||
Say Y here if your system has a dual role high speed USB
|
||||
controller based on the Mentor Graphics silicon IP. Then
|
||||
@ -35,21 +35,21 @@ choice
|
||||
|
||||
config USB_MUSB_HOST
|
||||
bool "Host only mode"
|
||||
depends on USB
|
||||
depends on USB=y || USB=USB_MUSB_HDRC
|
||||
help
|
||||
Select this when you want to use MUSB in host mode only,
|
||||
thereby the gadget feature will be regressed.
|
||||
|
||||
config USB_MUSB_GADGET
|
||||
bool "Gadget only mode"
|
||||
depends on USB_GADGET
|
||||
depends on USB_GADGET=y || USB_GADGET=USB_MUSB_HDRC
|
||||
help
|
||||
Select this when you want to use MUSB in gadget mode only,
|
||||
thereby the host feature will be regressed.
|
||||
|
||||
config USB_MUSB_DUAL_ROLE
|
||||
bool "Dual Role mode"
|
||||
depends on (USB && USB_GADGET)
|
||||
depends on ((USB=y || USB=USB_MUSB_HDRC) && (USB_GADGET=y || USB_GADGET=USB_MUSB_HDRC))
|
||||
help
|
||||
This is the default mode of working of MUSB controller where
|
||||
both host and gadget features are enabled.
|
||||
@ -93,6 +93,12 @@ config USB_MUSB_BLACKFIN
|
||||
config USB_MUSB_UX500
|
||||
tristate "Ux500 platforms"
|
||||
|
||||
config USB_MUSB_JZ4740
|
||||
tristate "JZ4740"
|
||||
depends on MACH_JZ4740 || COMPILE_TEST
|
||||
depends on USB_MUSB_GADGET
|
||||
depends on USB_OTG_BLACKLIST_HUB
|
||||
|
||||
endchoice
|
||||
|
||||
config USB_MUSB_AM335X_CHILD
|
||||
@ -100,7 +106,7 @@ config USB_MUSB_AM335X_CHILD
|
||||
|
||||
choice
|
||||
prompt 'MUSB DMA mode'
|
||||
default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM
|
||||
default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM || USB_MUSB_JZ4740
|
||||
default USB_UX500_DMA if USB_MUSB_UX500
|
||||
default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
|
||||
default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI
|
||||
|
@ -19,6 +19,7 @@ obj-$(CONFIG_USB_MUSB_DAVINCI) += davinci.o
|
||||
obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o
|
||||
obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o
|
||||
obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
|
||||
obj-$(CONFIG_USB_MUSB_JZ4740) += jz4740.o
|
||||
|
||||
|
||||
obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o
|
||||
|
201
drivers/usb/musb/jz4740.c
Normal file
201
drivers/usb/musb/jz4740.c
Normal file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Ingenic JZ4740 "glue layer"
|
||||
*
|
||||
* Copyright (C) 2013, Apelete Seketeli <apelete@seketeli.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "musb_core.h"
|
||||
|
||||
struct jz4740_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *musb;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci)
|
||||
{
|
||||
unsigned long flags;
|
||||
irqreturn_t retval = IRQ_NONE;
|
||||
struct musb *musb = __hci;
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
|
||||
musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
|
||||
musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
|
||||
musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
|
||||
|
||||
/*
|
||||
* The controller is gadget only, the state of the host mode IRQ bits is
|
||||
* undefined. Mask them to make sure that the musb driver core will
|
||||
* never see them set
|
||||
*/
|
||||
musb->int_usb &= MUSB_INTR_SUSPEND | MUSB_INTR_RESUME |
|
||||
MUSB_INTR_RESET | MUSB_INTR_SOF;
|
||||
|
||||
if (musb->int_usb || musb->int_tx || musb->int_rx)
|
||||
retval = musb_interrupt(musb);
|
||||
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = {
|
||||
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
|
||||
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, },
|
||||
};
|
||||
|
||||
static struct musb_hdrc_config jz4740_musb_config = {
|
||||
/* Silicon does not implement USB OTG. */
|
||||
.multipoint = 0,
|
||||
/* Max EPs scanned, driver will decide which EP can be used. */
|
||||
.num_eps = 4,
|
||||
/* RAMbits needed to configure EPs from table */
|
||||
.ram_bits = 9,
|
||||
.fifo_cfg = jz4740_musb_fifo_cfg,
|
||||
.fifo_cfg_size = ARRAY_SIZE(jz4740_musb_fifo_cfg),
|
||||
};
|
||||
|
||||
static struct musb_hdrc_platform_data jz4740_musb_platform_data = {
|
||||
.mode = MUSB_PERIPHERAL,
|
||||
.config = &jz4740_musb_config,
|
||||
};
|
||||
|
||||
static int jz4740_musb_init(struct musb *musb)
|
||||
{
|
||||
musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
|
||||
if (!musb->xceiv) {
|
||||
pr_err("HS UDC: no transceiver configured\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Silicon does not implement ConfigData register.
|
||||
* Set dyn_fifo to avoid reading EP config from hardware.
|
||||
*/
|
||||
musb->dyn_fifo = true;
|
||||
|
||||
musb->isr = jz4740_musb_interrupt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jz4740_musb_exit(struct musb *musb)
|
||||
{
|
||||
usb_put_phy(musb->xceiv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct musb_platform_ops jz4740_musb_ops = {
|
||||
.init = jz4740_musb_init,
|
||||
.exit = jz4740_musb_exit,
|
||||
};
|
||||
|
||||
static int jz4740_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct musb_hdrc_platform_data *pdata = &jz4740_musb_platform_data;
|
||||
struct platform_device *musb;
|
||||
struct jz4740_glue *glue;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue)
|
||||
return -ENOMEM;
|
||||
|
||||
musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
|
||||
if (!musb) {
|
||||
dev_err(&pdev->dev, "failed to allocate musb device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, "udc");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "failed to get clock\n");
|
||||
ret = PTR_ERR(clk);
|
||||
goto err_platform_device_put;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable clock\n");
|
||||
goto err_platform_device_put;
|
||||
}
|
||||
|
||||
musb->dev.parent = &pdev->dev;
|
||||
|
||||
glue->dev = &pdev->dev;
|
||||
glue->musb = musb;
|
||||
glue->clk = clk;
|
||||
|
||||
pdata->platform_ops = &jz4740_musb_ops;
|
||||
|
||||
platform_set_drvdata(pdev, glue);
|
||||
|
||||
ret = platform_device_add_resources(musb, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add resources\n");
|
||||
goto err_clk_disable;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add platform_data\n");
|
||||
goto err_clk_disable;
|
||||
}
|
||||
|
||||
ret = platform_device_add(musb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register musb device\n");
|
||||
goto err_clk_disable;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk_disable:
|
||||
clk_disable_unprepare(clk);
|
||||
err_platform_device_put:
|
||||
platform_device_put(musb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int jz4740_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct jz4740_glue *glue = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_unregister(glue->musb);
|
||||
clk_disable_unprepare(glue->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver jz4740_driver = {
|
||||
.probe = jz4740_probe,
|
||||
.remove = jz4740_remove,
|
||||
.driver = {
|
||||
.name = "musb-jz4740",
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("JZ4740 MUSB Glue Layer");
|
||||
MODULE_AUTHOR("Apelete Seketeli <apelete@seketeli.net>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
module_platform_driver(jz4740_driver);
|
@ -478,8 +478,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
|
||||
musb->port1_status |=
|
||||
(USB_PORT_STAT_C_SUSPEND << 16)
|
||||
| MUSB_PORT_STAT_RESUME;
|
||||
musb->rh_timer = jiffies
|
||||
+ msecs_to_jiffies(20);
|
||||
schedule_delayed_work(
|
||||
&musb->finish_resume_work, 20);
|
||||
|
||||
musb->xceiv->state = OTG_STATE_A_HOST;
|
||||
musb->is_active = 1;
|
||||
@ -1813,6 +1813,21 @@ static void musb_free(struct musb *musb)
|
||||
musb_host_free(musb);
|
||||
}
|
||||
|
||||
static void musb_deassert_reset(struct work_struct *work)
|
||||
{
|
||||
struct musb *musb;
|
||||
unsigned long flags;
|
||||
|
||||
musb = container_of(work, struct musb, deassert_reset_work.work);
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
|
||||
if (musb->port1_status & USB_PORT_STAT_RESET)
|
||||
musb_port_reset(musb, false);
|
||||
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform generic per-controller initialization.
|
||||
*
|
||||
@ -1897,6 +1912,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
|
||||
|
||||
/* Init IRQ workqueue before request_irq */
|
||||
INIT_WORK(&musb->irq_work, musb_irq_work);
|
||||
INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset);
|
||||
INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume);
|
||||
|
||||
/* setup musb parts of the core (especially endpoints) */
|
||||
status = musb_core_init(plat->config->multipoint
|
||||
@ -1940,17 +1957,26 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
|
||||
switch (musb->port_mode) {
|
||||
case MUSB_PORT_MODE_HOST:
|
||||
status = musb_host_setup(musb, plat->power);
|
||||
if (status < 0)
|
||||
goto fail3;
|
||||
status = musb_platform_set_mode(musb, MUSB_HOST);
|
||||
break;
|
||||
case MUSB_PORT_MODE_GADGET:
|
||||
status = musb_gadget_setup(musb);
|
||||
if (status < 0)
|
||||
goto fail3;
|
||||
status = musb_platform_set_mode(musb, MUSB_PERIPHERAL);
|
||||
break;
|
||||
case MUSB_PORT_MODE_DUAL_ROLE:
|
||||
status = musb_host_setup(musb, plat->power);
|
||||
if (status < 0)
|
||||
goto fail3;
|
||||
status = musb_gadget_setup(musb);
|
||||
if (status)
|
||||
if (status) {
|
||||
musb_host_cleanup(musb);
|
||||
goto fail3;
|
||||
}
|
||||
status = musb_platform_set_mode(musb, MUSB_OTG);
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unsupported port mode %d\n", musb->port_mode);
|
||||
@ -1981,6 +2007,8 @@ fail4:
|
||||
|
||||
fail3:
|
||||
cancel_work_sync(&musb->irq_work);
|
||||
cancel_delayed_work_sync(&musb->finish_resume_work);
|
||||
cancel_delayed_work_sync(&musb->deassert_reset_work);
|
||||
if (musb->dma_controller)
|
||||
dma_controller_destroy(musb->dma_controller);
|
||||
fail2_5:
|
||||
@ -2044,6 +2072,8 @@ static int musb_remove(struct platform_device *pdev)
|
||||
dma_controller_destroy(musb->dma_controller);
|
||||
|
||||
cancel_work_sync(&musb->irq_work);
|
||||
cancel_delayed_work_sync(&musb->finish_resume_work);
|
||||
cancel_delayed_work_sync(&musb->deassert_reset_work);
|
||||
musb_free(musb);
|
||||
device_init_wakeup(dev, 0);
|
||||
return 0;
|
||||
@ -2216,16 +2246,28 @@ static int musb_suspend(struct device *dev)
|
||||
*/
|
||||
}
|
||||
|
||||
musb_save_context(musb);
|
||||
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int musb_resume_noirq(struct device *dev)
|
||||
{
|
||||
/* for static cmos like DaVinci, register values were preserved
|
||||
struct musb *musb = dev_to_musb(dev);
|
||||
|
||||
/*
|
||||
* For static cmos like DaVinci, register values were preserved
|
||||
* unless for some reason the whole soc powered down or the USB
|
||||
* module got reset through the PSC (vs just being disabled).
|
||||
*
|
||||
* For the DSPS glue layer though, a full register restore has to
|
||||
* be done. As it shouldn't harm other platforms, we do it
|
||||
* unconditionally.
|
||||
*/
|
||||
|
||||
musb_restore_context(musb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2283,19 +2325,4 @@ static struct platform_driver musb_driver = {
|
||||
.shutdown = musb_shutdown,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __init musb_init(void)
|
||||
{
|
||||
if (usb_disabled())
|
||||
return 0;
|
||||
|
||||
return platform_driver_register(&musb_driver);
|
||||
}
|
||||
module_init(musb_init);
|
||||
|
||||
static void __exit musb_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&musb_driver);
|
||||
}
|
||||
module_exit(musb_cleanup);
|
||||
module_platform_driver(musb_driver);
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/musb.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct musb;
|
||||
struct musb_hw_ep;
|
||||
@ -295,6 +296,8 @@ struct musb {
|
||||
|
||||
irqreturn_t (*isr)(int, void *);
|
||||
struct work_struct irq_work;
|
||||
struct delayed_work deassert_reset_work;
|
||||
struct delayed_work finish_resume_work;
|
||||
u16 hwvers;
|
||||
|
||||
u16 intrrxe;
|
||||
|
@ -83,6 +83,8 @@ struct dsps_musb_wrapper {
|
||||
u16 coreintr_status;
|
||||
u16 phy_utmi;
|
||||
u16 mode;
|
||||
u16 tx_mode;
|
||||
u16 rx_mode;
|
||||
|
||||
/* bit positions for control */
|
||||
unsigned reset:5;
|
||||
@ -106,10 +108,24 @@ struct dsps_musb_wrapper {
|
||||
|
||||
/* bit positions for mode */
|
||||
unsigned iddig:5;
|
||||
unsigned iddig_mux:5;
|
||||
/* miscellaneous stuff */
|
||||
u8 poll_seconds;
|
||||
};
|
||||
|
||||
/*
|
||||
* register shadow for suspend
|
||||
*/
|
||||
struct dsps_context {
|
||||
u32 control;
|
||||
u32 epintr;
|
||||
u32 coreintr;
|
||||
u32 phy_utmi;
|
||||
u32 mode;
|
||||
u32 tx_mode;
|
||||
u32 rx_mode;
|
||||
};
|
||||
|
||||
/**
|
||||
* DSPS glue structure.
|
||||
*/
|
||||
@ -119,6 +135,8 @@ struct dsps_glue {
|
||||
const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
|
||||
struct timer_list timer; /* otg_workaround timer */
|
||||
unsigned long last_timer; /* last timer data for each instance */
|
||||
|
||||
struct dsps_context context;
|
||||
};
|
||||
|
||||
static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
|
||||
@ -341,8 +359,9 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
|
||||
if (musb->int_tx || musb->int_rx || musb->int_usb)
|
||||
ret |= musb_interrupt(musb);
|
||||
|
||||
/* Poll for ID change */
|
||||
if (musb->xceiv->state == OTG_STATE_B_IDLE)
|
||||
/* Poll for ID change in OTG port mode */
|
||||
if (musb->xceiv->state == OTG_STATE_B_IDLE &&
|
||||
musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
|
||||
mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
|
||||
out:
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
@ -406,6 +425,54 @@ static int dsps_musb_exit(struct musb *musb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsps_musb_set_mode(struct musb *musb, u8 mode)
|
||||
{
|
||||
struct device *dev = musb->controller;
|
||||
struct dsps_glue *glue = dev_get_drvdata(dev->parent);
|
||||
const struct dsps_musb_wrapper *wrp = glue->wrp;
|
||||
void __iomem *ctrl_base = musb->ctrl_base;
|
||||
void __iomem *base = musb->mregs;
|
||||
u32 reg;
|
||||
|
||||
reg = dsps_readl(base, wrp->mode);
|
||||
|
||||
switch (mode) {
|
||||
case MUSB_HOST:
|
||||
reg &= ~(1 << wrp->iddig);
|
||||
|
||||
/*
|
||||
* if we're setting mode to host-only or device-only, we're
|
||||
* going to ignore whatever the PHY sends us and just force
|
||||
* ID pin status by SW
|
||||
*/
|
||||
reg |= (1 << wrp->iddig_mux);
|
||||
|
||||
dsps_writel(base, wrp->mode, reg);
|
||||
dsps_writel(ctrl_base, wrp->phy_utmi, 0x02);
|
||||
break;
|
||||
case MUSB_PERIPHERAL:
|
||||
reg |= (1 << wrp->iddig);
|
||||
|
||||
/*
|
||||
* if we're setting mode to host-only or device-only, we're
|
||||
* going to ignore whatever the PHY sends us and just force
|
||||
* ID pin status by SW
|
||||
*/
|
||||
reg |= (1 << wrp->iddig_mux);
|
||||
|
||||
dsps_writel(base, wrp->mode, reg);
|
||||
break;
|
||||
case MUSB_OTG:
|
||||
dsps_writel(base, wrp->phy_utmi, 0x02);
|
||||
break;
|
||||
default:
|
||||
dev_err(glue->dev, "unsupported mode %d\n", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct musb_platform_ops dsps_ops = {
|
||||
.init = dsps_musb_init,
|
||||
.exit = dsps_musb_exit,
|
||||
@ -414,6 +481,7 @@ static struct musb_platform_ops dsps_ops = {
|
||||
.disable = dsps_musb_disable,
|
||||
|
||||
.try_idle = dsps_musb_try_idle,
|
||||
.set_mode = dsps_musb_set_mode,
|
||||
};
|
||||
|
||||
static u64 musb_dmamask = DMA_BIT_MASK(32);
|
||||
@ -507,6 +575,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,
|
||||
|
||||
config->num_eps = get_int_prop(dn, "mentor,num-eps");
|
||||
config->ram_bits = get_int_prop(dn, "mentor,ram-bits");
|
||||
config->host_port_deassert_reset_at_resume = 1;
|
||||
pdata.mode = get_musb_port_mode(dev);
|
||||
/* DT keeps this entry in mA, musb expects it as per USB spec */
|
||||
pdata.power = get_int_prop(dn, "mentor,power") / 2;
|
||||
@ -605,9 +674,12 @@ static const struct dsps_musb_wrapper am33xx_driver_data = {
|
||||
.coreintr_status = 0x34,
|
||||
.phy_utmi = 0xe0,
|
||||
.mode = 0xe8,
|
||||
.tx_mode = 0x70,
|
||||
.rx_mode = 0x74,
|
||||
.reset = 0,
|
||||
.otg_disable = 21,
|
||||
.iddig = 8,
|
||||
.iddig_mux = 7,
|
||||
.usb_shift = 0,
|
||||
.usb_mask = 0x1ff,
|
||||
.usb_bitmap = (0x1ff << 0),
|
||||
@ -628,11 +700,52 @@ static const struct of_device_id musb_dsps_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int dsps_suspend(struct device *dev)
|
||||
{
|
||||
struct dsps_glue *glue = dev_get_drvdata(dev);
|
||||
const struct dsps_musb_wrapper *wrp = glue->wrp;
|
||||
struct musb *musb = platform_get_drvdata(glue->musb);
|
||||
void __iomem *mbase = musb->ctrl_base;
|
||||
|
||||
glue->context.control = dsps_readl(mbase, wrp->control);
|
||||
glue->context.epintr = dsps_readl(mbase, wrp->epintr_set);
|
||||
glue->context.coreintr = dsps_readl(mbase, wrp->coreintr_set);
|
||||
glue->context.phy_utmi = dsps_readl(mbase, wrp->phy_utmi);
|
||||
glue->context.mode = dsps_readl(mbase, wrp->mode);
|
||||
glue->context.tx_mode = dsps_readl(mbase, wrp->tx_mode);
|
||||
glue->context.rx_mode = dsps_readl(mbase, wrp->rx_mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsps_resume(struct device *dev)
|
||||
{
|
||||
struct dsps_glue *glue = dev_get_drvdata(dev);
|
||||
const struct dsps_musb_wrapper *wrp = glue->wrp;
|
||||
struct musb *musb = platform_get_drvdata(glue->musb);
|
||||
void __iomem *mbase = musb->ctrl_base;
|
||||
|
||||
dsps_writel(mbase, wrp->control, glue->context.control);
|
||||
dsps_writel(mbase, wrp->epintr_set, glue->context.epintr);
|
||||
dsps_writel(mbase, wrp->coreintr_set, glue->context.coreintr);
|
||||
dsps_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi);
|
||||
dsps_writel(mbase, wrp->mode, glue->context.mode);
|
||||
dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode);
|
||||
dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
|
||||
|
||||
static struct platform_driver dsps_usbss_driver = {
|
||||
.probe = dsps_probe,
|
||||
.remove = dsps_remove,
|
||||
.driver = {
|
||||
.name = "musb-dsps",
|
||||
.pm = &dsps_pm_ops,
|
||||
.of_match_table = musb_dsps_of_match,
|
||||
},
|
||||
};
|
||||
|
@ -1727,14 +1727,14 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
|
||||
ep->end_point.name = ep->name;
|
||||
INIT_LIST_HEAD(&ep->end_point.ep_list);
|
||||
if (!epnum) {
|
||||
ep->end_point.maxpacket = 64;
|
||||
usb_ep_set_maxpacket_limit(&ep->end_point, 64);
|
||||
ep->end_point.ops = &musb_g_ep0_ops;
|
||||
musb->g.ep0 = &ep->end_point;
|
||||
} else {
|
||||
if (is_in)
|
||||
ep->end_point.maxpacket = hw_ep->max_packet_sz_tx;
|
||||
usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_tx);
|
||||
else
|
||||
ep->end_point.maxpacket = hw_ep->max_packet_sz_rx;
|
||||
usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_rx);
|
||||
ep->end_point.ops = &musb_ep_ops;
|
||||
list_add_tail(&ep->end_point.ep_list, &musb->g.ep_list);
|
||||
}
|
||||
@ -2119,7 +2119,15 @@ __acquires(musb->lock)
|
||||
/* Normal reset, as B-Device;
|
||||
* or else after HNP, as A-Device
|
||||
*/
|
||||
if (devctl & MUSB_DEVCTL_BDEVICE) {
|
||||
if (!musb->g.is_otg) {
|
||||
/* USB device controllers that are not OTG compatible
|
||||
* may not have DEVCTL register in silicon.
|
||||
* In that case, do not rely on devctl for setting
|
||||
* peripheral mode.
|
||||
*/
|
||||
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
|
||||
musb->g.is_a_peripheral = 0;
|
||||
} else if (devctl & MUSB_DEVCTL_BDEVICE) {
|
||||
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
|
||||
musb->g.is_a_peripheral = 0;
|
||||
} else {
|
||||
|
@ -2433,6 +2433,8 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
|
||||
struct musb *musb = hcd_to_musb(hcd);
|
||||
u8 devctl;
|
||||
|
||||
musb_port_suspend(musb, true);
|
||||
|
||||
if (!is_host_active(musb))
|
||||
return 0;
|
||||
|
||||
@ -2462,7 +2464,12 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
|
||||
|
||||
static int musb_bus_resume(struct usb_hcd *hcd)
|
||||
{
|
||||
/* resuming child port does the work */
|
||||
struct musb *musb = hcd_to_musb(hcd);
|
||||
|
||||
if (musb->config &&
|
||||
musb->config->host_port_deassert_reset_at_resume)
|
||||
musb_port_reset(musb, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,9 @@ extern void musb_host_rx(struct musb *, u8);
|
||||
extern void musb_root_disconnect(struct musb *musb);
|
||||
extern void musb_host_resume_root_hub(struct musb *musb);
|
||||
extern void musb_host_poke_root_hub(struct musb *musb);
|
||||
extern void musb_port_suspend(struct musb *musb, bool do_suspend);
|
||||
extern void musb_port_reset(struct musb *musb, bool do_reset);
|
||||
extern void musb_host_finish_resume(struct work_struct *work);
|
||||
#else
|
||||
static inline struct musb *hcd_to_musb(struct usb_hcd *hcd)
|
||||
{
|
||||
@ -121,6 +124,9 @@ static inline void musb_root_disconnect(struct musb *musb) {}
|
||||
static inline void musb_host_resume_root_hub(struct musb *musb) {}
|
||||
static inline void musb_host_poll_rh_status(struct musb *musb) {}
|
||||
static inline void musb_host_poke_root_hub(struct musb *musb) {}
|
||||
static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {}
|
||||
static inline void musb_port_reset(struct musb *musb, bool do_reset) {}
|
||||
static inline void musb_host_finish_resume(struct work_struct *work) {}
|
||||
#endif
|
||||
|
||||
struct usb_hcd;
|
||||
|
@ -44,7 +44,38 @@
|
||||
|
||||
#include "musb_core.h"
|
||||
|
||||
static void musb_port_suspend(struct musb *musb, bool do_suspend)
|
||||
void musb_host_finish_resume(struct work_struct *work)
|
||||
{
|
||||
struct musb *musb;
|
||||
unsigned long flags;
|
||||
u8 power;
|
||||
|
||||
musb = container_of(work, struct musb, finish_resume_work.work);
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
|
||||
power = musb_readb(musb->mregs, MUSB_POWER);
|
||||
power &= ~MUSB_POWER_RESUME;
|
||||
dev_dbg(musb->controller, "root port resume stopped, power %02x\n",
|
||||
power);
|
||||
musb_writeb(musb->mregs, MUSB_POWER, power);
|
||||
|
||||
/*
|
||||
* ISSUE: DaVinci (RTL 1.300) disconnects after
|
||||
* resume of high speed peripherals (but not full
|
||||
* speed ones).
|
||||
*/
|
||||
musb->is_active = 1;
|
||||
musb->port1_status &= ~(USB_PORT_STAT_SUSPEND | MUSB_PORT_STAT_RESUME);
|
||||
musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
|
||||
usb_hcd_poll_rh_status(musb->hcd);
|
||||
/* NOTE: it might really be A_WAIT_BCON ... */
|
||||
musb->xceiv->state = OTG_STATE_A_HOST;
|
||||
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
}
|
||||
|
||||
void musb_port_suspend(struct musb *musb, bool do_suspend)
|
||||
{
|
||||
struct usb_otg *otg = musb->xceiv->otg;
|
||||
u8 power;
|
||||
@ -105,11 +136,11 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
|
||||
|
||||
/* later, GetPortStatus will stop RESUME signaling */
|
||||
musb->port1_status |= MUSB_PORT_STAT_RESUME;
|
||||
musb->rh_timer = jiffies + msecs_to_jiffies(20);
|
||||
schedule_delayed_work(&musb->finish_resume_work, 20);
|
||||
}
|
||||
}
|
||||
|
||||
static void musb_port_reset(struct musb *musb, bool do_reset)
|
||||
void musb_port_reset(struct musb *musb, bool do_reset)
|
||||
{
|
||||
u8 power;
|
||||
void __iomem *mbase = musb->mregs;
|
||||
@ -150,7 +181,7 @@ static void musb_port_reset(struct musb *musb, bool do_reset)
|
||||
|
||||
musb->port1_status |= USB_PORT_STAT_RESET;
|
||||
musb->port1_status &= ~USB_PORT_STAT_ENABLE;
|
||||
musb->rh_timer = jiffies + msecs_to_jiffies(50);
|
||||
schedule_delayed_work(&musb->deassert_reset_work, 50);
|
||||
} else {
|
||||
dev_dbg(musb->controller, "root port reset stopped\n");
|
||||
musb_writeb(mbase, MUSB_POWER,
|
||||
@ -325,36 +356,6 @@ int musb_hub_control(
|
||||
if (wIndex != 1)
|
||||
goto error;
|
||||
|
||||
/* finish RESET signaling? */
|
||||
if ((musb->port1_status & USB_PORT_STAT_RESET)
|
||||
&& time_after_eq(jiffies, musb->rh_timer))
|
||||
musb_port_reset(musb, false);
|
||||
|
||||
/* finish RESUME signaling? */
|
||||
if ((musb->port1_status & MUSB_PORT_STAT_RESUME)
|
||||
&& time_after_eq(jiffies, musb->rh_timer)) {
|
||||
u8 power;
|
||||
|
||||
power = musb_readb(musb->mregs, MUSB_POWER);
|
||||
power &= ~MUSB_POWER_RESUME;
|
||||
dev_dbg(musb->controller, "root port resume stopped, power %02x\n",
|
||||
power);
|
||||
musb_writeb(musb->mregs, MUSB_POWER, power);
|
||||
|
||||
/* ISSUE: DaVinci (RTL 1.300) disconnects after
|
||||
* resume of high speed peripherals (but not full
|
||||
* speed ones).
|
||||
*/
|
||||
|
||||
musb->is_active = 1;
|
||||
musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
|
||||
| MUSB_PORT_STAT_RESUME);
|
||||
musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
|
||||
usb_hcd_poll_rh_status(musb->hcd);
|
||||
/* NOTE: it might really be A_WAIT_BCON ... */
|
||||
musb->xceiv->state = OTG_STATE_A_HOST;
|
||||
}
|
||||
|
||||
put_unaligned(cpu_to_le32(musb->port1_status
|
||||
& ~MUSB_PORT_STAT_RESUME),
|
||||
(__le32 *) buf);
|
||||
|
@ -336,7 +336,9 @@ static int ux500_dma_controller_start(struct ux500_dma_controller *controller)
|
||||
data ?
|
||||
data->dma_filter :
|
||||
NULL,
|
||||
param_array[ch_num]);
|
||||
param_array ?
|
||||
param_array[ch_num] :
|
||||
NULL);
|
||||
|
||||
if (!ux500_channel->dma_chan) {
|
||||
ERR("Dma pipe allocation error dir=%d ch=%d\n",
|
||||
|
@ -6,6 +6,15 @@ menu "USB Physical Layer drivers"
|
||||
config USB_PHY
|
||||
def_bool n
|
||||
|
||||
config USB_OTG_FSM
|
||||
tristate "USB 2.0 OTG FSM implementation"
|
||||
depends on USB
|
||||
select USB_OTG
|
||||
select USB_PHY
|
||||
help
|
||||
Implements OTG Final State Machine as specified in On-The-Go
|
||||
and Embedded Host Supplement to the USB Revision 2.0 Specification.
|
||||
|
||||
#
|
||||
# USB Transceiver Drivers
|
||||
#
|
||||
@ -19,9 +28,8 @@ config AB8500_USB
|
||||
in host mode, low speed.
|
||||
|
||||
config FSL_USB2_OTG
|
||||
tristate "Freescale USB OTG Transceiver Driver"
|
||||
depends on USB_EHCI_FSL && USB_FSL_USB2 && PM_RUNTIME
|
||||
depends on USB
|
||||
bool "Freescale USB OTG Transceiver Driver"
|
||||
depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM_RUNTIME
|
||||
select USB_OTG
|
||||
select USB_PHY
|
||||
help
|
||||
@ -40,7 +48,16 @@ config ISP1301_OMAP
|
||||
Instruments OMAP processors.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called isp1301_omap.
|
||||
will be called phy-isp1301-omap.
|
||||
|
||||
config KEYSTONE_USB_PHY
|
||||
tristate "Keystone USB PHY Driver"
|
||||
depends on ARCH_KEYSTONE || COMPILE_TEST
|
||||
select NOP_USB_XCEIV
|
||||
help
|
||||
Enable this to support Keystone USB phy. This driver provides
|
||||
interface to interact with USB 2.0 and USB 3.0 PHY that is part
|
||||
of the Keystone SOC.
|
||||
|
||||
config MV_U3D_PHY
|
||||
bool "Marvell USB 3.0 PHY controller Driver"
|
||||
@ -136,6 +153,31 @@ config USB_GPIO_VBUS
|
||||
optionally control of a D+ pullup GPIO as well as a VBUS
|
||||
current limit regulator.
|
||||
|
||||
config OMAP_OTG
|
||||
tristate "OMAP USB OTG controller driver"
|
||||
depends on ARCH_OMAP_OTG && EXTCON
|
||||
help
|
||||
Enable this to support some transceivers on OMAP1 platforms. OTG
|
||||
controller is needed to switch between host and peripheral modes.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called phy-omap-otg.
|
||||
|
||||
config TAHVO_USB
|
||||
tristate "Tahvo USB transceiver driver"
|
||||
depends on MFD_RETU && EXTCON
|
||||
select USB_PHY
|
||||
help
|
||||
Enable this to support USB transceiver on Tahvo. This is used
|
||||
at least on Nokia 770.
|
||||
|
||||
config TAHVO_USB_HOST_BY_DEFAULT
|
||||
depends on TAHVO_USB
|
||||
boolean "Device in USB host mode by default"
|
||||
help
|
||||
Say Y here, if you want the device to enter USB host mode
|
||||
by default on bootup.
|
||||
|
||||
config USB_ISP1301
|
||||
tristate "NXP ISP1301 USB transceiver support"
|
||||
depends on USB || USB_GADGET
|
||||
@ -147,7 +189,7 @@ config USB_ISP1301
|
||||
and OTG drivers (to be selected separately).
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called isp1301.
|
||||
module will be called phy-isp1301.
|
||||
|
||||
config USB_MSM_OTG
|
||||
tristate "OTG support for Qualcomm on-chip USB controller"
|
||||
|
@ -3,18 +3,20 @@
|
||||
#
|
||||
obj-$(CONFIG_USB_PHY) += phy.o
|
||||
obj-$(CONFIG_OF) += of.o
|
||||
obj-$(CONFIG_USB_OTG_FSM) += phy-fsm-usb.o
|
||||
|
||||
# transceiver drivers, keep the list sorted
|
||||
|
||||
obj-$(CONFIG_AB8500_USB) += phy-ab8500-usb.o
|
||||
phy-fsl-usb2-objs := phy-fsl-usb.o phy-fsm-usb.o
|
||||
obj-$(CONFIG_FSL_USB2_OTG) += phy-fsl-usb2.o
|
||||
obj-$(CONFIG_FSL_USB2_OTG) += phy-fsl-usb.o
|
||||
obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o
|
||||
obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o
|
||||
obj-$(CONFIG_NOP_USB_XCEIV) += phy-generic.o
|
||||
obj-$(CONFIG_TAHVO_USB) += phy-tahvo.o
|
||||
obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o
|
||||
obj-$(CONFIG_AM335X_CONTROL_USB) += phy-am335x-control.o
|
||||
obj-$(CONFIG_AM335X_PHY_USB) += phy-am335x.o
|
||||
obj-$(CONFIG_OMAP_OTG) += phy-omap-otg.o
|
||||
obj-$(CONFIG_OMAP_USB3) += phy-omap-usb3.o
|
||||
obj-$(CONFIG_SAMSUNG_USBPHY) += phy-samsung-usb.o
|
||||
obj-$(CONFIG_SAMSUNG_USB2PHY) += phy-samsung-usb2.o
|
||||
@ -30,3 +32,4 @@ obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o
|
||||
obj-$(CONFIG_USB_RCAR_GEN2_PHY) += phy-rcar-gen2-usb.o
|
||||
obj-$(CONFIG_USB_ULPI) += phy-ulpi.o
|
||||
obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o
|
||||
obj-$(CONFIG_KEYSTONE_USB_PHY) += phy-keystone.o
|
||||
|
@ -1415,8 +1415,6 @@ static int ab8500_usb_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, ab);
|
||||
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier);
|
||||
|
||||
/* all: Disable phy when called from set_host and set_peripheral */
|
||||
INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
|
||||
|
||||
|
@ -3,11 +3,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
struct phy_control {
|
||||
void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on);
|
||||
void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on);
|
||||
};
|
||||
#include "am35x-phy-control.h"
|
||||
|
||||
struct am335x_control_usb {
|
||||
struct device *dev;
|
||||
|
@ -63,6 +63,19 @@ static int am335x_phy_probe(struct platform_device *pdev)
|
||||
am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown;
|
||||
|
||||
platform_set_drvdata(pdev, am_phy);
|
||||
device_init_wakeup(dev, true);
|
||||
|
||||
/*
|
||||
* If we leave PHY wakeup enabled then AM33XX wakes up
|
||||
* immediately from DS0. To avoid this we mark dev->power.can_wakeup
|
||||
* to false. The same is checked in suspend routine to decide
|
||||
* on whether to enable PHY wakeup or not.
|
||||
* PHY wakeup works fine in standby mode, there by allowing us to
|
||||
* handle remote wakeup, wakeup on disconnect and connect.
|
||||
*/
|
||||
|
||||
device_set_wakeup_enable(dev, false);
|
||||
phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -75,38 +88,48 @@ static int am335x_phy_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
|
||||
static int am335x_phy_runtime_suspend(struct device *dev)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int am335x_phy_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct am335x_phy *am_phy = platform_get_drvdata(pdev);
|
||||
|
||||
/*
|
||||
* Enable phy wakeup only if dev->power.can_wakeup is true.
|
||||
* Make sure to enable wakeup to support remote wakeup in
|
||||
* standby mode ( same is not supported in OFF(DS0) mode).
|
||||
* Enable it by doing
|
||||
* echo enabled > /sys/bus/platform/devices/<usb-phy-id>/power/wakeup
|
||||
*/
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, true);
|
||||
|
||||
phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int am335x_phy_runtime_resume(struct device *dev)
|
||||
static int am335x_phy_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct am335x_phy *am_phy = platform_get_drvdata(pdev);
|
||||
|
||||
phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops am335x_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(am335x_phy_runtime_suspend,
|
||||
am335x_phy_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(am335x_phy_suspend, am335x_phy_resume)
|
||||
};
|
||||
|
||||
#define DEV_PM_OPS (&am335x_pm_ops)
|
||||
#define DEV_PM_OPS (&am335x_pm_ops)
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static const struct of_device_id am335x_phy_ids[] = {
|
||||
|
@ -848,7 +848,7 @@ static int fsl_otg_conf(struct platform_device *pdev)
|
||||
pr_info("Couldn't init OTG timers\n");
|
||||
goto err;
|
||||
}
|
||||
spin_lock_init(&fsl_otg_tc->fsm.lock);
|
||||
mutex_init(&fsl_otg_tc->fsm.lock);
|
||||
|
||||
/* Set OTG state machine operations */
|
||||
fsl_otg_tc->fsm.ops = &fsl_otg_ops;
|
||||
@ -1017,10 +1017,9 @@ static int show_fsl_usb2_otg_state(struct device *dev,
|
||||
struct otg_fsm *fsm = &fsl_otg_dev->fsm;
|
||||
char *next = buf;
|
||||
unsigned size = PAGE_SIZE;
|
||||
unsigned long flags;
|
||||
int t;
|
||||
|
||||
spin_lock_irqsave(&fsm->lock, flags);
|
||||
mutex_lock(&fsm->lock);
|
||||
|
||||
/* basic driver infomation */
|
||||
t = scnprintf(next, size,
|
||||
@ -1088,7 +1087,7 @@ static int show_fsl_usb2_otg_state(struct device *dev,
|
||||
size -= t;
|
||||
next += t;
|
||||
|
||||
spin_unlock_irqrestore(&fsm->lock, flags);
|
||||
mutex_unlock(&fsm->lock);
|
||||
|
||||
return PAGE_SIZE - size;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "phy-fsm-usb.h"
|
||||
#include <linux/usb/otg-fsm.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
|
@ -23,13 +23,12 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/otg.h>
|
||||
|
||||
#include "phy-fsm-usb.h"
|
||||
#include <linux/usb/otg-fsm.h>
|
||||
|
||||
/* Change USB protocol when there is a protocol change */
|
||||
static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
|
||||
@ -65,7 +64,7 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
|
||||
static int state_changed;
|
||||
|
||||
/* Called when leaving a state. Do state clean up jobs here */
|
||||
void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
|
||||
static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
|
||||
{
|
||||
switch (old_state) {
|
||||
case OTG_STATE_B_IDLE:
|
||||
@ -122,7 +121,7 @@ void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
|
||||
}
|
||||
|
||||
/* Called when entering a state */
|
||||
int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
|
||||
static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
|
||||
{
|
||||
state_changed = 1;
|
||||
if (fsm->otg->phy->state == new_state)
|
||||
@ -245,9 +244,8 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
|
||||
int otg_statemachine(struct otg_fsm *fsm)
|
||||
{
|
||||
enum usb_otg_state state;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&fsm->lock, flags);
|
||||
mutex_lock(&fsm->lock);
|
||||
|
||||
state = fsm->otg->phy->state;
|
||||
state_changed = 0;
|
||||
@ -359,7 +357,7 @@ int otg_statemachine(struct otg_fsm *fsm)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&fsm->lock, flags);
|
||||
mutex_unlock(&fsm->lock);
|
||||
|
||||
VDBG("quit statemachine, changed = %d\n", state_changed);
|
||||
return state_changed;
|
||||
|
@ -241,7 +241,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
|
||||
nop->phy.otg->set_host = nop_set_host;
|
||||
nop->phy.otg->set_peripheral = nop_set_peripheral;
|
||||
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy);
|
||||
|
@ -314,8 +314,6 @@ static int gpio_vbus_probe(struct platform_device *pdev)
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier);
|
||||
|
||||
INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work);
|
||||
|
||||
gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw");
|
||||
|
@ -1277,7 +1277,7 @@ isp1301_set_host(struct usb_otg *otg, struct usb_bus *host)
|
||||
{
|
||||
struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy);
|
||||
|
||||
if (!otg || isp != the_transceiver)
|
||||
if (isp != the_transceiver)
|
||||
return -ENODEV;
|
||||
|
||||
if (!host) {
|
||||
@ -1333,7 +1333,7 @@ isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
|
||||
{
|
||||
struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy);
|
||||
|
||||
if (!otg || isp != the_transceiver)
|
||||
if (isp != the_transceiver)
|
||||
return -ENODEV;
|
||||
|
||||
if (!gadget) {
|
||||
@ -1414,8 +1414,7 @@ isp1301_start_srp(struct usb_otg *otg)
|
||||
struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy);
|
||||
u32 otg_ctrl;
|
||||
|
||||
if (!otg || isp != the_transceiver
|
||||
|| isp->phy.state != OTG_STATE_B_IDLE)
|
||||
if (isp != the_transceiver || isp->phy.state != OTG_STATE_B_IDLE)
|
||||
return -ENODEV;
|
||||
|
||||
otg_ctrl = omap_readl(OTG_CTRL);
|
||||
@ -1442,7 +1441,7 @@ isp1301_start_hnp(struct usb_otg *otg)
|
||||
struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy);
|
||||
u32 l;
|
||||
|
||||
if (!otg || isp != the_transceiver)
|
||||
if (isp != the_transceiver)
|
||||
return -ENODEV;
|
||||
if (otg->default_a && (otg->host == NULL || !otg->host->b_hnp_enable))
|
||||
return -ENOTCONN;
|
||||
|
136
drivers/usb/phy/phy-keystone.c
Normal file
136
drivers/usb/phy/phy-keystone.c
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* phy-keystone - USB PHY, talking to dwc3 controller in Keystone.
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Author: WingMan Kwok <w-kwok2@ti.com>
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/usb_phy_gen_xceiv.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "phy-generic.h"
|
||||
|
||||
/* USB PHY control register offsets */
|
||||
#define USB_PHY_CTL_UTMI 0x0000
|
||||
#define USB_PHY_CTL_PIPE 0x0004
|
||||
#define USB_PHY_CTL_PARAM_1 0x0008
|
||||
#define USB_PHY_CTL_PARAM_2 0x000c
|
||||
#define USB_PHY_CTL_CLOCK 0x0010
|
||||
#define USB_PHY_CTL_PLL 0x0014
|
||||
|
||||
#define PHY_REF_SSP_EN BIT(29)
|
||||
|
||||
struct keystone_usbphy {
|
||||
struct usb_phy_gen_xceiv usb_phy_gen;
|
||||
void __iomem *phy_ctrl;
|
||||
};
|
||||
|
||||
static inline u32 keystone_usbphy_readl(void __iomem *base, u32 offset)
|
||||
{
|
||||
return readl(base + offset);
|
||||
}
|
||||
|
||||
static inline void keystone_usbphy_writel(void __iomem *base,
|
||||
u32 offset, u32 value)
|
||||
{
|
||||
writel(value, base + offset);
|
||||
}
|
||||
|
||||
static int keystone_usbphy_init(struct usb_phy *phy)
|
||||
{
|
||||
struct keystone_usbphy *k_phy = dev_get_drvdata(phy->dev);
|
||||
u32 val;
|
||||
|
||||
val = keystone_usbphy_readl(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK);
|
||||
keystone_usbphy_writel(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK,
|
||||
val | PHY_REF_SSP_EN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void keystone_usbphy_shutdown(struct usb_phy *phy)
|
||||
{
|
||||
struct keystone_usbphy *k_phy = dev_get_drvdata(phy->dev);
|
||||
u32 val;
|
||||
|
||||
val = keystone_usbphy_readl(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK);
|
||||
keystone_usbphy_writel(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK,
|
||||
val &= ~PHY_REF_SSP_EN);
|
||||
}
|
||||
|
||||
static int keystone_usbphy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct keystone_usbphy *k_phy;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
k_phy = devm_kzalloc(dev, sizeof(*k_phy), GFP_KERNEL);
|
||||
if (!k_phy)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
k_phy->phy_ctrl = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(k_phy->phy_ctrl))
|
||||
return PTR_ERR(k_phy->phy_ctrl);
|
||||
|
||||
ret = usb_phy_gen_create_phy(dev, &k_phy->usb_phy_gen, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
k_phy->usb_phy_gen.phy.init = keystone_usbphy_init;
|
||||
k_phy->usb_phy_gen.phy.shutdown = keystone_usbphy_shutdown;
|
||||
|
||||
platform_set_drvdata(pdev, k_phy);
|
||||
|
||||
ret = usb_add_phy_dev(&k_phy->usb_phy_gen.phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int keystone_usbphy_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct keystone_usbphy *k_phy = platform_get_drvdata(pdev);
|
||||
|
||||
usb_remove_phy(&k_phy->usb_phy_gen.phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id keystone_usbphy_ids[] = {
|
||||
{ .compatible = "ti,keystone-usbphy" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, keystone_usbphy_ids);
|
||||
|
||||
static struct platform_driver keystone_usbphy_driver = {
|
||||
.probe = keystone_usbphy_probe,
|
||||
.remove = keystone_usbphy_remove,
|
||||
.driver = {
|
||||
.name = "keystone-usbphy",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = keystone_usbphy_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(keystone_usbphy_driver);
|
||||
|
||||
MODULE_ALIAS("platform:keystone-usbphy");
|
||||
MODULE_AUTHOR("Texas Instruments Inc.");
|
||||
MODULE_DESCRIPTION("Keystone USB phy driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -63,9 +63,13 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
|
||||
|
||||
static int mxs_phy_init(struct usb_phy *phy)
|
||||
{
|
||||
int ret;
|
||||
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
|
||||
|
||||
clk_prepare_enable(mxs_phy->clk);
|
||||
ret = clk_prepare_enable(mxs_phy->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mxs_phy_hw_init(mxs_phy);
|
||||
}
|
||||
|
||||
@ -81,6 +85,7 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
|
||||
|
||||
static int mxs_phy_suspend(struct usb_phy *x, int suspend)
|
||||
{
|
||||
int ret;
|
||||
struct mxs_phy *mxs_phy = to_mxs_phy(x);
|
||||
|
||||
if (suspend) {
|
||||
@ -89,7 +94,9 @@ static int mxs_phy_suspend(struct usb_phy *x, int suspend)
|
||||
x->io_priv + HW_USBPHY_CTRL_SET);
|
||||
clk_disable_unprepare(mxs_phy->clk);
|
||||
} else {
|
||||
clk_prepare_enable(mxs_phy->clk);
|
||||
ret = clk_prepare_enable(mxs_phy->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
writel(BM_USBPHY_CTRL_CLKGATE,
|
||||
x->io_priv + HW_USBPHY_CTRL_CLR);
|
||||
writel(0, x->io_priv + HW_USBPHY_PWD);
|
||||
@ -160,8 +167,6 @@ static int mxs_phy_probe(struct platform_device *pdev)
|
||||
mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect;
|
||||
mxs_phy->phy.type = USB_PHY_TYPE_USB2;
|
||||
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&mxs_phy->phy.notifier);
|
||||
|
||||
mxs_phy->clk = clk;
|
||||
|
||||
platform_set_drvdata(pdev, mxs_phy);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user